diff --git a/include/parselink/proto/message.h b/include/parselink/proto/message.h index 843700b..87c77f1 100644 --- a/include/parselink/proto/message.h +++ b/include/parselink/proto/message.h @@ -18,13 +18,13 @@ #ifndef message_0c61530748b9f966 #define message_0c61530748b9f966 +#include + #include #include #include #include -#include - namespace parselink { namespace proto { @@ -44,8 +44,8 @@ struct error_message { // C->S: Request to (re)connect. struct connect_message { - std::uint32_t user_id; // The user id. std::uint32_t version; // The version of the client. + std::uint32_t user_id; // The user id. std::span session_token; // An optional existing session token. }; diff --git a/include/parselink/proto/session.h b/include/parselink/proto/session.h index f55430c..064fc44 100644 --- a/include/parselink/proto/session.h +++ b/include/parselink/proto/session.h @@ -20,14 +20,15 @@ #include "parselink/msgpack/token.h" #include "parselink/proto/session_id.h" + +#include + #include #include #include #include #include -#include - template <> struct std::hash> { constexpr static std::uint32_t seed_var = 0x811c9dc5; diff --git a/include/parselink/utility/file.h b/include/parselink/utility/file.h new file mode 100644 index 0000000..d2918bc --- /dev/null +++ b/include/parselink/utility/file.h @@ -0,0 +1,133 @@ +//----------------------------------------------------------------------------- +// ___ __ _ _ +// / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __ +// / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ / +// / ___/ (_| | | \__ \ __/ /__| | | | | < +// \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ . +// +//----------------------------------------------------------------------------- +// Author: Kurt Sassenrath +// Module: Utility +// +// Utility wrappers for dealing with files. +// +// Copyright (c) 2023 Kurt Sassenrath. +// +// License TBD. +//----------------------------------------------------------------------------- + +#ifndef utility_file_8b49e5e471a7c3e5 +#define utility_file_8b49e5e471a7c3e5 + +#include +#include + +#include +#include +#include +#include +#include + +namespace parselink { +namespace utility { +namespace file { + +struct [[nodiscard]] handle { + constexpr handle() noexcept = default; + + constexpr handle(int fd) noexcept + : fd_(fd) { + if (fd_ < 0) fd_ = -errno; + } + + constexpr handle(handle const&) noexcept = delete; + + constexpr handle(handle&& other) noexcept + : fd_(other.fd_) { + other.fd_ = -1; + } + + constexpr handle& operator=(handle const&) noexcept = delete; + + constexpr handle& operator=(handle&& other) noexcept { + close(); + fd_ = other.fd_; + return *this; + } + + constexpr operator bool() const noexcept { return fd_ >= 0; } + + constexpr int operator*() const noexcept { return fd_; } + + void close() { + if (*this) { + ::close(fd_); + fd_ = -1; + } + } + + int fd_{-1}; +}; + +inline tl::expected open( + std::string_view path, int flags) noexcept { + handle file(::open(std::string{path}.c_str(), flags)); + if (file) { + return file; + } else { + return tl::make_unexpected( + std::make_error_code(static_cast(-*file))); + } +} + +inline tl::expected, std::error_code> read_some( + handle file, std::size_t amount) noexcept { + std::vector data; + + if (!file) { + return tl::make_unexpected( + std::make_error_code(static_cast(-*file))); + } + + data.resize(amount); + + auto amt_read = ::read(*file, data.data(), amount); + + if (amt_read < data.size()) { + data.resize(amt_read); + } + + return data; +} + +template + requires(std::is_trivially_default_constructible_v && sizeof(T) == 1) +inline tl::expected, std::error_code> read( + handle file) noexcept { + std::vector data; + + if (!file) { + return tl::make_unexpected( + std::make_error_code(static_cast(-*file))); + } + + auto cur = lseek(*file, 0, SEEK_CUR); + auto end = lseek(*file, 0, SEEK_END); + std::size_t amount = end - cur; + lseek(*file, SEEK_SET, cur); + data.resize(amount); + + auto amt_read = ::read(*file, data.data(), amount); + + if (amt_read < data.size()) { + data.resize(amt_read); + } + + return data; +} + +} // namespace file +} // namespace utility +} // namespace parselink + +#endif // utility_file_8b49e5e471a7c3e5 diff --git a/source/proto/session.cpp b/source/proto/session.cpp index c4d8851..e74c062 100644 --- a/source/proto/session.cpp +++ b/source/proto/session.cpp @@ -19,12 +19,13 @@ //----------------------------------------------------------------------------- #include "parselink/proto/session.h" -#include "hydrogen.h" #include "parselink/logging.h" #include "parselink/msgpack/token.h" #include +#include "hydrogen.h" + namespace { void ensure_initialized() { @@ -187,14 +188,11 @@ tl::expected proto::parse_connect( } } -session::session(std::string_view user_id, close_handle hdl) noexcept +session::session(std::string_view user_id) noexcept : id_() , user_id_(std::string{user_id}) - , closer_(std::move(hdl)) , last_activity_(std::chrono::system_clock::now()) { logger.debug("New session with id {} created for {}", id_.raw(), user_id_); } -session::~session() { - if (closer_) closer_("Destroyed"); -} +session::~session() {} diff --git a/source/server.cpp b/source/server.cpp index 68ff155..4f26ede 100644 --- a/source/server.cpp +++ b/source/server.cpp @@ -25,6 +25,11 @@ #include "parselink/msgpack/token/reader.h" #include "parselink/msgpack/token/views.h" #include "parselink/proto/session.h" +#include "parselink/utility/file.h" + +#include + +#include "hydrogen.h" #include #include #include @@ -39,8 +44,6 @@ #include #include -#include - using namespace parselink; #include @@ -151,6 +154,7 @@ namespace { logging::logger logger("server"); constexpr auto no_ex_coro = net::as_tuple(use_awaitable); constexpr auto no_ex_defer = net::as_tuple(deferred); + } // namespace #include @@ -171,6 +175,9 @@ public: private: awaitable user_listen(); + tl::expected load_keys() noexcept; + + hydro_kx_keypair kp_; net::io_context io_context_; net::io_context::strand session_strand_; memory_session_manager session_mgr_; @@ -279,8 +286,6 @@ public: co_return; } session_ = *session; - - auto writer = msgpack::writer(msgbuf); } enum class state { init, authenticated, active }; @@ -298,6 +303,8 @@ monolithic_server::monolithic_server(std::string_view address, , addr_(net::ip::address::from_string(std::string{address})) , user_port_{user_port} , websocket_port_{websocket_port} { + load_keys(); + logger.debug("Creating monolithic_server(address = {}, user_port = {}, " "websocket_port = {})", address, user_port_, websocket_port_); @@ -329,6 +336,40 @@ std::error_code monolithic_server::run() noexcept { return {}; } +tl::expected +monolithic_server::load_keys() noexcept { + std::string_view filename = "server_kp.keys"; + + auto load_key = + [this](auto raw) -> tl::expected { + if (sizeof(kp_) != raw.size()) { + return tl::make_unexpected( + std::make_error_code(std::errc::bad_message)); + } + std::ranges::transform(std::begin(raw), + std::next(std::begin(raw), sizeof(kp_.pk)), std::begin(kp_.pk), + [](auto c) { return std::bit_cast(c); }); + return tl::monostate{}; + }; + + auto generate_keys = [this](auto const& err) + -> tl::expected { + logger.warning("Could not load server keys, generating a keypair"); + hydro_kx_keygen(&kp_); + std::span pk( + reinterpret_cast(kp_.pk), sizeof(kp_.pk)); + std::span sk( + reinterpret_cast(kp_.sk), sizeof(kp_.pk)); + logger.debug("\n\tPK: {}\n\tSK: {}", pk, sk); + return tl::monostate{}; + }; + + return utility::file::open(filename, O_RDWR | O_CREAT) + .and_then(utility::file::read) + .and_then(load_key) + .or_else(generate_keys); +} + net::awaitable> monolithic_server::create_session(std::shared_ptr const& conn, proto::connect_info const& info) {