diff --git a/Builds/VisualStudio2012/RippleD.vcxproj b/Builds/VisualStudio2012/RippleD.vcxproj
index af2cf8faa3..2ea6065806 100644
--- a/Builds/VisualStudio2012/RippleD.vcxproj
+++ b/Builds/VisualStudio2012/RippleD.vcxproj
@@ -1499,6 +1499,7 @@
+
diff --git a/Builds/VisualStudio2012/RippleD.vcxproj.filters b/Builds/VisualStudio2012/RippleD.vcxproj.filters
index 1a14689e5c..e7e7198244 100644
--- a/Builds/VisualStudio2012/RippleD.vcxproj.filters
+++ b/Builds/VisualStudio2012/RippleD.vcxproj.filters
@@ -1703,6 +1703,9 @@
[1] Ripple\ripple_asio\sockets
+
+ [1] Ripple\ripple_asio\sockets
+
diff --git a/modules/ripple_app/peers/ripple_Peer.cpp b/modules/ripple_app/peers/ripple_Peer.cpp
index f7186817c8..9337c828ac 100644
--- a/modules/ripple_app/peers/ripple_Peer.cpp
+++ b/modules/ripple_app/peers/ripple_Peer.cpp
@@ -465,7 +465,7 @@ void PeerImp::handleConnect (const boost::system::error_code& error, boost::asio
WriteLog (lsINFO, Peer) << "Connect peer: success.";
#if RIPPLE_USES_BEAST_SOCKETS
- mSocketSsl.native_object ().set_verify_mode (boost::asio::ssl::verify_none);
+ mSocketSsl.this_layer ().set_verify_mode (boost::asio::ssl::verify_none);
#else
mSocketSsl.set_verify_mode (boost::asio::ssl::verify_none);
#endif
@@ -511,7 +511,7 @@ void PeerImp::connected (const boost::system::error_code& error)
WriteLog (lsINFO, Peer) << "Peer: Inbound: Accepted: " << addressToString (this) << ": " << strIp << " " << iPort;
#if RIPPLE_USES_BEAST_SOCKETS
- mSocketSsl.native_object ().set_verify_mode (boost::asio::ssl::verify_none);
+ mSocketSsl.this_layer ().set_verify_mode (boost::asio::ssl::verify_none);
#else
mSocketSsl.set_verify_mode (boost::asio::ssl::verify_none);
#endif
@@ -2221,7 +2221,7 @@ void PeerImp::addTxSet (uint256 const& hash)
void PeerImp::getSessionCookie (std::string& strDst)
{
#if RIPPLE_USES_BEAST_SOCKETS
- SSL* ssl = mSocketSsl.native_object ().native_handle ();
+ SSL* ssl = mSocketSsl.this_layer ().native_handle ();
#else
SSL* ssl = mSocketSsl.native_handle ();
#endif
diff --git a/modules/ripple_asio/ripple_asio.cpp b/modules/ripple_asio/ripple_asio.cpp
index c3889ad947..64b8230018 100644
--- a/modules/ripple_asio/ripple_asio.cpp
+++ b/modules/ripple_asio/ripple_asio.cpp
@@ -26,7 +26,6 @@ namespace ripple
#include "boost/ripple_IoService.cpp"
#include "boost/ripple_SslContext.cpp"
-#include "sockets/ripple_RippleTlsContext.h" // private
#include "sockets/ripple_RippleTlsContext.cpp"
#include "sockets/ripple_MultiSocket.cpp"
diff --git a/modules/ripple_asio/ripple_asio.h b/modules/ripple_asio/ripple_asio.h
index a949d6bca7..24c595166d 100644
--- a/modules/ripple_asio/ripple_asio.h
+++ b/modules/ripple_asio/ripple_asio.h
@@ -32,6 +32,8 @@ using namespace beast;
#include "boost/ripple_SslContext.h"
#include "sockets/ripple_MultiSocket.h"
+# include "sockets/ripple_RippleTlsContext.h"
+#include "sockets/ripple_MultiSocketType.h"
}
diff --git a/modules/ripple_asio/sockets/ripple_MultiSocket.cpp b/modules/ripple_asio/sockets/ripple_MultiSocket.cpp
index 3442b22225..6496077650 100644
--- a/modules/ripple_asio/sockets/ripple_MultiSocket.cpp
+++ b/modules/ripple_asio/sockets/ripple_MultiSocket.cpp
@@ -4,7 +4,7 @@
*/
//==============================================================================
-RippleMultiSocket::Options::Options (Flags flags)
+MultiSocket::Options::Options (Flags flags)
: useClientSsl (false)
, enableServerSsl (false)
, requireServerSsl (false)
@@ -13,7 +13,7 @@ RippleMultiSocket::Options::Options (Flags flags)
setFromFlags (flags);
}
-void RippleMultiSocket::Options::setFromFlags (Flags flags)
+void MultiSocket::Options::setFromFlags (Flags flags)
{
useClientSsl = (flags & client_ssl) != 0;
enableServerSsl = (flags & (server_ssl | server_ssl_required)) != 0;
@@ -23,664 +23,201 @@ void RippleMultiSocket::Options::setFromFlags (Flags flags)
//------------------------------------------------------------------------------
-template
-class RippleMultiSocketType : public RippleMultiSocket
+MultiSocket* MultiSocket::New (boost::asio::io_service& io_service,
+ Options const& options)
{
-public:
- // This shouldn't be needed
- /*
- struct SocketInterfaces
- : SocketInterface::Socket
- , SocketInterface::Stream
- , SocketInterface::Handshake
- {};
- */
-
- typedef typename boost::remove_reference ::type next_layer_type;
- typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
-
- typedef typename boost::add_reference ::type next_layer_type_ref;
- typedef typename boost::asio::ssl::stream SslStreamType;
-
- typedef RippleMultiSocketType ThisType;
-
- enum Status
- {
- needMore,
- proxy,
- plain,
- ssl
- };
-
- template
- explicit RippleMultiSocketType (Arg& arg, Options options = Options())
- : m_options (options)
- , m_context (RippleTlsContext::New ())
- , m_next_layer (arg)
- , m_io_service (m_next_layer.get_io_service ())
- , m_strand (m_io_service)
- , m_status (needMore)
- , m_role (Socket::client)
-
- {
- }
-
- //--------------------------------------------------------------------------
-
- bool is_handshaked ()
- {
- return true;
- }
-
- void* native_object_raw ()
- {
- return &m_next_layer;
- }
-
- boost::asio::io_service& get_io_service () noexcept
- {
- return m_io_service;
- }
-
- next_layer_type& next_layer () noexcept
- {
- return m_next_layer;
- }
-
- next_layer_type const& next_layer () const noexcept
- {
- return m_next_layer;
- }
-
- lowest_layer_type& lowest_layer () noexcept
- {
- return m_next_layer.lowest_layer ();
- }
-
- lowest_layer_type const& lowest_layer () const noexcept
- {
- return m_next_layer.lowest_layer ();
- }
-
- //--------------------------------------------------------------------------
-
- Socket& stream () const noexcept
- {
- fatal_assert (m_stream != nullptr);
- return *m_stream;
- }
-
- //--------------------------------------------------------------------------
- //
- // SocketInterface
- //
- //--------------------------------------------------------------------------
-
- boost::system::error_code cancel (boost::system::error_code& ec)
- {
- return lowest_layer ().cancel (ec);
- }
-
- boost::system::error_code close (boost::system::error_code& ec)
- {
- return lowest_layer ().close (ec);
- }
-
- boost::system::error_code shutdown (Socket::shutdown_type what, boost::system::error_code& ec)
- {
- return lowest_layer ().shutdown (what, ec);
- }
-
- //--------------------------------------------------------------------------
- //
- // StreamInterface
- //
- //--------------------------------------------------------------------------
-
- std::size_t read_some (MutableBuffers const& buffers, boost::system::error_code& ec)
- {
- if (m_buffer.size () > 0)
- {
- ec = boost::system::error_code ();
- std::size_t const amount = boost::asio::buffer_copy (buffers, m_buffer.data ());
- m_buffer.consume (amount);
- return amount;
- }
- return stream ().read_some (buffers, ec);
- }
-
- std::size_t write_some (ConstBuffers const& buffers, boost::system::error_code& ec)
- {
- return stream ().write_some (buffers, ec);
- }
-
- BOOST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (boost::system::error_code, std::size_t))
- async_read_some (MutableBuffers const& buffers, BOOST_ASIO_MOVE_ARG(TransferCall) handler)
- {
- if (m_buffer.size () > 0)
- {
- // Return the leftover bytes from the handshake
- std::size_t const amount = boost::asio::buffer_copy (buffers, m_buffer.data ());
- m_buffer.consume (amount);
- return m_io_service.post (m_strand.wrap (boost::bind (
- BOOST_ASIO_MOVE_CAST(TransferCall)(handler), boost::system::error_code (), amount)));
- }
- return stream ().async_read_some (buffers, m_strand.wrap (boost::bind (
- BOOST_ASIO_MOVE_CAST(TransferCall)(handler), boost::asio::placeholders::error,
- boost::asio::placeholders::bytes_transferred)));
- }
-
- BOOST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (boost::system::error_code, std::size_t))
- async_write_some (ConstBuffers const& buffers, BOOST_ASIO_MOVE_ARG(TransferCall) handler)
- {
- return stream ().async_write_some (buffers,
- BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
- }
-
- //--------------------------------------------------------------------------
-
- boost::system::error_code handshake (Socket::handshake_type role, boost::system::error_code& ec)
- {
- Action action = calcAction (role);
-
- switch (action)
- {
- default:
- case actionPlain:
- handshakePlain (ec);
- break;
-
- case actionSsl:
- handshakeSsl (ec);
- break;
-
- case actionDetect:
- detectHandshake (ec);
- if (! ec)
- {
- action = calcDetectAction (ec);
- switch (action)
- {
- default:
- case actionPlain:
- handshakePlain (ec);
- break;
- case actionSsl:
- handshakeSsl (ec);
- break;
- };
- }
- break;
- }
-
- return ec;
- }
-
- BOOST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (boost::system::error_code))
- async_handshake (handshake_type type, BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
- {
- Action const action = calcAction (type);
- switch (action)
- {
- default:
- case actionPlain:
- return handshakePlainAsync (BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
- break;
-
- case actionSsl:
- return handshakeSslAsync (BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
- break;
-
- case actionDetect:
- return detectHandshakeAsync (BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
- break;
- }
- }
-
-#if BOOST_ASIO_HAS_BUFFEREDHANDSHAKE
- boost::system::error_code handshake (handshake_type type,
- ConstBuffers const& buffers, boost::system::error_code& ec)
- {
- Action action = calcAction (type);
- ec = boost::system::error_code ();
- switch (action)
- {
- default:
- case actionPlain:
- handshakePlain (buffers, ec);
- break;
- case actionSsl:
- handshakeSsl (buffers, ec);
- break;
- case actionDetect:
- detectHandshake (buffers, ec);
- if (! ec)
- {
- action = calcDetectAction (ec);
- switch (action)
- {
- default:
- case actionPlain:
- handshakePlain (buffers, ec);
- break;
- case actionSsl:
- handshakeSsl (buffers, ec);
- break;
- };
- }
- break;
- }
- return ec;
- }
-
- BOOST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (boost::system::error_code, std::size_t))
- async_handshake (handshake_type type, ConstBuffers const& buffers,
- BOOST_ASIO_MOVE_ARG(TransferCall) handler)
- {
- Action const action = calcAction (type);
- switch (action)
- {
- default:
- case actionPlain:
- return handshakePlainAsync (buffers,
- BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
- break;
-
- case actionSsl:
- return handshakeSslAsync (buffers,
- BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
- break;
-
- case actionDetect:
- return detectHandshakeAsync (buffers,
- BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
- break;
- }
- }
-#endif
-
- boost::system::error_code shutdown (boost::system::error_code& ec)
- {
- if (m_status == ssl)
- {
- return m_ssl_stream->shutdown (ec);
- }
- else
- {
- // we need to close the lwest layer
- return m_next_layer.shutdown (next_layer_type::shutdown_both, ec);
- }
- }
-
- BOOST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (boost::system::error_code))
- async_shutdown (BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
- {
- if (m_status == ssl)
- {
- m_ssl_stream->async_shutdown (m_strand.wrap (boost::bind (
- BOOST_ASIO_MOVE_CAST(ErrorCall)(handler),
- boost::asio::placeholders::error)));
- }
- else
- {
- boost::system::error_code ec;
- m_next_layer.shutdown (next_layer_type::shutdown_both, ec);
- m_io_service.post (m_strand.wrap (boost::bind (
- BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec)));
- }
- }
-
- //--------------------------------------------------------------------------
-
- enum Action
- {
- actionDetect,
- actionPlain,
- actionSsl,
- actionFail
- };
-
- // Determines what action to take based on
- // the stream options and the desired role.
- //
- Action calcAction (Socket::handshake_type role)
- {
- m_role = role;
-
- if (role == Socket::server)
- {
- if (! m_options.enableServerSsl &&
- ! m_options.requireServerSsl &&
- ! m_options.requireServerProxy)
- {
- return actionPlain;
- }
- else if (m_options.requireServerSsl && ! m_options.requireServerProxy)
- {
- return actionSsl;
- }
- else
- {
- return actionDetect;
- }
- }
- else if (m_role == Socket::client)
- {
- if (m_options.useClientSsl)
- {
- return actionSsl;
- }
- else
- {
- return actionPlain;
- }
- }
-
- return actionPlain;
- }
-
- // Determines what action to take based on the auto-detected
- // handshake, the stream options, and desired role.
- //
- Action calcDetectAction (boost::system::error_code& ec)
- {
- ec = boost::system::error_code ();
-
- if (m_status == plain)
- {
- if (! m_options.requireServerProxy && ! m_options.requireServerSsl)
- {
- return actionPlain;
- }
- else
- {
- failedHandshake (ec);
- return actionFail;
- }
- }
- else if (m_status == ssl)
- {
- if (! m_options.requireServerProxy)
- {
- if (m_options.enableServerSsl || m_options.requireServerSsl)
- {
- return actionSsl;
- }
- else
- {
- failedHandshake (ec);
- return actionFail;
- }
- }
- else
- {
- failedHandshake (ec);
- return actionFail;
- }
- }
- else if (m_status == proxy)
- {
- if (m_options.requireServerProxy)
- {
- // read the rest of the proxy string
- // then transition to SSL handshake mode
- failedHandshake (ec);
- return actionFail;
- }
- else
- {
- // Can we make PROXY optional?
- failedHandshake (ec);
- return actionFail;
- }
- }
-
- failedHandshake (ec);
- return actionFail;
- }
-
- //--------------------------------------------------------------------------
-
- // called when options disallow handshake
- void failedHandshake (boost::system::error_code& ec)
- {
- // VFALCO TODO maybe use a ripple error category?
- // set this to something custom that we can recognize later?
- ec = boost::asio::error::invalid_argument;
- }
-
- void createPlainStream ()
- {
- m_status = plain;
- m_stream = new SocketWrapper (m_next_layer);
- }
-
- void handshakePlain (boost::system::error_code& ec)
- {
- ec = boost::system::error_code ();
- createPlainStream ();
- }
-
- void handshakePlain (ConstBuffers const& buffers, boost::system::error_code& ec)
- {
- fatal_assert (boost::asio::buffer_size (buffers) == 0 );
- ec = boost::system::error_code ();
- createPlainStream ();
- }
-
- BOOST_ASIO_INITFN_RESULT_TYPE(ErrorCall, void (boost::system::error_code))
- handshakePlainAsync (BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
- {
- createPlainStream ();
- return m_io_service.post (m_strand.wrap (boost::bind (
- BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), boost::system::error_code())));
- }
-
- void createSslStream ()
- {
- m_status = ssl;
- m_ssl_stream = new SslStreamType (m_next_layer, m_context->getBoostContext ());
- m_stream = new SocketWrapper (*m_ssl_stream);
- }
-
- void handshakeSsl (boost::system::error_code& ec)
- {
- createSslStream ();
- m_ssl_stream->handshake (m_role, ec);
- }
-
- BOOST_ASIO_INITFN_RESULT_TYPE(ErrorCall, void (boost::system::error_code))
- handshakeSslAsync (BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
- {
- createSslStream ();
- return m_ssl_stream->async_handshake (m_role,
- BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
- }
-
-#if BOOST_ASIO_HAS_BUFFEREDHANDSHAKE
- BOOST_ASIO_INITFN_RESULT_TYPE(TransferCall, void (boost::system::error_code, std::size_t))
- handshakePlainAsync (ConstBuffers const& buffers,
- BOOST_ASIO_MOVE_ARG (TransferCall) handler)
- {
- fatal_assert (boost::asio::buffer_size (buffers) == 0);
- createPlainStream ();
- return m_io_service.post (m_strand.wrap (boost::bind (
- BOOST_ASIO_MOVE_CAST(TransferCall)(handler),
- boost::system::error_code(), 0)));
- }
-
- void handshakeSsl (ConstBuffers const& buffers, boost::system::error_code& ec)
- {
- createSslStream ();
- m_ssl_stream->handshake (m_role, buffers, ec);
- }
-
- BOOST_ASIO_INITFN_RESULT_TYPE (TransferCall, void (boost::system::error_code, std::size_t))
- handshakeSslAsync (ConstBuffers const& buffers, BOOST_ASIO_MOVE_ARG(TransferCall) handler)
- {
- createSslStream ();
- return m_ssl_stream->async_handshake (m_role, buffers,
- BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
- }
-#endif
-
- //--------------------------------------------------------------------------
-
- enum
- {
- autoDetectBytes = 5
- };
-
- void detectHandshake (boost::system::error_code& ec)
- {
- // Top up our buffer
- bassert (m_buffer.size () == 0);
- std::size_t const needed = autoDetectBytes;
- std::size_t const amount = m_next_layer.receive (
- m_buffer.prepare (needed), boost::asio::socket_base::message_peek, ec);
- m_buffer.commit (amount);
- if (! ec)
- {
- analyzeHandshake (m_buffer.data ());
- m_buffer.consume (amount);
- if (m_status == needMore)
- ec = boost::asio::error::invalid_argument; // should never happen
- }
- }
-
-#if BOOST_ASIO_HAS_BUFFEREDHANDSHAKE
- void detectHandshake (ConstBuffers const& buffers, boost::system::error_code& ec)
- {
- m_buffer.commit (boost::asio::buffer_copy (
- m_buffer.prepare (boost::asio::buffer_size (buffers)), buffers));
- detectHandshake (ec);
- }
-#endif
-
- //--------------------------------------------------------------------------
-
- void onDetectRead (BOOST_ASIO_MOVE_ARG(ErrorCall) handler,
- boost::system::error_code const& ec, std::size_t bytes_transferred)
- {
- m_buffer.commit (bytes_transferred);
-
- if (! ec)
- {
- analyzeHandshake (m_buffer.data ());
-
- boost::system::error_code ec;
-
- if (m_status != needMore)
- {
- m_buffer.consume (bytes_transferred);
-
- Action action = calcDetectAction (ec);
- if (! ec)
- {
- switch (action)
- {
- default:
- case actionPlain:
- handshakePlainAsync (
- BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
- break;
- case actionSsl:
- handshakeSslAsync (
- BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
- break;
- };
- }
- }
- else
- {
- ec = boost::asio::error::invalid_argument;
- }
-
- if (ec)
- {
- m_io_service.post (m_strand.wrap (boost::bind (
- BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec)));
- }
- }
- }
-
- BOOST_ASIO_INITFN_RESULT_TYPE(ErrorCall, void (boost::system::error_code))
- detectHandshakeAsync (BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
- {
- bassert (m_buffer.size () == 0);
- return m_next_layer.async_receive (
- m_buffer.prepare (autoDetectBytes), boost::asio::socket_base::message_peek,
- m_strand.wrap (boost::bind (&ThisType::onDetectRead, this,
- BOOST_ASIO_MOVE_CAST(ErrorCall)(handler),
- boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)));
- }
-
-#if BOOST_ASIO_HAS_BUFFEREDHANDSHAKE
- BOOST_ASIO_INITFN_RESULT_TYPE(TransferCall, void (boost::system::error_code, std::size_t))
- detectHandshakeAsync (ConstBuffers const& buffers, BOOST_ASIO_MOVE_ARG(TransferCall) handler)
- {
- fatal_error ("unimplemented");
- }
-#endif
-
- //--------------------------------------------------------------------------
-
- static inline bool isPrintable (unsigned char c)
- {
- return (c < 127) && (c > 31);
- }
-
- template
- void analyzeHandshake (ConstBufferSequence const& buffers)
- {
- m_status = needMore;
-
- unsigned char data [5];
-
- std::size_t const bytes = boost::asio::buffer_copy (boost::asio::buffer (data), buffers);
-
- if (bytes > 0)
- {
- if ( isPrintable (data [0]) &&
- ((bytes < 2) || isPrintable (data [1])) &&
- ((bytes < 3) || isPrintable (data [2])) &&
- ((bytes < 4) || isPrintable (data [3])) &&
- ((bytes < 5) || isPrintable (data [4])))
- {
- if (bytes < 5 || memcmp (data, "PROXY", 5) != 0)
- {
- m_status = plain;
- }
- else
- {
- m_status = proxy;
- }
- }
- else
- {
- m_status = ssl;
- }
- }
- }
-
-private:
- Options m_options;
- ScopedPointer m_context;
- Stream m_next_layer;
- boost::asio::io_service& m_io_service;
- boost::asio::io_service::strand m_strand;
- Status m_status;
- Socket::handshake_type m_role;
- ScopedPointer m_stream;
- ScopedPointer m_ssl_stream;
- boost::asio::streambuf m_buffer;
-};
+ return new MultiSocketType (io_service, options);
+}
//------------------------------------------------------------------------------
-RippleMultiSocket* RippleMultiSocket::New (boost::asio::io_service& io_service,
- Options const& options)
+class MultiSocketTests : public UnitTest
{
- return new RippleMultiSocketType (io_service, options);
-}
+public:
+ class Details : public TestPeerDetails
+ {
+ public:
+ typedef int arg_type;
+
+ // These flags get combined to determine the multisocket attributes
+ //
+ enum Flags
+ {
+ none = 0,
+ client_ssl = 1,
+ server_ssl = 2,
+ server_ssl_required = 4,
+ server_proxy = 8,
+
+ // these are for producing the endpoint test parameters
+ tcpv4 = 16,
+ tcpv6 = 32
+ };
+
+ Details (arg_type flags)
+ : m_flags (flags)
+ {
+ m_socketOptions.useClientSsl = (flags & client_ssl) != 0;
+ m_socketOptions.enableServerSsl = (flags & (server_ssl | server_ssl_required)) != 0;
+ m_socketOptions.requireServerSsl = (flags & server_ssl_required) != 0;
+ m_socketOptions.requireServerProxy = (flags & server_proxy) !=0;
+ }
+
+ static String getArgName (arg_type arg)
+ {
+ String s;
+ if (arg != 0)
+ {
+ s << "[";
+ if (arg & client_ssl) s << "client_ssl,";
+ if (arg & server_ssl) s << "server_ssl,";
+ if (arg & server_ssl_required) s << "server_ssl_required,";
+ if (arg & server_proxy) s << "server_proxy,";
+ if (arg & tcpv4) s << "tcpv4,";
+ if (arg & tcpv6) s << "tcpv6,";
+ s = s.substring (0, s.length () - 1) + "]";
+ }
+ else
+ {
+ s = "[plain]";
+ }
+ return s;
+ }
+
+ String name ()
+ {
+ return getArgName (m_flags);
+ }
+
+ arg_type getFlags () const noexcept
+ {
+ return m_flags;
+ }
+
+ MultiSocket::Options const& getSocketOptions () const noexcept
+ {
+ return m_socketOptions;
+ }
+
+ protected:
+ arg_type m_flags;
+ MultiSocket::Options m_socketOptions;
+ };
+
+ template
+ class DetailsType : public Details
+ {
+ protected:
+ typedef InternetProtocol protocol_type;
+ typedef typename protocol_type::socket socket_type;
+ typedef typename protocol_type::acceptor acceptor_type;
+ typedef typename protocol_type::endpoint endpoint_type;
+ typedef typename protocol_type::resolver resolver_type;
+
+ public:
+ typedef socket_type native_socket_type;
+ typedef acceptor_type native_acceptor_type;
+
+ explicit DetailsType (arg_type flags = none)
+ : Details (flags)
+ , m_socket (get_io_service ())
+ , m_acceptor (get_io_service ())
+ , m_multiSocket (m_socket, getSocketOptions ())
+ , m_acceptor_wrapper (m_acceptor)
+ {
+ }
+
+ Socket& get_socket ()
+ {
+ return m_multiSocket;
+ }
+
+ Socket& get_acceptor ()
+ {
+ return m_acceptor_wrapper;
+ }
+
+ socket_type& get_native_socket ()
+ {
+ return m_socket;
+ }
+
+ acceptor_type& get_native_acceptor ()
+ {
+ return m_acceptor;
+ }
+
+ endpoint_type get_endpoint (TestPeer::Role role)
+ {
+ if (getFlags () & Details::tcpv4)
+ {
+ if (role == TestPeer::Role::server)
+ {
+ return endpoint_type (boost::asio::ip::address_v4::any (), 1053);
+ }
+ else
+ {
+ return endpoint_type (boost::asio::ip::address_v4::loopback (), 1053);
+ }
+ }
+ else
+ {
+ if (role == TestPeer::Role::server)
+ return endpoint_type (boost::asio::ip::tcp::v6 (), 1052);
+ else
+ return endpoint_type (boost::asio::ip::address_v6 ().from_string ("::1"), 1052);
+ }
+ }
+
+ protected:
+ socket_type m_socket;
+ acceptor_type m_acceptor;
+ MultiSocketType m_multiSocket;
+ SocketWrapper m_acceptor_wrapper;
+ };
+
+ MultiSocketTests () : UnitTest ("MultiSocket", "ripple")
+ {
+ }
+
+ enum
+ {
+ timeoutSeconds = 3
+ };
+
+ template
+ void testAsync (Arg const& arg)
+ {
+ TestPeerTestType::run
+ (arg, timeoutSeconds).report (*this);
+ }
+
+ template
+ void testProtocol (Arg const& arg)
+ {
+ testAsync > (arg);
+ }
+
+ void testOptions (int flags)
+ {
+ testProtocol (flags);
+ }
+
+ //--------------------------------------------------------------------------
+
+ void runTest ()
+ {
+ // These should pass
+ testOptions (Details::none);
+ testOptions (Details::server_ssl);
+ testOptions (Details::client_ssl | Details::server_ssl);
+ testOptions (Details::client_ssl | Details::server_ssl_required);
+
+ // These should fail
+ testOptions (Details::client_ssl);
+ testOptions (Details::server_ssl_required);
+ }
+};
+
+static MultiSocketTests multiSocketTests;
diff --git a/modules/ripple_asio/sockets/ripple_MultiSocket.h b/modules/ripple_asio/sockets/ripple_MultiSocket.h
index 19c88260f7..4e3634e378 100644
--- a/modules/ripple_asio/sockets/ripple_MultiSocket.h
+++ b/modules/ripple_asio/sockets/ripple_MultiSocket.h
@@ -9,7 +9,7 @@
/** A Socket that can handshake with multiple protocols.
*/
-class RippleMultiSocket : public Socket
+class MultiSocket : public Socket
{
public:
enum Flags
@@ -42,7 +42,7 @@ public:
void setFromFlags (Flags flags);
};
- static RippleMultiSocket* New (boost::asio::io_service& io_service,
+ static MultiSocket* New (boost::asio::io_service& io_service,
Options const& options = none);
};
diff --git a/modules/ripple_asio/sockets/ripple_MultiSocketType.h b/modules/ripple_asio/sockets/ripple_MultiSocketType.h
new file mode 100644
index 0000000000..a5701558a4
--- /dev/null
+++ b/modules/ripple_asio/sockets/ripple_MultiSocketType.h
@@ -0,0 +1,709 @@
+//------------------------------------------------------------------------------
+/*
+ Copyright (c) 2011-2013, OpenCoin, Inc.
+*/
+//==============================================================================
+
+#ifndef RIPPLE_MULTISOCKETTYPE_H_INCLUDED
+#define RIPPLE_MULTISOCKETTYPE_H_INCLUDED
+
+/** Template for producing instances of MultiSocket
+
+ StreamSocket must meet these requirements:
+
+ SocketInterface::Socket, SocketInterface::Stream
+*/
+template
+class MultiSocketType
+ : public MultiSocket
+ , protected SocketWrapperBasics
+{
+public:
+ typedef typename boost::remove_reference ::type next_layer_type;
+ typedef typename boost::add_reference ::type next_layer_type_ref;
+ typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
+ typedef typename boost::asio::ssl::stream ssl_stream_type;
+
+ typedef MultiSocketType ThisType;
+
+ enum Status
+ {
+ needMore,
+ proxy,
+ plain,
+ ssl
+ };
+
+ template
+ explicit MultiSocketType (Arg& arg, Options options = Options())
+ : m_options (options)
+ , m_context (RippleTlsContext::New ())
+ , m_next_layer (arg)
+ , m_io_service (m_next_layer.get_io_service ())
+ , m_strand (m_io_service)
+ , m_status (needMore)
+ , m_role (Socket::client)
+
+ {
+ }
+
+ Socket& stream () const noexcept
+ {
+ fatal_assert (m_stream != nullptr);
+ return *m_stream;
+ }
+
+ next_layer_type& next_layer () noexcept
+ {
+ return m_next_layer;
+ }
+
+ next_layer_type const& next_layer () const noexcept
+ {
+ return m_next_layer;
+ }
+
+ lowest_layer_type& lowest_layer () noexcept
+ {
+ return m_next_layer.lowest_layer ();
+ }
+
+ lowest_layer_type const& lowest_layer () const noexcept
+ {
+ return m_next_layer.lowest_layer ();
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // General
+ //
+ //--------------------------------------------------------------------------
+
+ boost::asio::io_service& get_io_service ()
+ {
+ return lowest_layer ().get_io_service ();
+ }
+
+ bool requires_handshake ()
+ {
+ return true;
+ }
+
+ void* this_layer_raw (char const* type_name) const
+ {
+ // 'this' layer will be the underlying StreamSocket since
+ // we support all of its functionality.
+#if 1
+ char const* const next_layer_type_name (typeid (next_layer_type).name ());
+ if (strcmp (type_name, next_layer_type_name) == 0)
+ return const_cast (static_cast (&next_layer ()));
+ return nullptr;
+#else
+ if (m_stream != nullptr)
+ {
+ if (strcmp (type_name, typeid (lowest_layer_type).name ()) == 0)
+ return const_cast (static_cast (&lowest_layer ()));
+ }
+ pure_virtual ();
+ return nullptr;
+#endif
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // SocketInterface::Close
+ //
+ //--------------------------------------------------------------------------
+
+ boost::system::error_code close (boost::system::error_code& ec)
+ {
+ return lowest_layer ().close (ec);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // SocketInterface::Acceptor
+ //
+ //--------------------------------------------------------------------------
+
+ // nothing yet
+
+ //--------------------------------------------------------------------------
+ //
+ // SocketInterface::LowestLayer
+ //
+ //--------------------------------------------------------------------------
+
+ void* lowest_layer_raw (char const* type_name) const
+ {
+ if (strcmp (type_name, typeid (lowest_layer_type).name ()) == 0)
+ return const_cast (static_cast (&lowest_layer ()));
+ return nullptr;
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // SocketInterface::Socket
+ //
+ //--------------------------------------------------------------------------
+
+ boost::system::error_code cancel (boost::system::error_code& ec)
+ {
+ return lowest_layer ().cancel (ec);
+ }
+
+ boost::system::error_code shutdown (Socket::shutdown_type what, boost::system::error_code& ec)
+ {
+ return lowest_layer ().shutdown (what, ec);
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // SocketInterface::Stream
+ //
+ //--------------------------------------------------------------------------
+
+ std::size_t read_some (MutableBuffers const& buffers, boost::system::error_code& ec)
+ {
+ if (m_buffer.size () > 0)
+ {
+ ec = boost::system::error_code ();
+ std::size_t const amount = boost::asio::buffer_copy (buffers, m_buffer.data ());
+ m_buffer.consume (amount);
+ return amount;
+ }
+ return stream ().read_some (buffers, ec);
+ }
+
+ std::size_t write_some (ConstBuffers const& buffers, boost::system::error_code& ec)
+ {
+ return stream ().write_some (buffers, ec);
+ }
+
+ BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (boost::system::error_code, std::size_t))
+ async_read_some (MutableBuffers const& buffers, BOOST_ASIO_MOVE_ARG(TransferCall) handler)
+ {
+ if (m_buffer.size () > 0)
+ {
+ // Return the leftover bytes from the handshake
+ std::size_t const amount = boost::asio::buffer_copy (buffers, m_buffer.data ());
+ m_buffer.consume (amount);
+ return m_io_service.post (m_strand.wrap (boost::bind (
+ BOOST_ASIO_MOVE_CAST(TransferCall)(handler), boost::system::error_code (), amount)));
+ }
+ return stream ().async_read_some (buffers, m_strand.wrap (boost::bind (
+ BOOST_ASIO_MOVE_CAST(TransferCall)(handler), boost::asio::placeholders::error,
+ boost::asio::placeholders::bytes_transferred)));
+ }
+
+ BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (boost::system::error_code, std::size_t))
+ async_write_some (ConstBuffers const& buffers, BOOST_ASIO_MOVE_ARG(TransferCall) handler)
+ {
+ return stream ().async_write_some (buffers,
+ BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
+ }
+
+ //--------------------------------------------------------------------------
+ //
+ // SocketInterface::Handshake
+ //
+ //--------------------------------------------------------------------------
+
+ boost::system::error_code handshake (Socket::handshake_type role, boost::system::error_code& ec)
+ {
+ Action action = calcAction (role);
+
+ switch (action)
+ {
+ default:
+ case actionPlain:
+ handshakePlain (ec);
+ break;
+
+ case actionSsl:
+ handshakeSsl (ec);
+ break;
+
+ case actionDetect:
+ detectHandshake (ec);
+ if (! ec)
+ {
+ action = calcDetectAction (ec);
+ switch (action)
+ {
+ default:
+ case actionPlain:
+ handshakePlain (ec);
+ break;
+ case actionSsl:
+ handshakeSsl (ec);
+ break;
+ };
+ }
+ break;
+ }
+
+ return ec;
+ }
+
+ BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (boost::system::error_code))
+ async_handshake (handshake_type type, BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
+ {
+ Action const action = calcAction (type);
+ switch (action)
+ {
+ default:
+ case actionPlain:
+ return handshakePlainAsync (BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
+ break;
+
+ case actionSsl:
+ return handshakeSslAsync (BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
+ break;
+
+ case actionDetect:
+ return detectHandshakeAsync (BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
+ break;
+ }
+ }
+
+#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
+ boost::system::error_code handshake (handshake_type type,
+ ConstBuffers const& buffers, boost::system::error_code& ec)
+ {
+ Action action = calcAction (type);
+ ec = boost::system::error_code ();
+ switch (action)
+ {
+ default:
+ case actionPlain:
+ handshakePlain (buffers, ec);
+ break;
+ case actionSsl:
+ handshakeSsl (buffers, ec);
+ break;
+ case actionDetect:
+ detectHandshake (buffers, ec);
+ if (! ec)
+ {
+ action = calcDetectAction (ec);
+ switch (action)
+ {
+ default:
+ case actionPlain:
+ handshakePlain (buffers, ec);
+ break;
+ case actionSsl:
+ handshakeSsl (buffers, ec);
+ break;
+ };
+ }
+ break;
+ }
+ return ec;
+ }
+
+ BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (boost::system::error_code, std::size_t))
+ async_handshake (handshake_type type, ConstBuffers const& buffers,
+ BOOST_ASIO_MOVE_ARG(TransferCall) handler)
+ {
+ Action const action = calcAction (type);
+ switch (action)
+ {
+ default:
+ case actionPlain:
+ return handshakePlainAsync (buffers,
+ BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
+ break;
+
+ case actionSsl:
+ return handshakeSslAsync (buffers,
+ BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
+ break;
+
+ case actionDetect:
+ return detectHandshakeAsync (buffers,
+ BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
+ break;
+ }
+ }
+#endif
+
+ boost::system::error_code shutdown (boost::system::error_code& ec)
+ {
+ if (m_status == ssl)
+ {
+ return m_ssl_stream->shutdown (ec);
+ }
+ else
+ {
+ // we need to close the lwest layer
+ return m_next_layer.shutdown (next_layer_type::shutdown_both, ec);
+ }
+ }
+
+ BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (boost::system::error_code))
+ async_shutdown (BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
+ {
+ if (m_status == ssl)
+ {
+ m_ssl_stream->async_shutdown (m_strand.wrap (boost::bind (
+ BOOST_ASIO_MOVE_CAST(ErrorCall)(handler),
+ boost::asio::placeholders::error)));
+ }
+ else
+ {
+ boost::system::error_code ec;
+ m_next_layer.shutdown (next_layer_type::shutdown_both, ec);
+ m_io_service.post (m_strand.wrap (boost::bind (
+ BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec)));
+ }
+ }
+
+ //--------------------------------------------------------------------------
+
+ enum Action
+ {
+ actionDetect,
+ actionPlain,
+ actionSsl,
+ actionFail
+ };
+
+ // Determines what action to take based on
+ // the stream options and the desired role.
+ //
+ Action calcAction (Socket::handshake_type role)
+ {
+ m_role = role;
+
+ if (role == Socket::server)
+ {
+ if (! m_options.enableServerSsl &&
+ ! m_options.requireServerSsl &&
+ ! m_options.requireServerProxy)
+ {
+ return actionPlain;
+ }
+ else if (m_options.requireServerSsl && ! m_options.requireServerProxy)
+ {
+ return actionSsl;
+ }
+ else
+ {
+ return actionDetect;
+ }
+ }
+ else if (m_role == Socket::client)
+ {
+ if (m_options.useClientSsl)
+ {
+ return actionSsl;
+ }
+ else
+ {
+ return actionPlain;
+ }
+ }
+
+ return actionPlain;
+ }
+
+ // Determines what action to take based on the auto-detected
+ // handshake, the stream options, and desired role.
+ //
+ Action calcDetectAction (boost::system::error_code& ec)
+ {
+ ec = boost::system::error_code ();
+
+ if (m_status == plain)
+ {
+ if (! m_options.requireServerProxy && ! m_options.requireServerSsl)
+ {
+ return actionPlain;
+ }
+ else
+ {
+ failedHandshake (ec);
+ return actionFail;
+ }
+ }
+ else if (m_status == ssl)
+ {
+ if (! m_options.requireServerProxy)
+ {
+ if (m_options.enableServerSsl || m_options.requireServerSsl)
+ {
+ return actionSsl;
+ }
+ else
+ {
+ failedHandshake (ec);
+ return actionFail;
+ }
+ }
+ else
+ {
+ failedHandshake (ec);
+ return actionFail;
+ }
+ }
+ else if (m_status == proxy)
+ {
+ if (m_options.requireServerProxy)
+ {
+ // read the rest of the proxy string
+ // then transition to SSL handshake mode
+ failedHandshake (ec);
+ return actionFail;
+ }
+ else
+ {
+ // Can we make PROXY optional?
+ failedHandshake (ec);
+ return actionFail;
+ }
+ }
+
+ failedHandshake (ec);
+ return actionFail;
+ }
+
+ //--------------------------------------------------------------------------
+
+ // called when options disallow handshake
+ void failedHandshake (boost::system::error_code& ec)
+ {
+ // VFALCO TODO maybe use a ripple error category?
+ // set this to something custom that we can recognize later?
+ ec = boost::asio::error::invalid_argument;
+ }
+
+ void createPlainStreamSocket ()
+ {
+ m_status = plain;
+ m_stream = new SocketWrapper (m_next_layer);
+ }
+
+ void handshakePlain (boost::system::error_code& ec)
+ {
+ ec = boost::system::error_code ();
+ createPlainStreamSocket ();
+ }
+
+ void handshakePlain (ConstBuffers const& buffers, boost::system::error_code& ec)
+ {
+ fatal_assert (boost::asio::buffer_size (buffers) == 0 );
+ ec = boost::system::error_code ();
+ createPlainStreamSocket ();
+ }
+
+ BOOST_ASIO_INITFN_RESULT_TYPE(ErrorCall, void (boost::system::error_code))
+ handshakePlainAsync (BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
+ {
+ createPlainStreamSocket ();
+ return m_io_service.post (m_strand.wrap (boost::bind (
+ BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), boost::system::error_code())));
+ }
+
+ void createSslStreamSocket ()
+ {
+ m_status = ssl;
+ m_ssl_stream = new ssl_stream_type (m_next_layer, m_context->getBoostContext ());
+ m_stream = new SocketWrapper (*m_ssl_stream);
+ }
+
+ void handshakeSsl (boost::system::error_code& ec)
+ {
+ createSslStreamSocket ();
+ m_ssl_stream->handshake (m_role, ec);
+ }
+
+ BOOST_ASIO_INITFN_RESULT_TYPE(ErrorCall, void (boost::system::error_code))
+ handshakeSslAsync (BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
+ {
+ createSslStreamSocket ();
+ return m_ssl_stream->async_handshake (m_role,
+ BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
+ }
+
+#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
+ BOOST_ASIO_INITFN_RESULT_TYPE(TransferCall, void (boost::system::error_code, std::size_t))
+ handshakePlainAsync (ConstBuffers const& buffers,
+ BOOST_ASIO_MOVE_ARG (TransferCall) handler)
+ {
+ fatal_assert (boost::asio::buffer_size (buffers) == 0);
+ createPlainStreamSocket ();
+ return m_io_service.post (m_strand.wrap (boost::bind (
+ BOOST_ASIO_MOVE_CAST(TransferCall)(handler),
+ boost::system::error_code(), 0)));
+ }
+
+ void handshakeSsl (ConstBuffers const& buffers, boost::system::error_code& ec)
+ {
+ createSslStreamSocket ();
+ m_ssl_stream->handshake (m_role, buffers, ec);
+ }
+
+ BOOST_ASIO_INITFN_RESULT_TYPE (TransferCall, void (boost::system::error_code, std::size_t))
+ handshakeSslAsync (ConstBuffers const& buffers, BOOST_ASIO_MOVE_ARG(TransferCall) handler)
+ {
+ createSslStreamSocket ();
+ return m_ssl_stream->async_handshake (m_role, buffers,
+ BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
+ }
+#endif
+
+ //--------------------------------------------------------------------------
+
+ enum
+ {
+ autoDetectBytes = 5
+ };
+
+ void detectHandshake (boost::system::error_code& ec)
+ {
+ // Top up our buffer
+ bassert (m_buffer.size () == 0);
+ std::size_t const needed = autoDetectBytes;
+ std::size_t const amount = m_next_layer.receive (
+ m_buffer.prepare (needed), boost::asio::socket_base::message_peek, ec);
+ m_buffer.commit (amount);
+ if (! ec)
+ {
+ analyzeHandshake (m_buffer.data ());
+ m_buffer.consume (amount);
+ if (m_status == needMore)
+ ec = boost::asio::error::invalid_argument; // should never happen
+ }
+ }
+
+#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
+ void detectHandshake (ConstBuffers const& buffers, boost::system::error_code& ec)
+ {
+ m_buffer.commit (boost::asio::buffer_copy (
+ m_buffer.prepare (boost::asio::buffer_size (buffers)), buffers));
+ detectHandshake (ec);
+ }
+#endif
+
+ //--------------------------------------------------------------------------
+
+ void onDetectRead (BOOST_ASIO_MOVE_ARG(ErrorCall) handler,
+ boost::system::error_code const& ec, std::size_t bytes_transferred)
+ {
+ m_buffer.commit (bytes_transferred);
+
+ if (! ec)
+ {
+ analyzeHandshake (m_buffer.data ());
+
+ boost::system::error_code ec;
+
+ if (m_status != needMore)
+ {
+ m_buffer.consume (bytes_transferred);
+
+ Action action = calcDetectAction (ec);
+ if (! ec)
+ {
+ switch (action)
+ {
+ default:
+ case actionPlain:
+ handshakePlainAsync (
+ BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
+ break;
+ case actionSsl:
+ handshakeSslAsync (
+ BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
+ break;
+ };
+ }
+ }
+ else
+ {
+ ec = boost::asio::error::invalid_argument;
+ }
+
+ if (ec)
+ {
+ m_io_service.post (m_strand.wrap (boost::bind (
+ BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec)));
+ }
+ }
+ }
+
+ BOOST_ASIO_INITFN_RESULT_TYPE(ErrorCall, void (boost::system::error_code))
+ detectHandshakeAsync (BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
+ {
+ bassert (m_buffer.size () == 0);
+ return m_next_layer.async_receive (
+ m_buffer.prepare (autoDetectBytes), boost::asio::socket_base::message_peek,
+ m_strand.wrap (boost::bind (&ThisType::onDetectRead, this,
+ BOOST_ASIO_MOVE_CAST(ErrorCall)(handler),
+ boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)));
+ }
+
+#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
+ BOOST_ASIO_INITFN_RESULT_TYPE(TransferCall, void (boost::system::error_code, std::size_t))
+ detectHandshakeAsync (ConstBuffers const& buffers, BOOST_ASIO_MOVE_ARG(TransferCall) handler)
+ {
+ fatal_error ("unimplemented");
+ }
+#endif
+
+ //--------------------------------------------------------------------------
+
+ static inline bool isPrintable (unsigned char c)
+ {
+ return (c < 127) && (c > 31);
+ }
+
+ template
+ void analyzeHandshake (ConstBufferSequence const& buffers)
+ {
+ m_status = needMore;
+
+ unsigned char data [5];
+
+ std::size_t const bytes = boost::asio::buffer_copy (boost::asio::buffer (data), buffers);
+
+ if (bytes > 0)
+ {
+ if ( isPrintable (data [0]) &&
+ ((bytes < 2) || isPrintable (data [1])) &&
+ ((bytes < 3) || isPrintable (data [2])) &&
+ ((bytes < 4) || isPrintable (data [3])) &&
+ ((bytes < 5) || isPrintable (data [4])))
+ {
+ if (bytes < 5 || memcmp (data, "PROXY", 5) != 0)
+ {
+ m_status = plain;
+ }
+ else
+ {
+ m_status = proxy;
+ }
+ }
+ else
+ {
+ m_status = ssl;
+ }
+ }
+ }
+
+private:
+ Options m_options;
+ ScopedPointer m_context;
+ StreamSocket m_next_layer;
+ boost::asio::io_service& m_io_service;
+ boost::asio::io_service::strand m_strand;
+ Status m_status;
+ Socket::handshake_type m_role;
+ ScopedPointer m_stream;
+ ScopedPointer m_ssl_stream;
+ boost::asio::streambuf m_buffer;
+};
+
+#endif
diff --git a/modules/ripple_asio/tests/ripple_AsioTests.cpp b/modules/ripple_asio/tests/ripple_AsioTests.cpp
index 81347d2012..521009e988 100644
--- a/modules/ripple_asio/tests/ripple_AsioTests.cpp
+++ b/modules/ripple_asio/tests/ripple_AsioTests.cpp
@@ -235,7 +235,7 @@ public:
return ec;
}
-#if BOOST_ASIO_HAS_BUFFEREDHANDSHAKE
+#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
template
boost::system::error_code handshake (handshake_type type,
ConstBufferSequence const& buffers, boost::system::error_code& ec)
@@ -295,7 +295,7 @@ public:
}
}
-#if BOOST_ASIO_HAS_BUFFEREDHANDSHAKE
+#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
template
BOOST_ASIO_INITFN_RESULT_TYPE(BufferedHandshakeHandler, void (boost::system::error_code, std::size_t))
async_handshake (handshake_type type, const ConstBufferSequence& buffers,
@@ -503,7 +503,7 @@ public:
BOOST_ASIO_MOVE_CAST(HandshakeHandler)(handler), system::error_code())));
}
-#if BOOST_ASIO_HAS_BUFFEREDHANDSHAKE
+#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
template
BOOST_ASIO_INITFN_RESULT_TYPE(BufferedHandshakeHandler, void (boost::system::error_code, std::size_t))
handshakePlainAsync (ConstBufferSequence const& buffers,
@@ -530,7 +530,7 @@ public:
m_ssl_stream->handshake (m_role, ec);
}
-#if BOOST_ASIO_HAS_BUFFEREDHANDSHAKE
+#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
template
void handshakeSsl (ConstBufferSequence const& buffers, system::error_code& ec)
{
@@ -548,7 +548,7 @@ public:
BOOST_ASIO_MOVE_CAST(HandshakeHandler)(handler));
}
-#if BOOST_ASIO_HAS_BUFFEREDHANDSHAKE
+#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
template
BOOST_ASIO_INITFN_RESULT_TYPE (BufferedHandshakeHandler, void (boost::system::error_code, std::size_t))
handshakeSslAsync (ConstBufferSequence const& buffers,
@@ -584,7 +584,7 @@ public:
}
}
-#if BOOST_ASIO_HAS_BUFFEREDHANDSHAKE
+#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
template
void detectHandshake (ConstBufferSequence const& buffers, system::error_code& ec)
{
@@ -654,7 +654,7 @@ public:
asio::placeholders::error, asio::placeholders::bytes_transferred)));
}
-#if BOOST_ASIO_HAS_BUFFEREDHANDSHAKE
+#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
template
BOOST_ASIO_INITFN_RESULT_TYPE(BufferedHandshakeHandler, void (boost::system::error_code, std::size_t))
detectHandshakeAsync (ConstBufferSequence const& buffers,
diff --git a/modules/ripple_websocket/autosocket/ripple_AutoSocket.h b/modules/ripple_websocket/autosocket/ripple_AutoSocket.h
index 613d27e8ce..ada35731aa 100644
--- a/modules/ripple_websocket/autosocket/ripple_AutoSocket.h
+++ b/modules/ripple_websocket/autosocket/ripple_AutoSocket.h
@@ -26,7 +26,8 @@ public:
public:
struct SocketInterfaces
: beast::SocketInterface::AsyncStream
- , beast::SocketInterface::AsyncHandshake { };
+ , beast::SocketInterface::AsyncHandshake
+ , beast::SocketInterface::LowestLayer { };
AutoSocket (boost::asio::io_service& s, boost::asio::ssl::context& c)
: mSecure (false)