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 
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 
283 protected:
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 
320 private:
322  bool mSecure;
325 };
326 
327 #endif
AutoSocket::lowest_layer
lowest_layer_type & lowest_layer()
Definition: AutoSocket.h:94
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:252
std::vector< char >
AutoSocket::async_read_until
void async_read_until(boost::asio::basic_streambuf< Allocator > &buffers, MatchCondition cond, Handler handler)
Definition: AutoSocket.h:206
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:321
AutoSocket::async_read
void async_read(const Buf &buffers, Condition cond, Handler handler)
Definition: AutoSocket.h:242
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:275
AutoSocket::cancel
boost::system::error_code cancel(boost::system::error_code &ec)
Definition: AutoSocket.h:108
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:192
AutoSocket::async_read
void async_read(const Buf &buffers, Handler handler)
Definition: AutoSocket.h:265
AutoSocket::async_write
void async_write(const Buf &buffers, Handler handler)
Definition: AutoSocket.h:220
AutoSocket::j_
beast::Journal j_
Definition: AutoSocket.h:324
AutoSocket::SSLSocket
ssl_socket & SSLSocket()
Definition: AutoSocket.h:71
AutoSocket::remote_endpoint
beast::IP::Endpoint remote_endpoint()
Definition: AutoSocket.h:88
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:285
AutoSocket::swap
void swap(AutoSocket &s) noexcept
Definition: AutoSocket.h:100
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:114
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:180
AutoSocket::async_write
void async_write(boost::asio::basic_streambuf< Allocator > &buffers, Handler handler)
Definition: AutoSocket.h:230
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:170
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:322
beast::IP::Endpoint
A version-independent IP address and port combination.
Definition: IPEndpoint.h:38
AutoSocket
Definition: AutoSocket.h:35
AutoSocket::async_shutdown
void async_shutdown(ShutdownHandler handler)
Definition: AutoSocket.h:147
std::unique_ptr< ssl_socket >
AutoSocket::local_endpoint
beast::IP::Endpoint local_endpoint()
Definition: AutoSocket.h:82
AutoSocket::mBuffer
std::vector< char > mBuffer
Definition: AutoSocket.h:323