From 2f1c3293d2c5776c4ecd9b2f1dce66492b15dbdd Mon Sep 17 00:00:00 2001 From: Dennis Brentjes Date: Wed, 31 Aug 2016 11:57:15 +0200 Subject: Split up the client and server parts in a separate network library --- CMakeLists.txt | 3 +++ libcmix-network/CMakeLists.txt | 29 +++++++++++++++++++++ libcmix-network/acceptor.cpp | 59 ++++++++++++++++++++++++++++++++++++++++++ libcmix-network/acceptor.hpp | 18 +++++++++++++ libcmix-network/client.cpp | 41 +++++++++++++++++++++++++++++ libcmix-network/client.hpp | 24 +++++++++++++++++ libcmix-network/nodeclient.cpp | 22 ++++++++++++++++ libcmix-network/nodeclient.hpp | 20 ++++++++++++++ libcmix-network/server.cpp | 31 ++++++++++++++++++++++ libcmix-network/server.hpp | 29 +++++++++++++++++++++ network-handler/CMakeLists.txt | 13 +--------- network-handler/acceptor.cpp | 59 ------------------------------------------ network-handler/acceptor.hpp | 18 ------------- network-handler/client.cpp | 41 ----------------------------- network-handler/client.hpp | 24 ----------------- network-handler/node.cpp | 21 --------------- network-handler/node.hpp | 21 --------------- network-handler/nodeclient.cpp | 22 ---------------- network-handler/nodeclient.hpp | 20 -------------- network-handler/server.cpp | 31 ---------------------- network-handler/server.hpp | 29 --------------------- node/CMakeLists.txt | 18 +++++++++++++ node/main.cpp | 4 +++ node/node.cpp | 21 +++++++++++++++ node/node.hpp | 21 +++++++++++++++ 25 files changed, 341 insertions(+), 298 deletions(-) create mode 100644 libcmix-network/CMakeLists.txt create mode 100644 libcmix-network/acceptor.cpp create mode 100644 libcmix-network/acceptor.hpp create mode 100644 libcmix-network/client.cpp create mode 100644 libcmix-network/client.hpp create mode 100644 libcmix-network/nodeclient.cpp create mode 100644 libcmix-network/nodeclient.hpp create mode 100644 libcmix-network/server.cpp create mode 100644 libcmix-network/server.hpp delete mode 100644 network-handler/acceptor.cpp delete mode 100644 network-handler/acceptor.hpp delete mode 100644 network-handler/client.cpp delete mode 100644 network-handler/client.hpp delete mode 100644 network-handler/node.cpp delete mode 100644 network-handler/node.hpp delete mode 100644 network-handler/nodeclient.cpp delete mode 100644 network-handler/nodeclient.hpp delete mode 100644 network-handler/server.cpp delete mode 100644 network-handler/server.hpp create mode 100644 node/CMakeLists.txt create mode 100644 node/main.cpp create mode 100644 node/node.cpp create mode 100644 node/node.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 97191ba..ea049cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,9 @@ endif(DOXYGEN_FOUND) add_subdirectory(libcmix-crypto) add_subdirectory(libcmix) +add_subdirectory(libcmix-network) + add_subdirectory(network-handler) +add_subdirectory(node) add_subdirectory(scratchpad) diff --git a/libcmix-network/CMakeLists.txt b/libcmix-network/CMakeLists.txt new file mode 100644 index 0000000..d819bec --- /dev/null +++ b/libcmix-network/CMakeLists.txt @@ -0,0 +1,29 @@ +find_package(Boost COMPONENTS system REQUIRED) + +add_library(cmix-network + acceptor.hpp acceptor.cpp + server.hpp server.cpp + client.hpp client.cpp + nodeclient.hpp nodeclient.cpp +) + +target_compile_options(cmix-network + PRIVATE "-std=c++11" +) + +target_include_directories(cmix-network + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_link_libraries(cmix-network + PRIVATE Boost::boost + PUBLIC Boost::system + PRIVATE cmix +) + +if(WIN32) + target_link_libraries(cmix-network + PUBLIC wsock32 + PUBLIC ws2_32 + ) +endif() diff --git a/libcmix-network/acceptor.cpp b/libcmix-network/acceptor.cpp new file mode 100644 index 0000000..34b5f0e --- /dev/null +++ b/libcmix-network/acceptor.cpp @@ -0,0 +1,59 @@ +#include "acceptor.hpp" + +#include +#include +#include +#include + + +using namespace boost::asio; +using namespace boost::asio::ip; + +void accept_loop(tcp::acceptor& acceptor, std::function f); + +void accept_connection(tcp::acceptor& acceptor, std::shared_ptr socket, boost::system::error_code ec, std::function f) +{ + if(!bool(ec)) + { + f(std::move(*socket)); + accept_loop(acceptor, f); + } else { + std::stringstream ss; + ss << ec; + throw std::runtime_error(ss.str()); + } + +} + +void accept_loop(tcp::acceptor& acceptor, std::function f) +{ + std::shared_ptr new_socket = std::make_shared(acceptor.get_io_service()); + + acceptor.async_accept(*new_socket, boost::bind(accept_connection, boost::ref(acceptor), new_socket, boost::asio::placeholders::error, f)); +} + +Acceptor::Acceptor(boost::asio::io_service &io_service, boost::asio::ip::address address, uint16_t port) +: acceptor(io_service) +, endpoint(address, port) +{} + +void Acceptor::bind_v6_and_v4_any(std::function accept_handler) { + acceptor.open(endpoint.protocol()); + + v6_only option(false); + acceptor.set_option(option); + + acceptor.bind(endpoint); + acceptor.listen(); + + accept_loop(acceptor, accept_handler); +} + +void Acceptor::setup_listen_socket(std::function accept_handler) +{ + acceptor.open(endpoint.protocol()); + acceptor.bind(endpoint); + acceptor.listen(); + + accept_loop(acceptor, accept_handler); +} diff --git a/libcmix-network/acceptor.hpp b/libcmix-network/acceptor.hpp new file mode 100644 index 0000000..7d8e0a2 --- /dev/null +++ b/libcmix-network/acceptor.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include + +class Acceptor{ + boost::asio::ip::tcp::acceptor acceptor; + boost::asio::ip::tcp::endpoint endpoint; + +public: + Acceptor(boost::asio::io_service& io_service, boost::asio::ip::address address, uint16_t port); + + boost::asio::ip::address get_address() { return endpoint.address(); } + + void bind_v6_and_v4_any(std::function accept_handler); + void setup_listen_socket(std::function accept_handler); +}; diff --git a/libcmix-network/client.cpp b/libcmix-network/client.cpp new file mode 100644 index 0000000..3098185 --- /dev/null +++ b/libcmix-network/client.cpp @@ -0,0 +1,41 @@ +#include "client.hpp" + +#include +#include + +#include + +using namespace boost::asio::ip; +using namespace boost::system; + +Client::Client(tcp::socket &&socket) +: socket(std::move(socket)) +, buffer() +{} + +void Client::handle_receive(MessageHandler message_handler, const error_code &ec, size_t read_bytes) +{ + buffer.commit(read_bytes); + std::istream is(&buffer); + + if(!ec) { + std::vector data(std::istream_iterator(is), {}); + message_handler(data); + receive(message_handler); + } else { + done(); + } +} + +void Client::receive(MessageHandler message_handler) { + using namespace boost::asio::placeholders; + + socket.async_receive( + buffer.prepare(512), + boost::bind(&Client::handle_receive, this, message_handler, error(), bytes_transferred()) + ); +} + +void Client::on_done(Client::OnDoneFT f) { + done = f; +} diff --git a/libcmix-network/client.hpp b/libcmix-network/client.hpp new file mode 100644 index 0000000..2b6a6df --- /dev/null +++ b/libcmix-network/client.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +#include + +class Client { +public: + typedef std::function OnDoneFT; + typedef std::function)> MessageHandler; + +private: + boost::asio::ip::tcp::socket socket; + boost::asio::streambuf buffer; + OnDoneFT done; + +public: + Client(boost::asio::ip::tcp::socket&& socket); + + void handle_receive(MessageHandler message_handler, boost::system::error_code const& ec, size_t read_bytes); + void receive(MessageHandler message_handler); + void on_done(OnDoneFT f); +}; diff --git a/libcmix-network/nodeclient.cpp b/libcmix-network/nodeclient.cpp new file mode 100644 index 0000000..9b026ba --- /dev/null +++ b/libcmix-network/nodeclient.cpp @@ -0,0 +1,22 @@ +#include "nodeclient.hpp" + +#include + +NodeClient::NodeClient(boost::asio::ip::tcp::socket &&socket) +: client(std::move(socket)) +{} + +void NodeClient::handle_message(std::vector message) +{ + std::cout << std::string(message.begin(), message.end()) << std::endl; +} + +void NodeClient::receive() +{ + client.receive(std::bind(&NodeClient::handle_message, this, std::placeholders::_1)); +} + +void NodeClient::on_done(Client::OnDoneFT done) { + client.on_done(done); +} + diff --git a/libcmix-network/nodeclient.hpp b/libcmix-network/nodeclient.hpp new file mode 100644 index 0000000..9a3799a --- /dev/null +++ b/libcmix-network/nodeclient.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include "client.hpp" + +#include + +#include + +class NodeClient +{ + Client client; + void handle_message(std::vector message); + +public: + NodeClient(boost::asio::ip::tcp::socket&& socket); + virtual ~NodeClient() = default; + + void receive(); + void on_done(Client::OnDoneFT done); +}; diff --git a/libcmix-network/server.cpp b/libcmix-network/server.cpp new file mode 100644 index 0000000..cb2bd34 --- /dev/null +++ b/libcmix-network/server.cpp @@ -0,0 +1,31 @@ +#include "server.hpp" + +using namespace boost::asio::ip; +using namespace boost::asio; + +Server::Server(io_service& io_service, const ListenSettings& listen_settings, AcceptHandler accept_handler) +: listen_settings(listen_settings) +, v4_acceptor(io_service, address_v4::from_string(listen_settings.ipv4_inaddr), listen_settings.port) +, v6_acceptor(io_service, address_v6::from_string(listen_settings.ipv6_inaddr), listen_settings.port) +{ + /* + * We can't bind both a v4 and v6 socket to both inaddr4_any and inaddr6_any. + * So in case both ipv4 and ipv6 are enabled and both want to bind to their + * respective inaddr_any we need to bind to v6 any and disable ipv6 only on + * the acceptor socket, else we can just bind to the interfaces normally. + */ + bool bind_v4_any = v4_acceptor.get_address().to_v4() == address_v4::any() && listen_settings.enable_ipv4; + bool bind_v6_any = v6_acceptor.get_address().to_v6() == address_v6::any() && listen_settings.enable_ipv6; + if(bind_v4_any && bind_v6_any) { + v6_acceptor.bind_v6_and_v4_any(accept_handler); + } else if(bind_v4_any || bind_v6_any) { + throw std::runtime_error("Cannot bind an INADDR_ANY and a non INADDR_ANY address on ipv4 and ipv6"); + } else { + if(listen_settings.enable_ipv4) { + v4_acceptor.setup_listen_socket(accept_handler); + } + if(listen_settings.enable_ipv6) { + v6_acceptor.setup_listen_socket(accept_handler); + } + } +} \ No newline at end of file diff --git a/libcmix-network/server.hpp b/libcmix-network/server.hpp new file mode 100644 index 0000000..942cb14 --- /dev/null +++ b/libcmix-network/server.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "acceptor.hpp" + +struct ListenSettings { + bool enable_ipv4; + std::string ipv4_inaddr; + bool enable_ipv6; + std::string ipv6_inaddr; + uint16_t port; +}; + +class Server +{ +public: + typedef std::function AcceptHandler; + +private: + ListenSettings const& listen_settings; + + Acceptor v4_acceptor; + Acceptor v6_acceptor; + +public: + Server(boost::asio::io_service& io_service, ListenSettings const& listen_settings, AcceptHandler accept_handler); + +}; diff --git a/network-handler/CMakeLists.txt b/network-handler/CMakeLists.txt index b4aef97..072172e 100644 --- a/network-handler/CMakeLists.txt +++ b/network-handler/CMakeLists.txt @@ -3,13 +3,8 @@ find_package(Boost COMPONENTS system program_options REQUIRED) add_executable(network-handler main.cpp - acceptor.hpp acceptor.cpp - server.hpp server.cpp networkhandler.hpp networkhandler.cpp - node.hpp node.cpp - client.hpp client.cpp userclient.hpp userclient.cpp - nodeclient.hpp nodeclient.cpp nodemanager.hpp nodemanager.cpp ) @@ -22,11 +17,5 @@ target_link_libraries(network-handler PRIVATE Boost::program_options PRIVATE Boost::system PRIVATE cmix + PRIVATE cmix-network ) - -if(WIN32) - target_link_libraries(network-handler - PRIVATE wsock32 - PRIVATE ws2_32 - ) -endif() diff --git a/network-handler/acceptor.cpp b/network-handler/acceptor.cpp deleted file mode 100644 index 34b5f0e..0000000 --- a/network-handler/acceptor.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "acceptor.hpp" - -#include -#include -#include -#include - - -using namespace boost::asio; -using namespace boost::asio::ip; - -void accept_loop(tcp::acceptor& acceptor, std::function f); - -void accept_connection(tcp::acceptor& acceptor, std::shared_ptr socket, boost::system::error_code ec, std::function f) -{ - if(!bool(ec)) - { - f(std::move(*socket)); - accept_loop(acceptor, f); - } else { - std::stringstream ss; - ss << ec; - throw std::runtime_error(ss.str()); - } - -} - -void accept_loop(tcp::acceptor& acceptor, std::function f) -{ - std::shared_ptr new_socket = std::make_shared(acceptor.get_io_service()); - - acceptor.async_accept(*new_socket, boost::bind(accept_connection, boost::ref(acceptor), new_socket, boost::asio::placeholders::error, f)); -} - -Acceptor::Acceptor(boost::asio::io_service &io_service, boost::asio::ip::address address, uint16_t port) -: acceptor(io_service) -, endpoint(address, port) -{} - -void Acceptor::bind_v6_and_v4_any(std::function accept_handler) { - acceptor.open(endpoint.protocol()); - - v6_only option(false); - acceptor.set_option(option); - - acceptor.bind(endpoint); - acceptor.listen(); - - accept_loop(acceptor, accept_handler); -} - -void Acceptor::setup_listen_socket(std::function accept_handler) -{ - acceptor.open(endpoint.protocol()); - acceptor.bind(endpoint); - acceptor.listen(); - - accept_loop(acceptor, accept_handler); -} diff --git a/network-handler/acceptor.hpp b/network-handler/acceptor.hpp deleted file mode 100644 index 7d8e0a2..0000000 --- a/network-handler/acceptor.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include - -#include - -class Acceptor{ - boost::asio::ip::tcp::acceptor acceptor; - boost::asio::ip::tcp::endpoint endpoint; - -public: - Acceptor(boost::asio::io_service& io_service, boost::asio::ip::address address, uint16_t port); - - boost::asio::ip::address get_address() { return endpoint.address(); } - - void bind_v6_and_v4_any(std::function accept_handler); - void setup_listen_socket(std::function accept_handler); -}; diff --git a/network-handler/client.cpp b/network-handler/client.cpp deleted file mode 100644 index 3098185..0000000 --- a/network-handler/client.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include "client.hpp" - -#include -#include - -#include - -using namespace boost::asio::ip; -using namespace boost::system; - -Client::Client(tcp::socket &&socket) -: socket(std::move(socket)) -, buffer() -{} - -void Client::handle_receive(MessageHandler message_handler, const error_code &ec, size_t read_bytes) -{ - buffer.commit(read_bytes); - std::istream is(&buffer); - - if(!ec) { - std::vector data(std::istream_iterator(is), {}); - message_handler(data); - receive(message_handler); - } else { - done(); - } -} - -void Client::receive(MessageHandler message_handler) { - using namespace boost::asio::placeholders; - - socket.async_receive( - buffer.prepare(512), - boost::bind(&Client::handle_receive, this, message_handler, error(), bytes_transferred()) - ); -} - -void Client::on_done(Client::OnDoneFT f) { - done = f; -} diff --git a/network-handler/client.hpp b/network-handler/client.hpp deleted file mode 100644 index 2b6a6df..0000000 --- a/network-handler/client.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include -#include - -#include - -class Client { -public: - typedef std::function OnDoneFT; - typedef std::function)> MessageHandler; - -private: - boost::asio::ip::tcp::socket socket; - boost::asio::streambuf buffer; - OnDoneFT done; - -public: - Client(boost::asio::ip::tcp::socket&& socket); - - void handle_receive(MessageHandler message_handler, boost::system::error_code const& ec, size_t read_bytes); - void receive(MessageHandler message_handler); - void on_done(OnDoneFT f); -}; diff --git a/network-handler/node.cpp b/network-handler/node.cpp deleted file mode 100644 index 497a920..0000000 --- a/network-handler/node.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "node.hpp" - -Node::Node(ListenSettings const& listen_settings) -: io_service() -, server(io_service, listen_settings, [this](boost::asio::ip::tcp::socket&& socket){accept_handler(std::move(socket));}) -, clients() -{} - -void Node::accept_handler(boost::asio::ip::tcp::socket&& socket) -{ - clients.emplace_back(std::move(socket)); - - auto it = --clients.end(); - clients.back().on_done( - [this, it]() { - clients.erase(it); - } - ); - - clients.back().receive(); -} diff --git a/network-handler/node.hpp b/network-handler/node.hpp deleted file mode 100644 index 7d30188..0000000 --- a/network-handler/node.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "server.hpp" -#include "nodeclient.hpp" - -#include - -#include - -class Node -{ - boost::asio::io_service io_service; - Server server; - std::list clients; - - void accept_handler(boost::asio::ip::tcp::socket&& socket); - -public: - Node(ListenSettings const& listen_settings); -}; - diff --git a/network-handler/nodeclient.cpp b/network-handler/nodeclient.cpp deleted file mode 100644 index 9b026ba..0000000 --- a/network-handler/nodeclient.cpp +++ /dev/null @@ -1,22 +0,0 @@ -#include "nodeclient.hpp" - -#include - -NodeClient::NodeClient(boost::asio::ip::tcp::socket &&socket) -: client(std::move(socket)) -{} - -void NodeClient::handle_message(std::vector message) -{ - std::cout << std::string(message.begin(), message.end()) << std::endl; -} - -void NodeClient::receive() -{ - client.receive(std::bind(&NodeClient::handle_message, this, std::placeholders::_1)); -} - -void NodeClient::on_done(Client::OnDoneFT done) { - client.on_done(done); -} - diff --git a/network-handler/nodeclient.hpp b/network-handler/nodeclient.hpp deleted file mode 100644 index 9a3799a..0000000 --- a/network-handler/nodeclient.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include "client.hpp" - -#include - -#include - -class NodeClient -{ - Client client; - void handle_message(std::vector message); - -public: - NodeClient(boost::asio::ip::tcp::socket&& socket); - virtual ~NodeClient() = default; - - void receive(); - void on_done(Client::OnDoneFT done); -}; diff --git a/network-handler/server.cpp b/network-handler/server.cpp deleted file mode 100644 index cb2bd34..0000000 --- a/network-handler/server.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "server.hpp" - -using namespace boost::asio::ip; -using namespace boost::asio; - -Server::Server(io_service& io_service, const ListenSettings& listen_settings, AcceptHandler accept_handler) -: listen_settings(listen_settings) -, v4_acceptor(io_service, address_v4::from_string(listen_settings.ipv4_inaddr), listen_settings.port) -, v6_acceptor(io_service, address_v6::from_string(listen_settings.ipv6_inaddr), listen_settings.port) -{ - /* - * We can't bind both a v4 and v6 socket to both inaddr4_any and inaddr6_any. - * So in case both ipv4 and ipv6 are enabled and both want to bind to their - * respective inaddr_any we need to bind to v6 any and disable ipv6 only on - * the acceptor socket, else we can just bind to the interfaces normally. - */ - bool bind_v4_any = v4_acceptor.get_address().to_v4() == address_v4::any() && listen_settings.enable_ipv4; - bool bind_v6_any = v6_acceptor.get_address().to_v6() == address_v6::any() && listen_settings.enable_ipv6; - if(bind_v4_any && bind_v6_any) { - v6_acceptor.bind_v6_and_v4_any(accept_handler); - } else if(bind_v4_any || bind_v6_any) { - throw std::runtime_error("Cannot bind an INADDR_ANY and a non INADDR_ANY address on ipv4 and ipv6"); - } else { - if(listen_settings.enable_ipv4) { - v4_acceptor.setup_listen_socket(accept_handler); - } - if(listen_settings.enable_ipv6) { - v6_acceptor.setup_listen_socket(accept_handler); - } - } -} \ No newline at end of file diff --git a/network-handler/server.hpp b/network-handler/server.hpp deleted file mode 100644 index 942cb14..0000000 --- a/network-handler/server.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - -#include "acceptor.hpp" - -struct ListenSettings { - bool enable_ipv4; - std::string ipv4_inaddr; - bool enable_ipv6; - std::string ipv6_inaddr; - uint16_t port; -}; - -class Server -{ -public: - typedef std::function AcceptHandler; - -private: - ListenSettings const& listen_settings; - - Acceptor v4_acceptor; - Acceptor v6_acceptor; - -public: - Server(boost::asio::io_service& io_service, ListenSettings const& listen_settings, AcceptHandler accept_handler); - -}; diff --git a/node/CMakeLists.txt b/node/CMakeLists.txt new file mode 100644 index 0000000..895cfb2 --- /dev/null +++ b/node/CMakeLists.txt @@ -0,0 +1,18 @@ +find_package(Boost COMPONENTS system program_options REQUIRED) + +add_executable(node + main.cpp + node.hpp node.cpp +) + +target_compile_options(node + PRIVATE "-std=c++11" +) + +target_link_libraries(node + PRIVATE Boost::boost + PRIVATE Boost::program_options + PRIVATE Boost::system + PRIVATE cmix + PRIVATE cmix-network +) diff --git a/node/main.cpp b/node/main.cpp new file mode 100644 index 0000000..970e150 --- /dev/null +++ b/node/main.cpp @@ -0,0 +1,4 @@ + +int main() { + +} diff --git a/node/node.cpp b/node/node.cpp new file mode 100644 index 0000000..497a920 --- /dev/null +++ b/node/node.cpp @@ -0,0 +1,21 @@ +#include "node.hpp" + +Node::Node(ListenSettings const& listen_settings) +: io_service() +, server(io_service, listen_settings, [this](boost::asio::ip::tcp::socket&& socket){accept_handler(std::move(socket));}) +, clients() +{} + +void Node::accept_handler(boost::asio::ip::tcp::socket&& socket) +{ + clients.emplace_back(std::move(socket)); + + auto it = --clients.end(); + clients.back().on_done( + [this, it]() { + clients.erase(it); + } + ); + + clients.back().receive(); +} diff --git a/node/node.hpp b/node/node.hpp new file mode 100644 index 0000000..7d30188 --- /dev/null +++ b/node/node.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "server.hpp" +#include "nodeclient.hpp" + +#include + +#include + +class Node +{ + boost::asio::io_service io_service; + Server server; + std::list clients; + + void accept_handler(boost::asio::ip::tcp::socket&& socket); + +public: + Node(ListenSettings const& listen_settings); +}; + -- cgit v1.2.3-70-g09d2