Horizon Official Technical Documentation
AsyncAcceptor.hpp
Go to the documentation of this file.
1/***************************************************
2 * _ _ _ *
3 * | | | | (_) *
4 * | |_| | ___ _ __ _ _______ _ __ *
5 * | _ |/ _ \| '__| |_ / _ \| '_ \ *
6 * | | | | (_) | | | |/ / (_) | | | | *
7 * \_| |_/\___/|_| |_/___\___/|_| |_| *
8 ***************************************************
9 * This file is part of Horizon (c).
10 *
11 * Copyright (c) 2019 Sagun K. (sagunxp@gmail.com).
12 * Copyright (c) 2019 Horizon Dev Team.
13 *
14 * Base Author - Sagun K. (sagunxp@gmail.com)
15 *
16 * This library is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation, either version 3 of the License, or
19 * (at your option) any later version.
20 *
21 * This library is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this library. If not, see <http://www.gnu.org/licenses/>.
28 **************************************************/
29
30#ifndef HORIZON_NETWORKING_ASYNCACCEPTOR_HPP
31#define HORIZON_NETWORKING_ASYNCACCEPTOR_HPP
32
34
35#include <boost/asio.hpp>
36#include <functional>
37#include <iostream>
38#include <atomic>
39#include <memory>
40#include <tuple>
41
42using boost::asio::ip::tcp;
43
44namespace Horizon
45{
46namespace Networking
47{
52{
53public:
54 typedef std::function<void(std::shared_ptr<tcp::socket>, uint32_t thread_index)> AcceptCallback;
55
57 {
58 _acceptor.reset();
59 _socket.reset();
60 }
61
68 AsyncAcceptor(boost::asio::io_context &io_context, std::string const &listen_ip, uint16_t port)
69 : _endpoint(boost::asio::ip::address::from_string(listen_ip), port),
70 _acceptor(std::make_shared<tcp::acceptor>(io_context, tcp::endpoint(boost::asio::ip::address::from_string(listen_ip), port))),
71 _socket(std::make_shared<tcp::socket>(io_context)), _closed(false), _socket_factory(std::bind(&AsyncAcceptor::default_socket_factory, this))
72 {
73 }
74
75 template <class T> void AsyncAccept();
76
86 {
87 std::shared_ptr<tcp::socket> socket;
88
89 uint32_t thread_index;
90
91 std::tie(socket, thread_index) = _socket_factory();
92
93 _acceptor->async_accept(*socket, [this, socket, callback, thread_index] (boost::system::error_code error)
94 {
95 if (!error) {
96 try {
97 socket->non_blocking(true);
98 callback(std::move(socket), thread_index);
99 } catch (boost::system::system_error const &err) {
100 HLog(error) << "Networking: AsyncAcceptor failed to initialize client's socket :" << err.what();
101 }
102 }
103
104 if (!_closed)
105 this->async_accept_with_callback(callback);
106 });
107 }
108
112 bool bind()
113 {
114 boost::system::error_code errorCode;
115
116 _acceptor->open(_endpoint.protocol(), errorCode);
117
118 if (errorCode) {
119 HLog(error) << "Failed to open acceptor " << errorCode.message().c_str();
120 return false;
121 }
122
123 _acceptor->bind(_endpoint, errorCode);
124
125 if (errorCode) {
126 HLog(error) << "Could not bind to " << _endpoint.address().to_string().c_str() << ":" << _endpoint.port() << " - "
127 << errorCode.message().c_str();
128 return false;
129 }
130
131 _acceptor->listen(boost::asio::socket_base::max_connections, errorCode);
132
133 if (errorCode) {
134 HLog(error) << "Failed to start listening on " << _endpoint.address().to_string().c_str() << ":" << _endpoint.port() << " " << errorCode.message().c_str();
135 return false;
136 }
137
138 return true;
139 }
140
144 void close()
145 {
146 if (_closed.exchange(true))
147 return;
148
149 _socket->close();
150
151 boost::system::error_code error;
152 _acceptor->close(error);
153
154 _acceptor.reset();
155 _socket.reset();
156 if (error)
157 HLog(error) << "Failed to close acceptor: " << error.message().c_str();
158 }
159
160 bool is_open() { return !_closed.load(); }
161
165 void set_socket_factory(std::function<std::pair<std::shared_ptr<tcp::socket>, uint32_t>()> &&func) { _socket_factory = func; }
166
167private:
168 std::pair<std::shared_ptr<tcp::socket>, uint32_t> default_socket_factory() { return std::make_pair(_socket, 0); }
169
170 tcp::endpoint _endpoint;
171 std::shared_ptr<tcp::acceptor> _acceptor;
172 std::shared_ptr<tcp::socket> _socket;
173 std::atomic<bool> _closed;
174 std::function<std::pair<std::shared_ptr<tcp::socket>, uint32_t>()> _socket_factory;
175};
176
177template <class T>
179{
180 _acceptor->async_accept(_socket, [this] (boost::system::error_code error)
181 {
182 if (!error) {
183 try {
184 std::make_shared<T>(std::move(this->_socket))->start();
185 } catch (boost::system::system_error const &err) {
186 std::cerr << "Network Error: failed to retrieve client's remote address " << err.what() << std::endl;
187 }
188 }
189
190 if (!_closed)
191 this->AsyncAccept<T>();
192 });
193}
194}
195}
196
197#endif // HORIZON_NETWORKING_ASYNCACCEPTOR_HPP
#define HLog(type)
Definition: Logger.hpp:122
Asynchronous acceptor for sockets.
Definition: AsyncAcceptor.hpp:52
~AsyncAcceptor()
Definition: AsyncAcceptor.hpp:56
void AsyncAccept()
Definition: AsyncAcceptor.hpp:178
AsyncAcceptor(boost::asio::io_context &io_context, std::string const &listen_ip, uint16_t port)
Constructor of the AsyncAcceptor object.
Definition: AsyncAcceptor.hpp:68
std::pair< std::shared_ptr< tcp::socket >, uint32_t > default_socket_factory()
Definition: AsyncAcceptor.hpp:168
void close()
Closes the acceptor across all threads.
Definition: AsyncAcceptor.hpp:144
void async_accept_with_callback(AcceptCallback callback)
Asynchronously accepts sockets and executes a callback function.
Definition: AsyncAcceptor.hpp:85
void set_socket_factory(std::function< std::pair< std::shared_ptr< tcp::socket >, uint32_t >()> &&func)
Sets the socket factory for the acceptor.
Definition: AsyncAcceptor.hpp:165
std::shared_ptr< tcp::acceptor > _acceptor
Definition: AsyncAcceptor.hpp:171
std::function< std::pair< std::shared_ptr< tcp::socket >, uint32_t >()> _socket_factory
Definition: AsyncAcceptor.hpp:174
tcp::endpoint _endpoint
Definition: AsyncAcceptor.hpp:170
std::function< void(std::shared_ptr< tcp::socket >, uint32_t thread_index)> AcceptCallback
Definition: AsyncAcceptor.hpp:54
bool bind()
Binds this instance to an endpoint, to listen for connections.
Definition: AsyncAcceptor.hpp:112
std::atomic< bool > _closed
Definition: AsyncAcceptor.hpp:173
bool is_open()
Definition: AsyncAcceptor.hpp:160
std::shared_ptr< tcp::socket > _socket
Definition: AsyncAcceptor.hpp:172
Definition: Element.hpp:7