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 "Concepts.h"
22#include "IoContext.h"
23#include "IpAddress.h"
24#include "Log.h"
25#include "Socket.h"
26#include <boost/asio/ip/tcp.hpp>
27#include <boost/asio/ip/v6_only.hpp>
28#include <atomic>
29
30#define TRINITY_MAX_LISTEN_CONNECTIONS boost::asio::socket_base::max_listen_connections
31
32namespace Trinity::Net
33{
34template <typename Callable>
35concept AcceptCallback = std::invocable<Callable, IoContextTcpSocket&&>;
36
37template <typename Callable>
39
41{
42public:
43 AsyncAcceptor(Asio::IoContext& ioContext, std::string const& bindIp, uint16 port) :
44 _acceptor(ioContext), _endpoint(make_address(bindIp), port), _closed(false)
45 {
46 }
47
48 template <SelectIoContextForNewSocketFn SelectIoContextForNewSocket, AcceptCallback Callback>
49 void AsyncAccept(SelectIoContextForNewSocket&& selectIoContext, Callback&& acceptCallback)
50 {
51 Asio::IoContext* context = selectIoContext();
52 _acceptor.async_accept(context->get_executor(), [this,
53 selectIoContext = std::forward<SelectIoContextForNewSocket>(selectIoContext),
54 acceptCallback = std::forward<Callback>(acceptCallback)](boost::system::error_code const& error, IoContextTcpSocket&& socket) mutable
55 {
56 if (!error)
57 {
58 try
59 {
60 socket.non_blocking(true);
61
62 acceptCallback(std::move(socket));
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(selectIoContext), 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 // v6_only is enabled on some *BSD distributions by default
95 // we want to allow both v4 and v6 connections to the same listener
96 if (_endpoint.protocol() == boost::asio::ip::tcp::v6())
97 {
98 _acceptor.set_option(boost::asio::ip::v6_only(false), errorCode);
99 if (errorCode)
100 {
101 TC_LOG_INFO("network", "Could not disable v6_only option {}", errorCode.message());
102 return false;
103 }
104 }
105
106 _acceptor.bind(_endpoint, errorCode);
107 if (errorCode)
108 {
109 TC_LOG_INFO("network", "Could not bind to {}:{} {}", _endpoint.address(), _endpoint.port(), errorCode.message());
110 return false;
111 }
112
113 _acceptor.listen(TRINITY_MAX_LISTEN_CONNECTIONS, errorCode);
114 if (errorCode)
115 {
116 TC_LOG_INFO("network", "Failed to start listening on {}:{} {}", _endpoint.address(), _endpoint.port(), errorCode.message());
117 return false;
118 }
119
120 return true;
121 }
122
123 void Close()
124 {
125 if (_closed.exchange(true))
126 return;
127
128 boost::system::error_code err;
129 _acceptor.close(err);
130 }
131
132private:
133 boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, IoContextTcpSocket::executor_type> _acceptor;
134 boost::asio::ip::tcp::endpoint _endpoint;
135 std::atomic<bool> _closed;
136};
137}
138
139#endif // TRINITYCORE_ASYNC_ACCEPTOR_H
#define TRINITY_MAX_LISTEN_CONNECTIONS
uint16_t uint16
Definition Define.h:155
#define TC_LOG_INFO(filterType__, message__,...)
Definition Log.h:184
Executor get_executor() noexcept
Definition IoContext.h:47
std::atomic< bool > _closed
AsyncAcceptor(Asio::IoContext &ioContext, std::string const &bindIp, uint16 port)
void AsyncAccept(SelectIoContextForNewSocket &&selectIoContext, Callback &&acceptCallback)
boost::asio::basic_socket_acceptor< boost::asio::ip::tcp, IoContextTcpSocket::executor_type > _acceptor
boost::asio::ip::tcp::endpoint _endpoint
boost::asio::basic_stream_socket< boost::asio::ip::tcp, boost::asio::io_context::executor_type > IoContextTcpSocket
Definition Socket.h:40