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

lsquic #254

Merged
merged 12 commits into from
Oct 5, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
6 changes: 6 additions & 0 deletions cmake/Hunter/config.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,9 @@
# SHA1 1234567890abcdef1234567890abcdef12345678
# CMAKE_ARGS "CMAKE_VARIABLE=value"
# )

hunter_config(lsquic
URL https://github.com/qdrvm/lsquic/archive/b79ff5c4be9936089d32dc1bc2dac70d54651e80.zip
SHA1 d628f8d7ec68ec33d7f404fbb7b433c62980aa13
KEEP_PACKAGE_SOURCES
)
4 changes: 2 additions & 2 deletions cmake/Hunter/init.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ set(
include(${CMAKE_CURRENT_LIST_DIR}/HunterGate.cmake)

HunterGate(
URL https://github.com/qdrvm/hunter/archive/refs/tags/v0.25.3-qdrvm15.zip
SHA1 b338eb3b6a989f19257d6d4acbc9f810abcf1b32
URL https://github.com/qdrvm/hunter/archive/refs/tags/v0.25.3-qdrvm16.zip
turuslan marked this conversation as resolved.
Show resolved Hide resolved
SHA1 990ea05207260b3757ce051e354cc163e910a211
LOCAL
)
3 changes: 3 additions & 0 deletions cmake/dependencies.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ find_package(OpenSSL CONFIG REQUIRED)
hunter_add_package(libsecp256k1)
find_package(libsecp256k1 CONFIG REQUIRED)

hunter_add_package(lsquic)
find_package(lsquic CONFIG REQUIRED)

# https://developers.google.com/protocol-buffers/
hunter_add_package(Protobuf)
find_package(Protobuf CONFIG REQUIRED)
Expand Down
1 change: 1 addition & 0 deletions cmake/libp2pConfig.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
include(CMakeFindDependencyMacro)

find_dependency(Boost CONFIG REQUIRED random filesystem program_options)
find_dependency(lsquic CONFIG REQUIRED)
find_dependency(OpenSSL CONFIG REQUIRED)
find_dependency(Protobuf CONFIG REQUIRED)
find_dependency(Threads)
Expand Down
3 changes: 2 additions & 1 deletion include/libp2p/injector/network_injector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <libp2p/security/tls.hpp>
#include <libp2p/security/tls/ssl_context.hpp>
#include <libp2p/transport/impl/upgrader_impl.hpp>
#include <libp2p/transport/quic/transport.hpp>
#include <libp2p/transport/tcp.hpp>

// clang-format off
Expand Down Expand Up @@ -344,7 +345,7 @@ namespace libp2p::injector {
di::bind<layer::LayerAdaptor *[]>().template to<layer::WsAdaptor, layer::WssAdaptor>(), // NOLINT
di::bind<security::SecurityAdaptor *[]>().template to<security::Plaintext, security::Secio, security::Noise, security::TlsAdaptor>(), // NOLINT
di::bind<muxer::MuxerAdaptor *[]>().template to<muxer::Yamux, muxer::Mplex>(), // NOLINT
di::bind<transport::TransportAdaptor *[]>().template to<transport::TcpTransport>(), // NOLINT
di::bind<transport::TransportAdaptor *[]>().template to<transport::TcpTransport, transport::QuicTransport>(), // NOLINT

// user-defined overrides...
std::forward<decltype(args)>(args)...
Expand Down
89 changes: 89 additions & 0 deletions include/libp2p/transport/quic/connection.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* Copyright Quadrivium LLC
* All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

#include <libp2p/common/metrics/instance_count.hpp>
#include <libp2p/connection/capable_connection.hpp>

namespace boost::asio {
class io_context;
} // namespace boost::asio

namespace libp2p::transport::lsquic {
class Engine;
struct ConnCtx;
} // namespace libp2p::transport::lsquic

namespace libp2p::transport {
class QuicConnection : public connection::CapableConnection,
public std::enable_shared_from_this<QuicConnection> {
public:
QuicConnection(std::shared_ptr<boost::asio::io_context> io_context,
lsquic::ConnCtx *conn_ctx,
bool initiator,
Multiaddress local,
Multiaddress remote,
PeerId peer,
crypto::PublicKey key);
~QuicConnection() override;

// clang-tidy cppcoreguidelines-special-member-functions
QuicConnection(const QuicConnection &) = delete;
void operator=(const QuicConnection &) = delete;
QuicConnection(QuicConnection &&) = delete;
void operator=(QuicConnection &&) = delete;

// Reader
void read(BytesOut out, size_t bytes, ReadCallbackFunc cb) override;
void readSome(BytesOut out, size_t bytes, ReadCallbackFunc cb) override;
void deferReadCallback(outcome::result<size_t> res,
ReadCallbackFunc cb) override;

// Writer
void writeSome(BytesIn in, size_t bytes, WriteCallbackFunc cb) override;
void deferWriteCallback(std::error_code ec, WriteCallbackFunc cb) override;

// Closeable
bool isClosed() const override;
outcome::result<void> close() override;

// LayerConnection
bool isInitiator() const noexcept override;
outcome::result<Multiaddress> remoteMultiaddr() override;
outcome::result<Multiaddress> localMultiaddr() override;

// SecureConnection
outcome::result<PeerId> localPeer() const override;
outcome::result<PeerId> remotePeer() const override;
outcome::result<crypto::PublicKey> remotePublicKey() const override;

// CapableConnection
void start() override;
void stop() override;
void newStream(StreamHandlerFunc cb) override;
outcome::result<std::shared_ptr<libp2p::connection::Stream>> newStream()
override;
void onStream(NewStreamHandlerFunc cb) override;

void onClose();
auto &onStream() const {
return on_stream_;
}

private:
std::shared_ptr<boost::asio::io_context> io_context_;
lsquic::ConnCtx *conn_ctx_;
bool initiator_;
Multiaddress local_, remote_;
PeerId peer_;
crypto::PublicKey key_;
NewStreamHandlerFunc on_stream_;

public:
LIBP2P_METRICS_INSTANCE_COUNT_IF_ENABLED(libp2p::transport::QuicConnection);
};
} // namespace libp2p::transport
119 changes: 119 additions & 0 deletions include/libp2p/transport/quic/engine.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#pragma once
turuslan marked this conversation as resolved.
Show resolved Hide resolved

#include <lsquic.h>
#include <boost/asio/ip/udp.hpp>
#include <boost/asio/steady_timer.hpp>
#include <libp2p/multi/multiaddress.hpp>
#include <libp2p/peer/peer_id.hpp>
#include <memory>
#include <qtils/bytes.hpp>
#include <qtils/outcome.hpp>

namespace boost::asio {
class io_context;
} // namespace boost::asio

namespace boost::asio::ssl {
class context;
} // namespace boost::asio::ssl

namespace libp2p::connection {
struct QuicStream;
} // namespace libp2p::connection

namespace libp2p::crypto::marshaller {
class KeyMarshaller;
} // namespace libp2p::crypto::marshaller

namespace libp2p::muxer {
struct MuxedConnectionConfig;
} // namespace libp2p::muxer

namespace libp2p::transport {
struct QuicConnection;
} // namespace libp2p::transport

namespace libp2p::transport::lsquic {
using connection::QuicStream;

struct Engine;
struct ConnCtx;
struct StreamCtx;

using OnConnect =
std::function<void(outcome::result<std::shared_ptr<QuicConnection>>)>;
struct Connecting {
boost::asio::ip::udp::endpoint remote;
PeerId peer;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this also relates to a remote peer

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we rename to endpoint or spell remote_endpoint?

OnConnect cb;
};
struct ConnCtx {
Engine *engine;
lsquic_conn_t *ls_conn;
std::optional<Connecting> connecting{};
std::optional<std::shared_ptr<QuicStream>> new_stream{};
std::weak_ptr<QuicConnection> conn{};
};

struct StreamCtx {
Engine *engine;
lsquic_stream_t *ls_stream;
std::weak_ptr<QuicStream> stream{};
struct Reading {
BytesOut out;
std::function<void(outcome::result<size_t>)> cb;
};
std::optional<Reading> reading{};
};

using OnAccept = std::function<void(std::shared_ptr<QuicConnection>)>;
class Engine : public std::enable_shared_from_this<Engine> {
public:
Engine(std::shared_ptr<boost::asio::io_context> io_context,
std::shared_ptr<boost::asio::ssl::context> ssl_context,
const muxer::MuxedConnectionConfig &mux_config,
std::shared_ptr<crypto::marshaller::KeyMarshaller> key_codec,
boost::asio::ip::udp::socket &&socket,
bool client);
~Engine();

// clang-tidy cppcoreguidelines-special-member-functions
Engine(const Engine &) = delete;
void operator=(const Engine &) = delete;
Engine(Engine &&) = delete;
void operator=(Engine &&) = delete;

auto &local() const {
return local_;
}
void start();
void connect(const boost::asio::ip::udp::endpoint &remote,
const PeerId &peer,
OnConnect cb);
outcome::result<std::shared_ptr<QuicStream>> newStream(ConnCtx *conn_ctx);
void onAccept(OnAccept cb) {
on_accept_ = std::move(cb);
}
void process();

private:
void readLoop();

std::shared_ptr<boost::asio::io_context> io_context_;
std::shared_ptr<boost::asio::ssl::context> ssl_context_;
std::shared_ptr<crypto::marshaller::KeyMarshaller> key_codec_;
boost::asio::ip::udp::socket socket_;
boost::asio::steady_timer timer_;
boost::asio::ip::udp::endpoint socket_local_;
Multiaddress local_;
lsquic_engine_t *engine_ = nullptr;
OnAccept on_accept_;
bool started_ = false;
std::optional<Connecting> connecting_;
struct Reading {
qtils::BytesN<64 << 10> buf;
turuslan marked this conversation as resolved.
Show resolved Hide resolved
boost::asio::ip::udp::endpoint remote;
};
Reading reading_;
};
} // namespace libp2p::transport::lsquic
turuslan marked this conversation as resolved.
Show resolved Hide resolved
32 changes: 32 additions & 0 deletions include/libp2p/transport/quic/error.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once
turuslan marked this conversation as resolved.
Show resolved Hide resolved

#include <qtils/enum_error_code.hpp>

namespace libp2p {
enum class QuicError {
HANDSHAKE_FAILED,
CONN_CLOSED,
STREAM_CLOSED,
TOO_MANY_STREAMS,
CANT_CREATE_CONNECTION,
CANT_OPEN_STREAM,
};
Q_ENUM_ERROR_CODE(QuicError) {
using E = decltype(e);
switch (e) {
case E::HANDSHAKE_FAILED:
return "HANDSHAKE_FAILED";
case E::CONN_CLOSED:
return "CONN_CLOSED";
case E::STREAM_CLOSED:
return "STREAM_CLOSED";
case E::TOO_MANY_STREAMS:
return "TOO_MANY_STREAMS";
case E::CANT_CREATE_CONNECTION:
return "CANT_CREATE_CONNECTION";
case E::CANT_OPEN_STREAM:
return "CANT_OPEN_STREAM";
}
abort();
}
} // namespace libp2p
16 changes: 16 additions & 0 deletions include/libp2p/transport/quic/init.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once
turuslan marked this conversation as resolved.
Show resolved Hide resolved

#include <lsquic.h>
#include <stdexcept>

namespace libp2p::transport {
inline void lsquicInit() {
static auto _ = [] {
if (lsquic_global_init(LSQUIC_GLOBAL_CLIENT | LSQUIC_GLOBAL_SERVER)
!= 0) {
throw std::logic_error{"lsquic_global_init"};
}
return 0;
}();
}
} // namespace libp2p::transport
49 changes: 49 additions & 0 deletions include/libp2p/transport/quic/listener.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#pragma once
turuslan marked this conversation as resolved.
Show resolved Hide resolved

#include <libp2p/muxer/muxed_connection_config.hpp>
#include <libp2p/transport/transport_listener.hpp>

namespace boost::asio {
class io_context;
} // namespace boost::asio

namespace boost::asio::ssl {
class context;
} // namespace boost::asio::ssl

namespace libp2p::crypto::marshaller {
class KeyMarshaller;
} // namespace libp2p::crypto::marshaller

namespace libp2p::transport::lsquic {
class Engine;
} // namespace libp2p::transport::lsquic

namespace libp2p::transport {
class QuicListener : public TransportListener,
public std::enable_shared_from_this<QuicListener> {
public:
QuicListener(std::shared_ptr<boost::asio::io_context> io_context,
std::shared_ptr<boost::asio::ssl::context> ssl_context,
const muxer::MuxedConnectionConfig &mux_config,
std::shared_ptr<crypto::marshaller::KeyMarshaller> key_codec,
TransportListener::HandlerFunc handler);

// Closeable
bool isClosed() const override;
outcome::result<void> close() override;

// TransportListener
outcome::result<void> listen(const Multiaddress &address) override;
bool canListen(const Multiaddress &ma) const override;
outcome::result<Multiaddress> getListenMultiaddr() const override;

private:
std::shared_ptr<boost::asio::io_context> io_context_;
std::shared_ptr<boost::asio::ssl::context> ssl_context_;
muxer::MuxedConnectionConfig mux_config_;
std::shared_ptr<crypto::marshaller::KeyMarshaller> key_codec_;
TransportListener::HandlerFunc handler_;
std::shared_ptr<lsquic::Engine> server_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lack of descriptive docstrings + confusing name a bit (server?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we rename to engine_ or spell server_engine_?

};
} // namespace libp2p::transport
Loading
Loading