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:
29 AutoSocket(boost::asio::io_context& s, boost::asio::ssl::context& c, bool secureOnly, bool plainOnly)
30 : mSecure(secureOnly), mBuffer((plainOnly || secureOnly) ? 0 : 4), j_{beast::Journal::getNullSink()}
31 {
33 }
34
35 AutoSocket(boost::asio::io_context& s, boost::asio::ssl::context& c) : AutoSocket(s, c, false, false)
36 {
37 }
38
39 bool
41 {
42 return mSecure;
43 }
46 {
47 return *mSocket;
48 }
51 {
52 return mSocket->next_layer();
53 }
54
60
66
69 {
70 return mSocket->lowest_layer();
71 }
72
73 void
74 swap(AutoSocket& s) noexcept
75 {
76 mBuffer.swap(s.mBuffer);
77 mSocket.swap(s.mSocket);
78 std::swap(mSecure, s.mSecure);
79 }
80
81 boost::system::error_code
82 cancel(boost::system::error_code& ec)
83 {
84 return lowest_layer().cancel(ec);
85 }
86
87 void
89 {
90 if ((type == ssl_socket::client) || (mSecure))
91 {
92 // must be ssl
93 mSecure = true;
94 mSocket->async_handshake(type, cbFunc);
95 }
96 else if (mBuffer.empty())
97 {
98 // must be plain
99 mSecure = false;
100 post(mSocket->get_executor(), boost::beast::bind_handler(cbFunc, error_code()));
101 }
102 else
103 {
104 // autodetect
105 mSocket->next_layer().async_receive(
106 boost::asio::buffer(mBuffer),
107 boost::asio::socket_base::message_peek,
108 std::bind(&AutoSocket::handle_autodetect, this, cbFunc, std::placeholders::_1, std::placeholders::_2));
109 }
110 }
111
112 template <typename ShutdownHandler>
113 void
114 async_shutdown(ShutdownHandler handler)
115 {
116 if (isSecure())
117 mSocket->async_shutdown(handler);
118 else
119 {
120 error_code ec;
121 try
122 {
123 lowest_layer().shutdown(plain_socket::shutdown_both);
124 }
125 catch (boost::system::system_error& e)
126 {
127 ec = e.code();
128 }
129 post(mSocket->get_executor(), boost::beast::bind_handler(handler, ec));
130 }
131 }
132
133 template <typename Seq, typename Handler>
134 void
135 async_read_some(Seq const& buffers, Handler handler)
136 {
137 if (isSecure())
138 mSocket->async_read_some(buffers, handler);
139 else
140 PlainSocket().async_read_some(buffers, handler);
141 }
142
143 template <typename Seq, typename Condition, typename Handler>
144 void
145 async_read_until(Seq const& buffers, Condition condition, Handler handler)
146 {
147 if (isSecure())
148 boost::asio::async_read_until(*mSocket, buffers, condition, handler);
149 else
150 boost::asio::async_read_until(PlainSocket(), buffers, condition, handler);
151 }
152
153 template <typename Allocator, typename Handler>
154 void
155 async_read_until(boost::asio::basic_streambuf<Allocator>& buffers, std::string const& delim, Handler handler)
156 {
157 if (isSecure())
158 boost::asio::async_read_until(*mSocket, buffers, delim, handler);
159 else
160 boost::asio::async_read_until(PlainSocket(), buffers, delim, handler);
161 }
162
163 template <typename Allocator, typename MatchCondition, typename Handler>
164 void
165 async_read_until(boost::asio::basic_streambuf<Allocator>& buffers, MatchCondition cond, Handler handler)
166 {
167 if (isSecure())
168 boost::asio::async_read_until(*mSocket, buffers, cond, handler);
169 else
170 boost::asio::async_read_until(PlainSocket(), buffers, cond, handler);
171 }
172
173 template <typename Buf, typename Handler>
174 void
175 async_write(Buf const& buffers, Handler handler)
176 {
177 if (isSecure())
178 boost::asio::async_write(*mSocket, buffers, handler);
179 else
180 boost::asio::async_write(PlainSocket(), buffers, handler);
181 }
182
183 template <typename Allocator, typename Handler>
184 void
185 async_write(boost::asio::basic_streambuf<Allocator>& buffers, Handler handler)
186 {
187 if (isSecure())
188 boost::asio::async_write(*mSocket, buffers, handler);
189 else
190 boost::asio::async_write(PlainSocket(), buffers, handler);
191 }
192
193 template <typename Buf, typename Condition, typename Handler>
194 void
195 async_read(Buf const& buffers, Condition cond, Handler handler)
196 {
197 if (isSecure())
198 boost::asio::async_read(*mSocket, buffers, cond, handler);
199 else
200 boost::asio::async_read(PlainSocket(), buffers, cond, handler);
201 }
202
203 template <typename Allocator, typename Condition, typename Handler>
204 void
205 async_read(boost::asio::basic_streambuf<Allocator>& buffers, Condition cond, Handler handler)
206 {
207 if (isSecure())
208 boost::asio::async_read(*mSocket, buffers, cond, handler);
209 else
210 boost::asio::async_read(PlainSocket(), buffers, cond, handler);
211 }
212
213 template <typename Buf, typename Handler>
214 void
215 async_read(Buf const& buffers, Handler handler)
216 {
217 if (isSecure())
218 boost::asio::async_read(*mSocket, buffers, handler);
219 else
220 boost::asio::async_read(PlainSocket(), buffers, handler);
221 }
222
223 template <typename Seq, typename Handler>
224 void
225 async_write_some(Seq const& buffers, Handler handler)
226 {
227 if (isSecure())
228 mSocket->async_write_some(buffers, handler);
229 else
230 PlainSocket().async_write_some(buffers, handler);
231 }
232
233protected:
234 void
235 handle_autodetect(callback cbFunc, error_code const& ec, size_t bytesTransferred)
236 {
237 using namespace xrpl;
238
239 if (ec)
240 {
241 JLOG(j_.warn()) << "Handle autodetect error: " << ec;
242 cbFunc(ec);
243 }
244 else if (
245 (mBuffer[0] < 127) && (mBuffer[0] > 31) &&
246 ((bytesTransferred < 2) || ((mBuffer[1] < 127) && (mBuffer[1] > 31))) &&
247 ((bytesTransferred < 3) || ((mBuffer[2] < 127) && (mBuffer[2] > 31))) &&
248 ((bytesTransferred < 4) || ((mBuffer[3] < 127) && (mBuffer[3] > 31))))
249 {
250 // not ssl
251 JLOG(j_.trace()) << "non-SSL";
252 mSecure = false;
253 cbFunc(ec);
254 }
255 else
256 {
257 // ssl
258 JLOG(j_.trace()) << "SSL";
259 mSecure = true;
260 mSocket->async_handshake(ssl_socket::server, cbFunc);
261 }
262 }
263
264private:
269};
T bind(T... args)
socket_ptr mSocket
Definition AutoSocket.h:265
void async_write(boost::asio::basic_streambuf< Allocator > &buffers, Handler handler)
Definition AutoSocket.h:185
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:62
void async_read(boost::asio::basic_streambuf< Allocator > &buffers, Condition cond, Handler handler)
Definition AutoSocket.h:205
void handle_autodetect(callback cbFunc, error_code const &ec, size_t bytesTransferred)
Definition AutoSocket.h:235
beast::Journal j_
Definition AutoSocket.h:268
boost::system::error_code error_code
Definition AutoSocket.h:25
AutoSocket(boost::asio::io_context &s, boost::asio::ssl::context &c)
Definition AutoSocket.h:35
bool isSecure()
Definition AutoSocket.h:40
void async_handshake(handshake_type type, callback cbFunc)
Definition AutoSocket.h:88
void async_read_until(boost::asio::basic_streambuf< Allocator > &buffers, MatchCondition cond, Handler handler)
Definition AutoSocket.h:165
void async_read_until(boost::asio::basic_streambuf< Allocator > &buffers, std::string const &delim, Handler handler)
Definition AutoSocket.h:155
void async_read(Buf const &buffers, Handler handler)
Definition AutoSocket.h:215
void async_write(Buf const &buffers, Handler handler)
Definition AutoSocket.h:175
lowest_layer_type & lowest_layer()
Definition AutoSocket.h:68
beast::IP::Endpoint local_endpoint()
Definition AutoSocket.h:56
void async_read_until(Seq const &buffers, Condition condition, Handler handler)
Definition AutoSocket.h:145
plain_socket & PlainSocket()
Definition AutoSocket.h:50
void async_read(Buf const &buffers, Condition cond, Handler handler)
Definition AutoSocket.h:195
void async_read_some(Seq const &buffers, Handler handler)
Definition AutoSocket.h:135
std::vector< char > mBuffer
Definition AutoSocket.h:267
void swap(AutoSocket &s) noexcept
Definition AutoSocket.h:74
void async_write_some(Seq const &buffers, Handler handler)
Definition AutoSocket.h:225
ssl_socket & SSLSocket()
Definition AutoSocket.h:45
void async_shutdown(ShutdownHandler handler)
Definition AutoSocket.h:114
boost::system::error_code cancel(boost::system::error_code &ec)
Definition AutoSocket.h:82
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:294
Stream warn() const
Definition Journal.h:312
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)