TrinityCore
Loading...
Searching...
No Matches
AsyncAcceptor.h
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#ifndef TRINITYCORE_ASYNC_ACCEPTOR_H
19#define TRINITYCORE_ASYNC_ACCEPTOR_H
20
21#include "IoContext.h"
22#include "IpAddress.h"
23#include "Log.h"
24#include "Socket.h"
25#include <boost/asio/ip/tcp.hpp>
26#include <atomic>
27#include <functional>
28
29using boost::asio::ip::tcp;
30
31#define TRINITY_MAX_LISTEN_CONNECTIONS boost::asio::socket_base::max_listen_connections
32
33namespace Trinity::Net
34{
35template <typename Callable>
36concept AcceptCallback = std::invocable<Callable, IoContextTcpSocket&&, uint32>;
37
39{
40public:
41 AsyncAcceptor(Asio::IoContext& ioContext, std::string const& bindIp, uint16 port) :
42 _acceptor(ioContext), _endpoint(make_address(bindIp), port),
43 _socket(ioContext), _closed(false), _socketFactory(std::bind(&AsyncAcceptor::DefeaultSocketFactory, this))
44 {
45 }
46
47 template <AcceptCallback Callback>
48 void AsyncAccept(Callback&& acceptCallback)
49 {
50 auto [tmpSocket, tmpThreadIndex] = _socketFactory();
51 // TODO: get rid of temporary variables (clang 15 cannot handle variables from structured bindings as lambda captures)
52 IoContextTcpSocket* socket = tmpSocket;
53 uint32 threadIndex = tmpThreadIndex;
54 _acceptor.async_accept(*socket, [this, socket, threadIndex, acceptCallback = std::forward<Callback>(acceptCallback)](boost::system::error_code const& error) mutable
55 {
56 if (!error)
57 {
58 try
59 {
60 socket->non_blocking(true);
61
62 acceptCallback(std::move(*socket), threadIndex);
63 }
64 catch (boost::system::system_error const& err)
65 {
66 TC_LOG_INFO("network", "Failed to initialize client's socket {}", err.what());
67 }
68 }
69
70 if (!_closed)
71 this->AsyncAccept(std::move(acceptCallback));
72 });
73 }
74
75 bool Bind()
76 {
77 boost::system::error_code errorCode;
78 _acceptor.open(_endpoint.protocol(), errorCode);
79 if (errorCode)
80 {
81 TC_LOG_INFO("network", "Failed to open acceptor {}", errorCode.message());
82 return false;
83 }
84
85#if TRINITY_PLATFORM != TRINITY_PLATFORM_WINDOWS
86 _acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true), errorCode);
87 if (errorCode)
88 {
89 TC_LOG_INFO("network", "Failed to set reuse_address option on acceptor {}", errorCode.message());
90 return false;
91 }
92#endif
93
94 _acceptor.bind(_endpoint, errorCode);
95 if (errorCode)
96 {
97 TC_LOG_INFO("network", "Could not bind to {}:{} {}", _endpoint.address().to_string(), _endpoint.port(), errorCode.message());
98 return false;
99 }
100
101 _acceptor.listen(TRINITY_MAX_LISTEN_CONNECTIONS, errorCode);
102 if (errorCode)
103 {
104 TC_LOG_INFO("network", "Failed to start listening on {}:{} {}", _endpoint.address().to_string(), _endpoint.port(), errorCode.message());
105 return false;
106 }
107
108 return true;
109 }
110
111 void Close()
112 {
113 if (_closed.exchange(true))
114 return;
115
116 boost::system::error_code err;
117 _acceptor.close(err);
118 }
119
120 void SetSocketFactory(std::function<std::pair<IoContextTcpSocket*, uint32>()> func) { _socketFactory = std::move(func); }
121
122private:
123 std::pair<IoContextTcpSocket*, uint32> DefeaultSocketFactory() { return std::make_pair(&_socket, 0); }
124
125 boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, IoContextTcpSocket::executor_type> _acceptor;
126 boost::asio::ip::tcp::endpoint _endpoint;
128 std::atomic<bool> _closed;
129 std::function<std::pair<IoContextTcpSocket*, uint32>()> _socketFactory;
130};
131}
132
133#endif // TRINITYCORE_ASYNC_ACCEPTOR_H
#define TRINITY_MAX_LISTEN_CONNECTIONS
uint16_t uint16
Definition Define.h:134
uint32_t uint32
Definition Define.h:133
#define TC_LOG_INFO(filterType__,...)
Definition Log.h:159
std::atomic< bool > _closed
AsyncAcceptor(Asio::IoContext &ioContext, std::string const &bindIp, uint16 port)
void SetSocketFactory(std::function< std::pair< IoContextTcpSocket *, uint32 >()> func)
boost::asio::basic_socket_acceptor< boost::asio::ip::tcp, IoContextTcpSocket::executor_type > _acceptor
boost::asio::ip::tcp::endpoint _endpoint
std::pair< IoContextTcpSocket *, uint32 > DefeaultSocketFactory()
IoContextTcpSocket _socket
std::function< std::pair< IoContextTcpSocket *, uint32 >()> _socketFactory
void AsyncAccept(Callback &&acceptCallback)
boost::asio::basic_stream_socket< boost::asio::ip::tcp, boost::asio::io_context::executor_type > IoContextTcpSocket
Definition Socket.h:41
STL namespace.