From 88c5130eccd06e63ffca732626c0fb59426743a7 Mon Sep 17 00:00:00 2001 From: Dennis Brentjes Date: Wed, 5 Oct 2016 12:56:52 +0200 Subject: Seperates Nodes and Clients for incoming connections. Created a PrevNode class to reflect the seperation. Made Client movable. Added 2 empty protobuf message that declare what each connecting client is, sent when connected to a node. --- libcmix-network/client.cpp | 10 ++--- libcmix-network/client.hpp | 12 +++++- libcmix-protobuf/cmix.proto | 10 +++++ node/CMakeLists.txt | 1 + node/main.cpp | 2 + node/nextnode.hpp | 9 +++-- node/node.cpp | 99 +++++++++++++++++++++++++++++++++------------ node/node.hpp | 10 ++++- node/prevnode.cpp | 14 +++++++ node/prevnode.hpp | 42 +++++++++++++++++++ 10 files changed, 172 insertions(+), 37 deletions(-) create mode 100644 node/prevnode.cpp create mode 100644 node/prevnode.hpp diff --git a/libcmix-network/client.cpp b/libcmix-network/client.cpp index 7c95234..9293bd1 100644 --- a/libcmix-network/client.cpp +++ b/libcmix-network/client.cpp @@ -16,7 +16,7 @@ using namespace boost::system; Client::Client(tcp::socket &&socket) : socket(std::move(socket)) -, buffer() +, buffer(new boost::asio::streambuf()) , done() {} @@ -61,8 +61,8 @@ void Client::send(std::string message) { std::vector Client::received_bytes_to_vector(size_t read_bytes) { - buffer.commit(read_bytes); - std::istream is(&buffer); + buffer->commit(read_bytes); + std::istream is(buffer.get()); is.unsetf(std::ios::skipws); return std::vector(std::istream_iterator(is), {}); @@ -92,7 +92,7 @@ void Client::handle_receive_size(Client::MessageHandler message_handler, const e size = ntohl(size); socket.async_receive( - buffer.prepare(size), + buffer->prepare(size), boost::bind(&Client::handle_receive_message, this, message_handler, error(), bytes_transferred()) ); } else { @@ -107,7 +107,7 @@ void Client::receive(MessageHandler message_handler) { using namespace boost::asio::placeholders; socket.async_receive( - buffer.prepare(4), + buffer->prepare(4), boost::bind(&Client::handle_receive_size, this, message_handler, error(), bytes_transferred()) ); } diff --git a/libcmix-network/client.hpp b/libcmix-network/client.hpp index 51dfa6f..dc3787d 100644 --- a/libcmix-network/client.hpp +++ b/libcmix-network/client.hpp @@ -31,7 +31,7 @@ protected: boost::asio::ip::tcp::socket socket; private: - boost::asio::streambuf buffer; + std::unique_ptr buffer; OnDoneFT done; @@ -51,6 +51,16 @@ public: Client(boost::asio::ip::tcp::socket&& socket); ~Client(); + /*! + * \brief Move constructor for Client. + */ + Client(Client&&) = default; + + /*! + * \brief Move assignment for Client. + */ + Client& operator=(Client&&) = default; + /*! * \brief async_connect Asynchronously connects to next_host:port and calls on_connect * \param next_host The host to connect to diff --git a/libcmix-protobuf/cmix.proto b/libcmix-protobuf/cmix.proto index 3068291..6e653f1 100644 --- a/libcmix-protobuf/cmix.proto +++ b/libcmix-protobuf/cmix.proto @@ -4,8 +4,18 @@ message Initialization { required bytes public_share = 1; } +message ImANode { + +} + +message ImAClient { + +} + message CMixMessage { oneof contents { Initialization initialization = 1; + ImANode imanode = 2; + ImAClient imaclient = 3; } } diff --git a/node/CMakeLists.txt b/node/CMakeLists.txt index 9151cbc..53ca12e 100644 --- a/node/CMakeLists.txt +++ b/node/CMakeLists.txt @@ -3,6 +3,7 @@ find_package(Boost COMPONENTS system program_options REQUIRED) add_executable(node main.cpp node.hpp node.cpp + prevnode.hpp prevnode.cpp nextnode.hpp nextnode.cpp ) diff --git a/node/main.cpp b/node/main.cpp index 1327ac5..031e0d0 100644 --- a/node/main.cpp +++ b/node/main.cpp @@ -12,6 +12,8 @@ int main(int argc, char* argv[]) { init_logging(boost::log::trivial::severity_level::trace); + BOOST_LOG_TRIVIAL(info) << "Started node"; + po::options_description desc("Allowed options"); desc.add_options() ("help,h", "produce help message.") diff --git a/node/nextnode.hpp b/node/nextnode.hpp index 9601ab5..862ca5c 100644 --- a/node/nextnode.hpp +++ b/node/nextnode.hpp @@ -15,12 +15,13 @@ * protobuf messages, This because there are seperate functions for each to type to use. * And there seems no way to solve this using templates. */ -#define MESSAGE_SETTER(T,F,NAME) \ -inline void message_setter(cmix_proto::CMixMessage& m, cmix_proto::T##NAME const& v) { \ - *m.mutable_##F##NAME() = v; \ +#define MESSAGE_SETTER(TYPE, NAME) \ +inline void message_setter(cmix_proto::CMixMessage& m, cmix_proto::TYPE const& v) { \ + *m.mutable_##NAME() = v; \ } \ -MESSAGE_SETTER(I,i,nitialization) +MESSAGE_SETTER(Initialization, initialization) +MESSAGE_SETTER(ImANode, imanode) #undef MESSAGE_SETTER diff --git a/node/node.cpp b/node/node.cpp index fb5b875..c02e5e6 100644 --- a/node/node.cpp +++ b/node/node.cpp @@ -13,6 +13,7 @@ Node::Node(ListenSettings const& listen_settings, NodeNetworkSettings network_se , server(io_service, listen_settings, [this](boost::asio::ip::tcp::socket&& socket){accept_handler(std::move(socket));}) , clients() , network_settings(network_settings) +, prev_node(Client(tcp::socket(io_service))) , next_node(tcp::socket(io_service)) , api(get_curve25519_implementation()) , keypair(api.create_key_pair()) @@ -21,6 +22,7 @@ Node::Node(ListenSettings const& listen_settings, NodeNetworkSettings network_se GOOGLE_PROTOBUF_VERIFY_VERSION; auto on_connect = [this, network_settings](){ + next_node.send(cmix_proto::ImANode()); if(network_settings.is_first) { start_initialisation(); } @@ -39,16 +41,18 @@ void Node::run() { void Node::accept_handler(boost::asio::ip::tcp::socket&& socket) { - clients.emplace_back(std::move(socket)); + purgatory.emplace_back(std::move(socket)); - auto it = --clients.end(); - clients.back().on_done( + std::list::iterator it = --purgatory.end(); + purgatory.back().on_done( [this, it]() { - clients.erase(it); + purgatory.erase(it); } ); - it->receive(std::bind(&Node::handle_message, this, std::placeholders::_1)); + it->receive([this, it](std::vector const& message_buffer) { + handle_message(decltype(it)(it), message_buffer); + }); } void Node::start_initialisation() { @@ -58,27 +62,6 @@ void Node::start_initialisation() { next_node.send(init); } -void Node::handle_message(const std::vector& message_buffer) -{ - cmix_proto::CMixMessage message; - if(!message.ParseFromArray(message_buffer.data(), message_buffer.size())) { - BOOST_LOG_TRIVIAL(error) << "Received something which was not a CMixMessage"; - clients.clear(); - io_service.stop(); - return; - } - - switch(message.contents_case()) { - case cmix_proto::CMixMessage::ContentsCase::kInitialization: { - handle_initialization(message.initialization()); - break; - } - default: { - BOOST_LOG_TRIVIAL(error) << "CMixMessage contains unknown contents."; - } - } -} - void Node::handle_initialization(const cmix_proto::Initialization& init) { if(network_settings.is_first) { @@ -114,6 +97,70 @@ void Node::handle_initialization(const cmix_proto::Initialization& init) } } +void Node::handle_message(const std::vector& message_buffer) +{ + cmix_proto::CMixMessage message; + if(!message.ParseFromArray(message_buffer.data(), message_buffer.size())) { + BOOST_LOG_TRIVIAL(error) << "Received something which was not a CMixMessage"; + clients.clear(); + io_service.stop(); + return; + } + + switch(message.contents_case()) { + case cmix_proto::CMixMessage::ContentsCase::kInitialization: { + handle_initialization(message.initialization()); + break; + } + default: { + BOOST_LOG_TRIVIAL(error) << "CMixMessage contains unknown contents."; + } + } +} + +void Node::handle_imanode(std::list::iterator handle) { + handle->on_done([]{}); + prev_node = PrevNode(std::move(*handle)); + purgatory.erase(handle); + prev_node.receive([this](std::vector const& message_buffer){ + handle_message(message_buffer); + }); +} + +void Node::handle_imaclient(std::list::iterator handle) { + clients.emplace_back(std::move(*handle)); + std::list::iterator it = clients.end()--; + it->on_done([this, it]{ + clients.erase(it); + }); + purgatory.erase(handle); +} + +void Node::handle_message(std::list::iterator handle, const std::vector& message_buffer) +{ + cmix_proto::CMixMessage message; + if(!message.ParseFromArray(message_buffer.data(), message_buffer.size())) { + BOOST_LOG_TRIVIAL(error) << "Received something which was not a CMixMessage"; + clients.clear(); + io_service.stop(); + return; + } + + switch(message.contents_case()) { + case cmix_proto::CMixMessage::ContentsCase::kImanode: { + handle_imanode(handle); + break; + } + case cmix_proto::CMixMessage::ContentsCase::kImaclient: { + handle_imaclient(handle); + break; + } + default: { + BOOST_LOG_TRIVIAL(error) << "CMixMessage contains unknown contents."; + } + } +} + void Node::start_precomputation() { clients.clear(); io_service.stop(); diff --git a/node/node.hpp b/node/node.hpp index a481c70..a4e21b3 100644 --- a/node/node.hpp +++ b/node/node.hpp @@ -2,6 +2,7 @@ #include "server.hpp" #include "nodeclient.hpp" +#include "prevnode.hpp" #include "nextnode.hpp" #include "api.h" @@ -33,10 +34,12 @@ class Node { boost::asio::io_service io_service; Server server; + std::list purgatory; std::list clients; NodeNetworkSettings network_settings; + PrevNode prev_node; NextNode next_node; Api api; @@ -48,8 +51,13 @@ class Node void start_precomputation(); void start_initialisation(); - void handle_message(std::vector const& message_buffer); void handle_initialization(cmix_proto::Initialization const& init); + void handle_message(std::vector const& message_buffer); + + void handle_imanode(std::list::iterator handle); + void handle_imaclient(std::list::iterator handle); + void handle_message(std::list::iterator handle, std::vector const& message_buffer); + public: /*! diff --git a/node/prevnode.cpp b/node/prevnode.cpp new file mode 100644 index 0000000..6af2242 --- /dev/null +++ b/node/prevnode.cpp @@ -0,0 +1,14 @@ +#include "prevnode.hpp" + +PrevNode::PrevNode(Client&& client) +: client(std::move(client)) +{} + +void PrevNode::receive(std::function&)> receive_handler) { + client.receive(receive_handler); +} + +void PrevNode::close() +{ + client.close(); +} diff --git a/node/prevnode.hpp b/node/prevnode.hpp new file mode 100644 index 0000000..6a6b431 --- /dev/null +++ b/node/prevnode.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include "client.hpp" + +#include "cmix.pb.h" + +#include + +/*! + * \file + */ + +/*! + * \brief The PrevNode class represents the previous node in the network, will only be received from. + */ +class PrevNode +{ + Client client; +public: + /*! + * \brief PrevNode + * \param socket an rvalue reference to the socket it takes ownership and uses to communicate with the previous node in the network. + */ + PrevNode(Client&& socket); + + /*! + * \brief PrevNode move assignment operator. + */ + PrevNode& operator=(PrevNode&&) = default; + + /*! + * \brief receive Forwards a receive request to the client. + * \param receive_handler The function to call with the received data. + */ + void receive(std::function const&)> receive_handler); + + /*! + * \brief close This function closes the underlying socket connection. + */ + void close(); +}; + -- cgit v1.2.3-70-g09d2