rippled
Loading...
Searching...
No Matches
AutoSocket.h
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#ifndef RIPPLE_WEBSOCKET_AUTOSOCKET_AUTOSOCKET_H_INCLUDED
21#define RIPPLE_WEBSOCKET_AUTOSOCKET_AUTOSOCKET_H_INCLUDED
22
23#include <xrpl/basics/Log.h>
24#include <xrpl/beast/net/IPAddressConversion.h>
25#include <boost/asio.hpp>
26#include <boost/asio/ip/tcp.hpp>
27#include <boost/asio/ssl.hpp>
28#include <boost/beast/core/bind_handler.hpp>
29
30// Socket wrapper that supports both SSL and non-SSL connections.
31// Generally, handle it as you would an SSL connection.
32// To force a non-SSL connection, just don't call async_handshake.
33// To force SSL only inbound, call setSSLOnly.
34
36{
37public:
38 using ssl_socket = boost::asio::ssl::stream<boost::asio::ip::tcp::socket>;
39 using endpoint_type = boost::asio::ip::tcp::socket::endpoint_type;
41 using plain_socket = ssl_socket::next_layer_type;
42 using lowest_layer_type = ssl_socket::lowest_layer_type;
43 using handshake_type = ssl_socket::handshake_type;
44 using error_code = boost::system::error_code;
46
47public:
49 boost::asio::io_service& s,
50 boost::asio::ssl::context& c,
51 bool secureOnly,
52 bool plainOnly)
53 : mSecure(secureOnly)
54 , mBuffer((plainOnly || secureOnly) ? 0 : 4)
55 , j_{beast::Journal::getNullSink()}
56 {
57 mSocket = std::make_unique<ssl_socket>(s, c);
58 }
59
60 AutoSocket(boost::asio::io_service& s, boost::asio::ssl::context& c)
61 : AutoSocket(s, c, false, false)
62 {
63 }
64
65 bool
67 {
68 return mSecure;
69 }
72 {
73 return *mSocket;
74 }
77 {
78 return mSocket->next_layer();
79 }
80
83 {
85 }
86
89 {
91 }
92
95 {
96 return mSocket->lowest_layer();
97 }
98
99 void
100 swap(AutoSocket& s) noexcept
101 {
102 mBuffer.swap(s.mBuffer);
103 mSocket.swap(s.mSocket);
104 std::swap(mSecure, s.mSecure);
105 }
106
107 boost::system::error_code
108 cancel(boost::system::error_code& ec)
109 {
110 return lowest_layer().cancel(ec);
111 }
112
113 void
115 {
116 if ((type == ssl_socket::client) || (mSecure))
117 {
118 // must be ssl
119 mSecure = true;
120 mSocket->async_handshake(type, cbFunc);
121 }
122 else if (mBuffer.empty())
123 {
124 // must be plain
125 mSecure = false;
126 post(
127 mSocket->get_executor(),
128 boost::beast::bind_handler(cbFunc, error_code()));
129 }
130 else
131 {
132 // autodetect
133 mSocket->next_layer().async_receive(
134 boost::asio::buffer(mBuffer),
135 boost::asio::socket_base::message_peek,
136 std::bind(
138 this,
139 cbFunc,
140 std::placeholders::_1,
141 std::placeholders::_2));
142 }
143 }
144
145 template <typename ShutdownHandler>
146 void
147 async_shutdown(ShutdownHandler handler)
148 {
149 if (isSecure())
150 mSocket->async_shutdown(handler);
151 else
152 {
153 error_code ec;
154 try
155 {
156 lowest_layer().shutdown(plain_socket::shutdown_both);
157 }
158 catch (boost::system::system_error& e)
159 {
160 ec = e.code();
161 }
162 post(
163 mSocket->get_executor(),
164 boost::beast::bind_handler(handler, ec));
165 }
166 }
167
168 template <typename Seq, typename Handler>
169 void
170 async_read_some(const Seq& buffers, Handler handler)
171 {
172 if (isSecure())
173 mSocket->async_read_some(buffers, handler);
174 else
175 PlainSocket().async_read_some(buffers, handler);
176 }
177
178 template <typename Seq, typename Condition, typename Handler>
179 void
180 async_read_until(const Seq& buffers, Condition condition, Handler handler)
181 {
182 if (isSecure())
183 boost::asio::async_read_until(
184 *mSocket, buffers, condition, handler);
185 else
186 boost::asio::async_read_until(
187 PlainSocket(), buffers, condition, handler);
188 }
189
190 template <typename Allocator, typename Handler>
191 void
193 boost::asio::basic_streambuf<Allocator>& buffers,
194 std::string const& delim,
195 Handler handler)
196 {
197 if (isSecure())
198 boost::asio::async_read_until(*mSocket, buffers, delim, handler);
199 else
200 boost::asio::async_read_until(
201 PlainSocket(), buffers, delim, handler);
202 }
203
204 template <typename Allocator, typename MatchCondition, typename Handler>
205 void
207 boost::asio::basic_streambuf<Allocator>& buffers,
208 MatchCondition cond,
209 Handler handler)
210 {
211 if (isSecure())
212 boost::asio::async_read_until(*mSocket, buffers, cond, handler);
213 else
214 boost::asio::async_read_until(
215 PlainSocket(), buffers, cond, handler);
216 }
217
218 template <typename Buf, typename Handler>
219 void
220 async_write(const Buf& buffers, Handler handler)
221 {
222 if (isSecure())
223 boost::asio::async_write(*mSocket, buffers, handler);
224 else
225 boost::asio::async_write(PlainSocket(), buffers, handler);
226 }
227
228 template <typename Allocator, typename Handler>
229 void
231 boost::asio::basic_streambuf<Allocator>& buffers,
232 Handler handler)
233 {
234 if (isSecure())
235 boost::asio::async_write(*mSocket, buffers, handler);
236 else
237 boost::asio::async_write(PlainSocket(), buffers, handler);
238 }
239
240 template <typename Buf, typename Condition, typename Handler>
241 void
242 async_read(const Buf& buffers, Condition cond, Handler handler)
243 {
244 if (isSecure())
245 boost::asio::async_read(*mSocket, buffers, cond, handler);
246 else
247 boost::asio::async_read(PlainSocket(), buffers, cond, handler);
248 }
249
250 template <typename Allocator, typename Condition, typename Handler>
251 void
253 boost::asio::basic_streambuf<Allocator>& buffers,
254 Condition cond,
255 Handler handler)
256 {
257 if (isSecure())
258 boost::asio::async_read(*mSocket, buffers, cond, handler);
259 else
260 boost::asio::async_read(PlainSocket(), buffers, cond, handler);
261 }
262
263 template <typename Buf, typename Handler>
264 void
265 async_read(const Buf& buffers, Handler handler)
266 {
267 if (isSecure())
268 boost::asio::async_read(*mSocket, buffers, handler);
269 else
270 boost::asio::async_read(PlainSocket(), buffers, handler);
271 }
272
273 template <typename Seq, typename Handler>
274 void
275 async_write_some(const Seq& buffers, Handler handler)
276 {
277 if (isSecure())
278 mSocket->async_write_some(buffers, handler);
279 else
280 PlainSocket().async_write_some(buffers, handler);
281 }
282
283protected:
284 void
286 callback cbFunc,
287 const error_code& ec,
288 size_t bytesTransferred)
289 {
290 using namespace ripple;
291
292 if (ec)
293 {
294 JLOG(j_.warn()) << "Handle autodetect error: " << ec;
295 cbFunc(ec);
296 }
297 else if (
298 (mBuffer[0] < 127) && (mBuffer[0] > 31) &&
299 ((bytesTransferred < 2) ||
300 ((mBuffer[1] < 127) && (mBuffer[1] > 31))) &&
301 ((bytesTransferred < 3) ||
302 ((mBuffer[2] < 127) && (mBuffer[2] > 31))) &&
303 ((bytesTransferred < 4) ||
304 ((mBuffer[3] < 127) && (mBuffer[3] > 31))))
305 {
306 // not ssl
307 JLOG(j_.trace()) << "non-SSL";
308 mSecure = false;
309 cbFunc(ec);
310 }
311 else
312 {
313 // ssl
314 JLOG(j_.trace()) << "SSL";
315 mSecure = true;
316 mSocket->async_handshake(ssl_socket::server, cbFunc);
317 }
318 }
319
320private:
325};
326
327#endif
T bind(T... args)
void async_write_some(const Seq &buffers, Handler handler)
Definition: AutoSocket.h:275
socket_ptr mSocket
Definition: AutoSocket.h:321
void async_write(boost::asio::basic_streambuf< Allocator > &buffers, Handler handler)
Definition: AutoSocket.h:230
ssl_socket::handshake_type handshake_type
Definition: AutoSocket.h:43
bool mSecure
Definition: AutoSocket.h:322
ssl_socket::lowest_layer_type lowest_layer_type
Definition: AutoSocket.h:42
ssl_socket::next_layer_type plain_socket
Definition: AutoSocket.h:41
boost::asio::ip::tcp::socket::endpoint_type endpoint_type
Definition: AutoSocket.h:39
beast::IP::Endpoint remote_endpoint()
Definition: AutoSocket.h:88
void async_read(boost::asio::basic_streambuf< Allocator > &buffers, Condition cond, Handler handler)
Definition: AutoSocket.h:252
void handle_autodetect(callback cbFunc, const error_code &ec, size_t bytesTransferred)
Definition: AutoSocket.h:285
beast::Journal j_
Definition: AutoSocket.h:324
boost::system::error_code error_code
Definition: AutoSocket.h:44
bool isSecure()
Definition: AutoSocket.h:66
void async_handshake(handshake_type type, callback cbFunc)
Definition: AutoSocket.h:114
void async_read_until(boost::asio::basic_streambuf< Allocator > &buffers, MatchCondition cond, Handler handler)
Definition: AutoSocket.h:206
void async_read_until(const Seq &buffers, Condition condition, 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:192
lowest_layer_type & lowest_layer()
Definition: AutoSocket.h:94
beast::IP::Endpoint local_endpoint()
Definition: AutoSocket.h:82
void async_read_some(const Seq &buffers, Handler handler)
Definition: AutoSocket.h:170
plain_socket & PlainSocket()
Definition: AutoSocket.h:76
std::vector< char > mBuffer
Definition: AutoSocket.h:323
void async_write(const Buf &buffers, Handler handler)
Definition: AutoSocket.h:220
void swap(AutoSocket &s) noexcept
Definition: AutoSocket.h:100
void async_read(const Buf &buffers, Condition cond, Handler handler)
Definition: AutoSocket.h:242
AutoSocket(boost::asio::io_service &s, boost::asio::ssl::context &c)
Definition: AutoSocket.h:60
ssl_socket & SSLSocket()
Definition: AutoSocket.h:71
void async_shutdown(ShutdownHandler handler)
Definition: AutoSocket.h:147
boost::system::error_code cancel(boost::system::error_code &ec)
Definition: AutoSocket.h:108
boost::asio::ssl::stream< boost::asio::ip::tcp::socket > ssl_socket
Definition: AutoSocket.h:38
void async_read(const Buf &buffers, Handler handler)
Definition: AutoSocket.h:265
AutoSocket(boost::asio::io_service &s, boost::asio::ssl::context &c, bool secureOnly, bool plainOnly)
Definition: AutoSocket.h:48
A version-independent IP address and port combination.
Definition: IPEndpoint.h:39
A generic endpoint for log messages.
Definition: Journal.h:59
Stream trace() const
Severity stream access functions.
Definition: Journal.h:311
Stream warn() const
Definition: Journal.h:329
T empty(T... args)
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:26
T swap(T... args)