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