From d8e48c32f8435076382543edfafbf81c223f9e87 Mon Sep 17 00:00:00 2001 From: Dennis Brentjes Date: Mon, 10 Oct 2016 15:52:14 +0200 Subject: Added a Client so we can start finishing up the setup phase of cMix. --- client/CMakeLists.txt | 29 +++++++++++++++++++++++ client/cmixclient.cpp | 42 +++++++++++++++++++++++++++++++++ client/cmixclient.hpp | 33 ++++++++++++++++++++++++++ client/main.cpp | 51 ++++++++++++++++++++++++++++++++++++++++ client/node.cpp | 19 +++++++++++++++ client/node.hpp | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 239 insertions(+) create mode 100644 client/CMakeLists.txt create mode 100644 client/cmixclient.cpp create mode 100644 client/cmixclient.hpp create mode 100644 client/main.cpp create mode 100644 client/node.cpp create mode 100644 client/node.hpp (limited to 'client') diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt new file mode 100644 index 0000000..e04bf6a --- /dev/null +++ b/client/CMakeLists.txt @@ -0,0 +1,29 @@ +find_package(Boost COMPONENTS system program_options REQUIRED) + +add_executable(client + main.cpp + cmixclient.hpp cmixclient.cpp + node.hpp node.cpp +) + +if(WIN32) + target_compile_options(client + PRIVATE "-std=gnu++11" + ) +else(WIN32) + target_compile_options(client + PRIVATE "-std=c++11" + ) +endif(WIN32) + + +target_link_libraries(client + PRIVATE Boost::boost + PRIVATE Boost::program_options + PRIVATE Boost::system + PRIVATE log + PRIVATE cmix + PRIVATE cmix-bignum + PRIVATE cmix-network + PRIVATE cmix-protobuf +) diff --git a/client/cmixclient.cpp b/client/cmixclient.cpp new file mode 100644 index 0000000..e3f5ac4 --- /dev/null +++ b/client/cmixclient.cpp @@ -0,0 +1,42 @@ + +#include "cmixclient.hpp" + +void CMixClient::initialized() { + BOOST_LOG_TRIVIAL(trace) << "Client connections were made"; + for(auto&& connection : network_connections) { + cmix_proto::Bye bye; + connection.send(bye); + } + io_service.stop(); +} + +void CMixClient::initialize_connections() { + network_connections.reserve(network_details.size()); + + int i = network_details.size(); + auto handler = [this, i]() mutable { + cmix_proto::ImAClient imaclient; + network_connections.at(network_details.size() - i).send(imaclient); + + if(--i == 0) { + initialized(); + } + }; + + for(auto&& details : network_details) { + network_connections.emplace_back(boost::asio::ip::tcp::socket(io_service)); + network_connections.back().async_connect(details.host, details.port, handler); + } +} + +CMixClient::CMixClient(std::vector details) +: io_service() +, network_details(details) +, network_connections() +{ + initialize_connections(); +} + +void CMixClient::run() { + io_service.run(); +} diff --git a/client/cmixclient.hpp b/client/cmixclient.hpp new file mode 100644 index 0000000..10438d1 --- /dev/null +++ b/client/cmixclient.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "node.hpp" + +#include "logging.hpp" +#include "client.hpp" +#include "connect.hpp" +#include "cmix.pb.h" + +#include +#include + +struct NodeDetails { + std::string host; + std::string port; +}; + +class CMixClient { + + boost::asio::io_service io_service; + + std::vector network_details; + std::vector network_connections; + + void initialized(); + + void initialize_connections(); + +public: + CMixClient(std::vector details); + + void run(); +}; \ No newline at end of file diff --git a/client/main.cpp b/client/main.cpp new file mode 100644 index 0000000..fb05171 --- /dev/null +++ b/client/main.cpp @@ -0,0 +1,51 @@ + +#include "cmixclient.hpp" + +#include "uriparser.hpp" +#include "logging.hpp" + +#include + +#include +#include + +int main(int argc, char* argv[]) { + namespace po = boost::program_options; + + init_logging(boost::log::trivial::severity_level::trace, "client"); + + BOOST_LOG_TRIVIAL(info) << "Started node"; + + po::options_description desc("Allowed options"); + desc.add_options() + ("help,h", "produce help message.") + ("network,n", po::value>()->multitoken(), "The addresses of the network nodes in order") + ; + + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); + + if (vm.count("help")) { + std::cout << desc << "\n"; + return 0; + } + + std::vector network; + if(vm.count("network")) { + network = vm["network"].as>(); + } else { + std::cerr << "network option is required." << std::endl; + return -1; + } + + std::vector node_details; + for(auto&& node : network) { + Uri uri = parse_uri(node); + + node_details.push_back({uri.host, uri.port}); + } + + CMixClient cmix_client(node_details); + cmix_client.run(); +} diff --git a/client/node.cpp b/client/node.cpp new file mode 100644 index 0000000..8fd1dd8 --- /dev/null +++ b/client/node.cpp @@ -0,0 +1,19 @@ +#include "node.hpp" + +#include "logging.hpp" + +using namespace boost::asio::ip; + +Node::Node(tcp::socket&& socket) +: client(std::move(socket)) +{} + +void Node::async_connect(std::string next_host, std::string next_port, std::function on_connect) +{ + client.async_connect(next_host, next_port, on_connect); +} + +void Node::close() +{ + client.close(); +} diff --git a/client/node.hpp b/client/node.hpp new file mode 100644 index 0000000..3719223 --- /dev/null +++ b/client/node.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "client.hpp" + +#include "cmix.pb.h" + +#include + +/*! + * \file + */ + +/*! + * MESSAGE_SETTER is a boilerplate macro that generates a setter function for our CMix + * 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(TYPE, NAME) \ +inline void message_setter(cmix_proto::CMixMessage& m, cmix_proto::TYPE const& v) { \ + *m.mutable_##NAME() = v; \ +} \ + +MESSAGE_SETTER(ImAClient, imaclient) +MESSAGE_SETTER(Bye, bye) + +#undef MESSAGE_SETTER + +/*! + * \brief The Node class represents a node in the network. + */ +class Node +{ + Client client; +public: + /*! + * \brief Node + * \param socket an rvalue reference to the socket it takes ownership and uses to communicate with the next node in the network. + */ + Node(boost::asio::ip::tcp::socket&& socket); + + /*! + * \brief send + * \param v The CMixMessage type we try to send and first have to wrap in a CMixMessage. + */ + template + void send(T v) { + cmix_proto::CMixMessage m; + message_setter(m, v); + client.send(m.SerializeAsString()); + } + + /*! + * \brief async_connect + * \param next_host The host of the next node. + * \param next_port The port of the next node. + * \param on_connect The callback to call when the connect was succesfull. + */ + void async_connect(std::string next_host, std::string next_port, std::function on_connect); + + /*! + * \brief close This function closes the underlying socket connection. + */ + void close(); +}; + -- cgit v1.2.3-70-g09d2