Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0RTT, Early data, session ticketing, key verification, stateless reset #153

Open
wants to merge 17 commits into
base: dev
Choose a base branch
from
Open
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
43 changes: 29 additions & 14 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
BasedOnStyle: Google

AccessModifierOffset: -2

# alignment
AlignAfterOpenBracket: AlwaysBreak
AlignConsecutiveAssignments: 'false'
AlignConsecutiveDeclarations: 'false'
AlignEscapedNewlines: Left
AlignOperands: AlignAfterOperator
AlignTrailingComments: 'true'

# inlining
AllowAllArgumentsOnNextLine: 'true'
AllowShortBlocksOnASingleLine: 'false'
AllowShortCaseLabelsOnASingleLine: 'false'
AllowShortFunctionsOnASingleLine: Inline
AllowShortFunctionsOnASingleLine: 'Inline'
AllowShortIfStatementsOnASingleLine: 'false'
AllowShortLoopsOnASingleLine: 'false'
RequiresClausePosition: 'OwnLine'

# breaking
AlwaysBreakAfterReturnType: None
AlwaysBreakTemplateDeclarations: Yes
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeConceptDeclarations: 'Always'
BreakBeforeTernaryOperators: 'true'
BreakConstructorInitializers: AfterColon
PenaltyBreakString: '3'

# bracing
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
Expand All @@ -33,29 +48,29 @@ BraceWrapping:
SplitEmptyFunction: false
SplitEmptyRecord: false
SplitEmptyNamespace: false
BreakBeforeTernaryOperators: 'true'
BreakConstructorInitializers: AfterColon

ColumnLimit: 125
CompactNamespaces: 'true'
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: 'true'
IndentWidth: 4
KeepEmptyLinesAtTheStartOfBlocks: 'true'
NamespaceIndentation: All
CompactNamespaces: 'true'
PenaltyBreakString: '3'
QualifierAlignment: Left
RemoveSemicolon: true
SortIncludes: true

# spacing
SpaceBeforeParens: ControlStatements
SpacesInAngles: 'false'
SpacesInContainerLiterals: 'false'
SpacesInParentheses: 'false'
SpacesInSquareBrackets: 'false'

Standard: c++20
UseTab: Never
SortIncludes: true
ColumnLimit: 125
IndentWidth: 4
AccessModifierOffset: -2
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
QualifierAlignment: Left

RemoveSemicolon: true
UseTab: Never

# treat pointers and reference declarations as if part of the type
DerivePointerAlignment: false
Expand Down
13 changes: 8 additions & 5 deletions .drone.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ local clang(version) = debian_pipeline(
cmake_extra='-DCMAKE_C_COMPILER=clang-' + version + ' -DCMAKE_CXX_COMPILER=clang++-' + version + ' '
);

local full_llvm(version) = debian_pipeline(
local full_llvm(version, _allow_fail=false) = debian_pipeline(
'Debian sid/llvm-' + version,
docker_base + 'debian-sid-clang',
deps=['clang-' + version, ' lld-' + version, ' libc++-' + version + '-dev', 'libc++abi-' + version + '-dev']
Expand All @@ -238,7 +238,8 @@ local full_llvm(version) = debian_pipeline(
'-DCMAKE_' + type + '_LINKER_FLAGS=-fuse-ld=lld-' + version
for type in ['EXE', 'MODULE', 'SHARED']
]) +
' -DOXEN_LOGGING_FORCE_SUBMODULES=ON'
' -DOXEN_LOGGING_FORCE_SUBMODULES=ON',
allow_fail=_allow_fail
);

// Macos build
Expand Down Expand Up @@ -288,7 +289,7 @@ local mac_builder(name,
'echo "Building on ${DRONE_STAGE_MACHINE}"',
apt_get_quiet + ' update',
apt_get_quiet + ' install -y eatmydata',
'eatmydata ' + apt_get_quiet + ' install --no-install-recommends -y git clang-format-15 jsonnet',
'eatmydata ' + apt_get_quiet + ' install --no-install-recommends -y git clang-format-16 jsonnet',
'./utils/ci/lint-check.sh',
],
}],
Expand All @@ -297,8 +298,10 @@ local mac_builder(name,
// Various debian builds
debian_pipeline('Debian sid', docker_base + 'debian-sid'),
debian_pipeline('Debian sid/Debug', docker_base + 'debian-sid', build_type='Debug'),
clang(16),
full_llvm(16),
clang(17),
full_llvm(17),
clang(18),
full_llvm(18, true), // will fail on warning RE: libc++-19 char_traits
debian_pipeline('Debian sid -GSO', docker_base + 'debian-sid', cmake_extra='-DLIBQUIC_SEND=sendmmsg'),
debian_pipeline('Debian sid -mmsg', docker_base + 'debian-sid', cmake_extra='-DLIBQUIC_SEND=sendmsg -DLIBQUIC_RECVMMSG=OFF'),
debian_pipeline('Debian sid -GSO/Debug', docker_base + 'debian-sid', build_type='Debug', cmake_extra='-DLIBQUIC_SEND=sendmmsg'),
Expand Down
31 changes: 19 additions & 12 deletions include/oxen/quic/address.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

#include "formattable.hpp"
#include "ip.hpp"
#include "utils.hpp"
#include "types.hpp"

#if defined(__OpenBSD__) || defined(__DragonFly__)
// These systems are known to disallow dual stack binding, and so on such systems when
Expand All @@ -25,8 +25,17 @@ namespace oxen::quic
{
inline constexpr std::array<uint8_t, 16> _ipv6_any_addr = {0};

template <typename T>
concept RawSockAddr = std::same_as<T, sockaddr> || std::same_as<T, sockaddr_in> || std::same_as<T, sockaddr_in6>;
struct Address;

inline namespace concepts
{
template <typename T>
concept raw_sockaddr_type =
std::same_as<T, sockaddr> || std::same_as<T, sockaddr_in> || std::same_as<T, sockaddr_in6>;

template <typename T>
concept quic_address_type = std::derived_from<T, Address>;
} // namespace concepts

// Holds an address, with a ngtcp2_addr held for easier passing into ngtcp2 functions
struct Address
Expand Down Expand Up @@ -71,7 +80,7 @@ namespace oxen::quic
explicit Address(const ipv6& v6, uint16_t port = 0);

// Assignment from a sockaddr pointer; we copy the sockaddr's contents
template <RawSockAddr T>
template <concepts::raw_sockaddr_type T>
Address& operator=(const T* s)
{
_addr.addrlen = std::is_same_v<T, sockaddr>
Expand Down Expand Up @@ -215,12 +224,12 @@ namespace oxen::quic
// pointer to other things (like bool) won't occur.
//
// If the given pointer is mutated you *must* call update_socklen() afterwards.
template <RawSockAddr T>
template <concepts::raw_sockaddr_type T>
operator T*()
{
return reinterpret_cast<T*>(&_sock_addr);
}
template <RawSockAddr T>
template <concepts::raw_sockaddr_type T>
operator const T*() const
{
return reinterpret_cast<const T*>(&_sock_addr);
Expand Down Expand Up @@ -366,12 +375,10 @@ namespace oxen::quic

namespace std
{
inline constexpr size_t inverse_golden_ratio = sizeof(size_t) >= 8 ? 0x9e37'79b9'7f4a'7c15 : 0x9e37'79b9;

template <>
struct hash<oxen::quic::Address>
{
size_t operator()(const oxen::quic::Address& addr) const
size_t operator()(const oxen::quic::Address& addr) const noexcept
{
std::string_view addr_data;
uint16_t port;
Expand All @@ -390,18 +397,18 @@ namespace std
}

auto h = hash<string_view>{}(addr_data);
h ^= hash<decltype(port)>{}(port) + inverse_golden_ratio + (h << 6) + (h >> 2);
h ^= hash<decltype(port)>{}(port) + oxen::quic::inverse_golden_ratio + (h << 6) + (h >> 2);
return h;
}
};

template <>
struct hash<oxen::quic::Path>
{
size_t operator()(const oxen::quic::Path& addr) const
size_t operator()(const oxen::quic::Path& addr) const noexcept
{
auto h = hash<oxen::quic::Address>{}(addr.local);
h ^= hash<oxen::quic::Address>{}(addr.remote) + inverse_golden_ratio + (h << 6) + (h >> 2);
h ^= hash<oxen::quic::Address>{}(addr.remote) + oxen::quic::inverse_golden_ratio + (h << 6) + (h >> 2);
return h;
}
};
Expand Down
2 changes: 0 additions & 2 deletions include/oxen/quic/btstream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

namespace oxen::quic
{
using time_point = std::chrono::steady_clock::time_point;

// timeout is used for sent requests awaiting responses
inline constexpr std::chrono::seconds DEFAULT_TIMEOUT{10s};

Expand Down
47 changes: 32 additions & 15 deletions include/oxen/quic/connection.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#pragma once

#include <concepts>
#include <cstddef>
#include <cstdint>
#include <cstdio>
Expand All @@ -9,13 +8,13 @@
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <stdexcept>

#include "connection_ids.hpp"
#include "context.hpp"
#include "format.hpp"
#include "types.hpp"
#include "utils.hpp"

namespace oxen::quic
{
Expand All @@ -25,9 +24,6 @@ namespace oxen::quic
inline constexpr uint64_t MAX_ACTIVE_CIDS{8};
inline constexpr size_t NGTCP2_RETRY_SCIDLEN{18};

template <typename T>
concept StreamDerived = std::derived_from<T, Stream>;

class connection_interface : public std::enable_shared_from_this<connection_interface>
{
protected:
Expand All @@ -45,7 +41,7 @@ namespace oxen::quic
/// ID; it will be made ready once the associated stream id is seen from the remote
/// connection. Note that this constructor bypasses the stream constructor callback for the
/// applicable stream id.
template <StreamDerived StreamT, typename... Args, typename EndpointDeferred = Endpoint>
template <concepts::stream_derived_type StreamT, typename... Args, typename EndpointDeferred = Endpoint>
std::shared_ptr<StreamT> queue_incoming_stream(Args&&... args)
{
// We defer resolution of `Endpoint` here via `EndpointDeferred` because the header only
Expand All @@ -70,7 +66,7 @@ namespace oxen::quic
/// such as from an increase in available stream ids resulting from the closure of an
/// existing stream. Note that this constructor bypasses the stream constructor callback
/// for the applicable stream id.
template <StreamDerived StreamT, typename... Args, typename EndpointDeferred = Endpoint>
template <concepts::stream_derived_type StreamT, typename... Args, typename EndpointDeferred = Endpoint>
requires std::derived_from<StreamT, Stream>
std::shared_ptr<StreamT> open_stream(Args&&... args)
{
Expand All @@ -90,7 +86,7 @@ namespace oxen::quic
/// StreamT is specified, is of the given Stream subclass). Returns nullptr if the id is
/// not currently an open stream; throws std::invalid_argument if the stream exists but is
/// not an instance of the given StreamT type.
template <StreamDerived StreamT = Stream>
template <concepts::stream_derived_type StreamT = Stream>
std::shared_ptr<StreamT> maybe_stream(int64_t id)
{
auto s = get_stream_impl(id);
Expand All @@ -111,7 +107,7 @@ namespace oxen::quic
/// StreamT is specified, is of the given Stream subclass). Otherwise throws
/// std::out_of_range if the stream was not found, and std::invalid_argument if the stream
/// was found, but is not an instance of StreamT.
template <StreamDerived StreamT = Stream>
template <concepts::stream_derived_type StreamT = Stream>
std::shared_ptr<StreamT> get_stream(int64_t id)
{
if (auto s = maybe_stream<StreamT>(id))
Expand Down Expand Up @@ -241,6 +237,7 @@ namespace oxen::quic
{
friend class TestHelper;
friend struct rotating_buffer;
friend struct connection_callbacks;

public:
// Non-movable/non-copyable; you must always hold a Connection in a shared_ptr
Expand Down Expand Up @@ -317,6 +314,11 @@ namespace oxen::quic
bool datagrams_enabled() const override { return _datagrams_enabled; }
bool packet_splitting_enabled() const override { return _packet_splitting; }

bool zero_rtt_enabled() const { return _0rtt_enabled; }
unsigned int zero_rtt_window() const { return _0rtt_window; }

bool stateless_reset_enabled() const { return _stateless_reset_enabled; }

std::optional<size_t> max_datagram_size_changed() override;

// public debug functions; to be removed with friend test fixture class
Expand All @@ -336,19 +338,23 @@ namespace oxen::quic
connection_established_callback conn_established_cb;
connection_closed_callback conn_closed_cb;

void early_data_rejected();

void set_remote_addr(const ngtcp2_addr& new_remote);

void store_associated_cid(const quic_cid& cid);

void delete_associated_cid(const quic_cid& cid);

std::unordered_set<quic_cid>& associated_cids() { return _associated_cids; }

int client_handshake_completed();

int server_handshake_completed();

int server_path_validation(const ngtcp2_path* path);
int recv_stateless_reset(std::shared_ptr<gtls_reset_token> tok);

int client_path_validation(const ngtcp2_path* path, bool res, uint32_t flags);

int server_path_validation(const ngtcp2_path* path, bool res, uint32_t flags);

void set_new_path(Path new_path);

Expand Down Expand Up @@ -396,6 +402,11 @@ namespace oxen::quic

Path _path;

bool _0rtt_enabled{false};
const unsigned int _0rtt_window{};

bool _stateless_reset_enabled{false};

const uint64_t _max_streams{DEFAULT_MAX_BIDI_STREAMS};
const bool _datagrams_enabled{false};
const bool _packet_splitting{false};
Expand All @@ -405,7 +416,13 @@ namespace oxen::quic
std::atomic<bool> _close_quietly{false};
std::atomic<bool> _is_validated{false};

ustring remote_pubkey;
ustring remote_pubkey{};

std::vector<int64_t> _early_streams;

void make_early_streams(ngtcp2_conn* connptr);

void revert_early_streams();

struct connection_deleter
{
Expand Down Expand Up @@ -466,7 +483,7 @@ namespace oxen::quic
// streams are added to the back and popped from the front (FIFO)
std::deque<std::shared_ptr<Stream>> pending_streams;

int init(
void init(
ngtcp2_settings& settings,
ngtcp2_transport_params& params,
ngtcp2_callbacks& callbacks,
Expand All @@ -492,7 +509,7 @@ namespace oxen::quic
void stream_execute_close(Stream& s, uint64_t app_code);
void stream_closed(int64_t id, uint64_t app_code);
void close_all_streams();
void check_pending_streams(uint64_t available);
void check_pending_streams(uint64_t available, bool is_early_stream = false);
int recv_datagram(bstring_view data, bool fin);
int ack_datagram(uint64_t dgram_id);
int recv_token(const uint8_t* token, size_t tokenlen);
Expand Down
7 changes: 5 additions & 2 deletions include/oxen/quic/connection_ids.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ namespace std
template <>
struct hash<oxen::quic::quic_cid>
{
size_t operator()(const oxen::quic::quic_cid& cid) const
size_t operator()(const oxen::quic::quic_cid& cid) const noexcept
{
static_assert(
alignof(oxen::quic::quic_cid) >= alignof(size_t) &&
Expand All @@ -89,6 +89,9 @@ namespace std
template <>
struct hash<oxen::quic::ConnectionID>
{
size_t operator()(const oxen::quic::ConnectionID& rid) const { return std::hash<decltype(rid.id)>{}(rid.id); }
size_t operator()(const oxen::quic::ConnectionID& rid) const noexcept
{
return std::hash<decltype(rid.id)>{}(rid.id);
}
};
} // namespace std
Loading