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