rippled
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 <ripple/basics/Log.h>
24 #include <ripple/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 {
37 public:
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 
47 public:
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)
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  }
70  ssl_socket&
72  {
73  return *mSocket;
74  }
77  {
78  return mSocket->next_layer();
79  }
80  void
82  {
83  mSecure = true;
84  }
85  void
87  {
88  mBuffer.clear();
89  }
90 
93  {
95  }
96 
99  {
101  }
102 
105  {
106  return mSocket->lowest_layer();
107  }
108 
109  void
110  swap(AutoSocket& s) noexcept
111  {
112  mBuffer.swap(s.mBuffer);
113  mSocket.swap(s.mSocket);
114  std::swap(mSecure, s.mSecure);
115  }
116 
117  boost::system::error_code
118  cancel(boost::system::error_code& ec)
119  {
120  return lowest_layer().cancel(ec);
121  }
122 
123  void
125  {
126  if ((type == ssl_socket::client) || (mSecure))
127  {
128  // must be ssl
129  mSecure = true;
130  mSocket->async_handshake(type, cbFunc);
131  }
132  else if (mBuffer.empty())
133  {
134  // must be plain
135  mSecure = false;
136  post(
137  mSocket->get_executor(),
138  boost::beast::bind_handler(cbFunc, error_code()));
139  }
140  else
141  {
142  // autodetect
143  mSocket->next_layer().async_receive(
144  boost::asio::buffer(mBuffer),
145  boost::asio::socket_base::message_peek,
146  std::bind(
148  this,
149  cbFunc,
150  std::placeholders::_1,
151  std::placeholders::_2));
152  }
153  }
154 
155  template <typename ShutdownHandler>
156  void
157  async_shutdown(ShutdownHandler handler)
158  {
159  if (isSecure())
160  mSocket->async_shutdown(handler);
161  else
162  {
163  error_code ec;
164  try
165  {
166  lowest_layer().shutdown(plain_socket::shutdown_both);
167  }
168  catch (boost::system::system_error& e)
169  {
170  ec = e.code();
171  }
172  post(
173  mSocket->get_executor(),
174  boost::beast::bind_handler(handler, ec));
175  }
176  }
177 
178  template <typename Seq, typename Handler>
179  void
180  async_read_some(const Seq& buffers, Handler handler)
181  {
182  if (isSecure())
183  mSocket->async_read_some(buffers, handler);
184  else
185  PlainSocket().async_read_some(buffers, handler);
186  }
187 
188  template <typename Seq, typename Condition, typename Handler>
189  void
190  async_read_until(const Seq& buffers, Condition condition, Handler handler)
191  {
192  if (isSecure())
193  boost::asio::async_read_until(
194  *mSocket, buffers, condition, handler);
195  else
196  boost::asio::async_read_until(
197  PlainSocket(), buffers, condition, handler);
198  }
199 
200  template <typename Allocator, typename Handler>
201  void
203  boost::asio::basic_streambuf<Allocator>& buffers,
204  std::string const& delim,
205  Handler handler)
206  {
207  if (isSecure())
208  boost::asio::async_read_until(*mSocket, buffers, delim, handler);
209  else
210  boost::asio::async_read_until(
211  PlainSocket(), buffers, delim, handler);
212  }
213 
214  template <typename Allocator, typename MatchCondition, typename Handler>
215  void
217  boost::asio::basic_streambuf<Allocator>& buffers,
218  MatchCondition cond,
219  Handler handler)
220  {
221  if (isSecure())
222  boost::asio::async_read_until(*mSocket, buffers, cond, handler);
223  else
224  boost::asio::async_read_until(
225  PlainSocket(), buffers, cond, handler);
226  }
227 
228  template <typename Buf, typename Handler>
229  void
230  async_write(const Buf& buffers, Handler handler)
231  {
232  if (isSecure())
233  boost::asio::async_write(*mSocket, buffers, handler);
234  else
235  boost::asio::async_write(PlainSocket(), buffers, handler);
236  }
237 
238  template <typename Allocator, typename Handler>
239  void
241  boost::asio::basic_streambuf<Allocator>& buffers,
242  Handler handler)
243  {
244  if (isSecure())
245  boost::asio::async_write(*mSocket, buffers, handler);
246  else
247  boost::asio::async_write(PlainSocket(), buffers, handler);
248  }
249 
250  template <typename Buf, typename Condition, typename Handler>
251  void
252  async_read(const Buf& buffers, Condition cond, Handler handler)
253  {
254  if (isSecure())
255  boost::asio::async_read(*mSocket, buffers, cond, handler);
256  else
257  boost::asio::async_read(PlainSocket(), buffers, cond, handler);
258  }
259 
260  template <typename Allocator, typename Condition, typename Handler>
261  void
263  boost::asio::basic_streambuf<Allocator>& buffers,
264  Condition cond,
265  Handler handler)
266  {
267  if (isSecure())
268  boost::asio::async_read(*mSocket, buffers, cond, handler);
269  else
270  boost::asio::async_read(PlainSocket(), buffers, cond, handler);
271  }
272 
273  template <typename Buf, typename Handler>
274  void
275  async_read(const Buf& buffers, Handler handler)
276  {
277  if (isSecure())
278  boost::asio::async_read(*mSocket, buffers, handler);
279  else
280  boost::asio::async_read(PlainSocket(), buffers, handler);
281  }
282 
283  template <typename Seq, typename Handler>
284  void
285  async_write_some(const Seq& buffers, Handler handler)
286  {
287  if (isSecure())
288  mSocket->async_write_some(buffers, handler);
289  else
290  PlainSocket().async_write_some(buffers, handler);
291  }
292 
293 protected:
294  void
296  callback cbFunc,
297  const error_code& ec,
298  size_t bytesTransferred)
299  {
300  using namespace ripple;
301 
302  if (ec)
303  {
304  JLOG(j_.warn()) << "Handle autodetect error: " << ec;
305  cbFunc(ec);
306  }
307  else if (
308  (mBuffer[0] < 127) && (mBuffer[0] > 31) &&
309  ((bytesTransferred < 2) ||
310  ((mBuffer[1] < 127) && (mBuffer[1] > 31))) &&
311  ((bytesTransferred < 3) ||
312  ((mBuffer[2] < 127) && (mBuffer[2] > 31))) &&
313  ((bytesTransferred < 4) ||
314  ((mBuffer[3] < 127) && (mBuffer[3] > 31))))
315  {
316  // not ssl
317  JLOG(j_.trace()) << "non-SSL";
318  mSecure = false;
319  cbFunc(ec);
320  }
321  else
322  {
323  // ssl
324  JLOG(j_.trace()) << "SSL";
325  mSecure = true;
326  mSocket->async_handshake(ssl_socket::server, cbFunc);
327  }
328  }
329 
330 private:
332  bool mSecure;
335 };
336 
337 #endif
AutoSocket::lowest_layer
lowest_layer_type & lowest_layer()
Definition: AutoSocket.h:104
std::bind
T bind(T... args)
AutoSocket::lowest_layer_type
ssl_socket::lowest_layer_type lowest_layer_type
Definition: AutoSocket.h:42
std::string
STL class.
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
AutoSocket::handshake_type
ssl_socket::handshake_type handshake_type
Definition: AutoSocket.h:43
AutoSocket::async_read
void async_read(boost::asio::basic_streambuf< Allocator > &buffers, Condition cond, Handler handler)
Definition: AutoSocket.h:262
std::vector< char >
AutoSocket::async_read_until
void async_read_until(boost::asio::basic_streambuf< Allocator > &buffers, MatchCondition cond, Handler handler)
Definition: AutoSocket.h:216
AutoSocket::setSSLOnly
void setSSLOnly()
Definition: AutoSocket.h:81
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
AutoSocket::AutoSocket
AutoSocket(boost::asio::io_service &s, boost::asio::ssl::context &c)
Definition: AutoSocket.h:60
AutoSocket::isSecure
bool isSecure()
Definition: AutoSocket.h:66
std::function
AutoSocket::mSocket
socket_ptr mSocket
Definition: AutoSocket.h:331
AutoSocket::async_read
void async_read(const Buf &buffers, Condition cond, Handler handler)
Definition: AutoSocket.h:252
beast::Journal::getNullSink
static Sink & getNullSink()
Returns a Sink which does nothing.
Definition: beast_Journal.cpp:72
AutoSocket::PlainSocket
plain_socket & PlainSocket()
Definition: AutoSocket.h:76
AutoSocket::async_write_some
void async_write_some(const Seq &buffers, Handler handler)
Definition: AutoSocket.h:285
std::vector::clear
T clear(T... args)
AutoSocket::cancel
boost::system::error_code cancel(boost::system::error_code &ec)
Definition: AutoSocket.h:118
AutoSocket::ssl_socket
boost::asio::ssl::stream< boost::asio::ip::tcp::socket > ssl_socket
Definition: AutoSocket.h:38
AutoSocket::async_read_until
void async_read_until(boost::asio::basic_streambuf< Allocator > &buffers, std::string const &delim, Handler handler)
Definition: AutoSocket.h:202
AutoSocket::async_read
void async_read(const Buf &buffers, Handler handler)
Definition: AutoSocket.h:275
AutoSocket::async_write
void async_write(const Buf &buffers, Handler handler)
Definition: AutoSocket.h:230
AutoSocket::j_
beast::Journal j_
Definition: AutoSocket.h:334
AutoSocket::SSLSocket
ssl_socket & SSLSocket()
Definition: AutoSocket.h:71
AutoSocket::remote_endpoint
beast::IP::Endpoint remote_endpoint()
Definition: AutoSocket.h:98
beast::IP::from_asio
Endpoint from_asio(boost::asio::ip::address const &address)
Convert to Endpoint.
Definition: IPAddressConversion.cpp:26
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
AutoSocket::endpoint_type
boost::asio::ip::tcp::socket::endpoint_type endpoint_type
Definition: AutoSocket.h:39
AutoSocket::handle_autodetect
void handle_autodetect(callback cbFunc, const error_code &ec, size_t bytesTransferred)
Definition: AutoSocket.h:295
AutoSocket::swap
void swap(AutoSocket &s) noexcept
Definition: AutoSocket.h:110
AutoSocket::plain_socket
ssl_socket::next_layer_type plain_socket
Definition: AutoSocket.h:41
std::vector::swap
T swap(T... args)
AutoSocket::async_handshake
void async_handshake(handshake_type type, callback cbFunc)
Definition: AutoSocket.h:124
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
AutoSocket::async_read_until
void async_read_until(const Seq &buffers, Condition condition, Handler handler)
Definition: AutoSocket.h:190
AutoSocket::async_write
void async_write(boost::asio::basic_streambuf< Allocator > &buffers, Handler handler)
Definition: AutoSocket.h:240
AutoSocket::AutoSocket
AutoSocket(boost::asio::io_service &s, boost::asio::ssl::context &c, bool secureOnly, bool plainOnly)
Definition: AutoSocket.h:48
AutoSocket::async_read_some
void async_read_some(const Seq &buffers, Handler handler)
Definition: AutoSocket.h:180
AutoSocket::error_code
boost::system::error_code error_code
Definition: AutoSocket.h:44
std::vector::empty
T empty(T... args)
AutoSocket::mSecure
bool mSecure
Definition: AutoSocket.h:332
beast::IP::Endpoint
A version-independent IP address and port combination.
Definition: IPEndpoint.h:39
AutoSocket
Definition: AutoSocket.h:35
AutoSocket::async_shutdown
void async_shutdown(ShutdownHandler handler)
Definition: AutoSocket.h:157
std::unique_ptr< ssl_socket >
AutoSocket::local_endpoint
beast::IP::Endpoint local_endpoint()
Definition: AutoSocket.h:92
AutoSocket::mBuffer
std::vector< char > mBuffer
Definition: AutoSocket.h:333
AutoSocket::setPlainOnly
void setPlainOnly()
Definition: AutoSocket.h:86