-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathAsioAcceptor.hpp
More file actions
215 lines (178 loc) · 7.49 KB
/
Copy pathAsioAcceptor.hpp
File metadata and controls
215 lines (178 loc) · 7.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#ifndef ASIO_FIX_ASIO_ACCEPTOR_HPP
#define ASIO_FIX_ASIO_ACCEPTOR_HPP
#include "AsioConnection.hpp"
#include "AsioWSEstablishing.hpp"
#include <quickfix/Acceptor.h>
#include <boost/asio/ip/tcp.hpp>
namespace FIX {
const char SOCKET_PROTOCOL[] = "SocketProtocol";
template <typename socket_t> class AsioSocketConnection;
class AsioTCPAcceptorServer : public std::enable_shared_from_this<AsioTCPAcceptorServer> {
public:
AsioTCPAcceptorServer(boost::asio::io_context &ioContext, Acceptor *socketAcceptor, uint16_t port)
: m_ioContext(ioContext),
m_socketAcceptor(socketAcceptor),
m_localEndpoint(boost::asio::ip::address_v4{}, port),
m_acceptor(ioContext.get_executor(), m_localEndpoint) {}
AsioTCPAcceptorServer(const AsioTCPAcceptorServer &) = delete;
AsioTCPAcceptorServer(AsioTCPAcceptorServer &&) = delete;
void doAccept() {
m_acceptor.async_accept(
[Self = this->shared_from_this()](boost::system::error_code ec, boost::asio::ip::tcp::socket socket) {
std::stringstream ss;
if (ec.failed()) {
ss << "Accept error: " << ec.to_string();
Self->m_socketAcceptor->getLog()->onEvent(ss.str());
std::this_thread::sleep_for(std::chrono::microseconds(10));
Self->doAccept();
return;
}
boost::system::error_code lec;
auto RemoteEndpoint = socket.remote_endpoint(lec);
auto LocalEndpoint = socket.local_endpoint(lec);
ss << "Accepted connection from " << RemoteEndpoint.address() << " on port " << LocalEndpoint.port();
Self->m_socketAcceptor->getLog()->onEvent(ss.str());
auto sharedConnection = std::make_shared<AsioConnection<>>(
std::move(socket),
Self->m_socketAcceptor->getLog(),
Self->m_socketAcceptor);
sharedConnection->start();
Self->doAccept();
});
}
protected:
boost::asio::io_context &m_ioContext;
Acceptor *m_socketAcceptor;
boost::asio::ip::tcp::endpoint m_localEndpoint;
boost::asio::ip::tcp::acceptor m_acceptor;
};
class AsioWSAcceptorServer : public std::enable_shared_from_this<AsioWSAcceptorServer> {
public:
AsioWSAcceptorServer(boost::asio::io_context &ioContext, Acceptor *socketAcceptor, uint16_t port)
: m_ioContext(ioContext),
m_socketAcceptor(socketAcceptor),
m_localEndpoint(boost::asio::ip::address_v4{}, port),
m_acceptor(ioContext.get_executor(), m_localEndpoint) {}
AsioWSAcceptorServer(const AsioWSAcceptorServer &) = delete;
AsioWSAcceptorServer(AsioWSAcceptorServer &&) = delete;
void doAccept() {
m_acceptor.async_accept(
[Self = this->shared_from_this()](boost::system::error_code ec, boost::asio::ip::tcp::socket socket) {
std::stringstream ss;
if (ec.failed()) {
ss << "Accept error: " << ec.to_string();
Self->m_socketAcceptor->getLog()->onEvent(ss.str());
std::this_thread::sleep_for(std::chrono::microseconds(10));
Self->doAccept();
return;
}
boost::system::error_code lec;
auto RemoteEndpoint = socket.remote_endpoint(lec);
auto LocalEndpoint = socket.local_endpoint(lec);
ss << "Accepted connection from " << RemoteEndpoint.address() << " on port " << LocalEndpoint.port();
Self->m_socketAcceptor->getLog()->onEvent(ss.str());
auto sharedConnection = std::make_shared<AsioWSEstablishingConnection<>>(
std::move(socket),
Self->m_socketAcceptor->getLog(),
Self->m_socketAcceptor);
sharedConnection->start();
Self->doAccept();
});
}
protected:
boost::asio::io_context &m_ioContext;
Acceptor *m_socketAcceptor;
boost::asio::ip::tcp::endpoint m_localEndpoint;
boost::asio::ip::tcp::acceptor m_acceptor;
};
/// Socket implementation of Acceptor.
class AsioAcceptor : public Acceptor {
public:
AsioAcceptor(
boost::asio::io_context &ioContext,
Application &application,
MessageStoreFactory &messageStoreFactory,
const SessionSettings &sessionSettings) EXCEPT(ConfigError)
: Acceptor(application, messageStoreFactory, sessionSettings),
m_ioContext(ioContext) {}
AsioAcceptor(
boost::asio::io_context &ioContext,
Application &application,
MessageStoreFactory &messageStoreFactory,
const SessionSettings &sessionSettings,
LogFactory &logFactory) EXCEPT(ConfigError)
: Acceptor(application, messageStoreFactory, sessionSettings, logFactory),
m_ioContext(ioContext) {}
virtual ~AsioAcceptor() {}
private:
void onConfigure(const SessionSettings &s) override EXCEPT(ConfigError) {
std::set<SessionID> sessions = s.getSessions();
std::set<SessionID>::iterator i;
for (i = sessions.begin(); i != sessions.end(); ++i) {
const Dictionary &settings = s.get(*i);
settings.getInt(SOCKET_ACCEPT_PORT);
if (settings.has(SOCKET_REUSE_ADDRESS)) {
settings.getBool(SOCKET_REUSE_ADDRESS);
}
if (settings.has(SOCKET_NODELAY)) {
settings.getBool(SOCKET_NODELAY);
}
}
}
void onInitialize(const SessionSettings &s) override EXCEPT(RuntimeError) {
uint16_t port = 0;
try {
std::set<SessionID> sessions = s.getSessions();
std::set<SessionID>::iterator i = sessions.begin();
for (; i != sessions.end(); ++i) {
const Dictionary &settings = s.get(*i);
port = (uint16_t)settings.getInt(SOCKET_ACCEPT_PORT);
std::string protocol = "TCP";
if (settings.has(SOCKET_PROTOCOL)) {
protocol = settings.getString(SOCKET_PROTOCOL);
}
/*
const bool reuseAddress = settings.has( SOCKET_REUSE_ADDRESS ) ?
settings.getBool( SOCKET_REUSE_ADDRESS ) : true;
const bool noDelay = settings.has( SOCKET_NODELAY ) ?
settings.getBool( SOCKET_NODELAY ) : false;
const int sendBufSize = settings.has( SOCKET_SEND_BUFFER_SIZE ) ?
settings.getInt( SOCKET_SEND_BUFFER_SIZE ) : 0;
const int rcvBufSize = settings.has( SOCKET_RECEIVE_BUFFER_SIZE ) ?
settings.getInt( SOCKET_RECEIVE_BUFFER_SIZE ) : 0;
*/
auto itServer = m_portToServer.find(port);
if (itServer == m_portToServer.end()) {
bool ok;
if (protocol == "TCP") {
auto server = std::make_shared<AsioTCPAcceptorServer>(m_ioContext, this, port);
server->doAccept();
std::tie(itServer, ok) = m_portToServer.try_emplace(port, server);
} else if (protocol == "WS") {
auto server = std::make_shared<AsioWSAcceptorServer>(m_ioContext, this, port);
server->doAccept();
std::tie(itServer, ok) = m_portToServer.try_emplace(port, server);
}
}
}
} catch (SocketException &e) {
throw RuntimeError(
"Unable to create, bind, or listen to port " + IntConvertor::convert((unsigned short)port) + " (" + e.what()
+ ")");
}
}
void onStart() override {
// io_context should be polled globally - do nothing here
}
bool onPoll() override {
// io_context should be polled globally - do nothing here
return true;
}
void onStop() override { m_ioContext.stop(); }
protected:
using server_variant_t = std::variant<std::shared_ptr<AsioTCPAcceptorServer>, std::shared_ptr<AsioWSAcceptorServer>>;
boost::asio::io_context &m_ioContext;
std::map<uint16_t, server_variant_t> m_portToServer;
};
} // namespace FIX
#endif // ASIO_FIX_ASIO_SOCKET_ACCEPTOR_HPP