rippled
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 : mSecure(secureOnly)
35 , mBuffer((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 bool
48 {
49 return mSecure;
50 }
53 {
54 return *mSocket;
55 }
58 {
59 return mSocket->next_layer();
60 }
61
67
73
76 {
77 return mSocket->lowest_layer();
78 }
79
80 void
81 swap(AutoSocket& s) noexcept
82 {
83 mBuffer.swap(s.mBuffer);
84 mSocket.swap(s.mSocket);
85 std::swap(mSecure, s.mSecure);
86 }
87
88 boost::system::error_code
89 cancel(boost::system::error_code& ec)
90 {
91 return lowest_layer().cancel(ec);
92 }
93
94 void
96 {
97 if ((type == ssl_socket::client) || (mSecure))
98 {
99 // must be ssl
100 mSecure = true;
101 mSocket->async_handshake(type, cbFunc);
102 }
103 else if (mBuffer.empty())
104 {
105 // must be plain
106 mSecure = false;
107 post(mSocket->get_executor(), boost::beast::bind_handler(cbFunc, error_code()));
108 }
109 else
110 {
111 // autodetect
112 mSocket->next_layer().async_receive(
113 boost::asio::buffer(mBuffer),
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 async_shutdown(ShutdownHandler handler)
127 {
128 if (isSecure())
129 mSocket->async_shutdown(handler);
130 else
131 {
132 error_code ec;
133 try
134 {
135 lowest_layer().shutdown(plain_socket::shutdown_both);
136 }
137 catch (boost::system::system_error& e)
138 {
139 ec = e.code();
140 }
141 post(mSocket->get_executor(), boost::beast::bind_handler(handler, ec));
142 }
143 }
144
145 template <typename Seq, typename Handler>
146 void
147 async_read_some(Seq const& buffers, Handler handler)
148 {
149 if (isSecure())
150 mSocket->async_read_some(buffers, handler);
151 else
152 PlainSocket().async_read_some(buffers, handler);
153 }
154
155 template <typename Seq, typename Condition, typename Handler>
156 void
157 async_read_until(Seq const& buffers, Condition condition, Handler handler)
158 {
159 if (isSecure())
160 boost::asio::async_read_until(*mSocket, buffers, condition, handler);
161 else
162 boost::asio::async_read_until(PlainSocket(), buffers, condition, handler);
163 }
164
165 template <typename Allocator, typename Handler>
166 void
168 boost::asio::basic_streambuf<Allocator>& buffers,
169 std::string const& delim,
170 Handler handler)
171 {
172 if (isSecure())
173 boost::asio::async_read_until(*mSocket, buffers, delim, handler);
174 else
175 boost::asio::async_read_until(PlainSocket(), buffers, delim, handler);
176 }
177
178 template <typename Allocator, typename MatchCondition, typename Handler>
179 void
181 boost::asio::basic_streambuf<Allocator>& buffers,
182 MatchCondition cond,
183 Handler handler)
184 {
185 if (isSecure())
186 boost::asio::async_read_until(*mSocket, buffers, cond, handler);
187 else
188 boost::asio::async_read_until(PlainSocket(), buffers, cond, handler);
189 }
190
191 template <typename Buf, typename Handler>
192 void
193 async_write(Buf const& buffers, Handler handler)
194 {
195 if (isSecure())
196 boost::asio::async_write(*mSocket, buffers, handler);
197 else
198 boost::asio::async_write(PlainSocket(), buffers, handler);
199 }
200
201 template <typename Allocator, typename Handler>
202 void
203 async_write(boost::asio::basic_streambuf<Allocator>& buffers, Handler handler)
204 {
205 if (isSecure())
206 boost::asio::async_write(*mSocket, buffers, handler);
207 else
208 boost::asio::async_write(PlainSocket(), buffers, handler);
209 }
210
211 template <typename Buf, typename Condition, typename Handler>
212 void
213 async_read(Buf const& buffers, Condition cond, Handler handler)
214 {
215 if (isSecure())
216 boost::asio::async_read(*mSocket, buffers, cond, handler);
217 else
218 boost::asio::async_read(PlainSocket(), buffers, cond, handler);
219 }
220
221 template <typename Allocator, typename Condition, typename Handler>
222 void
223 async_read(boost::asio::basic_streambuf<Allocator>& buffers, Condition cond, Handler handler)
224 {
225 if (isSecure())
226 boost::asio::async_read(*mSocket, buffers, cond, handler);
227 else
228 boost::asio::async_read(PlainSocket(), buffers, cond, handler);
229 }
230
231 template <typename Buf, typename Handler>
232 void
233 async_read(Buf const& buffers, Handler handler)
234 {
235 if (isSecure())
236 boost::asio::async_read(*mSocket, buffers, handler);
237 else
238 boost::asio::async_read(PlainSocket(), buffers, handler);
239 }
240
241 template <typename Seq, typename Handler>
242 void
243 async_write_some(Seq const& buffers, Handler handler)
244 {
245 if (isSecure())
246 mSocket->async_write_some(buffers, handler);
247 else
248 PlainSocket().async_write_some(buffers, handler);
249 }
250
251protected:
252 void
253 handle_autodetect(callback cbFunc, error_code const& ec, size_t bytesTransferred)
254 {
255 using namespace xrpl;
256
257 if (ec)
258 {
259 JLOG(j_.warn()) << "Handle autodetect error: " << ec;
260 cbFunc(ec);
261 }
262 else if (
263 (mBuffer[0] < 127) && (mBuffer[0] > 31) &&
264 ((bytesTransferred < 2) || ((mBuffer[1] < 127) && (mBuffer[1] > 31))) &&
265 ((bytesTransferred < 3) || ((mBuffer[2] < 127) && (mBuffer[2] > 31))) &&
266 ((bytesTransferred < 4) || ((mBuffer[3] < 127) && (mBuffer[3] > 31))))
267 {
268 // not ssl
269 JLOG(j_.trace()) << "non-SSL";
270 mSecure = false;
271 cbFunc(ec);
272 }
273 else
274 {
275 // ssl
276 JLOG(j_.trace()) << "SSL";
277 mSecure = true;
278 mSocket->async_handshake(ssl_socket::server, cbFunc);
279 }
280 }
281
282private:
287};
T bind(T... args)
socket_ptr mSocket
Definition AutoSocket.h:283
void async_write(boost::asio::basic_streambuf< Allocator > &buffers, Handler handler)
Definition AutoSocket.h:203
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
beast::IP::Endpoint remote_endpoint()
Definition AutoSocket.h:69
void async_read(boost::asio::basic_streambuf< Allocator > &buffers, Condition cond, Handler handler)
Definition AutoSocket.h:223
void handle_autodetect(callback cbFunc, error_code const &ec, size_t bytesTransferred)
Definition AutoSocket.h:253
beast::Journal j_
Definition AutoSocket.h:286
boost::system::error_code error_code
Definition AutoSocket.h:25
AutoSocket(boost::asio::io_context &s, boost::asio::ssl::context &c)
Definition AutoSocket.h:41
bool isSecure()
Definition AutoSocket.h:47
void async_handshake(handshake_type type, callback cbFunc)
Definition AutoSocket.h:95
void async_read_until(boost::asio::basic_streambuf< Allocator > &buffers, MatchCondition cond, Handler handler)
Definition AutoSocket.h:180
void async_read_until(boost::asio::basic_streambuf< Allocator > &buffers, std::string const &delim, Handler handler)
Definition AutoSocket.h:167
void async_read(Buf const &buffers, Handler handler)
Definition AutoSocket.h:233
void async_write(Buf const &buffers, Handler handler)
Definition AutoSocket.h:193
lowest_layer_type & lowest_layer()
Definition AutoSocket.h:75
beast::IP::Endpoint local_endpoint()
Definition AutoSocket.h:63
void async_read_until(Seq const &buffers, Condition condition, Handler handler)
Definition AutoSocket.h:157
plain_socket & PlainSocket()
Definition AutoSocket.h:57
void async_read(Buf const &buffers, Condition cond, Handler handler)
Definition AutoSocket.h:213
void async_read_some(Seq const &buffers, Handler handler)
Definition AutoSocket.h:147
std::vector< char > mBuffer
Definition AutoSocket.h:285
void swap(AutoSocket &s) noexcept
Definition AutoSocket.h:81
void async_write_some(Seq const &buffers, Handler handler)
Definition AutoSocket.h:243
ssl_socket & SSLSocket()
Definition AutoSocket.h:52
void async_shutdown(ShutdownHandler handler)
Definition AutoSocket.h:126
boost::system::error_code cancel(boost::system::error_code &ec)
Definition AutoSocket.h:89
boost::asio::ssl::stream< boost::asio::ip::tcp::socket > ssl_socket
Definition AutoSocket.h:19
A version-independent IP address and port combination.
Definition IPEndpoint.h:18
A generic endpoint for log messages.
Definition Journal.h:40
Stream trace() const
Severity stream access functions.
Definition Journal.h:295
Stream warn() const
Definition Journal.h:313
T empty(T... args)
T is_same_v
Endpoint from_asio(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)