xrpld
Loading...
Searching...
No Matches
AutoSocket.h
1#pragma once
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/beast/net/IPAddressConversion.h>
5
6#include <boost/asio.hpp>
7#include <boost/asio/ip/tcp.hpp>
8#include <boost/asio/ssl.hpp>
9#include <boost/beast/core/bind_handler.hpp>
10
11// Socket wrapper that supports both SSL and non-SSL connections.
12// Generally, handle it as you would an SSL connection.
13// To force a non-SSL connection, just don't call async_handshake.
14// To force SSL only inbound, call setSSLOnly.
15
17{
18public:
19 using ssl_socket = boost::asio::ssl::stream<boost::asio::ip::tcp::socket>;
20 using endpoint_type = boost::asio::ip::tcp::socket::endpoint_type;
22 using plain_socket = ssl_socket::next_layer_type;
23 using lowest_layer_type = ssl_socket::lowest_layer_type;
24 using handshake_type = ssl_socket::handshake_type;
25 using error_code = boost::system::error_code;
27
28public:
30 boost::asio::io_context& s,
31 boost::asio::ssl::context& c,
32 bool secureOnly,
33 bool plainOnly)
34 : secure_(secureOnly)
35 , buffer_((plainOnly || secureOnly) ? 0 : 4)
36 , j_{beast::Journal::getNullSink()}
37 {
39 }
40
41 AutoSocket(boost::asio::io_context& s, boost::asio::ssl::context& c)
42 : AutoSocket(s, c, false, false)
43 {
44 }
45
46 [[nodiscard]] bool
47 isSecure() const
48 {
49 return secure_;
50 }
53 {
54 return *socket_;
55 }
58 {
59 return socket_->next_layer();
60 }
61
64 {
65 return beast::IP::fromAsio(lowestLayer().local_endpoint());
66 }
67
70 {
71 return beast::IP::fromAsio(lowestLayer().remote_endpoint());
72 }
73
76 {
77 return socket_->lowest_layer();
78 }
79
80 void
81 swap(AutoSocket& s) noexcept
82 {
83 buffer_.swap(s.buffer_);
84 socket_.swap(s.socket_);
85 std::swap(secure_, s.secure_);
86 }
87
88 boost::system::error_code
89 cancel(boost::system::error_code& ec)
90 {
91 return lowestLayer().cancel(ec);
92 }
93
94 void
96 {
97 if ((type == ssl_socket::client) || (secure_))
98 {
99 // must be ssl
100 secure_ = true;
101 socket_->async_handshake(type, cbFunc);
102 }
103 else if (buffer_.empty())
104 {
105 // must be plain
106 secure_ = false;
107 post(socket_->get_executor(), boost::beast::bind_handler(cbFunc, error_code()));
108 }
109 else
110 {
111 // autodetect
112 socket_->next_layer().async_receive(
113 boost::asio::buffer(buffer_),
114 boost::asio::socket_base::message_peek,
115 std::bind(
117 this,
118 cbFunc,
119 std::placeholders::_1,
120 std::placeholders::_2));
121 }
122 }
123
124 template <typename ShutdownHandler>
125 void
126 asyncShutdown(ShutdownHandler handler)
127 {
128 if (isSecure())
129 {
130 socket_->async_shutdown(handler);
131 }
132 else
133 {
134 error_code ec;
135 try
136 {
137 lowestLayer().shutdown(plain_socket::shutdown_both);
138 }
139 catch (boost::system::system_error const& e)
140 {
141 ec = e.code();
142 }
143 post(socket_->get_executor(), boost::beast::bind_handler(handler, ec));
144 }
145 }
146
147 template <typename Seq, typename Handler>
148 void
149 asyncReadSome(Seq const& buffers, Handler handler)
150 {
151 if (isSecure())
152 {
153 socket_->async_read_some(buffers, handler);
154 }
155 else
156 {
157 plainSocket().async_read_some(buffers, handler);
158 }
159 }
160
161 template <typename Seq, typename Condition, typename Handler>
162 void
163 asyncReadUntil(Seq const& buffers, Condition condition, Handler handler)
164 {
165 if (isSecure())
166 {
167 boost::asio::async_read_until(*socket_, buffers, condition, handler);
168 }
169 else
170 {
171 boost::asio::async_read_until(plainSocket(), buffers, condition, handler);
172 }
173 }
174
175 template <typename Allocator, typename Handler>
176 void
178 boost::asio::basic_streambuf<Allocator>& buffers,
179 std::string const& delim,
180 Handler handler)
181 {
182 if (isSecure())
183 {
184 boost::asio::async_read_until(*socket_, buffers, delim, handler);
185 }
186 else
187 {
188 boost::asio::async_read_until(plainSocket(), buffers, delim, handler);
189 }
190 }
191
192 template <typename Allocator, typename MatchCondition, typename Handler>
193 void
195 boost::asio::basic_streambuf<Allocator>& buffers,
196 MatchCondition cond,
197 Handler handler)
198 {
199 if (isSecure())
200 {
201 boost::asio::async_read_until(*socket_, buffers, cond, handler);
202 }
203 else
204 {
205 boost::asio::async_read_until(plainSocket(), buffers, cond, handler);
206 }
207 }
208
209 template <typename Buf, typename Handler>
210 void
211 asyncWrite(Buf const& buffers, Handler handler)
212 {
213 if (isSecure())
214 {
215 boost::asio::async_write(*socket_, buffers, handler);
216 }
217 else
218 {
219 boost::asio::async_write(plainSocket(), buffers, handler);
220 }
221 }
222
223 template <typename Allocator, typename Handler>
224 void
225 asyncWrite(boost::asio::basic_streambuf<Allocator>& buffers, Handler handler)
226 {
227 if (isSecure())
228 {
229 boost::asio::async_write(*socket_, buffers, handler);
230 }
231 else
232 {
233 boost::asio::async_write(plainSocket(), buffers, handler);
234 }
235 }
236
237 template <typename Buf, typename Condition, typename Handler>
238 void
239 asyncRead(Buf const& buffers, Condition cond, Handler handler)
240 {
241 if (isSecure())
242 {
243 boost::asio::async_read(*socket_, buffers, cond, handler);
244 }
245 else
246 {
247 boost::asio::async_read(plainSocket(), buffers, cond, handler);
248 }
249 }
250
251 template <typename Allocator, typename Condition, typename Handler>
252 void
253 asyncRead(boost::asio::basic_streambuf<Allocator>& buffers, Condition cond, Handler handler)
254 {
255 if (isSecure())
256 {
257 boost::asio::async_read(*socket_, buffers, cond, handler);
258 }
259 else
260 {
261 boost::asio::async_read(plainSocket(), buffers, cond, handler);
262 }
263 }
264
265 template <typename Buf, typename Handler>
266 void
267 asyncRead(Buf const& buffers, Handler handler)
268 {
269 if (isSecure())
270 {
271 boost::asio::async_read(*socket_, buffers, handler);
272 }
273 else
274 {
275 boost::asio::async_read(plainSocket(), buffers, handler);
276 }
277 }
278
279 template <typename Seq, typename Handler>
280 void
281 asyncWriteSome(Seq const& buffers, Handler handler)
282 {
283 if (isSecure())
284 {
285 socket_->async_write_some(buffers, handler);
286 }
287 else
288 {
289 plainSocket().async_write_some(buffers, handler);
290 }
291 }
292
293protected:
294 void
295 handleAutodetect(callback cbFunc, error_code const& ec, size_t bytesTransferred)
296 {
297 using namespace xrpl;
298
299 if (ec)
300 {
301 JLOG(j_.warn()) << "Handle autodetect error: " << ec;
302 cbFunc(ec);
303 }
304 else if (
305 (buffer_[0] < 127) && (buffer_[0] > 31) &&
306 ((bytesTransferred < 2) || ((buffer_[1] < 127) && (buffer_[1] > 31))) &&
307 ((bytesTransferred < 3) || ((buffer_[2] < 127) && (buffer_[2] > 31))) &&
308 ((bytesTransferred < 4) || ((buffer_[3] < 127) && (buffer_[3] > 31))))
309 {
310 // not ssl
311 JLOG(j_.trace()) << "non-SSL";
312 secure_ = false;
313 cbFunc(ec);
314 }
315 else
316 {
317 // ssl
318 JLOG(j_.trace()) << "SSL";
319 secure_ = true;
320 socket_->async_handshake(ssl_socket::server, cbFunc);
321 }
322 }
323
324private:
329};
T bind(T... args)
std::function< void(error_code)> callback
Definition AutoSocket.h:26
AutoSocket(boost::asio::io_context &s, boost::asio::ssl::context &c, bool secureOnly, bool plainOnly)
Definition AutoSocket.h:29
ssl_socket::handshake_type handshake_type
Definition AutoSocket.h:24
ssl_socket::lowest_layer_type lowest_layer_type
Definition AutoSocket.h:23
ssl_socket::next_layer_type plain_socket
Definition AutoSocket.h:22
boost::asio::ip::tcp::socket::endpoint_type endpoint_type
Definition AutoSocket.h:20
lowest_layer_type & lowestLayer()
Definition AutoSocket.h:75
beast::Journal j_
Definition AutoSocket.h:328
plain_socket & plainSocket()
Definition AutoSocket.h:57
boost::system::error_code error_code
Definition AutoSocket.h:25
std::vector< char > buffer_
Definition AutoSocket.h:327
void asyncRead(Buf const &buffers, Condition cond, Handler handler)
Definition AutoSocket.h:239
AutoSocket(boost::asio::io_context &s, boost::asio::ssl::context &c)
Definition AutoSocket.h:41
std::unique_ptr< ssl_socket > socket_ptr
Definition AutoSocket.h:21
void asyncReadUntil(Seq const &buffers, Condition condition, Handler handler)
Definition AutoSocket.h:163
void asyncReadUntil(boost::asio::basic_streambuf< Allocator > &buffers, std::string const &delim, Handler handler)
Definition AutoSocket.h:177
beast::IP::Endpoint remoteEndpoint()
Definition AutoSocket.h:69
socket_ptr socket_
Definition AutoSocket.h:325
void asyncShutdown(ShutdownHandler handler)
Definition AutoSocket.h:126
void swap(AutoSocket &s) noexcept
Definition AutoSocket.h:81
void handleAutodetect(callback cbFunc, error_code const &ec, size_t bytesTransferred)
Definition AutoSocket.h:295
void asyncRead(Buf const &buffers, Handler handler)
Definition AutoSocket.h:267
void asyncWriteSome(Seq const &buffers, Handler handler)
Definition AutoSocket.h:281
void asyncRead(boost::asio::basic_streambuf< Allocator > &buffers, Condition cond, Handler handler)
Definition AutoSocket.h:253
bool isSecure() const
Definition AutoSocket.h:47
void asyncReadSome(Seq const &buffers, Handler handler)
Definition AutoSocket.h:149
boost::system::error_code cancel(boost::system::error_code &ec)
Definition AutoSocket.h:89
ssl_socket & sslSocket()
Definition AutoSocket.h:52
boost::asio::ssl::stream< boost::asio::ip::tcp::socket > ssl_socket
Definition AutoSocket.h:19
void asyncWrite(Buf const &buffers, Handler handler)
Definition AutoSocket.h:211
void asyncHandshake(handshake_type type, callback cbFunc)
Definition AutoSocket.h:95
void asyncReadUntil(boost::asio::basic_streambuf< Allocator > &buffers, MatchCondition cond, Handler handler)
Definition AutoSocket.h:194
beast::IP::Endpoint localEndpoint()
Definition AutoSocket.h:63
void asyncWrite(boost::asio::basic_streambuf< Allocator > &buffers, Handler handler)
Definition AutoSocket.h:225
A version-independent IP address and port combination.
Definition IPEndpoint.h:17
A generic endpoint for log messages.
Definition Journal.h:38
T make_unique(T... args)
Endpoint fromAsio(boost::asio::ip::address const &address)
Convert to Endpoint.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
T swap(T... args)