Skip to content

Commit

Permalink
Move ALPN code to Endpoint where it belongs
Browse files Browse the repository at this point in the history
Also adds tests for ALPNs

Adds configurable connection handshake timeout

Reworks tests/008-ed-keys to no longer care about ALPNs
  • Loading branch information
tewinget committed Sep 25, 2023
1 parent ba19583 commit d9fec7f
Show file tree
Hide file tree
Showing 11 changed files with 296 additions and 132 deletions.
17 changes: 15 additions & 2 deletions include/quic/connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ namespace oxen::quic
std::function<std::shared_ptr<Stream>(Connection& c, Endpoint& e)> make_stream) = 0;

public:
virtual std::string_view selected_alpn() const = 0;

template <typename StreamT = Stream, typename... Args, std::enable_if_t<std::is_base_of_v<Stream, StreamT>, int> = 0>
std::shared_ptr<StreamT> queue_stream(Args&&... args)
{
Expand Down Expand Up @@ -157,11 +159,13 @@ namespace oxen::quic
const ConnectionID& dcid,
const Path& path,
std::shared_ptr<IOContext> ctx,
const std::vector<std::string>& alpns,
std::chrono::nanoseconds handshake_timeout,
ngtcp2_pkt_hd* hdr = nullptr);

void packet_io_ready();

TLSSession* get_session() { return tls_session.get(); };
TLSSession* get_session() const { return tls_session.get(); };

std::shared_ptr<Stream> queue_stream_impl(
std::function<std::shared_ptr<Stream>(Connection& c, Endpoint& e)> make_stream) override;
Expand All @@ -172,6 +176,7 @@ namespace oxen::quic
Direction direction() const { return dir; }
bool is_inbound() const { return dir == Direction::INBOUND; }
bool is_outbound() const { return dir == Direction::OUTBOUND; }
std::string_view direction_str() const { return dir == Direction::INBOUND ? "server"sv : "client"sv; }

void halt_events();
bool is_closing() const { return closing; }
Expand All @@ -190,6 +195,8 @@ namespace oxen::quic
Endpoint& endpoint() { return _endpoint; }
const Endpoint& endpoint() const { return _endpoint; }

std::string_view selected_alpn() const override;

int get_streams_available() const override;
size_t get_max_datagram_size() const override;
int get_max_streams() const override { return _max_streams; }
Expand All @@ -214,6 +221,8 @@ namespace oxen::quic
const ConnectionID& dcid,
const Path& path,
std::shared_ptr<IOContext> ctx,
const std::vector<std::string>& alpns,
std::chrono::nanoseconds handshake_timeout,
ngtcp2_pkt_hd* hdr = nullptr);

Endpoint& _endpoint;
Expand Down Expand Up @@ -274,7 +283,11 @@ 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(ngtcp2_settings& settings, ngtcp2_transport_params& params, ngtcp2_callbacks& callbacks);
int init(
ngtcp2_settings& settings,
ngtcp2_transport_params& params,
ngtcp2_callbacks& callbacks,
std::chrono::nanoseconds handshake_timeout);

io_result read_packet(const Packet& pkt);

Expand Down
3 changes: 2 additions & 1 deletion include/quic/crypto.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace oxen::quic
class TLSCreds
{
public:
virtual std::unique_ptr<TLSSession> make_session(bool is_client) = 0;
virtual std::unique_ptr<TLSSession> make_session(bool is_client, const std::vector<std::string>& alpns) = 0;
virtual ~TLSCreds() = default;
};

Expand All @@ -25,6 +25,7 @@ namespace oxen::quic
public:
ngtcp2_crypto_conn_ref conn_ref;
virtual void* get_session() = 0;
virtual std::string_view selected_alpn() = 0;
virtual ~TLSSession() = default;
};

Expand Down
15 changes: 14 additions & 1 deletion include/quic/endpoint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ namespace oxen::quic
{
private:
void handle_ep_opt(opt::enable_datagrams dc);
void handle_ep_opt(opt::outbound_alpns alpns);
void handle_ep_opt(opt::inbound_alpns alpns);
void handle_ep_opt(opt::handshake_timeout timeout);
void handle_ep_opt(dgram_data_callback dgram_cb);
void handle_ep_opt(connection_open_callback conn_established_cb);
void handle_ep_opt(connection_closed_callback conn_closed_cb);
Expand Down Expand Up @@ -123,7 +126,13 @@ namespace oxen::quic
if (auto [itr, success] = conns.emplace(ConnectionID::random(), nullptr); success)
{
itr->second = Connection::make_conn(
*this, itr->first, ConnectionID::random(), std::move(path), outbound_ctx);
*this,
itr->first,
ConnectionID::random(),
std::move(path),
outbound_ctx,
outbound_alpns,
handshake_timeout);

p.set_value(itr->second);
return;
Expand Down Expand Up @@ -227,6 +236,10 @@ namespace oxen::quic
std::shared_ptr<IOContext> outbound_ctx;
std::shared_ptr<IOContext> inbound_ctx;

std::vector<std::string> outbound_alpns;
std::vector<std::string> inbound_alpns;
std::chrono::nanoseconds handshake_timeout{5s};

void _init_internals();

void _set_context_globals(std::shared_ptr<IOContext>& ctx);
Expand Down
20 changes: 9 additions & 11 deletions include/quic/gnutls_crypto.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,6 @@ namespace oxen::quic
// Construct from raw Ed25519 keys
GNUTLSCreds(std::string ed_seed, std::string ed_pubkey, bool snode = false);

std::vector<std::string> allowed_alpn_strings;
std::vector<gnutls_datum_t> allowed_alpns;

std::string outbound_alpn_string;
gnutls_datum_t outbound_alpn;

public:
~GNUTLSCreds();

Expand All @@ -210,15 +204,12 @@ namespace oxen::quic

void set_key_verify_callback(gnutls_key_verify_callback cb) { key_verify = std::move(cb); }

void set_outbound_alpn(const std::string& alpn);
void set_allowed_alpns(const std::vector<std::string>& alpns);

static std::shared_ptr<GNUTLSCreds> make(
std::string remote_key, std::string remote_cert, std::string local_cert = "", std::string ca_arg = "");

static std::shared_ptr<GNUTLSCreds> make_from_ed_keys(std::string seed, std::string pubkey, bool is_relay = false);

std::unique_ptr<TLSSession> make_session(bool is_client = false) override;
std::unique_ptr<TLSSession> make_session(bool is_client, const std::vector<std::string>& alpns) override;
};

class GNUTLSSession : public TLSSession
Expand All @@ -235,11 +226,18 @@ namespace oxen::quic

void set_tls_hook_functions(); // TODO: which and when?
public:
GNUTLSSession(GNUTLSCreds& creds, bool is_client, std::optional<gnutls_key> expected_key = std::nullopt);
GNUTLSSession(
GNUTLSCreds& creds,
bool is_client,
const std::vector<std::string>& alpns,
std::optional<gnutls_key> expected_key = std::nullopt);

~GNUTLSSession();

void* get_session() override { return session; };

std::string_view selected_alpn() override;

int do_tls_callback(
gnutls_session_t session,
unsigned int htype,
Expand Down
17 changes: 17 additions & 0 deletions include/quic/opt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,21 @@ namespace oxen::quic::opt
}
};

// supported ALPNs for outbound connections
struct outbound_alpns
{
std::vector<std::string> alpns;
};

// supported ALPNs for inbound connections
struct inbound_alpns
{
std::vector<std::string> alpns;
};

struct handshake_timeout : public std::chrono::nanoseconds
{
using std::chrono::nanoseconds::nanoseconds;
};

} // namespace oxen::quic::opt
27 changes: 21 additions & 6 deletions src/connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,8 +337,9 @@ namespace oxen::quic
// drop conn without calling ngtcp2_conn_write_connection_close()
log::trace(
log_cat,
"Note: CID-{} encountered ngtcp2 crypto error {} (code: {}); signaling endpoint to delete "
"Note: {} CID-{} encountered ngtcp2 crypto error {} (code: {}); signaling endpoint to delete "
"connection",
direction_str(),
scid(),
ngtcp2_conn_get_tls_alert(*this),
ngtcp2_strerror(rv));
Expand Down Expand Up @@ -1046,6 +1047,11 @@ namespace oxen::quic
return 0;
}

std::string_view Connection::selected_alpn() const
{
return _endpoint.call_get([this]() { return get_session()->selected_alpn(); });
}

void Connection::send_datagram(bstring_view data, std::shared_ptr<void> keep_alive)
{
log::trace(log_cat, "{} called", __PRETTY_FUNCTION__);
Expand Down Expand Up @@ -1076,7 +1082,11 @@ namespace oxen::quic
return 0;
}

int Connection::init(ngtcp2_settings& settings, ngtcp2_transport_params& params, ngtcp2_callbacks& callbacks)
int Connection::init(
ngtcp2_settings& settings,
ngtcp2_transport_params& params,
ngtcp2_callbacks& callbacks,
std::chrono::nanoseconds handshake_timeout)
{
auto* ev_base = endpoint().get_loop().get();

Expand Down Expand Up @@ -1136,7 +1146,7 @@ namespace oxen::quic
settings.initial_rtt = NGTCP2_DEFAULT_INITIAL_RTT;
settings.max_window = 24_Mi;
settings.max_stream_window = 16_Mi;
settings.handshake_timeout = std::chrono::nanoseconds(5s).count();
settings.handshake_timeout = handshake_timeout.count();

ngtcp2_transport_params_default(&params);

Expand Down Expand Up @@ -1185,6 +1195,8 @@ namespace oxen::quic
const ConnectionID& dcid,
const Path& path,
std::shared_ptr<IOContext> ctx,
const std::vector<std::string>& alpns,
std::chrono::nanoseconds handshake_timeout,
ngtcp2_pkt_hd* hdr) :
_endpoint{ep},
context{std::move(ctx)},
Expand Down Expand Up @@ -1212,7 +1224,7 @@ namespace oxen::quic
ngtcp2_conn* connptr;
int rv = 0;

if (rv = init(settings, params, callbacks); rv != 0)
if (rv = init(settings, params, callbacks, handshake_timeout); rv != 0)
log::critical(log_cat, "Error: {} connection not created", d_str);

if (is_outbound)
Expand Down Expand Up @@ -1258,7 +1270,7 @@ namespace oxen::quic
throw std::runtime_error{"Failed to initialize connection object: "s + ngtcp2_strerror(rv)};
}

tls_session = tls_creds->make_session(is_outbound);
tls_session = tls_creds->make_session(is_outbound, alpns);
tls_session->conn_ref.get_conn = get_conn;
tls_session->conn_ref.user_data = this;
ngtcp2_conn_set_tls_native_handle(connptr, tls_session->get_session());
Expand All @@ -1280,10 +1292,13 @@ namespace oxen::quic
const ConnectionID& dcid,
const Path& path,
std::shared_ptr<IOContext> ctx,
const std::vector<std::string>& alpns,
std::chrono::nanoseconds handshake_timeout,
ngtcp2_pkt_hd* hdr)
{
log::trace(log_cat, "{} called", __PRETTY_FUNCTION__);
std::shared_ptr<Connection> conn{new Connection{ep, scid, dcid, path, std::move(ctx), hdr}};
std::shared_ptr<Connection> conn{
new Connection{ep, scid, dcid, path, std::move(ctx), alpns, handshake_timeout, hdr}};

conn->packet_io_ready();

Expand Down
18 changes: 17 additions & 1 deletion src/endpoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,21 @@ namespace oxen::quic
_packet_splitting ? "" : "no");
}

void Endpoint::handle_ep_opt(opt::outbound_alpns alpns)
{
outbound_alpns = std::move(alpns.alpns);
}

void Endpoint::handle_ep_opt(opt::inbound_alpns alpns)
{
inbound_alpns = std::move(alpns.alpns);
}

void Endpoint::handle_ep_opt(opt::handshake_timeout timeout)
{
handshake_timeout = timeout;
}

void Endpoint::handle_ep_opt(dgram_data_callback func)
{
log::trace(log_cat, "Endpoint given datagram recv callback");
Expand Down Expand Up @@ -372,7 +387,8 @@ namespace oxen::quic
{
if (auto [itr, success] = conns.emplace(ConnectionID::random(), nullptr); success)
{
itr->second = Connection::make_conn(*this, itr->first, hdr.scid, pkt.path, inbound_ctx, &hdr);
itr->second = Connection::make_conn(
*this, itr->first, hdr.scid, pkt.path, inbound_ctx, inbound_alpns, handshake_timeout, &hdr);
return itr->second.get();
}
}
Expand Down

0 comments on commit d9fec7f

Please sign in to comment.