Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 59 additions & 39 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ include(CheckOpenSSLIsQuictls)
include(CheckOpenSSLIsAwsLc)
include(CheckOpenSSLHasQuicTlsCbs)
include(CheckOpenSSLHasNativeQuic)
include(CheckQuicheHasQmux)
find_package(OpenSSL REQUIRED)
check_openssl_is_boringssl(SSLLIB_IS_BORINGSSL BORINGSSL_VERSION "${OPENSSL_INCLUDE_DIR}")
check_openssl_is_awslc(SSLLIB_IS_AWSLC AWSLC_VERSION "${OPENSSL_INCLUDE_DIR}")
Expand Down Expand Up @@ -329,41 +330,19 @@ endif()

check_openssl_has_native_quic(SSLLIB_HAS_NATIVE_QUIC "${OPENSSL_INCLUDE_DIR}")

if(DEFINED ENABLE_OPENSSL_QUIC
AND NOT ENABLE_OPENSSL_QUIC STREQUAL "AUTO"
AND ENABLE_OPENSSL_QUIC
)
if(ENABLE_QUICHE)
message(FATAL_ERROR "ENABLE_OPENSSL_QUIC and ENABLE_QUICHE are mutually exclusive QUIC backends")
endif()
if(NOT SSLLIB_HAS_NATIVE_QUIC)
message(FATAL_ERROR "OpenSSL native QUIC support requires OpenSSL 3.5 or newer with OSSL_QUIC_server_method")
endif()
if(SSLLIB_IS_BORINGSSL
OR SSLLIB_IS_AWSLC
OR SSLLIB_IS_QUICTLS
)
message(FATAL_ERROR "OpenSSL native QUIC support requires upstream OpenSSL 3.5 or newer")
endif()
endif()

set(OPENSSL_QUIC_AVAILABLE ${SSLLIB_HAS_NATIVE_QUIC})
if(SSLLIB_IS_BORINGSSL
OR SSLLIB_IS_AWSLC
OR SSLLIB_IS_QUICTLS
OR ENABLE_QUICHE
# OpenSSL's native QUIC is a capability of the mandatory OpenSSL dependency, not an optional
# component to opt into -- same footing as SSLLIB_IS_BORINGSSL or SSLLIB_HAS_QUIC_TLS_CBS above.
# It's mutually exclusive with quiche by construction: quiche requires BoringSSL or the TLS
# callback compat shim, neither of which implements this upstream-OpenSSL-3.5+ API.
set(TS_HAS_OPENSSL_QUIC FALSE)
if(SSLLIB_HAS_NATIVE_QUIC
AND NOT SSLLIB_IS_BORINGSSL
AND NOT SSLLIB_IS_AWSLC
AND NOT SSLLIB_IS_QUICTLS
AND NOT ENABLE_QUICHE
)
set(OPENSSL_QUIC_AVAILABLE FALSE)
set(TS_HAS_OPENSSL_QUIC TRUE)
endif()
auto_option(
OPENSSL_QUIC
FEATURE_VAR
TS_HAS_OPENSSL_QUIC
DESCRIPTION
"Use OpenSSL native QUIC"
VAR_DEPENDS
OPENSSL_QUIC_AVAILABLE
)

if(ENABLE_PROFILER)
find_package(profiler REQUIRED)
Expand All @@ -380,19 +359,13 @@ elseif(TS_HAS_MIMALLOC)
link_libraries(mimalloc)
endif()

if(TS_HAS_OPENSSL_QUIC)
set(TS_USE_QUIC TRUE)
message(STATUS "Using OpenSSL native QUIC")
endif()

if(ENABLE_QUICHE)
if(TS_OPENSSL_QUIC_TLS_CBS_COMPAT)
set(quiche_USE_STATIC TRUE)
endif()
find_package(quiche REQUIRED)

set(TS_HAS_QUICHE ${quiche_FOUND})
set(TS_USE_QUIC ${TS_HAS_QUICHE})
if(NOT SSLLIB_IS_BORINGSSL
AND NOT SSLLIB_IS_QUICTLS
AND NOT TS_OPENSSL_QUIC_TLS_CBS_COMPAT
Expand All @@ -411,6 +384,53 @@ if(ENABLE_QUICHE)
elseif(TS_OPENSSL_QUIC_TLS_CBS_COMPAT)
message(STATUS "Using OpenSSL QUIC TLS callbacks compatibility for quiche")
endif()

check_quiche_has_qmux(TS_QUICHE_HAS_QMUX)
endif()

# A QUIC backend supplies the protocol implementation; the transport options
# below decide how QUIC streams are actually carried on the wire. At least one
# transport must be enabled for QUIC to be reachable.
if(TS_HAS_OPENSSL_QUIC OR TS_HAS_QUICHE)
set(TS_HAS_QUIC_BACKEND TRUE)
else()
set(TS_HAS_QUIC_BACKEND FALSE)
endif()

auto_option(
QUIC
DESCRIPTION
"Carry QUIC over UDP (default AUTO: on when a QUIC backend is available)"
FEATURE_VAR
TS_USE_QUIC
VAR_DEPENDS
TS_HAS_QUIC_BACKEND
)

if(TS_USE_QUIC)
if(TS_HAS_OPENSSL_QUIC)
message(STATUS "Using OpenSSL native QUIC")
elseif(TS_HAS_QUICHE)
message(STATUS "Using quiche for QUIC transport")
endif()
endif()

auto_option(
QMUX
DESCRIPTION
"Carry QUIC over TLS/TCP as QMux (default AUTO: on when quiche has qmux support)"
FEATURE_VAR
TS_USE_QMUX
VAR_DEPENDS
TS_HAS_QUICHE
TS_QUICHE_HAS_QMUX
)

if(TS_HAS_QUIC_BACKEND
AND NOT TS_USE_QUIC
AND NOT TS_USE_QMUX
)
message(WARNING "A QUIC backend is enabled but neither UDP QUIC nor QMux is, so QUIC will not be served.")
endif()

find_package(maxminddb) # Header_rewrite experimental/maxmind_acl
Expand Down
41 changes: 41 additions & 0 deletions cmake/CheckQuicheHasQmux.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#######################
#
# 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.
#
#######################

# quiche.h always declares quiche_config_enable_qmux(), regardless of whether quiche was built
# with its `qmux` Rust feature -- only the compiled library conditionally exports the symbol. So
# this must be a full compile-and-link check against the actual quiche library, not a header-only
# check, or it would report qmux support as available even when the linked quiche lacks it.
function(CHECK_QUICHE_HAS_QMUX OUT_VAR)
set(CHECK_PROGRAM
"
#include <quiche.h>

int main() {
quiche_config *config = quiche_config_new(QUICHE_PROTOCOL_VERSION);
quiche_config_enable_qmux(config, true);
return 0;
}
"
)
set(CMAKE_REQUIRED_LIBRARIES quiche::quiche)
include(CheckCXXSourceCompiles)
check_cxx_source_compiles("${CHECK_PROGRAM}" ${OUT_VAR})
set(${OUT_VAR}
${${OUT_VAR}}
PARENT_SCOPE
)
endfunction()
132 changes: 132 additions & 0 deletions include/iocore/net/qmux/QMuxConnection.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/** @file

QMux connection wrapping quiche_conn (draft-opik-quic-qmux-01)

@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 "iocore/net/quic/QUICConnection.h"
#include "iocore/net/quic/QUICStream.h"
#include "iocore/eventsystem/Continuation.h"
#include "tscore/ink_inet.h"

#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>

struct quiche_conn;
struct quiche_config;

class Event;
class NetVConnection;
class VIO;
class MIOBuffer;
class IOBufferReader;
class QUICContext;
class QUICApplicationMap;
class QUICStreamManager;

/**
* QMux connection implementing QUICConnection interface.
* Wraps a quiche_conn* created with QMux-enabled config.
* Also acts as the I/O event handler (Continuation) that bridges
* the SSLNetVConnection byte stream to quiche framing, and as the
* QUICStreamIO backend that QUICStream uses to move stream data.
*/
class QMuxConnection : public QUICConnection, public Continuation, public QUICStreamIO
{
public:
explicit QMuxConnection(NetVConnection *netvc);
~QMuxConnection() override;

// QUICConnectionInfoProvider
QUICConnectionId peer_connection_id() const override;
QUICConnectionId original_connection_id() const override;
QUICConnectionId first_connection_id() const override;
QUICConnectionId retry_source_connection_id() const override;
QUICConnectionId initial_source_connection_id() const override;
QUICConnectionId connection_id() const override;
std::string_view cids() const override;
const QUICFiveTuple five_tuple() const override;
uint32_t pmtu() const override;
NetVConnectionContext_t direction() const override;
bool is_closed() const override;
bool is_at_anti_amplification_limit() const override;
bool is_address_validation_completed() const override;
bool is_handshake_completed() const override;
QUICVersion negotiated_version() const override;
std::string_view negotiated_application_name() const override;
void on_stream_updated() override;

// QUICStreamIO
int64_t read_stream(QUICStreamId stream_id, uint8_t *buf, size_t len, bool &fin, QUICStreamIO::ErrorCode &error_code) override;
bool stream_read_finished(QUICStreamId stream_id) override;
int64_t stream_write_capacity(QUICStreamId stream_id) override;
int64_t write_stream(QUICStreamId stream_id, uint8_t const *buf, size_t len, bool fin,
QUICStreamIO::ErrorCode &error_code) override;

// QUICConnection
QUICStreamManager *stream_manager() override;
void close_quic_connection(QUICConnectionErrorUPtr error) override;
void reset_quic_connection() override;
void handle_received_packet(UDPPacket *packet) override;
void ping() override;

void start(NetVConnection *netvc);
void signal_write_ready();

private:
int main_event(int event, void *data);
void _handle_read();
void _handle_write();
void _flush_quiche_output();
void _handle_read_streams();
void _handle_write_streams();
void _schedule_quiche_timeout();
void _unschedule_quiche_timeout();

static quiche_config *_shared_config;
static void _init_shared_config();

quiche_conn *_quiche_con = nullptr;

sockaddr_storage _local_addr = {};
socklen_t _local_addr_len = 0;
sockaddr_storage _peer_addr = {};
socklen_t _peer_addr_len = 0;

std::unique_ptr<QUICApplicationMap> _app_map;
std::unique_ptr<QUICContext> _context;
std::unique_ptr<QUICStreamManager> _stream_manager;

QUICConnectionId _synthetic_cid;
std::string _cids_str;

bool _closed = false;
bool _in_write = false;

MIOBuffer *_read_buf = nullptr;
IOBufferReader *_read_reader = nullptr;
MIOBuffer *_write_buf = nullptr;
VIO *_write_vio = nullptr;
Event *_quiche_timeout = nullptr;
};
2 changes: 1 addition & 1 deletion include/iocore/net/quic/QUICStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ class QUICStream

QUICStream() {}
QUICStream(QUICConnectionInfoProvider *cinfo, QUICStreamId sid);
~QUICStream();
virtual ~QUICStream();

QUICStreamId id() const;
const QUICConnectionInfoProvider *connection_info();
Expand Down
3 changes: 3 additions & 0 deletions include/ts/apidefs.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -1512,13 +1512,15 @@ extern const char *const TS_ALPN_PROTOCOL_HTTP_3;
extern const char *const TS_ALPN_PROTOCOL_HTTP_3_D29;
extern const char *const TS_ALPN_PROTOCOL_HTTP_QUIC;
extern const char *const TS_ALPN_PROTOCOL_HTTP_QUIC_D29;
extern const char *const TS_ALPN_PROTOCOL_H3QX;

extern int TS_ALPN_PROTOCOL_INDEX_HTTP_0_9;
extern int TS_ALPN_PROTOCOL_INDEX_HTTP_1_0;
extern int TS_ALPN_PROTOCOL_INDEX_HTTP_1_1;
extern int TS_ALPN_PROTOCOL_INDEX_HTTP_2_0;
extern int TS_ALPN_PROTOCOL_INDEX_HTTP_3;
extern int TS_ALPN_PROTOCOL_INDEX_HTTP_QUIC;
extern int TS_ALPN_PROTOCOL_INDEX_H3QX;

extern const char *const TS_ALPN_PROTOCOL_GROUP_HTTP;
extern const char *const TS_ALPN_PROTOCOL_GROUP_HTTP2;
Expand All @@ -1528,6 +1530,7 @@ extern const char *const TS_PROTO_TAG_HTTP_1_1;
extern const char *const TS_PROTO_TAG_HTTP_2_0;
extern const char *const TS_PROTO_TAG_HTTP_3;
extern const char *const TS_PROTO_TAG_HTTP_QUIC;
extern const char *const TS_PROTO_TAG_H3QX;
extern const char *const TS_PROTO_TAG_TLS_1_3;
extern const char *const TS_PROTO_TAG_TLS_1_2;
extern const char *const TS_PROTO_TAG_TLS_1_1;
Expand Down
1 change: 1 addition & 0 deletions include/tscore/ink_config.h.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ const int DEFAULT_STACKSIZE = @DEFAULT_STACK_SIZE@;
#cmakedefine01 TS_USE_ALLOCATOR_METRICS
#cmakedefine01 TS_USE_POSIX_CAP
#cmakedefine01 TS_USE_QUIC
#cmakedefine01 TS_USE_QMUX
#cmakedefine01 TS_USE_REMOTE_UNWINDING
#cmakedefine01 TS_USE_TLS13
#cmakedefine01 TS_USE_TLS_ASYNC
Expand Down
1 change: 1 addition & 0 deletions include/tscore/ink_inet.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ extern const std::string_view IP_PROTO_TAG_HTTP_QUIC;
extern const std::string_view IP_PROTO_TAG_HTTP_3;
extern const std::string_view IP_PROTO_TAG_HTTP_QUIC_D29;
extern const std::string_view IP_PROTO_TAG_HTTP_3_D29;
extern const std::string_view IP_PROTO_TAG_H3QX;

struct IpAddr; // forward declare.
struct UnAddr; // forward declare.
Expand Down
Loading