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

Connection established and closed callbacks #40

Merged
merged 7 commits into from
Sep 18, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions .drone.jsonnet
Expand Up @@ -78,7 +78,7 @@ local generic_build(jobs, build_type, lto, werror, cmake_extra, local_mirror, te
+ (if tests then [
'cd build',
'../utils/gen-certs.sh',
(if gdb then '../utils/ci/drone-gdb.sh ' else '') + './tests/alltests --no-ipv6 --colour-mode ansi',
(if gdb then '../utils/ci/drone-gdb.sh ' else '') + './tests/alltests --log-level debug --no-ipv6 --colour-mode ansi',
'cd ..',
] else []);

Expand Down Expand Up @@ -172,7 +172,7 @@ local windows_cross_pipeline(name,
'-DBUILD_TESTS=' + (if tests then 'ON ' else 'OFF ') +
ci_dep_mirror(local_mirror),
'make -j' + jobs + ' VERBOSE=1',
//'wine-stable tests/alltests.exe --colour-mode ansi', // doesn't work yet :(
//'wine-stable tests/alltests.exe --log-level debug --colour-mode ansi', // doesn't work yet :(
] + extra_cmds,
},
],
Expand Down
1 change: 1 addition & 0 deletions include/quic.hpp
Expand Up @@ -6,6 +6,7 @@
#include "quic/crypto.hpp"
#include "quic/datagram.hpp"
#include "quic/endpoint.hpp"
#include "quic/error.hpp"
#include "quic/format.hpp"
#include "quic/gnutls_crypto.hpp"
#include "quic/messages.hpp"
Expand Down
6 changes: 2 additions & 4 deletions include/quic/connection.hpp
Expand Up @@ -116,7 +116,7 @@ namespace oxen::quic
virtual int last_cleared() const = 0;
virtual int datagram_bufsize() const = 0;

virtual void close_connection() = 0;
virtual void close_connection(uint64_t error_code = 0) = 0;

virtual ~connection_interface() = default;

Expand Down Expand Up @@ -165,7 +165,6 @@ namespace oxen::quic
void set_closing() { closing = true; }
bool is_draining() const { return draining; }
void set_draining() { draining = true; }
void call_close_cb();
stream_data_callback get_default_data_callback() const;

const ConnectionID& scid() const override { return _source_cid; }
Expand All @@ -191,7 +190,7 @@ namespace oxen::quic

void send_datagram(bstring_view data, std::shared_ptr<void> keep_alive = nullptr) override;

void close_connection() override;
void close_connection(uint64_t error_code = 0) override;

private:
// private Constructor (publicly construct via `make_conn` instead, so that we can properly
Expand All @@ -210,7 +209,6 @@ namespace oxen::quic
const ConnectionID _source_cid;
ConnectionID _dest_cid;
Path _path;
std::function<void(Connection&)> on_closing; // clear immediately after use
const int _max_streams{DEFAULT_MAX_BIDI_STREAMS};
const bool _datagrams_enabled{false};
const bool _packet_splitting{false};
Expand Down
16 changes: 14 additions & 2 deletions include/quic/endpoint.hpp
Expand Up @@ -34,13 +34,21 @@ extern "C"

namespace oxen::quic
{
using connection_open_callback = std::function<void(connection_interface& conn)>;
using connection_closed_callback = std::function<void(connection_interface& conn, uint64_t ec)>;

class Endpoint : std::enable_shared_from_this<Endpoint>
{
private:
void handle_ep_opt(opt::enable_datagrams dc);
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);

public:
connection_open_callback connection_open_cb;
connection_closed_callback connection_close_cb;

// Non-movable/non-copyable; you must always hold a Endpoint in a shared_ptr
Endpoint(const Endpoint&) = delete;
Endpoint& operator=(const Endpoint&) = delete;
Expand Down Expand Up @@ -169,9 +177,11 @@ namespace oxen::quic

void close_conns(std::optional<Direction> d = std::nullopt);

void close_connection(Connection& conn, int code = NGTCP2_NO_ERROR, std::string_view msg = "NO_ERROR"sv);
void drop_connection(Connection& conn);

void close_connection(ConnectionID cid, int code = NGTCP2_NO_ERROR, std::string_view msg = "NO_ERROR"sv);
void close_connection(Connection& conn, io_error ec = io_error{0}, std::string_view msg = "NO_ERROR"sv);

void close_connection(ConnectionID cid, io_error code = io_error{0}, std::string_view msg = "NO_ERROR"sv);

const Address& local() { return _local; }

Expand All @@ -192,6 +202,8 @@ namespace oxen::quic
void delete_connection(const ConnectionID& cid);
void drain_connection(Connection& conn);

void connection_established(connection_interface& conn);

int _rbufsize{4096};

private:
Expand Down
75 changes: 75 additions & 0 deletions include/quic/error.hpp
@@ -0,0 +1,75 @@
#pragma once

#include "utils.hpp"

namespace oxen::quic
{
constexpr uint64_t LIBQUIC_ERROR_BASE = 0x6c696271756963; // "libquic"

enum class error : uint64_t {
NO_ERR = 0,

CONN_WRITE_CLOSE_FAIL = LIBQUIC_ERROR_BASE,
CONN_SEND_CLOSE_FAIL = LIBQUIC_ERROR_BASE + 1,

STREAM_EXCEPTION = LIBQUIC_ERROR_BASE + 32,
STREAM_CONNECTION_EXPIRED = LIBQUIC_ERROR_BASE + 33,

DATAGRAM_EXCEPTION = LIBQUIC_ERROR_BASE + 64
};
dr7ana marked this conversation as resolved.
Show resolved Hide resolved

inline const char* quic_strerror(uint64_t e)
{
switch (static_cast<error>(e))
{
case error::NO_ERR:
return "No error";
case error::DATAGRAM_EXCEPTION:
return "Error - datagram exception";
case error::STREAM_EXCEPTION:
return "Error - stream exception";
case error::STREAM_CONNECTION_EXPIRED:
return "Error - stream connection expired";
case error::CONN_WRITE_CLOSE_FAIL:
return "Error - Failed to write connection close";
case error::CONN_SEND_CLOSE_FAIL:
return "Error - Failed to send connection close";
default:
return "Application-Specified Error";
}
}

struct io_error
{
private:
uint64_t _code{0};

public:
bool is_ngtcp2 = false;

io_error() = default;
explicit io_error(int e) : _code{static_cast<uint64_t>(e)} { is_ngtcp2 = true; }
explicit io_error(uint64_t e) : _code{e} { is_ngtcp2 = false; }
explicit io_error(error e) : _code{static_cast<uint64_t>(e)} {}

uint64_t code() const { return _code; }

int ngtcp2_code() const { return static_cast<int>(_code); }

uint64_t ngtcp2() const
{
if (not is_ngtcp2)
log::info(log_cat, "Error code {} is not an ngtcp2 error code", _code);
return _code;
}

const char* strerror() const
{
if (is_ngtcp2)
return ngtcp2_strerror(_code);
else
return quic_strerror(_code);
}
};

} // namespace oxen::quic
3 changes: 2 additions & 1 deletion include/quic/stream.hpp
Expand Up @@ -16,6 +16,7 @@ extern "C"
#include <vector>

#include "datagram.hpp"
#include "error.hpp"
#include "types.hpp"
#include "utils.hpp"

Expand Down Expand Up @@ -59,7 +60,7 @@ namespace oxen::quic

std::shared_ptr<Stream> get_stream() override;

void close(uint64_t error_code = 0);
void close(io_error ec = io_error{});

void send(bstring_view data, std::shared_ptr<void> keep_alive = nullptr) override;

Expand Down
8 changes: 0 additions & 8 deletions include/quic/types.hpp
Expand Up @@ -4,14 +4,6 @@

namespace oxen::quic
{
struct ngtcp2_error_code_t final
{};

// Tag value to pass into the constructor to indicate an ngtcp2 error code.
//
// (For ngtcp2, error codes are arbitrary negative values without any connection to errno).
static inline constexpr ngtcp2_error_code_t ngtcp2_error_code{};

enum class Direction { OUTBOUND = 0, INBOUND = 1 };

enum class Splitting { NONE = 0, ACTIVE = 1 };
Expand Down
7 changes: 7 additions & 0 deletions include/quic/utils.hpp
Expand Up @@ -61,6 +61,13 @@ namespace oxen::quic
false;
#endif

struct ngtcp2_error_code_t final
{};

// Tag value to pass into the io_result/io_error constructors to indicate an ngtcp2 error code.
// (For ngtcp2, error codes are arbitrary negative values without any connection to errno).
static inline constexpr ngtcp2_error_code_t ngtcp2_error_code{};

// SI (1000) and non-SI (1024-based) modifier prefix operators. E.g.
// 50_M is 50'000'000 and 50_Mi is 52'428'800.
constexpr unsigned long long operator""_k(unsigned long long int x)
Expand Down