#include "networkhandler.hpp" #include #include #include 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) { auto accept_handler = [this](tcp::socket&& socket) { accepted_connections.push_back(std::move(socket)); std::cout << "Yippie" << std::endl; }; /* * 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_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; 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); } 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); } if(listen_settings.enable_ipv6) { setup_listen_socket(v6_acceptor, v6_endpoint, accept_handler); } } } void NetworkHandler::run() { io_service.run(); }