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

Tunnel binaries #125

Open
wants to merge 5 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
30 changes: 29 additions & 1 deletion include/oxen/quic/address.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <oxenc/bt.h>
#include <oxenc/endian.h>

#include <compare>
Expand Down Expand Up @@ -272,11 +273,17 @@ namespace oxen::quic
// sockaddr pointer).
void update_socklen(socklen_t len) { _addr.addrlen = len; }

std::string host() const;
std::string host(bool no_format = false) const;

// Convenience method for debugging, etc. This is usually called implicitly by passing the
// Address to fmt to format it.
std::string to_string() const;

std::string bt_encode() const;

void bt_encode(oxenc::bt_dict_producer& btdp) const;

static std::optional<Address> bt_decode(oxenc::bt_dict_consumer& btdc);
};

struct RemoteAddress : public Address
Expand Down Expand Up @@ -340,6 +347,10 @@ namespace oxen::quic
return *this;
}

bool operator==(const Path& other) const { return std::tie(local, remote) == std::tie(other.local, other.remote); }

bool operator!=(const Path& other) const { return !(*this == other); }

// template code to pass Path as ngtcp2_path into ngtcp2 functions
template <typename T>
requires std::same_as<T, ngtcp2_path>
Expand All @@ -357,6 +368,12 @@ namespace oxen::quic
Path invert() const { return {remote, local}; }

std::string to_string() const;

std::string bt_encode() const;

void bt_encode(oxenc::bt_dict_producer& btdp) const;

static std::optional<Path> bt_decode(oxenc::bt_dict_consumer& btdc);
};
} // namespace oxen::quic

Expand Down Expand Up @@ -390,4 +407,15 @@ namespace std
return h;
}
};

template <>
struct hash<oxen::quic::Path>
{
size_t operator()(const oxen::quic::Path& addr) const
{
auto h = hash<oxen::quic::Address>{}(addr.local);
h ^= hash<oxen::quic::Address>{}(addr.remote);
return h;
}
};
} // namespace std
8 changes: 5 additions & 3 deletions include/oxen/quic/connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ namespace oxen::quic
template <oxenc::basic_char Char>
void send_datagram(std::vector<Char>&& buf)
{
send_datagram(
std::basic_string_view<Char>{buf.data(), buf.size()},
std::make_shared<std::vector<Char>>(std::move(buf)));
auto keep_alive = std::make_shared<std::vector<Char>>(std::move(buf));
std::basic_string_view<Char> view{keep_alive->data(), keep_alive->size()};
send_datagram(view, std::move(keep_alive));
}

template <oxenc::basic_char CharType>
Expand Down Expand Up @@ -490,6 +490,8 @@ namespace oxen::quic
int stream_ack(int64_t id, size_t size);
int stream_receive(int64_t id, bstring_view data, bool fin);
void stream_execute_close(Stream& s, uint64_t app_code);
void stream_stop_sending(int64_t id, uint64_t app_code);
void stream_reset(int64_t id, 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);
Expand Down
3 changes: 2 additions & 1 deletion include/oxen/quic/endpoint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ namespace oxen::quic
// Returns a random value suitable for use as the Endpoint static secret value.
static ustring make_static_secret();

// Receive a packet constructed in the function call or moved into it
void manually_receive_packet(Packet&& pkt);

private:
Expand Down Expand Up @@ -231,7 +232,7 @@ namespace oxen::quic
std::map<ustring, ustring> encoded_transport_params;
std::map<ustring, ustring> path_validation_tokens;

const std::shared_ptr<event_base>& get_loop() { return net.loop(); }
const std::shared_ptr<event_base>& get_loop() { return net.ev_loop(); }

const std::unique_ptr<UDPSocket>& get_socket() { return socket; }

Expand Down
6 changes: 6 additions & 0 deletions include/oxen/quic/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ namespace oxen::quic
// Application error code we close with if the stream data handle throws
inline constexpr uint64_t STREAM_ERROR_EXCEPTION = ERROR_BASE + 100;

// Application error code for signalling a remote shut down stream reading
inline constexpr uint64_t STREAM_REMOTE_READ_SHUTDOWN = ERROR_BASE + 101;

// Application error code for signalling a remote shut down stream writing
inline constexpr uint64_t STREAM_REMOTE_WRITE_SHUTDOWN = ERROR_BASE + 102;

// Application error if a bt request stream handle throws an exception
inline constexpr uint64_t BPARSER_ERROR_EXCEPTION = ERROR_BASE + 105;

Expand Down
4 changes: 3 additions & 1 deletion include/oxen/quic/network.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ namespace oxen::quic
Network();
~Network();

const std::shared_ptr<::event_base>& loop() const { return _loop->loop(); }
const std::shared_ptr<::event_base>& ev_loop() const { return _loop->loop(); }

const std::shared_ptr<Loop>& loop() const { return _loop; }

bool in_event_loop() const { return _loop->in_event_loop(); }

Expand Down
40 changes: 38 additions & 2 deletions include/oxen/quic/opt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
#include <stdexcept>

#include "address.hpp"
#include "crypto.hpp"
#include "types.hpp"
#include "connection_ids.hpp"

namespace oxen::quic
{
Expand Down Expand Up @@ -202,5 +201,42 @@ namespace oxen::quic
_hook = nullptr;
}
};

// Used to provide callbacks for remote stream reset. Application can pass one or both callbacks to indicate what
// logic should be executed when the remote shuts down stream reading or writing. The signature of `on_reset_hook_t`
// matches that of other hooks, so we wrap it in an opt struct to differentiate and to structure access.
struct remote_stream_reset
{
using on_reset_hook_t = std::function<void(Stream&, uint64_t)>;

private:
on_reset_hook_t _on_stop_sending = nullptr;
on_reset_hook_t _on_stream_reset = nullptr;

public:
remote_stream_reset() = default;

explicit remote_stream_reset(on_reset_hook_t _stop_sending, on_reset_hook_t _stream_reset = nullptr) :
_on_stop_sending{std::move(_stop_sending)}, _on_stream_reset{std::move(_stream_reset)}
{
if (not _on_stop_sending and not _on_stream_reset)
throw std::invalid_argument{"Must set at least one of `on_stop_sending` and `on_stream_reset`!"};
}

explicit operator bool() const { return has_stop_sending_hook() and has_stream_reset_hook(); }

void clear()
{
_on_stop_sending = nullptr;
_on_stream_reset = nullptr;
}

bool has_stop_sending_hook() const { return _on_stop_sending != nullptr; }
bool has_stream_reset_hook() const { return _on_stream_reset != nullptr; }

void on_remote_stop_sending(Stream& s, uint64_t ec) { return _on_stop_sending(s, ec); }
void on_remote_stream_reset(Stream& s, uint64_t ec) { return _on_stream_reset(s, ec); }
};

} // namespace opt
} // namespace oxen::quic
36 changes: 35 additions & 1 deletion include/oxen/quic/stream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,39 @@ namespace oxen::quic

bool is_paused() const;

/** Remote Stream Reset:
- Applications can call `::set_remote_reset_hooks(...)` to emplace logic to be executed when the remote stream
shuts down reading and/or writing
- This only happens once per lifetime of the stream; as a result, do NOT set more hooks while inside the body of
the hooks themselves!
*/
void set_remote_reset_hooks(opt::remote_stream_reset hooks);

void clear_remote_reset_hooks();

bool has_remote_reset_hooks() const;

void stop_reading();

void stop_writing();

void stop_sending(uint64_t code = STREAM_REMOTE_READ_SHUTDOWN);

void reset_stream(uint64_t code = STREAM_REMOTE_WRITE_SHUTDOWN);

bool is_reading() const;

bool is_writing() const;

// These public methods are synchronized so that they can be safely called from outside the
// libquic main loop thread.
bool available() const;
bool is_ready() const;

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

std::shared_ptr<connection_interface> get_conn_interface();

void close(uint64_t app_err_code = 0);

void set_stream_data_cb(stream_data_callback cb) { data_callback = std::move(cb); }
Expand Down Expand Up @@ -147,7 +173,7 @@ namespace oxen::quic
bool _paused{false};
int64_t _stream_id;

size_t _paused_offset{0};
std::atomic<size_t> _paused_offset{0};

bool _is_watermarked{false};

Expand All @@ -160,6 +186,14 @@ namespace oxen::quic
opt::watermark _high_water;
opt::watermark _low_water;

opt::remote_stream_reset _remote_reset;

bool _in_reset{false};

bool _is_reading{true};
bool _is_writing{true};
uint64_t _deferred_ec{0};

void wrote(size_t bytes) override;

void append_buffer(bstring_view buffer, std::shared_ptr<void> keep_alive);
Expand Down
13 changes: 12 additions & 1 deletion include/oxen/quic/udp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ extern "C"

#include "address.hpp"
#include "types.hpp"
#include "utils.hpp"

namespace oxen::quic
{
Expand All @@ -33,6 +32,10 @@ namespace oxen::quic
// Simple struct wrapping a raw packet and its corresponding information
struct Packet
{
private:
explicit Packet() = default;

public:
Path path;
ngtcp2_pkt_info pkt_info{};
std::variant<bstring_view, bstring> pkt_data;
Expand All @@ -47,6 +50,10 @@ namespace oxen::quic
pkt_data);
}

bool operator==(const Packet& other) const { return (path == other.path) and (data() == other.data()); }

bool operator!=(const Packet& other) const { return !(*this == other); }

/// Constructs a packet from a path and data view:
Packet(Path p, bstring_view d) : path{std::move(p)}, pkt_data{std::move(d)} {}

Expand All @@ -56,6 +63,10 @@ namespace oxen::quic
/// Constructs a packet from a local address, data, and the IP header; remote addr and ECN
/// data are extracted from the header.
Packet(const Address& local, bstring_view data, msghdr& hdr);

std::string bt_encode() const;

static std::optional<Packet> bt_decode(bstring buf);
};

/// RAII class wrapping a UDP socket; the socket is bound at construction and closed during
Expand Down
3 changes: 3 additions & 0 deletions include/oxen/quic/utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,9 @@ namespace oxen::quic
return true;
}

/// Checks rv for being -1 and, if so, raises a system_error from errno. Otherwise returns it.
int check_rv(int rv, std::string_view action);

// Shortcut for a const-preserving `reinterpret_cast`ing c.data() from a std::byte to a uint8_t
// pointer, because we need it all over the place in the ngtcp2 API
template <typename Container>
Expand Down
Loading