From a736abb4e3668771f248e7400a093cb40b5313b7 Mon Sep 17 00:00:00 2001 From: Dennis Brentjes Date: Mon, 29 Aug 2016 13:29:30 +0200 Subject: Adds the Acceptor and Client class. The acceptor combines the endpoint and acceptor to reduce clutter in NetworkHandler class. The client will handle the connection for the network handler for every separate client. The networkhander now has a std::list of Client, to keep track and ownership of all the Clients. --- network-handler/CMakeLists.txt | 13 +++++-- network-handler/acceptor.cpp | 59 +++++++++++++++++++++++++++++++ network-handler/acceptor.hpp | 18 ++++++++++ network-handler/client.cpp | 39 +++++++++++++++++++++ network-handler/client.hpp | 23 ++++++++++++ network-handler/networkhandler.cpp | 72 ++++++++++++-------------------------- network-handler/networkhandler.hpp | 17 +++++---- 7 files changed, 182 insertions(+), 59 deletions(-) create mode 100644 network-handler/acceptor.cpp create mode 100644 network-handler/acceptor.hpp create mode 100644 network-handler/client.cpp create mode 100644 network-handler/client.hpp diff --git a/network-handler/CMakeLists.txt b/network-handler/CMakeLists.txt index 9f3366c..12898dc 100644 --- a/network-handler/CMakeLists.txt +++ b/network-handler/CMakeLists.txt @@ -4,14 +4,23 @@ find_package(Boost COMPONENTS system program_options REQUIRED) add_executable(network-handler main.cpp networkhandler.hpp networkhandler.cpp + acceptor.hpp acceptor.cpp + client.hpp client.cpp ) target_compile_options(network-handler - PRIVATE "-std=c++11" + PRIVATE "-std=c++14" ) target_link_libraries(network-handler PRIVATE Boost::boost PRIVATE Boost::program_options PRIVATE Boost::system -) \ No newline at end of file +) + +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 new file mode 100644 index 0000000..34b5f0e --- /dev/null +++ b/network-handler/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/network-handler/acceptor.hpp b/network-handler/acceptor.hpp new file mode 100644 index 0000000..7d8e0a2 --- /dev/null +++ b/network-handler/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/network-handler/client.cpp b/network-handler/client.cpp new file mode 100644 index 0000000..816753c --- /dev/null +++ b/network-handler/client.cpp @@ -0,0 +1,39 @@ +#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(const error_code &ec, size_t read_bytes) +{ + if(!ec) { + std::string str(buffer.begin(), buffer.end()); + std::cout << "Received: " << str << std::endl; + receive(); + } else { + on_done(); + } +} + +void Client::receive() { + using namespace boost::asio::placeholders; + + memset(buffer.data(), 0, buffer.size()); + socket.async_receive( + boost::asio::buffer(buffer), + boost::bind(&Client::handle_receive, this, error(), bytes_transferred()) + ); +} + +void Client::set_on_done(Client::OnDoneFT f) { + on_done = f; +} diff --git a/network-handler/client.hpp b/network-handler/client.hpp new file mode 100644 index 0000000..878c5be --- /dev/null +++ b/network-handler/client.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include + +#include + +class Client { +public: + typedef std::function OnDoneFT; + +private: + boost::asio::ip::tcp::socket socket; + std::array buffer; + OnDoneFT on_done; + + +public: + Client(boost::asio::ip::tcp::socket&& socket); + + void handle_receive(boost::system::error_code const& ec, size_t read_bytes); + void receive(); + void set_on_done(OnDoneFT f); +}; diff --git a/network-handler/networkhandler.cpp b/network-handler/networkhandler.cpp index 987d2a1..8c5997f 100644 --- a/network-handler/networkhandler.cpp +++ b/network-handler/networkhandler.cpp @@ -1,6 +1,7 @@ #include "networkhandler.hpp" #include +#include #include #include @@ -8,48 +9,25 @@ using namespace boost::asio::ip; using namespace boost::asio; -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)); -} - -void setup_listen_socket(tcp::acceptor& acceptor, tcp::endpoint& endpoint, std::function f) { - acceptor.open(endpoint.protocol()); - acceptor.bind(endpoint); - acceptor.listen(); - - accept_loop(acceptor, f); -} - NetworkHandler::NetworkHandler(const ListenSettings& listen_settings) : listen_settings(listen_settings) , io_service() -, v4_acceptor(io_service) -, v6_acceptor(io_service) -, v4_endpoint(address_v4::from_string(listen_settings.ipv4_inaddr), listen_settings.port) -, v6_endpoint(address_v6::from_string(listen_settings.ipv6_inaddr), listen_settings.port) +, 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) +, stdin_buffer() +, clients() { auto accept_handler = [this](tcp::socket&& socket) { - accepted_connections.push_back(std::move(socket)); - std::cout << "Yippie" << std::endl; + clients.push_back(Client(std::move(socket))); + auto it = --clients.end(); + + clients.back().set_on_done( + [this, it]() { + clients.erase(it); + } + ); + + clients.back().receive(); }; /* @@ -58,28 +36,22 @@ NetworkHandler::NetworkHandler(const ListenSettings& listen_settings) * 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_endpoint.address().to_v4() == address_v4::any() && listen_settings.enable_ipv4; - bool bind_v6_any = v6_endpoint.address().to_v6() == address_v6::any() && listen_settings.enable_ipv6; + 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.open(v6_endpoint.protocol()); - - v6_only option(false); - v6_acceptor.set_option(option); - - v6_acceptor.bind(v6_endpoint); - v6_acceptor.listen(); - - accept_loop(v6_acceptor, accept_handler); + 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) { - setup_listen_socket(v4_acceptor, v4_endpoint, accept_handler); + v4_acceptor.setup_listen_socket(accept_handler); } if(listen_settings.enable_ipv6) { - setup_listen_socket(v6_acceptor, v6_endpoint, accept_handler); + v6_acceptor.setup_listen_socket(accept_handler); } } + + //read_stdin(); } void NetworkHandler::run() { diff --git a/network-handler/networkhandler.hpp b/network-handler/networkhandler.hpp index d0eab6f..c4930ca 100644 --- a/network-handler/networkhandler.hpp +++ b/network-handler/networkhandler.hpp @@ -1,7 +1,10 @@ #pragma once +#include "acceptor.hpp" +#include "client.hpp" + #include -#include +#include #include #include @@ -20,12 +23,12 @@ class NetworkHandler ListenSettings const& listen_settings; boost::asio::io_service io_service; - boost::asio::ip::tcp::acceptor v4_acceptor; - boost::asio::ip::tcp::acceptor v6_acceptor; - boost::asio::ip::tcp::endpoint v4_endpoint; - boost::asio::ip::tcp::endpoint v6_endpoint; - - std::list accepted_connections; + Acceptor v4_acceptor; + Acceptor v6_acceptor; + + boost::asio::streambuf stdin_buffer; + + std::list clients; public: NetworkHandler(ListenSettings const& listen_settings); -- cgit v1.2.3-70-g09d2