mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-21 03:26:01 +00:00
Update MultiSocket for handshake detect and refactored SocketWrapper
This commit is contained in:
@@ -26,6 +26,10 @@ namespace ripple
|
|||||||
#include "boost/ripple_IoService.cpp"
|
#include "boost/ripple_IoService.cpp"
|
||||||
#include "boost/ripple_SslContext.cpp"
|
#include "boost/ripple_SslContext.cpp"
|
||||||
|
|
||||||
|
# include "sockets/ripple_RippleTlsContext.h"
|
||||||
|
# include "sockets/ripple_MultiSocket.h"
|
||||||
|
#include "sockets/ripple_MultiSocketType.h"
|
||||||
|
|
||||||
#include "sockets/ripple_RippleTlsContext.cpp"
|
#include "sockets/ripple_RippleTlsContext.cpp"
|
||||||
#include "sockets/ripple_MultiSocket.cpp"
|
#include "sockets/ripple_MultiSocket.cpp"
|
||||||
|
|
||||||
|
|||||||
@@ -31,10 +31,6 @@ using namespace beast;
|
|||||||
#include "boost/ripple_IoService.h"
|
#include "boost/ripple_IoService.h"
|
||||||
#include "boost/ripple_SslContext.h"
|
#include "boost/ripple_SslContext.h"
|
||||||
|
|
||||||
#include "sockets/ripple_MultiSocket.h"
|
|
||||||
# include "sockets/ripple_RippleTlsContext.h"
|
|
||||||
#include "sockets/ripple_MultiSocketType.h"
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -23,10 +23,16 @@ void MultiSocket::Options::setFromFlags (Flags flags)
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
MultiSocket* MultiSocket::New (boost::asio::io_service& io_service,
|
MultiSocket* MultiSocket::New (boost::asio::io_service& io_service, int flags)
|
||||||
Options const& options)
|
|
||||||
{
|
{
|
||||||
return new MultiSocketType <boost::asio::ip::tcp::socket> (io_service, options);
|
return new MultiSocketType <boost::asio::ip::tcp::socket> (io_service, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
SslContextBase::BoostContextType &MultiSocket::getRippleTlsBoostContext ()
|
||||||
|
{
|
||||||
|
static ScopedPointer <RippleTlsContext> context (RippleTlsContext::New ());
|
||||||
|
|
||||||
|
return context->getBoostContext ();
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -39,48 +45,35 @@ public:
|
|||||||
public:
|
public:
|
||||||
typedef int arg_type;
|
typedef int arg_type;
|
||||||
|
|
||||||
// These flags get combined to determine the multisocket attributes
|
MultiSocketDetails (int flags)
|
||||||
//
|
|
||||||
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
|
|
||||||
};
|
|
||||||
|
|
||||||
MultiSocketDetails (arg_type flags)
|
|
||||||
: m_flags (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)
|
static String getArgName (arg_type arg)
|
||||||
{
|
{
|
||||||
String s;
|
String s;
|
||||||
if (arg & tcpv4) s << "tcpv4:";
|
|
||||||
if (arg & tcpv6) s << "tcpv6:";
|
if (arg & MultiSocket::Flag::client_role)
|
||||||
if (arg != 0)
|
s << "client,";
|
||||||
|
|
||||||
|
if (arg & MultiSocket::Flag::server_role)
|
||||||
|
s << "server,";
|
||||||
|
|
||||||
|
if (arg & MultiSocket::Flag::ssl)
|
||||||
|
s << "ssl,";
|
||||||
|
|
||||||
|
if (arg & MultiSocket::Flag::ssl_required)
|
||||||
|
s << "ssl_required,";
|
||||||
|
|
||||||
|
if (arg & MultiSocket::Flag::proxy)
|
||||||
|
s << "proxy,";
|
||||||
|
|
||||||
|
if (s != String::empty)
|
||||||
{
|
{
|
||||||
s << "[";
|
s = "(" + s.substring (0, s.length () - 1) + ")";
|
||||||
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,";
|
|
||||||
s = s.substring (0, s.length () - 1) + "]";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s = "[plain]";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,23 +87,17 @@ public:
|
|||||||
return m_flags;
|
return m_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
MultiSocket::Options const& getSocketOptions () const noexcept
|
|
||||||
{
|
|
||||||
return m_socketOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
arg_type m_flags;
|
arg_type m_flags;
|
||||||
MultiSocket::Options m_socketOptions;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
template <class InternetProtocol>
|
template <class Protocol>
|
||||||
class MultiSocketDetailsType : public MultiSocketDetails
|
class MultiSocketDetailsType : public MultiSocketDetails
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
typedef InternetProtocol protocol_type;
|
typedef Protocol protocol_type;
|
||||||
typedef typename protocol_type::socket socket_type;
|
typedef typename protocol_type::socket socket_type;
|
||||||
typedef typename protocol_type::acceptor acceptor_type;
|
typedef typename protocol_type::acceptor acceptor_type;
|
||||||
typedef typename protocol_type::endpoint endpoint_type;
|
typedef typename protocol_type::endpoint endpoint_type;
|
||||||
@@ -120,11 +107,11 @@ public:
|
|||||||
typedef socket_type native_socket_type;
|
typedef socket_type native_socket_type;
|
||||||
typedef acceptor_type native_acceptor_type;
|
typedef acceptor_type native_acceptor_type;
|
||||||
|
|
||||||
explicit MultiSocketDetailsType (arg_type flags = none)
|
explicit MultiSocketDetailsType (arg_type flags)
|
||||||
: MultiSocketDetails (flags)
|
: MultiSocketDetails (flags)
|
||||||
, m_socket (get_io_service ())
|
, m_socket (get_io_service ())
|
||||||
, m_acceptor (get_io_service ())
|
, m_acceptor (get_io_service ())
|
||||||
, m_multiSocket (m_socket, getSocketOptions ())
|
, m_multiSocket (m_socket, flags)
|
||||||
, m_acceptor_wrapper (m_acceptor)
|
, m_acceptor_wrapper (m_acceptor)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -151,85 +138,90 @@ public:
|
|||||||
|
|
||||||
endpoint_type get_endpoint (PeerRole role)
|
endpoint_type get_endpoint (PeerRole role)
|
||||||
{
|
{
|
||||||
if (getFlags () & MultiSocketDetails::tcpv6)
|
if (role == PeerRole::server)
|
||||||
{
|
return endpoint_type (boost::asio::ip::tcp::v6 (), 1052);
|
||||||
if (role == PeerRole::server)
|
|
||||||
return endpoint_type (boost::asio::ip::tcp::v6 (), 1052);
|
|
||||||
else
|
|
||||||
return endpoint_type (boost::asio::ip::address_v6 ().from_string ("::1"), 1052);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
return endpoint_type (boost::asio::ip::address_v6 ().from_string ("::1"), 1052);
|
||||||
if (role == PeerRole::server)
|
|
||||||
return endpoint_type (boost::asio::ip::address_v4::any (), 1053);
|
|
||||||
else
|
|
||||||
return endpoint_type (boost::asio::ip::address_v4::loopback (), 1053);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
socket_type m_socket;
|
socket_type m_socket;
|
||||||
acceptor_type m_acceptor;
|
acceptor_type m_acceptor;
|
||||||
MultiSocketType <socket_type&> m_multiSocket;
|
MultiSocketType <socket_type&> m_multiSocket;
|
||||||
SocketWrapper <acceptor_type> m_acceptor_wrapper;
|
SocketWrapper <acceptor_type&> m_acceptor_wrapper;
|
||||||
};
|
};
|
||||||
|
|
||||||
MultiSocketTests () : UnitTest ("MultiSocket", "ripple", runManual)
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <typename Protocol, typename ClientArg, typename ServerArg>
|
||||||
|
void run_async (ClientArg const& clientArg, ServerArg const& serverArg)
|
||||||
{
|
{
|
||||||
|
PeerTest::run <MultiSocketDetailsType <Protocol>,
|
||||||
|
TestPeerLogicAsyncClient, TestPeerLogicAsyncServer> (clientArg, serverArg, timeoutSeconds).report (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Protocol, typename ClientArg, typename ServerArg>
|
||||||
|
void run (ClientArg const& clientArg, ServerArg const& serverArg)
|
||||||
|
{
|
||||||
|
PeerTest::run <MultiSocketDetailsType <Protocol>,
|
||||||
|
TestPeerLogicSyncClient, TestPeerLogicSyncServer> (clientArg, serverArg, timeoutSeconds).report (*this);
|
||||||
|
|
||||||
|
PeerTest::run <MultiSocketDetailsType <Protocol>,
|
||||||
|
TestPeerLogicAsyncClient, TestPeerLogicSyncServer> (clientArg, serverArg, timeoutSeconds).report (*this);
|
||||||
|
|
||||||
|
PeerTest::run <MultiSocketDetailsType <Protocol>,
|
||||||
|
TestPeerLogicSyncClient, TestPeerLogicAsyncServer> (clientArg, serverArg, timeoutSeconds).report (*this);
|
||||||
|
|
||||||
|
run_async <Protocol> (clientArg, serverArg);
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template <typename Protocol>
|
||||||
|
void testFlags (int extraClientFlags, int extraServerFlags)
|
||||||
|
{
|
||||||
|
check_precondition (! MultiSocket::Flag (extraClientFlags).any_set (MultiSocket::Flag::client_role | MultiSocket::Flag::server_role));
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
run <Protocol> (MultiSocket::Flag::client_role | extraClientFlags, MultiSocket::Flag::server_role | extraServerFlags);
|
||||||
|
#else
|
||||||
|
run_async <Protocol> (MultiSocket::Flag::client_role | extraClientFlags, MultiSocket::Flag::server_role | extraServerFlags);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Protocol>
|
||||||
|
void testProtocol ()
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
// These should pass.
|
||||||
|
run <Protocol> (0, 0);
|
||||||
|
run <Protocol> (MultiSocket::Flag::client_role, 0);
|
||||||
|
run <Protocol> (0, MultiSocket::Flag::server_role);
|
||||||
|
run <Protocol> (MultiSocket::Flag::client_role, MultiSocket::Flag::server_role);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// These should pass
|
||||||
|
testFlags <Protocol> (MultiSocket::Flag::ssl, MultiSocket::Flag::ssl_required);
|
||||||
|
testFlags <Protocol> (0, MultiSocket::Flag::ssl);
|
||||||
|
testFlags <Protocol> (MultiSocket::Flag::ssl, MultiSocket::Flag::ssl);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void runTest ()
|
||||||
|
{
|
||||||
|
testProtocol <boost::asio::ip::tcp> ();
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
timeoutSeconds = 1
|
timeoutSeconds = 10
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename InternetProtocol, class Arg>
|
MultiSocketTests () : UnitTest ("MultiSocket", "ripple", runManual)
|
||||||
PeerTest::Results runProtocol (Arg const& arg)
|
|
||||||
{
|
{
|
||||||
return PeerTest::run <MultiSocketDetailsType <InternetProtocol>,
|
|
||||||
TestPeerLogicAsyncServer, TestPeerLogicAsyncClient> (arg, timeoutSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Analyzes the results of the test based on the flags
|
|
||||||
//
|
|
||||||
void reportResults (int flags, PeerTest::Results const& results)
|
|
||||||
{
|
|
||||||
if ( (flags & MultiSocketDetails::client_ssl) != 0)
|
|
||||||
{
|
|
||||||
if ( ((flags & MultiSocketDetails::server_ssl) == 0) &&
|
|
||||||
((flags & MultiSocketDetails::server_ssl_required) == 0))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
results.report (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testOptions (int flags)
|
|
||||||
{
|
|
||||||
PeerTest::Results const results = runProtocol <boost::asio::ip::tcp> (flags);
|
|
||||||
|
|
||||||
results.report (*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void runTest ()
|
|
||||||
{
|
|
||||||
// These should pass
|
|
||||||
testOptions (MultiSocketDetails::none);
|
|
||||||
testOptions (MultiSocketDetails::server_ssl);
|
|
||||||
testOptions (MultiSocketDetails::client_ssl | MultiSocketDetails::server_ssl);
|
|
||||||
testOptions (MultiSocketDetails::client_ssl | MultiSocketDetails::server_ssl_required);
|
|
||||||
|
|
||||||
// These should fail
|
|
||||||
testOptions (MultiSocketDetails::client_ssl);
|
|
||||||
testOptions (MultiSocketDetails::server_ssl_required);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,59 @@
|
|||||||
class MultiSocket : public Socket
|
class MultiSocket : public Socket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
// immutable flags
|
||||||
|
struct Flag
|
||||||
|
{
|
||||||
|
enum Bit
|
||||||
|
{
|
||||||
|
peer = 0, // no handshaking. remaining flags ignored.
|
||||||
|
client_role = 1, // operate in client role
|
||||||
|
server_role = 2, // operate in server role
|
||||||
|
|
||||||
|
proxy = 4, // client: will send PROXY handshake
|
||||||
|
// server: PROXY handshake required
|
||||||
|
|
||||||
|
ssl = 8, // client: will use ssl
|
||||||
|
// server: will allow, but not require ssl
|
||||||
|
|
||||||
|
ssl_required = 16 // client: ignored
|
||||||
|
// server: will require ssl (ignores ssl flag)
|
||||||
|
};
|
||||||
|
|
||||||
|
Flag (int flags) noexcept
|
||||||
|
: m_flags (flags)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator== (Flag const& other) const noexcept
|
||||||
|
{
|
||||||
|
return m_flags == other.m_flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool set (int mask) const noexcept
|
||||||
|
{
|
||||||
|
return (m_flags & mask) == mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool any_set (int mask) const noexcept
|
||||||
|
{
|
||||||
|
return (m_flags & mask) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Flag with (int mask) const noexcept
|
||||||
|
{
|
||||||
|
return Flag (m_flags | mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
Flag without (int mask) const noexcept
|
||||||
|
{
|
||||||
|
return Flag (m_flags & ~mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_flags;
|
||||||
|
};
|
||||||
|
|
||||||
enum Flags
|
enum Flags
|
||||||
{
|
{
|
||||||
none = 0,
|
none = 0,
|
||||||
@@ -42,8 +95,12 @@ public:
|
|||||||
void setFromFlags (Flags flags);
|
void setFromFlags (Flags flags);
|
||||||
};
|
};
|
||||||
|
|
||||||
static MultiSocket* New (boost::asio::io_service& io_service,
|
static MultiSocket* New (boost::asio::io_service& io_service, int flags = 0);
|
||||||
Options const& options = none);
|
|
||||||
|
// Ripple uses a SSL/TLS context with specific parameters and this returns
|
||||||
|
// a reference to the corresponding boost::asio::ssl::context object.
|
||||||
|
//
|
||||||
|
static SslContextBase::BoostContextType &getRippleTlsBoostContext ();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -7,11 +7,103 @@
|
|||||||
#ifndef RIPPLE_MULTISOCKETTYPE_H_INCLUDED
|
#ifndef RIPPLE_MULTISOCKETTYPE_H_INCLUDED
|
||||||
#define RIPPLE_MULTISOCKETTYPE_H_INCLUDED
|
#define RIPPLE_MULTISOCKETTYPE_H_INCLUDED
|
||||||
|
|
||||||
/** Template for producing instances of MultiSocket
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
StreamSocket must meet these requirements:
|
template <typename Stream>
|
||||||
|
class ssl_detector
|
||||||
|
: public boost::asio::ssl::stream_base
|
||||||
|
, public boost::asio::socket_base
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef typename boost::remove_reference <Stream>::type stream_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
#if 0
|
||||||
|
struct SocketInterfaces
|
||||||
|
: SocketInterface::Handshake
|
||||||
|
{ };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename Arg>
|
||||||
|
ssl_detector (Arg& arg)
|
||||||
|
: m_next_layer (arg)
|
||||||
|
, m_stream (m_next_layer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// basic_io_object
|
||||||
|
|
||||||
|
boost::asio::io_service& get_io_service ()
|
||||||
|
{
|
||||||
|
return m_next_layer.get_io_service ();
|
||||||
|
}
|
||||||
|
|
||||||
SocketInterface::Socket, SocketInterface::Stream
|
// basic_socket
|
||||||
|
|
||||||
|
typedef typename stream_type::protocol_type protocol_type;
|
||||||
|
typedef typename stream_type::lowest_layer_type lowest_layer_type;
|
||||||
|
|
||||||
|
lowest_layer_type& lowest_layer ()
|
||||||
|
{
|
||||||
|
return m_next_layer.lowest_layer ();
|
||||||
|
}
|
||||||
|
|
||||||
|
lowest_layer_type const& lowest_layer () const
|
||||||
|
{
|
||||||
|
return m_next_layer.lowest_layer ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ssl::stream
|
||||||
|
|
||||||
|
boost::system::error_code handshake (handshake_type type, boost::system::error_code& ec)
|
||||||
|
{
|
||||||
|
ec = boost::system::error_code ();
|
||||||
|
|
||||||
|
m_buffer.commit (boost::asio::read (m_next_layer,
|
||||||
|
m_buffer.prepare (m_detector.needed ()), ec));
|
||||||
|
|
||||||
|
if (!ec)
|
||||||
|
{
|
||||||
|
bool const finished = m_detector.analyze (m_buffer.data ());
|
||||||
|
|
||||||
|
if (finished)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename HandshakeHandler>
|
||||||
|
BOOST_ASIO_INITFN_RESULT_TYPE(HandshakeHandler, void (boost::system::error_code))
|
||||||
|
async_handshake(handshake_type type, BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
|
||||||
|
template <typename ConstBufferSequence>
|
||||||
|
void handshake (handshake_type type, const ConstBufferSequence& buffers)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ConstBufferSequence, typename BufferedHandshakeHandler>
|
||||||
|
BOOST_ASIO_INITFN_RESULT_TYPE(BufferedHandshakeHandler, void (boost::system::error_code, std::size_t))
|
||||||
|
async_handshake(handshake_type type, const ConstBufferSequence& buffers,
|
||||||
|
BOOST_ASIO_MOVE_ARG(BufferedHandshakeHandler) handler)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
Stream m_next_layer;
|
||||||
|
boost::asio::streambuf m_buffer;
|
||||||
|
boost::asio::buffered_read_stream <stream_type&> m_stream;
|
||||||
|
HandshakeDetectorType <SSL3> m_detector;
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Template for producing instances of MultiSocket
|
||||||
*/
|
*/
|
||||||
template <class StreamSocket>
|
template <class StreamSocket>
|
||||||
class MultiSocketType
|
class MultiSocketType
|
||||||
@@ -24,32 +116,19 @@ public:
|
|||||||
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
|
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
|
||||||
typedef typename boost::asio::ssl::stream <next_layer_type_ref> ssl_stream_type;
|
typedef typename boost::asio::ssl::stream <next_layer_type_ref> ssl_stream_type;
|
||||||
|
|
||||||
typedef MultiSocketType <StreamSocket> ThisType;
|
|
||||||
|
|
||||||
enum Status
|
|
||||||
{
|
|
||||||
needMore,
|
|
||||||
proxy,
|
|
||||||
plain,
|
|
||||||
ssl
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class Arg>
|
template <class Arg>
|
||||||
explicit MultiSocketType (Arg& arg, Options options = Options())
|
explicit MultiSocketType (Arg& arg, int flags = 0, Options const& options = Options ())
|
||||||
: m_options (options)
|
: m_options (options)
|
||||||
, m_context (RippleTlsContext::New ())
|
, m_flags (cleaned_flags (flags))
|
||||||
, m_next_layer (arg)
|
, m_next_layer (arg)
|
||||||
, m_io_service (m_next_layer.get_io_service ())
|
, m_stream (new_current_stream (true))
|
||||||
, m_strand (m_io_service)
|
, m_strand (get_io_service ())
|
||||||
, m_status (needMore)
|
|
||||||
, m_role (Socket::client)
|
|
||||||
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Socket& stream () const noexcept
|
Socket& stream () const noexcept
|
||||||
{
|
{
|
||||||
fatal_assert (m_stream != nullptr);
|
bassert (m_stream != nullptr);
|
||||||
return *m_stream;
|
return *m_stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,77 +154,34 @@ public:
|
|||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// General
|
// basic_io_object
|
||||||
//
|
//
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
boost::asio::io_service& get_io_service ()
|
boost::asio::io_service& get_io_service ()
|
||||||
{
|
{
|
||||||
return lowest_layer ().get_io_service ();
|
return m_next_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 <void*> (static_cast <void const*>(&next_layer ()));
|
|
||||||
return nullptr;
|
|
||||||
#else
|
|
||||||
if (m_stream != nullptr)
|
|
||||||
{
|
|
||||||
if (strcmp (type_name, typeid (lowest_layer_type).name ()) == 0)
|
|
||||||
return const_cast <void*> (static_cast <void const*>(&lowest_layer ()));
|
|
||||||
}
|
|
||||||
pure_virtual ();
|
|
||||||
return nullptr;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// SocketInterface::Close
|
// basic_socket
|
||||||
//
|
//
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
boost::system::error_code close (boost::system::error_code& ec)
|
void* lowest_layer (char const* type_name) const
|
||||||
{
|
{
|
||||||
return lowest_layer ().close (ec);
|
char const* const name (typeid (lowest_layer_type).name ());
|
||||||
}
|
if (strcmp (name, type_name) == 0)
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
//
|
|
||||||
// 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 <void*> (static_cast <void const*>(&lowest_layer ()));
|
return const_cast <void*> (static_cast <void const*>(&lowest_layer ()));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
void* native_handle (char const* type_name) const
|
||||||
//
|
{
|
||||||
// SocketInterface::Socket
|
char const* const name (typeid (next_layer_type).name ());
|
||||||
//
|
if (strcmp (name, type_name) == 0)
|
||||||
//--------------------------------------------------------------------------
|
return const_cast <void*> (static_cast <void const*>(&next_layer ()));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
boost::system::error_code cancel (boost::system::error_code& ec)
|
boost::system::error_code cancel (boost::system::error_code& ec)
|
||||||
{
|
{
|
||||||
@@ -157,21 +193,18 @@ public:
|
|||||||
return lowest_layer ().shutdown (what, ec);
|
return lowest_layer ().shutdown (what, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::system::error_code close (boost::system::error_code& ec)
|
||||||
|
{
|
||||||
|
return lowest_layer ().close (ec);
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// SocketInterface::Stream
|
// basic_stream_socket
|
||||||
//
|
//
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
std::size_t read_some (MutableBuffers const& buffers, boost::system::error_code& ec)
|
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);
|
return stream ().read_some (buffers, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,65 +216,33 @@ public:
|
|||||||
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (boost::system::error_code, std::size_t))
|
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)
|
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 (
|
return stream ().async_read_some (buffers, m_strand.wrap (boost::bind (
|
||||||
BOOST_ASIO_MOVE_CAST(TransferCall)(handler), boost::asio::placeholders::error,
|
BOOST_ASIO_MOVE_CAST(TransferCall)(handler), boost::asio::placeholders::error,
|
||||||
boost::asio::placeholders::bytes_transferred)));
|
boost::asio::placeholders::bytes_transferred)));
|
||||||
}
|
}
|
||||||
|
|
||||||
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(TransferCall, void (boost::system::error_code, std::size_t))
|
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)
|
async_write_some (ConstBuffers const& buffers, BOOST_ASIO_MOVE_ARG(TransferCall) handler)
|
||||||
{
|
{
|
||||||
return stream ().async_write_some (buffers,
|
return stream ().async_write_some (buffers, m_strand.wrap (boost::bind (
|
||||||
BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
|
BOOST_ASIO_MOVE_CAST(TransferCall)(handler), boost::asio::placeholders::error,
|
||||||
|
boost::asio::placeholders::bytes_transferred)));
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// SocketInterface::Handshake
|
// ssl::stream
|
||||||
//
|
//
|
||||||
//--------------------------------------------------------------------------
|
|
||||||
|
|
||||||
boost::system::error_code handshake (Socket::handshake_type role, boost::system::error_code& ec)
|
bool requires_handshake ()
|
||||||
{
|
{
|
||||||
Action action = calcAction (role);
|
return stream ().requires_handshake ();
|
||||||
|
}
|
||||||
|
|
||||||
switch (action)
|
boost::system::error_code handshake (Socket::handshake_type type, boost::system::error_code& ec)
|
||||||
{
|
{
|
||||||
default:
|
if (! prepare_handshake (type, ec))
|
||||||
case actionPlain:
|
return stream ().handshake (type, ec);
|
||||||
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;
|
return ec;
|
||||||
}
|
}
|
||||||
@@ -249,57 +250,22 @@ public:
|
|||||||
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (boost::system::error_code))
|
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (boost::system::error_code))
|
||||||
async_handshake (handshake_type type, BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
|
async_handshake (handshake_type type, BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
|
||||||
{
|
{
|
||||||
Action const action = calcAction (type);
|
boost::system::error_code ec;
|
||||||
switch (action)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
case actionPlain:
|
|
||||||
return handshakePlainAsync (BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case actionSsl:
|
if (! prepare_handshake (type, ec))
|
||||||
return handshakeSslAsync (BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
|
return stream ().async_handshake (type, BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
|
||||||
break;
|
|
||||||
|
|
||||||
case actionDetect:
|
return get_io_service ().post (boost::bind (
|
||||||
return detectHandshakeAsync (BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
|
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec));
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
|
#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
|
||||||
boost::system::error_code handshake (handshake_type type,
|
boost::system::error_code handshake (handshake_type type,
|
||||||
ConstBuffers const& buffers, boost::system::error_code& ec)
|
ConstBuffers const& buffers, boost::system::error_code& ec)
|
||||||
{
|
{
|
||||||
Action action = calcAction (type);
|
if (! prepare_handshake (type, ec))
|
||||||
ec = boost::system::error_code ();
|
return stream ().handshake (type, buffers, ec);
|
||||||
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;
|
return ec;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,402 +273,202 @@ public:
|
|||||||
async_handshake (handshake_type type, ConstBuffers const& buffers,
|
async_handshake (handshake_type type, ConstBuffers const& buffers,
|
||||||
BOOST_ASIO_MOVE_ARG(TransferCall) handler)
|
BOOST_ASIO_MOVE_ARG(TransferCall) handler)
|
||||||
{
|
{
|
||||||
Action const action = calcAction (type);
|
boost::system::error_code ec;
|
||||||
switch (action)
|
|
||||||
{
|
|
||||||
default:
|
|
||||||
case actionPlain:
|
|
||||||
return handshakePlainAsync (buffers,
|
|
||||||
BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case actionSsl:
|
if (! prepare_handshake (type, ec))
|
||||||
return handshakeSslAsync (buffers,
|
return stream ().async_handshake (type, buffers,
|
||||||
BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
|
BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
|
||||||
break;
|
|
||||||
|
|
||||||
case actionDetect:
|
return get_io_service ().post (boost::bind (
|
||||||
return detectHandshakeAsync (buffers,
|
BOOST_ASIO_MOVE_CAST(TransferCall)(handler), ec, 0));
|
||||||
BOOST_ASIO_MOVE_CAST(TransferCall)(handler));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
boost::system::error_code shutdown (boost::system::error_code& ec)
|
boost::system::error_code shutdown (boost::system::error_code& ec)
|
||||||
{
|
{
|
||||||
if (m_status == ssl)
|
if (stream ().requires_handshake ())
|
||||||
{
|
return stream ().shutdown (ec);
|
||||||
return m_ssl_stream->shutdown (ec);
|
|
||||||
}
|
return handshake_error (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))
|
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (boost::system::error_code))
|
||||||
async_shutdown (BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
|
async_shutdown (BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
|
||||||
{
|
{
|
||||||
if (m_status == ssl)
|
if (stream ().requires_handshake ())
|
||||||
|
return stream ().async_shutdown (BOOST_ASIO_MOVE_CAST(ErrorCall)(handler));
|
||||||
|
|
||||||
|
boost::system::error_code ec;
|
||||||
|
handshake_error (ec);
|
||||||
|
return get_io_service ().post (boost::bind (
|
||||||
|
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec));
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Handshake implementation details
|
||||||
|
//
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Checks flags for preconditions and returns a cleaned-up version
|
||||||
|
//
|
||||||
|
static Flag cleaned_flags (Flag flags)
|
||||||
|
{
|
||||||
|
// Can't set both client and server
|
||||||
|
check_precondition (! flags.set (Flag::client_role | Flag::server_role));
|
||||||
|
|
||||||
|
if (flags.set (Flag::client_role))
|
||||||
{
|
{
|
||||||
m_ssl_stream->async_shutdown (m_strand.wrap (boost::bind (
|
// clients ignore ssl_required
|
||||||
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler),
|
flags = flags.without (Flag::ssl_required);
|
||||||
boost::asio::placeholders::error)));
|
}
|
||||||
|
else if (flags.set (Flag::server_role))
|
||||||
|
{
|
||||||
|
// servers ignore ssl when ssl_required is set
|
||||||
|
if (flags.set (Flag::ssl_required))
|
||||||
|
flags = flags.without (Flag::ssl);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
boost::system::error_code ec;
|
// if not client or server, clear out all the flags
|
||||||
m_next_layer.shutdown (next_layer_type::shutdown_both, ec);
|
flags = Flag::peer;
|
||||||
m_io_service.post (m_strand.wrap (boost::bind (
|
|
||||||
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
enum Action
|
Socket* new_plain_stream ()
|
||||||
{
|
{
|
||||||
actionDetect,
|
return new SocketWrapper <next_layer_type&> (m_next_layer);
|
||||||
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
|
Socket* new_ssl_stream ()
|
||||||
// handshake, the stream options, and desired role.
|
|
||||||
//
|
|
||||||
Action calcDetectAction (boost::system::error_code& ec)
|
|
||||||
{
|
{
|
||||||
ec = boost::system::error_code ();
|
typedef typename boost::asio::ssl::stream <next_layer_type&> ssl_stream_type;
|
||||||
|
|
||||||
if (m_status == plain)
|
return new SocketWrapper <ssl_stream_type> (
|
||||||
|
m_next_layer, MultiSocket::getRippleTlsBoostContext ());
|
||||||
|
}
|
||||||
|
|
||||||
|
Socket* new_detect_ssl_stream ()
|
||||||
|
{
|
||||||
|
return new SocketWrapper <ssl_detector <next_layer_type&> > (m_next_layer);
|
||||||
|
//return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Socket* new_proxy_stream ()
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a Socket representing what the current stream should
|
||||||
|
// be based on the flags and the state of the handshaking engine.
|
||||||
|
//
|
||||||
|
Socket* new_current_stream (bool createPlain)
|
||||||
|
{
|
||||||
|
Socket* result = nullptr;
|
||||||
|
|
||||||
|
if (m_flags.set (Flag::client_role))
|
||||||
{
|
{
|
||||||
if (! m_options.requireServerProxy && ! m_options.requireServerSsl)
|
if (m_flags.set (Flag::proxy))
|
||||||
{
|
{
|
||||||
return actionPlain;
|
// unsupported function
|
||||||
|
SocketBase::pure_virtual ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_flags.set (Flag::ssl))
|
||||||
|
{
|
||||||
|
result = new_ssl_stream ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
failedHandshake (ec);
|
result = nullptr;
|
||||||
return actionFail;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (m_status == ssl)
|
else
|
||||||
{
|
{
|
||||||
if (! m_options.requireServerProxy)
|
if (m_flags.set (Flag::proxy))
|
||||||
{
|
{
|
||||||
if (m_options.enableServerSsl || m_options.requireServerSsl)
|
result = new_proxy_stream ();
|
||||||
{
|
}
|
||||||
return actionSsl;
|
else if (m_flags.set (Flag::ssl_required))
|
||||||
}
|
{
|
||||||
else
|
result = new_ssl_stream ();
|
||||||
{
|
}
|
||||||
failedHandshake (ec);
|
else if (m_flags.set (Flag::ssl))
|
||||||
return actionFail;
|
{
|
||||||
}
|
result = new_detect_ssl_stream ();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
failedHandshake (ec);
|
result = nullptr;
|
||||||
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);
|
if (createPlain)
|
||||||
return actionFail;
|
{
|
||||||
|
if (result == nullptr)
|
||||||
|
result = new_plain_stream ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
// called when options disallow handshake
|
// Bottleneck to indicate a failed handshake.
|
||||||
void failedHandshake (boost::system::error_code& ec)
|
//
|
||||||
|
boost::system::error_code handshake_error (boost::system::error_code& ec)
|
||||||
{
|
{
|
||||||
// VFALCO TODO maybe use a ripple error category?
|
// VFALCO TODO maybe use a ripple error category?
|
||||||
// set this to something custom that we can recognize later?
|
// set this to something custom that we can recognize later?
|
||||||
ec = boost::asio::error::invalid_argument;
|
//
|
||||||
|
return ec = boost::asio::error::invalid_argument;
|
||||||
}
|
}
|
||||||
|
|
||||||
void createPlainStreamSocket ()
|
// Sanity checks and cleans up our flags based on the desired handshake
|
||||||
{
|
// type and correctly sets the current stream based on the settings.
|
||||||
m_status = plain;
|
// If the requested handshake type is incompatible with the socket flags
|
||||||
m_stream = new SocketWrapper <next_layer_type> (m_next_layer);
|
// set on construction, an error is returned.
|
||||||
}
|
//
|
||||||
|
boost::system::error_code prepare_handshake (handshake_type type,
|
||||||
void handshakePlain (boost::system::error_code& ec)
|
boost::system::error_code& ec)
|
||||||
{
|
{
|
||||||
ec = boost::system::error_code ();
|
ec = boost::system::error_code ();
|
||||||
createPlainStreamSocket ();
|
|
||||||
}
|
|
||||||
|
|
||||||
void handshakePlain (ConstBuffers const& buffers, boost::system::error_code& ec)
|
// If we constructed as 'peer' then become a client
|
||||||
{
|
// or a server as needed according to the handshake type.
|
||||||
fatal_assert (boost::asio::buffer_size (buffers) == 0 );
|
//
|
||||||
ec = boost::system::error_code ();
|
if (m_flags == Flag (Flag::peer))
|
||||||
createPlainStreamSocket ();
|
m_flags = (type == server) ?
|
||||||
}
|
Flag (Flag::server_role) : Flag (Flag::client_role);
|
||||||
|
|
||||||
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (boost::system::error_code))
|
// If we constructed with a specific role, the handshake
|
||||||
handshakePlainAsync (BOOST_ASIO_MOVE_ARG(ErrorCall) handler)
|
// must match the role.
|
||||||
{
|
//
|
||||||
createPlainStreamSocket ();
|
if ( (type == client && ! m_flags.set (Flag::client_role)) ||
|
||||||
return m_io_service.post (m_strand.wrap (boost::bind (
|
(type == server && ! m_flags.set (Flag::server_role)))
|
||||||
BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), boost::system::error_code())));
|
return handshake_error (ec);
|
||||||
}
|
|
||||||
|
|
||||||
void createSslStreamSocket ()
|
// Figure out what type of new stream we need.
|
||||||
{
|
// We pass false to avoid creating a redundant plain stream
|
||||||
m_status = ssl;
|
Socket* socket = new_current_stream (false);
|
||||||
m_ssl_stream = new ssl_stream_type (m_next_layer, m_context->getBoostContext ());
|
|
||||||
m_stream = new SocketWrapper <ssl_stream_type> (*m_ssl_stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
void handshakeSsl (boost::system::error_code& ec)
|
if (socket != nullptr)
|
||||||
{
|
m_stream = socket;
|
||||||
createSslStreamSocket ();
|
|
||||||
m_ssl_stream->handshake (m_role, ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (boost::system::error_code))
|
return ec;
|
||||||
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
|
|
||||||
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(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);
|
|
||||||
}
|
|
||||||
|
|
||||||
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(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 (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)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(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, handler,
|
|
||||||
boost::asio::placeholders::error, 0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
|
|
||||||
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(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 <class ConstBufferSequence>
|
|
||||||
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:
|
private:
|
||||||
Options m_options;
|
Options m_options; // DEPRECATED
|
||||||
ScopedPointer <RippleTlsContext> m_context;
|
|
||||||
|
Flag m_flags;
|
||||||
StreamSocket m_next_layer;
|
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 <Socket> m_stream;
|
ScopedPointer <Socket> m_stream;
|
||||||
ScopedPointer <ssl_stream_type> m_ssl_stream;
|
boost::asio::io_service::strand m_strand;
|
||||||
boost::asio::streambuf m_buffer;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -24,10 +24,12 @@ public:
|
|||||||
typedef boost::function<void (error_code)> callback;
|
typedef boost::function<void (error_code)> callback;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
#if 0
|
||||||
struct SocketInterfaces
|
struct SocketInterfaces
|
||||||
: beast::SocketInterface::AsyncStream
|
: beast::SocketInterface::AsyncStream
|
||||||
, beast::SocketInterface::AsyncHandshake
|
, beast::SocketInterface::AsyncHandshake
|
||||||
, beast::SocketInterface::LowestLayer { };
|
, beast::SocketInterface::LowestLayer { };
|
||||||
|
#endif
|
||||||
|
|
||||||
AutoSocket (boost::asio::io_service& s, boost::asio::ssl::context& c)
|
AutoSocket (boost::asio::io_service& s, boost::asio::ssl::context& c)
|
||||||
: mSecure (false)
|
: mSecure (false)
|
||||||
|
|||||||
Reference in New Issue
Block a user