From 405c9be33761818ac2f2f57c16dc9a2f75e5cdc3 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Fri, 9 Aug 2013 19:39:16 -0700 Subject: [PATCH] TestPeer boost::asio Socket and UnitTest framework --- .../Builds/VisualStudio2012/beast.vcxproj | 61 ++++ .../VisualStudio2012/beast.vcxproj.filters | 69 ++++ .../beast/modules/beast_asio/beast_asio.cpp | 10 + .../beast/modules/beast_asio/beast_asio.h | 15 + .../beast_asio/sockets/beast_Socket.cpp | 249 +++++++++++++ .../modules/beast_asio/sockets/beast_Socket.h | 183 +++++++--- .../beast_asio/sockets/beast_SocketBase.cpp | 30 ++ .../beast_asio/sockets/beast_SocketBase.h | 6 +- .../sockets/beast_SocketInterface.h | 108 ++---- .../beast_asio/sockets/beast_SocketWrapper.h | 345 ++++++++++++------ .../sockets/beast_SocketWrapperBasics.h | 110 ++++++ .../beast_asio/system/beast_BoostIncludes.h | 18 +- .../modules/beast_asio/tests/beast_TestPeer.h | 63 ++++ .../beast_asio/tests/beast_TestPeerBasics.cpp | 101 +++++ .../beast_asio/tests/beast_TestPeerBasics.h | 143 ++++++++ .../beast_asio/tests/beast_TestPeerDetails.h | 45 +++ .../beast_asio/tests/beast_TestPeerLogic.h | 83 +++++ .../beast_asio/tests/beast_TestPeerTest.h | 128 +++++++ .../beast_asio/tests/beast_TestPeerTests.cpp | 46 +++ .../tests/detail/beast_TestPeerDetailsTcp.h | 110 ++++++ .../detail/beast_TestPeerLogicAsyncClient.cpp | 108 ++++++ .../detail/beast_TestPeerLogicAsyncClient.h | 38 ++ .../detail/beast_TestPeerLogicAsyncServer.cpp | 104 ++++++ .../detail/beast_TestPeerLogicAsyncServer.h | 38 ++ .../detail/beast_TestPeerLogicSyncClient.cpp | 97 +++++ .../detail/beast_TestPeerLogicSyncClient.h | 32 ++ .../detail/beast_TestPeerLogicSyncServer.cpp | 80 ++++ .../detail/beast_TestPeerLogicSyncServer.h | 32 ++ .../tests/detail/beast_TestPeerTestType.h | 119 ++++++ .../tests/detail/beast_TestPeerType.h | 176 +++++++++ .../beast_core/diagnostic/beast_UnitTest.cpp | 11 +- 31 files changed, 2487 insertions(+), 271 deletions(-) create mode 100644 Subtrees/beast/modules/beast_asio/sockets/beast_Socket.cpp create mode 100644 Subtrees/beast/modules/beast_asio/sockets/beast_SocketBase.cpp create mode 100644 Subtrees/beast/modules/beast_asio/sockets/beast_SocketWrapperBasics.h create mode 100644 Subtrees/beast/modules/beast_asio/tests/beast_TestPeer.h create mode 100644 Subtrees/beast/modules/beast_asio/tests/beast_TestPeerBasics.cpp create mode 100644 Subtrees/beast/modules/beast_asio/tests/beast_TestPeerBasics.h create mode 100644 Subtrees/beast/modules/beast_asio/tests/beast_TestPeerDetails.h create mode 100644 Subtrees/beast/modules/beast_asio/tests/beast_TestPeerLogic.h create mode 100644 Subtrees/beast/modules/beast_asio/tests/beast_TestPeerTest.h create mode 100644 Subtrees/beast/modules/beast_asio/tests/beast_TestPeerTests.cpp create mode 100644 Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerDetailsTcp.h create mode 100644 Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicAsyncClient.cpp create mode 100644 Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicAsyncClient.h create mode 100644 Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicAsyncServer.cpp create mode 100644 Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicAsyncServer.h create mode 100644 Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicSyncClient.cpp create mode 100644 Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicSyncClient.h create mode 100644 Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicSyncServer.cpp create mode 100644 Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicSyncServer.h create mode 100644 Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerTestType.h create mode 100644 Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerType.h diff --git a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj index a66eabb50e..422474a3a5 100644 --- a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj +++ b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj @@ -75,8 +75,21 @@ + + + + + + + + + + + + + @@ -279,12 +292,60 @@ + + true + true + true + true + + + true + true + true + true + true true true true + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + true diff --git a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters index c443c1bd32..f379219bac 100644 --- a/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters +++ b/Subtrees/beast/Builds/VisualStudio2012/beast.vcxproj.filters @@ -149,6 +149,12 @@ {c7a576bb-27b2-486e-aa14-3c51aa86c50f} + + {422da6a1-e57e-4a96-9fce-e5958c16026e} + + + {5d8ed68a-e3b5-49f3-938b-fbe7365f6293} + @@ -770,6 +776,45 @@ beast_asio\sockets + + beast_asio\tests + + + beast_asio\tests + + + beast_asio\sockets + + + beast_asio\tests\detail + + + beast_asio\tests + + + beast_asio\tests\detail + + + beast_asio\tests + + + beast_asio\tests + + + beast_asio\tests\detail + + + beast_asio\tests\detail + + + beast_asio\tests\detail + + + beast_asio\tests\detail + + + beast_asio\tests\detail + @@ -1192,6 +1237,30 @@ beast_asio\sockets + + beast_asio\tests + + + beast_asio\tests + + + beast_asio\sockets + + + beast_asio\sockets + + + beast_asio\tests\detail + + + beast_asio\tests\detail + + + beast_asio\tests\detail + + + beast_asio\tests\detail + diff --git a/Subtrees/beast/modules/beast_asio/beast_asio.cpp b/Subtrees/beast/modules/beast_asio/beast_asio.cpp index b9e45eae60..b77cf24606 100644 --- a/Subtrees/beast/modules/beast_asio/beast_asio.cpp +++ b/Subtrees/beast/modules/beast_asio/beast_asio.cpp @@ -24,6 +24,16 @@ namespace beast { +#include "sockets/beast_SocketBase.cpp" +#include "sockets/beast_Socket.cpp" #include "sockets/beast_SslContext.cpp" +#include "tests/beast_TestPeerBasics.cpp" +#include "tests/beast_TestPeerTests.cpp" + +#include "tests/detail/beast_TestPeerLogicSyncServer.cpp" +#include "tests/detail/beast_TestPeerLogicSyncClient.cpp" +#include "tests/detail/beast_TestPeerLogicAsyncServer.cpp" +#include "tests/detail/beast_TestPeerLogicAsyncClient.cpp" + } diff --git a/Subtrees/beast/modules/beast_asio/beast_asio.h b/Subtrees/beast/modules/beast_asio/beast_asio.h index 12646080c7..ac453b669f 100644 --- a/Subtrees/beast/modules/beast_asio/beast_asio.h +++ b/Subtrees/beast/modules/beast_asio/beast_asio.h @@ -51,10 +51,25 @@ namespace beast #include "sockets/beast_SocketBase.h" #include "sockets/beast_Socket.h" #include "sockets/beast_SocketInterface.h" +#include "sockets/beast_SocketWrapperBasics.h" #include "sockets/beast_SocketWrapper.h" #include "sockets/beast_SharedSocket.h" #include "sockets/beast_SslContext.h" +#include "tests/beast_TestPeerBasics.h" +#include "tests/beast_TestPeer.h" +#include "tests/beast_TestPeerDetails.h" +#include "tests/beast_TestPeerLogic.h" +#include "tests/beast_TestPeerTest.h" + +#include "tests/detail/beast_TestPeerType.h" +#include "tests/detail/beast_TestPeerTestType.h" +#include "tests/detail/beast_TestPeerDetailsTcp.h" +#include "tests/detail/beast_TestPeerLogicSyncServer.h" +#include "tests/detail/beast_TestPeerLogicSyncClient.h" +#include "tests/detail/beast_TestPeerLogicAsyncServer.h" +#include "tests/detail/beast_TestPeerLogicAsyncClient.h" + } #endif diff --git a/Subtrees/beast/modules/beast_asio/sockets/beast_Socket.cpp b/Subtrees/beast/modules/beast_asio/sockets/beast_Socket.cpp new file mode 100644 index 0000000000..5849680776 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/sockets/beast_Socket.cpp @@ -0,0 +1,249 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +Socket::~Socket () +{ +} + +//------------------------------------------------------------------------------ +// +// General +// +//------------------------------------------------------------------------------ + +bool Socket::requires_handshake () +{ + return false; +} + +//------------------------------------------------------------------------------ +// +// SocketInterface::Close +// +//------------------------------------------------------------------------------ + +boost::system::error_code Socket::close (boost::system::error_code& ec) +{ + return pure_virtual (ec); +} + +//------------------------------------------------------------------------------ +// +// SocketInterface::Acceptor +// +//------------------------------------------------------------------------------ + +boost::system::error_code Socket::accept (Socket&, boost::system::error_code& ec) +{ + return pure_virtual (ec); +} + +BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(Socket::ErrorCall, void (boost::system::error_code)) +Socket::async_accept (Socket&, BOOST_ASIO_MOVE_ARG(ErrorCall) handler) +{ +#if BEAST_ASIO_HAS_FUTURE_RETURNS + boost::asio::detail::async_result_init< + ErrorCall, void (boost::system::error_code)> init( + BOOST_ASIO_MOVE_CAST(ErrorCall)(handler)); + boost::system::error_code ec; + ec = pure_virtual (ec); + get_io_service ().post (boost::bind ( + BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec)); + return init.result.get(); +#else + boost::system::error_code ec; + ec = pure_virtual (ec); + get_io_service ().post (boost::bind ( + BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec)); +#endif +} + +//------------------------------------------------------------------------------ +// +// SocketInterface::LowestLayer +// +//------------------------------------------------------------------------------ + +void* Socket::lowest_layer_raw (char const*) const +{ + pure_virtual (); + return nullptr; +} + +//-------------------------------------------------------------------------- +// +// SocketInterface::Socket +// +//-------------------------------------------------------------------------- + +boost::system::error_code Socket::cancel (boost::system::error_code& ec) +{ + return pure_virtual (ec); +} + +boost::system::error_code Socket::shutdown (shutdown_type, boost::system::error_code& ec) +{ + return pure_virtual (ec); +} + +//-------------------------------------------------------------------------- +// +// SocketInterface::Stream +// +//-------------------------------------------------------------------------- + +std::size_t Socket::read_some (MutableBuffers const&, boost::system::error_code& ec) +{ + pure_virtual (ec); + return 0; +} + +std::size_t Socket::write_some (ConstBuffers const&, boost::system::error_code& ec) +{ + pure_virtual (ec); + return 0; +} + +BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(Socket::TransferCall, void (boost::system::error_code, std::size_t)) +Socket::async_read_some (MutableBuffers const&, BOOST_ASIO_MOVE_ARG(TransferCall) handler) +{ +#if BEAST_ASIO_HAS_FUTURE_RETURNS + boost::asio::detail::async_result_init< + TransferCall, void (boost::system::error_code, std::size_t)> init( + BOOST_ASIO_MOVE_CAST(TransferCall)(handler)); + boost::system::error_code ec; + ec = pure_virtual (ec); + get_io_service ().post (boost::bind (BOOST_ASIO_MOVE_CAST(TransferCall)(handler), ec, 0)); + return init.result.get(); +#else + boost::system::error_code ec; + ec = pure_virtual (ec); + get_io_service ().post (boost::bind (BOOST_ASIO_MOVE_CAST(TransferCall)(handler), ec, 0)); +#endif +} + +BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(Socket::TransferCall, void (boost::system::error_code, std::size_t)) +Socket::async_write_some (ConstBuffers const&, BOOST_ASIO_MOVE_ARG(TransferCall) handler) +{ +#if BEAST_ASIO_HAS_FUTURE_RETURNS + boost::asio::detail::async_result_init< + TransferCall, void (boost::system::error_code, std::size_t)> init( + BOOST_ASIO_MOVE_CAST(TransferCall)(handler)); + boost::system::error_code ec; + ec = pure_virtual (ec); + get_io_service ().post (boost::bind ( + BOOST_ASIO_MOVE_CAST(TransferCall)(handler), ec, 0)); + return init.result.get(); +#else + boost::system::error_code ec; + ec = pure_virtual (ec); + get_io_service ().post (boost::bind ( + BOOST_ASIO_MOVE_CAST(TransferCall)(handler), ec, 0)); +#endif +} + +//-------------------------------------------------------------------------- +// +// SocketInterface::Handshake +// +//-------------------------------------------------------------------------- + +boost::system::error_code Socket::handshake (handshake_type, boost::system::error_code& ec) +{ + return pure_virtual (ec); +} + +BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(Socket::ErrorCall, void (boost::system::error_code)) +Socket::async_handshake (handshake_type, BOOST_ASIO_MOVE_ARG(ErrorCall) handler) +{ +#if BEAST_ASIO_HAS_FUTURE_RETURNS + boost::asio::detail::async_result_init< + ErrorCall, void (boost::system::error_code)> init( + BOOST_ASIO_MOVE_CAST(ErrorCall)(handler)); + boost::system::error_code ec; + ec = pure_virtual (ec); + get_io_service ().post (boost::bind ( + BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec)); + return init.result.get(); +#else + boost::system::error_code ec; + ec = pure_virtual (ec); + get_io_service ().post (boost::bind ( + BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec)); +#endif +} + +//-------------------------------------------------------------------------- + +#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE + +boost::system::error_code Socket::handshake (handshake_type, + ConstBuffers const&, boost::system::error_code& ec) +{ + return pure_virtual (ec); +} + +BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(Socket::TransferCall, void (boost::system::error_code, std::size_t)) +Socket::async_handshake (handshake_type, ConstBuffers const&, + BOOST_ASIO_MOVE_ARG(TransferCall) handler) +{ +#if BEAST_ASIO_HAS_FUTURE_RETURNS + boost::asio::detail::async_result_init< + TransferCall, void (boost::system::error_code, std::size_t)> init( + BOOST_ASIO_MOVE_CAST(TransferCall)(handler)); + boost::system::error_code ec; + ec = pure_virtual (ec); + get_io_service ().post (boost::bind ( + BOOST_ASIO_MOVE_CAST(TransferCall)(handler), ec, 0)); + return init.result.get(); +#else + boost::system::error_code ec; + ec = pure_virtual (ec); + get_io_service ().post (boost::bind ( + BOOST_ASIO_MOVE_CAST(TransferCall)(handler), ec, 0)); +#endif +} + +#endif + +boost::system::error_code Socket::shutdown (boost::system::error_code& ec) +{ + return pure_virtual (ec); +} + +BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(Socket::ErrorCall, void (boost::system::error_code)) +Socket::async_shutdown (BOOST_ASIO_MOVE_ARG(ErrorCall) handler) +{ +#if BEAST_ASIO_HAS_FUTURE_RETURNS + boost::asio::detail::async_result_init< + ErrorCall, void (boost::system::error_code, std::size_t)> init( + BOOST_ASIO_MOVE_CAST(ErrorCall)(handler)); + boost::system::error_code ec; + ec = pure_virtual (ec); + get_io_service ().post (boost::bind ( + BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec)); + return init.result.get(); +#else + boost::system::error_code ec; + ec = pure_virtual (ec); + get_io_service ().post (boost::bind ( + BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), ec)); +#endif +} + diff --git a/Subtrees/beast/modules/beast_asio/sockets/beast_Socket.h b/Subtrees/beast/modules/beast_asio/sockets/beast_Socket.h index 2a29bfe922..59d92684d7 100644 --- a/Subtrees/beast/modules/beast_asio/sockets/beast_Socket.h +++ b/Subtrees/beast/modules/beast_asio/sockets/beast_Socket.h @@ -46,38 +46,29 @@ class Socket , public boost::asio::socket_base { public: - virtual ~Socket () { } + virtual ~Socket (); //-------------------------------------------------------------------------- // - // General attributes + // General // //-------------------------------------------------------------------------- -#if 0 - typedef Socket next_layer_type; - typedef Socket lowest_layer_type; - - virtual next_layer_type& next_layer () = 0; - - virtual next_layer_type const& next_layer () const = 0; - - virtual lowest_layer_type& lowest_layer () = 0; - - virtual lowest_layer_type const& lowest_layer () const = 0; -#endif + virtual boost::asio::io_service& get_io_service () = 0; /** Determines if the underlying stream requires a handshake. - If is_handshaked is true, it will be necessary to call handshake or + If requires_handshake is true, it will be necessary to call handshake or async_handshake after the connection is established. Furthermore it will be necessary to call the shutdown member from the HandshakeInterface to close the connection. Do not close the underlying socket or else the closure will not be graceful. Only one side should initiate the handshaking shutdon. The other side should observe it. Which side does what is up to the user. + + The default version returns false */ - virtual bool is_handshaked () = 0; + virtual bool requires_handshake (); /** Retrieve the underlying object. Returns nullptr if the implementation doesn't match. Usually @@ -88,27 +79,127 @@ public: void set_options (Socket& socket) { - bost::boost::asio::ip::tcp::socket* sock = - socket.native_object (); + typedef bost::boost::asio::ip::tcp Protocol; + typedef Protocol::socket; + Protocol::socket* const sock = + socket.this_layer (); if (sock != nullptr) sock->set_option ( - boost::boost::asio::ip::tcp::no_delay (true)); + Protocol::no_delay (true)); } @endcode */ - template - Object& native_object () + Object& this_layer () { - void* const object = native_object_raw (); + Object* object (this_layer_ptr ()); if (object == nullptr) Throw (std::bad_cast (), __FILE__, __LINE__); - return *static_cast (object); + return *object; } - virtual void* native_object_raw () = 0; + template + Object const& this_layer () const + { + Object const* object (this_layer_ptr ()); + if (object == nullptr) + Throw (std::bad_cast (), __FILE__, __LINE__); + return *object; + } + + template + Object* this_layer_ptr () + { + return static_cast ( + this_layer_raw (typeid (Object).name ())); + } + + template + Object const* this_layer_ptr () const + { + return static_cast ( + this_layer_raw (typeid (Object).name ())); + } + + // Shouldn't call this directly, use this_layer<> instead + virtual void* this_layer_raw (char const* type_name) const = 0; + + //-------------------------------------------------------------------------- + // + // SocketInterface::Close + // + //-------------------------------------------------------------------------- + + void close () + { + boost::system::error_code ec; + throw_error (close (ec)); + } + + virtual boost::system::error_code close (boost::system::error_code& ec); + + //-------------------------------------------------------------------------- + // + // SocketInterface::Acceptor + // + //-------------------------------------------------------------------------- + + virtual boost::system::error_code accept (Socket& peer, boost::system::error_code& ec); + + template + BOOST_ASIO_INITFN_RESULT_TYPE(AcceptHandler, void (boost::system::error_code)) + async_accept (Socket& peer, BOOST_ASIO_MOVE_ARG(AcceptHandler) handler) + { + return async_accept (peer, ErrorCall ( + BOOST_ASIO_MOVE_CAST(AcceptHandler)(handler))); + } + + virtual + BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (boost::system::error_code)) + async_accept (Socket& peer, BOOST_ASIO_MOVE_ARG(ErrorCall) handler); + + //-------------------------------------------------------------------------- + // + // SocketInterface::LowestLayer + // + //-------------------------------------------------------------------------- + + template + Object& lowest_layer () + { + Object* object (lowest_layer_ptr ()); + if (object == nullptr) + Throw (std::bad_cast (), __FILE__, __LINE__); + return *object; + } + + template + Object const& lowest_layer () const + { + Object const* object (lowest_layer_ptr ()); + if (object == nullptr) + Throw (std::bad_cast (), __FILE__, __LINE__); + return *object; + } + + template + Object* lowest_layer_ptr () + { + return static_cast ( + lowest_layer_raw (typeid (Object).name ())); + } + + template + Object const* lowest_layer_ptr () const + { + return static_cast ( + lowest_layer_raw (typeid (Object).name ())); + } + + // Shouldn't call this directly, use lowest_layer<> instead + virtual void* lowest_layer_raw (char const* type_name) const; //-------------------------------------------------------------------------- // @@ -122,7 +213,7 @@ public: throw_error (cancel (ec)); } - virtual boost::system::error_code cancel (boost::system::error_code& ec) = 0; + virtual boost::system::error_code cancel (boost::system::error_code& ec); void shutdown (shutdown_type what) { @@ -131,15 +222,7 @@ public: } virtual boost::system::error_code shutdown (shutdown_type what, - boost::system::error_code& ec) = 0; - - void close () - { - boost::system::error_code ec; - throw_error (close (ec)); - } - - virtual boost::system::error_code close (boost::system::error_code& ec) = 0; + boost::system::error_code& ec); //-------------------------------------------------------------------------- // @@ -158,7 +241,7 @@ public: return read_some (MutableBuffers (buffers), ec); } - virtual std::size_t read_some (MutableBuffers const& buffers, boost::system::error_code& ec) = 0; + virtual std::size_t read_some (MutableBuffers const& buffers, boost::system::error_code& ec); // SyncWriteStream // @@ -170,7 +253,7 @@ public: return write_some (BOOST_ASIO_MOVE_CAST(ConstBuffers)(ConstBuffers (buffers)), ec); } - virtual std::size_t write_some (ConstBuffers const& buffers, boost::system::error_code& ec) = 0; + virtual std::size_t write_some (ConstBuffers const& buffers, boost::system::error_code& ec); // AsyncReadStream // @@ -185,8 +268,8 @@ public: } virtual - 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) = 0; + 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); // AsyncWriteStream // @@ -201,8 +284,8 @@ public: } virtual - 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) = 0; + 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); //-------------------------------------------------------------------------- // @@ -223,7 +306,7 @@ public: // http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ssl__stream/handshake/overload2.html // virtual boost::system::error_code handshake (handshake_type type, - boost::system::error_code& ec) = 0; + boost::system::error_code& ec); // ssl::stream::async_handshake (1 of 2) // http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ssl__stream/async_handshake/overload1.html @@ -237,12 +320,12 @@ public: } virtual - BOOST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (boost::system::error_code)) - async_handshake (handshake_type type, BOOST_ASIO_MOVE_ARG(ErrorCall) handler) = 0; + BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (boost::system::error_code)) + async_handshake (handshake_type type, BOOST_ASIO_MOVE_ARG(ErrorCall) handler); //-------------------------------------------------------------------------- -#if BOOST_ASIO_HAS_BUFFEREDHANDSHAKE +#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE // ssl::stream::handshake (3 of 4) // http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ssl__stream/handshake/overload3.html // @@ -264,7 +347,7 @@ public: } virtual boost::system::error_code handshake (handshake_type type, - ConstBuffers const& buffers, boost::system::error_code& ec) = 0; + ConstBuffers const& buffers, boost::system::error_code& ec); // ssl::stream::async_handshake (2 of 2) // http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ssl__stream/async_handshake/overload2.html @@ -279,9 +362,9 @@ public: } virtual - BOOST_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_handshake (handshake_type type, ConstBuffers const& buffers, - BOOST_ASIO_MOVE_ARG(TransferCall) handler) = 0; + BOOST_ASIO_MOVE_ARG(TransferCall) handler); #endif //-------------------------------------------------------------------------- @@ -295,7 +378,7 @@ public: throw_error (shutdown (ec)); } - virtual boost::system::error_code shutdown (boost::system::error_code& ec) = 0; + virtual boost::system::error_code shutdown (boost::system::error_code& ec); // ssl::stream::async_shutdown // http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ssl__stream/async_shutdown.html @@ -307,8 +390,8 @@ public: } virtual - BOOST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (boost::system::error_code)) - async_shutdown (BOOST_ASIO_MOVE_ARG(ErrorCall) handler) = 0; + BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (boost::system::error_code)) + async_shutdown (BOOST_ASIO_MOVE_ARG(ErrorCall) handler); }; #endif diff --git a/Subtrees/beast/modules/beast_asio/sockets/beast_SocketBase.cpp b/Subtrees/beast/modules/beast_asio/sockets/beast_SocketBase.cpp new file mode 100644 index 0000000000..cb17009cad --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/sockets/beast_SocketBase.cpp @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +void SocketBase::pure_virtual () +{ + fatal_error ("A beast::Socket function was called on an object that doesn't support the interface"); +} + +boost::system::error_code SocketBase::pure_virtual (boost::system::error_code& ec) +{ + pure_virtual (); + return ec = boost::system::errc::make_error_code ( + boost::system::errc::function_not_supported); +} diff --git a/Subtrees/beast/modules/beast_asio/sockets/beast_SocketBase.h b/Subtrees/beast/modules/beast_asio/sockets/beast_SocketBase.h index c537d9104f..07527d69ff 100644 --- a/Subtrees/beast/modules/beast_asio/sockets/beast_SocketBase.h +++ b/Subtrees/beast/modules/beast_asio/sockets/beast_SocketBase.h @@ -20,11 +20,15 @@ #ifndef BEAST_SOCKETBASE_H_INCLUDED #define BEAST_SOCKETBASE_H_INCLUDED -/** Implementation details for AbstractSocket. +/** Implementation details for Socket. Normally you wont need to use this. */ class SocketBase { +protected: + static void pure_virtual (); + static boost::system::error_code pure_virtual (boost::system::error_code& ec); + protected: //-------------------------------------------------------------------------- // diff --git a/Subtrees/beast/modules/beast_asio/sockets/beast_SocketInterface.h b/Subtrees/beast/modules/beast_asio/sockets/beast_SocketInterface.h index 947ae8e50f..f1d47d5753 100644 --- a/Subtrees/beast/modules/beast_asio/sockets/beast_SocketInterface.h +++ b/Subtrees/beast/modules/beast_asio/sockets/beast_SocketInterface.h @@ -23,102 +23,40 @@ /** These define the interfaces that SocketWrapper can adapt with SFINAE. */ struct SocketInterface { - /** Tag for some compatibility with asio::basic_socket + // has close() + struct Close { }; + + /** Tag for some compatibility with boost::asio::basic_socket_acceptor + http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/basic_socket_acceptor.html + */ + struct Acceptor : Close { }; + + // Has lowest_layer() and lowest_layer_type + struct LowestLayer { }; + + /** Tag for parts of boost::asio::basic_socket http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/basic_socket.html */ - struct Socket { }; + struct Socket : Close, LowestLayer { }; - /** Tag for some compatibility with asio::basic_stream_socket + /** Tag for parts of boost::asio::basic_stream_socket http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/basic_stream_socket.html */ struct SyncStream { }; struct AsyncStream { }; struct Stream : SyncStream, AsyncStream { }; - /** Tags for compatibility with asio::ssl::stream + /** Tags for parts of boost::asio::ssl::stream http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ssl__stream.html */ - struct SyncHandshake { }; - struct SyncBufferedHandshake : SyncHandshake { }; - struct AsyncHandshake { }; - struct AsyncBufferedHandshake : AsyncHandshake{ }; - struct Handshake : SyncBufferedHandshake, AsyncBufferedHandshake { }; - -protected: - //-------------------------------------------------------------------------- - - /** Template specialization to determine available interfaces. */ - template - struct InterfacesOf - { - /** Intrusive tag support. - - To use this, add a struct called SocketInterfaces to your - class and derive it from the interfaces that you support. - For example: - - @code - - struct MyHandshakingStream - { - struct SocketInterfaces - : SocketInterface::Stream - , SocketInterface::Handshake - { - }; - } - - @endcode - */ - typedef typename Object::SocketInterfaces type; - typedef type value; - }; - - // Specialization for boost::asio::basic_socket - template - struct InterfacesOf > - { - struct value : SocketInterface::Socket { }; - typedef value type; - }; - - // Specialization for boost::asio::basic_stream_socket - template - struct InterfacesOf > - { - struct value : SocketInterface::Socket, SocketInterface::Stream { }; - typedef value type; - }; - - // Specialization for boost::asio::ssl::stream - template - struct InterfacesOf > - { - struct value : SocketInterface::Stream , SocketInterface::Handshake { }; - typedef value type; - }; - -#if 1 - // Less elegant, but works. - // Determines if Object supports the specified Interface - template - struct HasInterface : boost::false_type { }; - - template - struct HasInterface ::type> >::type > - : boost::true_type { }; -#else - // This should work, but doesn't. - // K-ballo from #boost suggested it. - // - // Determines if Object supports the specified Interface - template - struct HasInterface : boost::is_base_of > - { - }; -#endif + struct AnyHandshake { }; + struct SyncHandshake : AnyHandshake { }; + struct AsyncHandshake : AnyHandshake { }; + struct BufferedSyncHandshake : AnyHandshake { }; + struct BufferedAsyncHandshake : AnyHandshake { }; + struct Handshake : SyncHandshake, AsyncHandshake, + BufferedSyncHandshake, BufferedAsyncHandshake, + LowestLayer { }; }; #endif diff --git a/Subtrees/beast/modules/beast_asio/sockets/beast_SocketWrapper.h b/Subtrees/beast/modules/beast_asio/sockets/beast_SocketWrapper.h index 90c1bf677b..8ead9fe06a 100644 --- a/Subtrees/beast/modules/beast_asio/sockets/beast_SocketWrapper.h +++ b/Subtrees/beast/modules/beast_asio/sockets/beast_SocketWrapper.h @@ -34,17 +34,14 @@ */ template class SocketWrapper - : public SocketInterface - , public virtual Socket + : public virtual Socket + , protected SocketWrapperBasics { public: - typedef Object ObjectType; - typedef typename boost::remove_reference ::type ObjectT; + typedef typename boost::remove_reference ::type ObjectType; SocketWrapper (Object& object) noexcept : m_impl (&object) - //, m_next_layer (object.next_layer ()) - //, m_lowest_layer (object.lowest_layer ()) { } @@ -65,10 +62,40 @@ public: return *m_impl; } - boost::asio::io_service& get_io_service () noexcept + // Retrieves a reference to the underlying socket. + // usually asio::basic_socket or asio::basic_stream_socket + // It must be compatible with our Protocol and SocketService + // or else a std::bad cast will be thrown. + // + // The reason its a template class and not a function is + // because it would otherwise generate a compile error + // if Object did not have a declaration for + // protocol_type::socket + // + template + struct native_socket { - return get_object ().get_io_service (); - } + typedef void* native_socket_type; + native_socket (Socket&) { pure_virtual (); } + native_socket_type& get () { pure_virtual (); return m_socket; } + native_socket_type& operator-> () noexcept { return get(); } + private: + native_socket_type m_socket; + }; + + template + struct native_socket >::type> + { + typedef typename Object::protocol_type::socket native_socket_type; + native_socket (Socket& peer) + : m_socket (&peer.this_layer ()) { } + native_socket_type& get () noexcept { return *m_socket; } + native_socket_type& operator-> () noexcept { return *m_socket; } + + private: + native_socket_type* m_socket; + }; //-------------------------------------------------------------------------- @@ -95,74 +122,44 @@ public: { return get_object ().lowest_layer (); } + #endif - + //-------------------------------------------------------------------------- + // // General + // + //-------------------------------------------------------------------------- - bool is_handshaked () + boost::asio::io_service& get_io_service () { - return HasInterface ::value; + return get_object ().get_io_service (); } - void* native_object_raw () + bool requires_handshake () { - return m_impl; + return Has ::value; + } + + void* this_layer_raw (char const* type_name) const + { + char const* const this_type_name (typeid (ObjectType).name ()); + if (strcmp (type_name, this_type_name) == 0) + return const_cast (static_cast (m_impl)); + return nullptr; } //-------------------------------------------------------------------------- // - // SocketInterface::Socket + // SocketInterface::Close // //-------------------------------------------------------------------------- -public: - boost::system::error_code cancel (boost::system::error_code& ec) - { - return cancel (ec, - HasInterface ()); - } - -private: - boost::system::error_code cancel (boost::system::error_code& ec, - boost::true_type) - { - return get_object ().cancel (ec); - } - - boost::system::error_code cancel (boost::system::error_code& ec, - boost::false_type) - { - return pure_virtual (ec); - } - -public: - boost::system::error_code shutdown (shutdown_type what, boost::system::error_code& ec) - { - return shutdown (what, ec, - HasInterface ()); - } - -private: - boost::system::error_code shutdown (Socket::shutdown_type what, boost::system::error_code& ec, - boost::true_type) - { - return get_object ().shutdown (what, ec); - } - - boost::system::error_code shutdown (Socket::shutdown_type, boost::system::error_code& ec, - boost::false_type) - { - return pure_virtual (ec); - } - -public: boost::system::error_code close (boost::system::error_code& ec) { return close (ec, - HasInterface ()); + Has ()); } -private: boost::system::error_code close (boost::system::error_code& ec, boost::true_type) { @@ -175,20 +172,164 @@ private: return pure_virtual (ec); } + //-------------------------------------------------------------------------- + // + // SocketInterface::Acceptor + // + //-------------------------------------------------------------------------- + + boost::system::error_code accept (Socket& peer, boost::system::error_code& ec) + { + return accept (peer, ec, + Has ()); + } + + boost::system::error_code accept (Socket& peer, boost::system::error_code& ec, + boost::true_type) + { +#if 1 + return get_object ().accept ( + native_socket (peer).get (), ec); +#else + typedef ObjectType::protocol_type::socket socket_type; + socket_type& socket (peer.this_layer ()); + return get_object ().accept (socket, ec); +#endif + } + + boost::system::error_code accept (Socket&, boost::system::error_code& ec, + boost::false_type) + { + return pure_virtual (ec); + } + + BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(ErrorCall, void (boost::system::error_code)) + async_accept (Socket& peer, BOOST_ASIO_MOVE_ARG(ErrorCall) handler) + { + return async_accept (peer, BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), + Has ()); + } + + template + BOOST_ASIO_INITFN_RESULT_TYPE(ErrorCall, void (boost::system::error_code)) + async_accept (Socket& peer, BOOST_ASIO_MOVE_ARG(AcceptHandler) handler, + boost::true_type) + { +#if 1 + return get_object ().async_accept ( + native_socket (peer).get (), handler); +#else + typedef ObjectType::protocol_type::socket socket_type; + socket_type& socket (peer.this_layer ()); + return get_object ().async_accept (socket, handler); +#endif + } + + template + BOOST_ASIO_INITFN_RESULT_TYPE(AcceptHandler, void (boost::system::error_code)) + async_accept (Socket&, BOOST_ASIO_MOVE_ARG(AcceptHandler) handler, + boost::false_type) + { +#if BEAST_ASIO_HAS_FUTURE_RETURNS + boost::asio::detail::async_result_init< + AcceptHandler, void (boost::system::error_code)> init( + BOOST_ASIO_MOVE_CAST(AcceptHandler)(handler)); + boost::system::error_code ec; + ec = pure_virtual (ec); + get_io_service ().post (boost::bind ( + BOOST_ASIO_MOVE_CAST(AcceptHandler)(handler), ec)); + return init.result.get(); +#else + boost::system::error_code ec; + ec = pure_virtual (ec); + get_io_service ().post (boost::bind ( + BOOST_ASIO_MOVE_CAST(AcceptHandler)(handler), ec)); +#endif + } + + //-------------------------------------------------------------------------- + // + // SocketInterface::LowestLayer + // + //-------------------------------------------------------------------------- + + void* lowest_layer_raw (char const* type_name) const + { + return lowest_layer_raw (type_name, + Has ()); + } + + void* lowest_layer_raw (char const* type_name, + boost::true_type) const + { + typedef typename ObjectType::lowest_layer_type lowest_layer_type; + char const* const lowest_layer_type_name (typeid (lowest_layer_type).name ()); + if (strcmp (type_name, lowest_layer_type_name) == 0) + return const_cast (static_cast (&get_object ().lowest_layer ())); + return nullptr; + } + + void* lowest_layer_raw (char const*, + boost::false_type) const + { + pure_virtual (); + return nullptr; + } + + //-------------------------------------------------------------------------- + // + // SocketInterface::Socket + // + //-------------------------------------------------------------------------- + + boost::system::error_code cancel (boost::system::error_code& ec) + { + return cancel (ec, + Has ()); + } + + boost::system::error_code cancel (boost::system::error_code& ec, + boost::true_type) + { + return get_object ().cancel (ec); + } + + boost::system::error_code cancel (boost::system::error_code& ec, + boost::false_type) + { + return pure_virtual (ec); + } + + boost::system::error_code shutdown (shutdown_type what, boost::system::error_code& ec) + { + return shutdown (what, ec, + Has ()); + } + + boost::system::error_code shutdown (Socket::shutdown_type what, boost::system::error_code& ec, + boost::true_type) + { + return get_object ().shutdown (what, ec); + } + + boost::system::error_code shutdown (Socket::shutdown_type, boost::system::error_code& ec, + boost::false_type) + { + return pure_virtual (ec); + } + //-------------------------------------------------------------------------- // // SocketInterface::Stream // //-------------------------------------------------------------------------- -public: std::size_t read_some (MutableBuffers const& buffers, boost::system::error_code& ec) { return read_some (buffers, ec, - HasInterface ()); + Has ()); } -private: template std::size_t read_some (MutableBufferSequence const& buffers, boost::system::error_code& ec, boost::true_type) @@ -204,14 +345,12 @@ private: return 0; } -public: std::size_t write_some (ConstBuffers const& buffers, boost::system::error_code& ec) { return write_some (buffers, ec, - HasInterface ()); + Has ()); } -private: template std::size_t write_some (ConstBufferSequence const& buffers, boost::system::error_code& ec, boost::true_type) @@ -227,15 +366,13 @@ private: return 0; } -public: - BOOST_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) { return async_read_some (buffers, BOOST_ASIO_MOVE_CAST(TransferCall)(handler), - HasInterface ()); + Has ()); } -private: template BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_some (MutableBufferSequence const& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, @@ -250,11 +387,11 @@ private: async_read_some (MutableBufferSequence const&, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, boost::false_type) { -#if BOOST_ASIO_HAS_FUTURE_RETURNS +#if BEAST_ASIO_HAS_FUTURE_RETURNS boost::asio::detail::async_result_init< ReadHandler, void (boost::system::error_code, std::size_t)> init( BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); - system::error_code ec; + boost::system::error_code ec; ec = pure_virtual (ec); get_io_service ().post (boost::bind (BOOST_ASIO_MOVE_CAST(ReadHandler)(handler), ec, 0)); return init.result.get(); @@ -265,15 +402,13 @@ private: #endif } -public: - BOOST_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) { return async_write_some (buffers, BOOST_ASIO_MOVE_CAST(TransferCall)(handler), - HasInterface ()); + Has ()); } -private: template BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_some (ConstBufferSequence const& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler, @@ -288,11 +423,11 @@ private: async_write_some (ConstBufferSequence const&, BOOST_ASIO_MOVE_ARG(WriteHandler) handler, boost::false_type) { -#if BOOST_ASIO_HAS_FUTURE_RETURNS +#if BEAST_ASIO_HAS_FUTURE_RETURNS boost::asio::detail::async_result_init< WriteHandler, void (boost::system::error_code, std::size_t)> init( BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); - system::error_code ec; + boost::system::error_code ec; ec = pure_virtual (ec); get_io_service ().post (boost::bind ( BOOST_ASIO_MOVE_CAST(WriteHandler)(handler), ec, 0)); @@ -307,18 +442,16 @@ private: //-------------------------------------------------------------------------- // - // Handshake + // SocketInterface::Handshake // //-------------------------------------------------------------------------- -public: boost::system::error_code handshake (handshake_type type, boost::system::error_code& ec) { return handshake (type, ec, - HasInterface ()); + Has ()); } -private: boost::system::error_code handshake (handshake_type type, boost::system::error_code& ec, boost::true_type) { @@ -331,15 +464,13 @@ private: return pure_virtual (ec); } -public: - BOOST_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) { return async_handshake (type, BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), - HasInterface ()); + Has ()); } -private: template BOOST_ASIO_INITFN_RESULT_TYPE(HandshakeHandler, void (boost::system::error_code)) async_handshake (handshake_type type, BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler, @@ -354,11 +485,11 @@ private: async_handshake (handshake_type, BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler, boost::false_type) { -#if BOOST_ASIO_HAS_FUTURE_RETURNS +#if BEAST_ASIO_HAS_FUTURE_RETURNS boost::asio::detail::async_result_init< HandshakeHandler, void (boost::system::error_code)> init( BOOST_ASIO_MOVE_CAST(HandshakeHandler)(handler)); - system::error_code ec; + boost::system::error_code ec; ec = pure_virtual (ec); get_io_service ().post (boost::bind ( BOOST_ASIO_MOVE_CAST(HandshakeHandler)(handler), ec)); @@ -371,16 +502,14 @@ private: #endif } -public: -#if BOOST_ASIO_HAS_BUFFEREDHANDSHAKE +#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE boost::system::error_code handshake (handshake_type type, ConstBuffers const& buffers, boost::system::error_code& ec) { return handshake (type, buffers, ec, - HasInterface ()); + Has ()); } -private: template boost::system::error_code handshake (handshake_type type, ConstBufferSequence const& buffers, boost::system::error_code& ec, @@ -397,17 +526,15 @@ private: return pure_virtual (ec); } -public: - BOOST_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_handshake (handshake_type type, ConstBuffers const& buffers, BOOST_ASIO_MOVE_ARG(TransferCall) handler) { return async_handshake (type, buffers, BOOST_ASIO_MOVE_CAST(TransferCall)(handler), - HasInterface ()); + Has ()); } -private: template BOOST_ASIO_INITFN_RESULT_TYPE(BufferedHandshakeHandler, void (boost::system::error_code, std::size_t)) async_handshake (handshake_type type, const ConstBufferSequence& buffers, @@ -424,7 +551,7 @@ private: BOOST_ASIO_MOVE_ARG(BufferedHandshakeHandler) handler, boost::false_type) { -#if BOOST_ASIO_HAS_FUTURE_RETURNS +#if BEAST_ASIO_HAS_FUTURE_RETURNS boost::asio::detail::async_result_init< BufferedHandshakeHandler, void (boost::system::error_code, std::size_t)> init( BOOST_ASIO_MOVE_CAST(BufferedHandshakeHandler)(handler)); @@ -442,14 +569,12 @@ private: } #endif -public: boost::system::error_code shutdown (boost::system::error_code& ec) { return shutdown (ec, - HasInterface ()); + Has ()); } -private: boost::system::error_code shutdown (boost::system::error_code& ec, boost::true_type) { @@ -462,14 +587,12 @@ private: return pure_virtual (ec); } -public: void async_shutdown (BOOST_ASIO_MOVE_ARG(ErrorCall) handler) { async_shutdown (BOOST_ASIO_MOVE_CAST(ErrorCall)(handler), - HasInterface ()); + Has ()); } -private: template BOOST_ASIO_INITFN_RESULT_TYPE(ShutdownHandler, void (boost::system::error_code)) async_shutdown (BOOST_ASIO_MOVE_ARG(ShutdownHandler) handler, @@ -484,11 +607,11 @@ private: async_shutdown (BOOST_ASIO_MOVE_ARG(ShutdownHandler) handler, boost::false_type) { -#if BOOST_ASIO_HAS_FUTURE_RETURNS +#if BEAST_ASIO_HAS_FUTURE_RETURNS boost::asio::detail::async_result_init< ShutdownHandler, void (boost::system::error_code, std::size_t)> init( BOOST_ASIO_MOVE_CAST(ShutdownHandler)(handler)); - system::error_code ec; + boost::system::error_code ec; ec = pure_virtual (ec); get_io_service ().post (boost::bind ( BOOST_ASIO_MOVE_CAST(ShutdownHandler)(handler), ec)); @@ -512,20 +635,10 @@ protected: m_impl = ptr; } -private: - static void pure_virtual () - { - fatal_error ("A beast::Socket function was called on an object that doesn't support the interface"); - } + template + struct Has : HasInterface { }; - static boost::system::error_code pure_virtual (boost::system::error_code& ec) - { - pure_virtual (); - return ec = boost::system::errc::make_error_code ( - boost::system::errc::function_not_supported); - } - -private: +public: Object* m_impl; }; diff --git a/Subtrees/beast/modules/beast_asio/sockets/beast_SocketWrapperBasics.h b/Subtrees/beast/modules/beast_asio/sockets/beast_SocketWrapperBasics.h new file mode 100644 index 0000000000..069e01b15d --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/sockets/beast_SocketWrapperBasics.h @@ -0,0 +1,110 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_SOCKETWRAPPERBASICS_H_INCLUDED +#define BEAST_SOCKETWRAPPERBASICS_H_INCLUDED + +/** Some utilities for SocketWrapper and others. +*/ +class SocketWrapperBasics +{ +protected: + /** Template specialization to determine available interfaces. */ + template + struct InterfacesOf + { + /** Intrusive tag support. + + To use this, add a struct called SocketInterfaces to your + class and derive it from the interfaces that you support. + For example: + + @code + + struct MyHandshakingStream + { + struct SocketInterfaces + : SocketInterface::Stream + , SocketInterface::Handshake + { + }; + } + + @endcode + */ + typedef typename Object::SocketInterfaces type; + typedef type value; + }; + + // Specialization for boost::asio::basic_socket_acceptor + template + struct InterfacesOf > + { + struct value : SocketInterface::Acceptor { }; + typedef value type; + }; + + // Specialization for boost::asio::basic_socket + template + struct InterfacesOf > + { + struct value : SocketInterface::Socket { }; + typedef value type; + }; + + // Specialization for boost::asio::basic_stream_socket + template + struct InterfacesOf > + { + struct value : SocketInterface::Socket, SocketInterface::Stream { }; + typedef value type; + }; + + // Specialization for boost::asio::ssl::stream + template + struct InterfacesOf > + { + struct value : SocketInterface::Stream , SocketInterface::Handshake { }; + typedef value type; + }; + +#if 1 + // Less elegant, but works. + // Determines if Object supports the specified Interface + template + struct HasInterface : boost::false_type { }; + + template + struct HasInterface ::type> >::type > + : boost::true_type { }; +#else + // This should work, but doesn't. + // K-ballo from #boost suggested it. + // + // Determines if Object supports the specified Interface + template + struct HasInterface : boost::is_base_of > + { + }; +#endif +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/system/beast_BoostIncludes.h b/Subtrees/beast/modules/beast_asio/system/beast_BoostIncludes.h index 4db3e957dd..e1c3c6c751 100644 --- a/Subtrees/beast/modules/beast_asio/system/beast_BoostIncludes.h +++ b/Subtrees/beast/modules/beast_asio/system/beast_BoostIncludes.h @@ -49,25 +49,25 @@ // Configure some options based on the version of boost #include #if (BOOST_VERSION / 100) >= 1054 -# define BOOST_ASIO_HAS_BUFFEREDHANDSHAKE 1 -# define BOOST_ASIO_HAS_FUTURE_RETURNS 1 +# define BEAST_ASIO_HAS_BUFFEREDHANDSHAKE 1 +# define BEAST_ASIO_HAS_FUTURE_RETURNS 1 #else -# define BOOST_ASIO_HAS_BUFFEREDHANDSHAKE 0 -# define BOOST_ASIO_HAS_FUTURE_RETURNS 0 +# define BEAST_ASIO_HAS_BUFFEREDHANDSHAKE 0 +# define BEAST_ASIO_HAS_FUTURE_RETURNS 0 #endif -#if ! BOOST_ASIO_HAS_FUTURE_RETURNS +#if ! BEAST_ASIO_HAS_FUTURE_RETURNS # define BOOST_ASIO_INITFN_RESULT_TYPE(expr,val) void -# define BOOST_ASIO_INITFN_RESULT_TYPE_MEMBER(expr,val) void +# define BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(expr,val) void #else # if defined(GENERATING_DOCUMENTATION) -# define BOOST_ASIO_INITFN_RESULT_TYPE_MEMBER(h, sig) \ +# define BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(h, sig) \ void_or_deduced # elif defined(_MSC_VER) && (_MSC_VER < 1500) -# define BOOST_ASIO_INITFN_RESULT_TYPE_MEMBER(h, sig) \ +# define BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(h, sig) \ boost::asio::detail::async_result_type_helper::type # else -# define BOOST_ASIO_INITFN_RESULT_TYPE_MEMBER(h, sig) \ +# define BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(h, sig) \ boost::asio::async_result ::type>::type # endif #endif diff --git a/Subtrees/beast/modules/beast_asio/tests/beast_TestPeer.h b/Subtrees/beast/modules/beast_asio/tests/beast_TestPeer.h new file mode 100644 index 0000000000..c87647605a --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/tests/beast_TestPeer.h @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_TESTPEER_H_INCLUDED +#define BEAST_TESTPEER_H_INCLUDED + +/** An abstract peer for unit tests. +*/ +class TestPeer + : public TestPeerBasics + , public Uncopyable +{ +public: + virtual ~TestPeer () { } + + /** Get the name of this peer. */ + virtual String name () const = 0; + + /** Start the peer. + If the peer is a server, the call will block until the + listening socket is ready to receive connections. + */ + virtual void start () = 0; + + /** Wait for the peer to finish. + + If the peer does not complete before the timout expires + then a timeout error is returned. If timeoutSeconds is less + than 0, then the wait is infinite. + + @return Any error code generated during the server operation. + */ + virtual boost::system::error_code join (int timeoutSeconds = -1) = 0; + + /** Runs a unit test on the specified pair of peers. + Returns true if the tests passed. + */ +#if 0 + static bool runTest (UnitTest& test, + TestPeer& server, + TestPeer& client, + int timeoutSeconds, + String const& name); +#endif +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/tests/beast_TestPeerBasics.cpp b/Subtrees/beast/modules/beast_asio/tests/beast_TestPeerBasics.cpp new file mode 100644 index 0000000000..d45a70de70 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/tests/beast_TestPeerBasics.cpp @@ -0,0 +1,101 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +boost::system::error_category const& TestPeerBasics::test_category () noexcept +{ + struct test_category_type : boost::system::error_category + { + char const* name () const noexcept + { + return "TestPeer"; + } + + std::string message (int ev) const + { + switch (ev) + { + case errc::none: return "No error"; + case errc::timeout: return "The timeout expired before the test could complete"; + case errc::unexpected: return "An unexpected test result was encountered"; + case errc::exceptioned: return "An unexpected exception was thrown"; + case errc::skipped: return "The test was skipped because of previous errors"; + default: + break; + }; + + return "An unknown error"; + } + + boost::system::error_condition default_error_condition (int ev) const noexcept + { + return boost::system::error_condition (ev, *this); + } + + bool equivalent (int ev, boost::system::error_condition const& condition) const noexcept + { + return default_error_condition (ev) == condition; + } + + bool equivalent (boost::system::error_code const& code, int ev) const noexcept + { + return *this == code.category() && code.value() == ev; + } + }; + + static test_category_type category; + + return category; +} + +boost::system::error_code TestPeerBasics::make_error (errc::errc_t ev) noexcept +{ + return boost::system::error_code (ev, test_category ()); +} + +boost::system::error_code TestPeerBasics::make_error (errc::errc_t ev, boost::system::error_code& ec) noexcept +{ + return ec = make_error (ev); +} + +bool TestPeerBasics::success (boost::system::error_code const& ec, bool eofIsOkay) noexcept +{ + if (eofIsOkay && ec == boost::asio::error::eof) + return true; + return ! ec; +} + +bool TestPeerBasics::failure (boost::system::error_code const& ec, bool eofIsOkay) noexcept +{ + return ! success (ec, eofIsOkay); +} + +bool TestPeerBasics::expected (bool condition, boost::system::error_code& ec) noexcept +{ + if (condition) + ec = boost::system::error_code (); + else + make_error (errc::unexpected, ec); + return condition; +} + +bool TestPeerBasics::unexpected (bool condition, boost::system::error_code& ec) noexcept +{ + return ! expected (condition, ec); +} + diff --git a/Subtrees/beast/modules/beast_asio/tests/beast_TestPeerBasics.h b/Subtrees/beast/modules/beast_asio/tests/beast_TestPeerBasics.h new file mode 100644 index 0000000000..8c57c18622 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/tests/beast_TestPeerBasics.h @@ -0,0 +1,143 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_TESTPEERBASICS_H_INCLUDED +#define BEAST_TESTPEERBASICS_H_INCLUDED + +/** Common declarations for TestPeer. + + @see TestPeer +*/ +struct TestPeerBasics +{ + // Custom error codes for distinguishing test conditions + struct errc + { + enum errc_t + { + none = 0, + timeout, // The peer join timeout expired + unexpected, // An expected condition was false + exceptioned, // An exception occurred + skipped // Test skipped due to previous errors + }; + }; + + /** Returns the category that represents TestPeer errors. + */ + static boost::system::error_category const& test_category () noexcept; + + /** Creates a test error_code from the give code value. + */ + static boost::system::error_code make_error (errc::errc_t ev) noexcept; + + /** Sets the passed error_code to a test error and returns it. + */ + static boost::system::error_code make_error (errc::errc_t ev, + boost::system::error_code& ec) noexcept; + + /** Returns true if the error code indicates success. + */ + static bool success (boost::system::error_code const& ec, bool eofIsOkay = false) noexcept; + + /** Returns false if the error code indicates failure. + */ + static bool failure (boost::system::error_code const& ec, bool eofIsOkay = false) noexcept; + + /** Set the error based on a failed condition and return the success. + */ + static bool expected (bool condition, boost::system::error_code& ec) noexcept; + + /** Set the error based on a passed condition and return the success. + */ + static bool unexpected (bool condition, boost::system::error_code& ec) noexcept; + + //-------------------------------------------------------------------------- + + struct Role + { + enum role_t + { + client, + server + }; + + Role (role_t role) + : m_role (role) + { + } + + String name () const noexcept + { + if (m_role == server) + return "server"; + return "client"; + } + + bool operator== (role_t role) const noexcept + { + return m_role == role; + } + + operator Socket::handshake_type () const noexcept + { + if (m_role == server) + return Socket::server; + return Socket::client; + } + + private: + role_t m_role; + }; + + //-------------------------------------------------------------------------- + + struct Model + { + enum model_t + { + sync, + async + }; + + Model (model_t model) + : m_model (model) + { + } + + String name () const noexcept + { + if (m_model == async) + return "async"; + return "sync"; + } + + bool operator== (model_t model) const noexcept + { + return m_model == model; + } + + private: + model_t m_model; + }; + + //-------------------------------------------------------------------------- +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/tests/beast_TestPeerDetails.h b/Subtrees/beast/modules/beast_asio/tests/beast_TestPeerDetails.h new file mode 100644 index 0000000000..ec2a6b9887 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/tests/beast_TestPeerDetails.h @@ -0,0 +1,45 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_TESTPEERDETAILS_H_INCLUDED +#define BEAST_TESTPEERDETAILS_H_INCLUDED + +/** Base class of all detail objects. +*/ +class TestPeerDetails : public Uncopyable +{ +public: + virtual ~TestPeerDetails () { } + + virtual String name () = 0; + + virtual Socket& get_socket () = 0; + + virtual Socket& get_acceptor () = 0; + + boost::asio::io_service& get_io_service () + { + return m_io_service; + } + +private: + boost::asio::io_service m_io_service; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/tests/beast_TestPeerLogic.h b/Subtrees/beast/modules/beast_asio/tests/beast_TestPeerLogic.h new file mode 100644 index 0000000000..a0094a01ad --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/tests/beast_TestPeerLogic.h @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_TESTPEERLOGIC_H_INCLUDED +#define BEAST_TESTPEERLOGIC_H_INCLUDED + +/** Interface for implementing the logic part of a peer test. +*/ +class TestPeerLogic + : public TestPeerBasics + , public Uncopyable +{ +public: + typedef boost::system::error_code error_code; + + explicit TestPeerLogic (Socket& socket) + : m_socket (socket) + { + } + + error_code& error () noexcept + { + return m_ec; + } + + error_code const& error () const noexcept + { + return m_ec; + } + + // also assigns, used for async handlers + error_code const& error (error_code const& ec) noexcept + { + return m_ec = ec; + } + + Socket& socket () noexcept + { + return m_socket; + } + + virtual Role get_role () const noexcept = 0; + + virtual Model get_model () const noexcept = 0; + + virtual void on_connect () + { + pure_virtual (); + } + + virtual void on_connect_async (error_code const&) + { + pure_virtual (); + } + +protected: + static void pure_virtual () + { + fatal_error ("A TestPeerLogic function was called incorrectly"); + } + +private: + error_code m_ec; + Socket& m_socket; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/tests/beast_TestPeerTest.h b/Subtrees/beast/modules/beast_asio/tests/beast_TestPeerTest.h new file mode 100644 index 0000000000..628359461a --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/tests/beast_TestPeerTest.h @@ -0,0 +1,128 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_TESTPEERTEST_H_INCLUDED +#define RIPPLE_TESTPEERTEST_H_INCLUDED + +/** Performs a test of two peers defined by template parameters. +*/ +struct TestPeerTest : protected TestPeerBasics +{ + enum + { + /** How long to wait before aborting a peer and reporting a timeout. + + @note Aborting synchronous logics may cause undefined behavior. + */ + defaultTimeoutSeconds = 30 + }; + + /** Holds the results for one peer. */ + class Result : protected TestPeerBasics + { + public: + /** Default constructor indicates the test was skipped. + */ + Result () + : m_ec (make_error (errc::skipped)) + , m_message (m_ec.message ()) + { + } + + /** Construct from an error code. + The prefix is prepended to the error message. + */ + explicit Result (boost::system::error_code const& ec, String const& prefix = "") + : m_ec (ec) + , m_message ((prefix == String::empty) ? ec.message () + : prefix + " " + ec.message ()) + { + } + + /** Returns true if the peer failed. + */ + bool failed () const noexcept + { + return failure (m_ec); + } + + /** Convenience for determining if the peer timed out. */ + bool timedout () const noexcept + { + return m_ec == make_error (errc::timeout); + } + + /** Provides a descriptive message. + This is suitable to pass to UnitTest::fail. + */ + String message () const noexcept + { + return m_message; + } + + /** Report the result to a UnitTest object. + A return value of true indicates success. + */ + bool report (UnitTest& test) + { + bool const success = test.unexpected (failed (), message ()); +#if 0 + // Option to report passing tests + if (success) + test.logMessage (String ("passed ") + message()); +#endif + return success; + } + + private: + boost::system::error_code m_ec; + String m_message; + }; + + //-------------------------------------------------------------------------- + + /** Holds the results for both peers. */ + struct Results + { + String name; // A descriptive name for this test case. + Result client; + Result server; + + Results () : name ("unknown") + { + } + + /** Report the results to a UnitTest object. + A return value of true indicates success. + */ + bool report (UnitTest& test, bool beginTestCase = true) + { + if (beginTestCase) + test.beginTestCase (name); + bool success = true; + if (! client.report (test)) + success = false; + if (! server.report (test)) + success = false; + return success; + } + }; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/tests/beast_TestPeerTests.cpp b/Subtrees/beast/modules/beast_asio/tests/beast_TestPeerTests.cpp new file mode 100644 index 0000000000..701051ae46 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/tests/beast_TestPeerTests.cpp @@ -0,0 +1,46 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +class TestPeerTests : public UnitTest +{ +public: + enum + { + timeoutSeconds = 3 + }; + + TestPeerTests () : UnitTest ("TestPeer", "beast") + { + } + + template + void testDetails (Arg const& arg = Arg ()) + { + TestPeerTestType::test
(*this, arg, timeoutSeconds); + } + + void runTest () + { + typedef boost::asio::ip::tcp protocol; + testDetails (protocol::v4 ()); + testDetails (protocol::v6 ()); + } +}; + +static TestPeerTests testPeerTests; diff --git a/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerDetailsTcp.h b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerDetailsTcp.h new file mode 100644 index 0000000000..e3fe271198 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerDetailsTcp.h @@ -0,0 +1,110 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_TESTPEERDETAILSTCP_H_INCLUDED +#define BEAST_TESTPEERDETAILSTCP_H_INCLUDED + +/** Some predefined Detail classes for TestPeer +*/ +struct TcpDetails : public TestPeerDetails +{ +protected: + typedef boost::asio::ip::tcp protocol_type; + typedef protocol_type::socket socket_type; + typedef protocol_type::acceptor acceptor_type; + typedef protocol_type::endpoint endpoint_type; + typedef protocol_type::resolver resolver_type; + + struct NoArg { }; // dummy + +public: + typedef protocol_type arg_type; + typedef socket_type native_socket_type; + typedef acceptor_type native_acceptor_type; + + explicit TcpDetails (arg_type protocol) + : m_protocol (protocol) + , m_socket (get_io_service ()) + , m_acceptor (get_io_service ()) + , m_socket_wrapper (m_socket) + , m_acceptor_wrapper (m_acceptor) + { + } + + static String getArgName (arg_type arg) + { + if (arg == protocol_type::v4 ()) + return "tcpv4"; + else if (arg == protocol_type::v6 ()) + return "tcpv6"; + return "tcp?"; + } + + String name () + { + return getArgName (m_protocol); + } + + Socket& get_socket () + { + return m_socket_wrapper; + } + + 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 (m_protocol == protocol_type::v4 ()) + { + if (role == TestPeer::Role::server) + return endpoint_type (m_protocol, 1053); + else + return endpoint_type (boost::asio::ip::address_v4::loopback (), 1053); + } + else + { + if (role == TestPeer::Role::server) + return endpoint_type (m_protocol, 1052); + else + return endpoint_type (boost::asio::ip::address_v6 ().from_string ("::1"), 1052); + } + } + +protected: + protocol_type m_protocol; + socket_type m_socket; + acceptor_type m_acceptor; + SocketWrapper m_socket_wrapper; + SocketWrapper m_acceptor_wrapper; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicAsyncClient.cpp b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicAsyncClient.cpp new file mode 100644 index 0000000000..b4233daf3c --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicAsyncClient.cpp @@ -0,0 +1,108 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +TestPeerLogicAsyncClient::TestPeerLogicAsyncClient (Socket& socket) + : TestPeerLogic (socket) +{ +} + +TestPeerBasics::Role TestPeerLogicAsyncClient::get_role () const noexcept +{ + return Role::client; +} + +TestPeerBasics::Model TestPeerLogicAsyncClient::get_model () const noexcept +{ + return Model::async; +} + +void TestPeerLogicAsyncClient::on_connect_async (error_code const& ec) +{ + if (failure (error (ec))) + return; + + if (socket ().requires_handshake ()) + { + socket ().async_handshake (Socket::client, + boost::bind (&TestPeerLogicAsyncClient::on_handshake, this, + boost::asio::placeholders::error)); + } + else + { + on_handshake (ec); + } +} + +void TestPeerLogicAsyncClient::on_handshake (error_code const& ec) +{ + if (failure (error (ec))) + return; + + boost::asio::async_write (socket (), boost::asio::buffer ("hello", 5), + boost::bind (&TestPeerLogicAsyncClient::on_write, this, + boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); +} + +void TestPeerLogicAsyncClient::on_write (error_code const& ec, std::size_t bytes_transferred) +{ + if (failure (error (ec))) + return; + + if (unexpected (bytes_transferred == 5, error ())) + return; + + boost::asio::async_read_until (socket (), m_buf, std::string ("goodbye"), + boost::bind (&TestPeerLogicAsyncClient::on_read, this, + boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); +} + +void TestPeerLogicAsyncClient::on_read (error_code const& ec, std::size_t bytes_transferred) +{ + if (failure (error (ec))) + return; + + if (unexpected (bytes_transferred == 7, error ())) + return; + + // should check the data here? + m_buf.consume (bytes_transferred); + + boost::asio::async_read (socket (), m_buf.prepare (1), + boost::bind (&TestPeerLogicAsyncClient::on_read_final, this, + boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); +} + +void TestPeerLogicAsyncClient::on_read_final (error_code const& ec, std::size_t) +{ + if (ec == boost::asio::error::eof) + { + if (failure (socket ().shutdown (Socket::shutdown_both, error ()))) + return; + + if (failure (socket ().close (error ()))) + return; + } + else + { + // If we don't get eof, then there should be some other + // error in there. We don't expect the server to send more bytes! + // + unexpected (success (error (ec)), error ()); + } +} diff --git a/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicAsyncClient.h b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicAsyncClient.h new file mode 100644 index 0000000000..4d51301e23 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicAsyncClient.h @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_TESTPEERLOGICASYNCCLIENT_H_INCLUDED +#define BEAST_TESTPEERLOGICASYNCCLIENT_H_INCLUDED + +class TestPeerLogicAsyncClient : public TestPeerLogic +{ +public: + explicit TestPeerLogicAsyncClient (Socket& socket); + Role get_role () const noexcept; + Model get_model () const noexcept; + void on_connect_async (error_code const& ec); + void on_handshake (error_code const& ec); + void on_write (error_code const& ec, std::size_t bytes_transferred); + void on_read (error_code const& ec, std::size_t bytes_transferred); + void on_read_final (error_code const& ec, std::size_t); +private: + boost::asio::streambuf m_buf; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicAsyncServer.cpp b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicAsyncServer.cpp new file mode 100644 index 0000000000..ebf8985cb4 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicAsyncServer.cpp @@ -0,0 +1,104 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +TestPeerLogicAsyncServer::TestPeerLogicAsyncServer (Socket& socket) + : TestPeerLogic (socket) +{ +} + +TestPeerBasics::Role TestPeerLogicAsyncServer::get_role () const noexcept +{ + return Role::server; +} + +TestPeerBasics::Model TestPeerLogicAsyncServer::get_model () const noexcept +{ + return Model::async; +} + +void TestPeerLogicAsyncServer::on_connect_async (error_code const& ec) +{ + if (failure (error (ec))) + return; + + if (socket ().requires_handshake ()) + { + socket ().async_handshake (Socket::server, + boost::bind (&TestPeerLogicAsyncServer::on_handshake, this, + boost::asio::placeholders::error)); + } + else + { + on_handshake (ec); + } +} + +void TestPeerLogicAsyncServer::on_handshake (error_code const& ec) +{ + if (failure (error (ec))) + return; + + boost::asio::async_read_until (socket (), m_buf, std::string ("hello"), + boost::bind (&TestPeerLogicAsyncServer::on_read, this, + boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); +} + +void TestPeerLogicAsyncServer::on_read (error_code const& ec, std::size_t bytes_transferred) +{ + if (failure (error (ec))) + return; + + if (unexpected (bytes_transferred == 5, error ())) + return; + + boost::asio::async_write (socket (), boost::asio::buffer ("goodbye", 7), + boost::bind (&TestPeerLogicAsyncServer::on_write, this, + boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); +} + +void TestPeerLogicAsyncServer::on_write (error_code const& ec, std::size_t bytes_transferred) +{ + if (failure (error (ec))) + return; + + if (unexpected (bytes_transferred == 7, error ())) + return; + + if (socket ().requires_handshake ()) + { + socket ().async_shutdown (boost::bind (&TestPeerLogicAsyncServer::on_shutdown, this, + boost::asio::placeholders::error)); + } + else + { + // we need another instance of ec so we can call on_shutdown() + error_code ec; + on_shutdown (socket ().shutdown (Socket::shutdown_both, ec)); + } +} + +void TestPeerLogicAsyncServer::on_shutdown (error_code const& ec) +{ + if (failure (error (ec), true)) + return; + + if (failure (socket ().close (error ()))) + return; +} + diff --git a/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicAsyncServer.h b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicAsyncServer.h new file mode 100644 index 0000000000..0b0d8e7f35 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicAsyncServer.h @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_TESTPEERLOGICASYNCSERVER_H_INCLUDED +#define BEAST_TESTPEERLOGICASYNCSERVER_H_INCLUDED + +class TestPeerLogicAsyncServer : public TestPeerLogic +{ +public: + explicit TestPeerLogicAsyncServer (Socket& socket); + Role get_role () const noexcept; + Model get_model () const noexcept; + void on_connect_async (error_code const& ec); + void on_handshake (error_code const& ec); + void on_read (error_code const& ec, std::size_t bytes_transferred); + void on_write (error_code const& ec, std::size_t bytes_transferred); + void on_shutdown (error_code const& ec); +private: + boost::asio::streambuf m_buf; +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicSyncClient.cpp b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicSyncClient.cpp new file mode 100644 index 0000000000..efcaf6558f --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicSyncClient.cpp @@ -0,0 +1,97 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +TestPeerLogicSyncClient::TestPeerLogicSyncClient (Socket& socket) + : TestPeerLogic (socket) +{ +} + +TestPeerBasics::Role TestPeerLogicSyncClient::get_role () const noexcept +{ + return Role::client; +} + +TestPeerBasics::Model TestPeerLogicSyncClient::get_model () const noexcept +{ + return Model::sync; +} + +void TestPeerLogicSyncClient::on_connect () +{ + if (socket ().requires_handshake ()) + { + if (failure (socket ().handshake (get_role (), error ()))) + return; + } + + { + std::size_t const amount = boost::asio::write ( + socket (), boost::asio::buffer ("hello", 5), error ()); + + if (failure (error ())) + return; + + if (unexpected (amount == 5, error ())) + return; + } + + { + char data [7]; + + size_t const amount = boost::asio::read ( + socket (), boost::asio::buffer (data, 7), error ()); + + if (failure (error ())) + return; + + if (unexpected (amount == 7, error ())) + return; + + if (unexpected (memcmp (&data, "goodbye", 7) == 0, error ())) + return; + } + + // Wait for 1 byte which should never come. Instead, + // the server should close its end and we will get eof + { + char data [1]; + boost::asio::read (socket (), boost::asio::buffer (data, 1), error ()); + + if (error () == boost::asio::error::eof) + { + error () = error_code (); + } + else if (unexpected (failure (error ()), error ())) + { + return; + } + } + + if (socket ().requires_handshake ()) + { + if (failure (socket ().shutdown (error ()), true)) + return; + } + + if (failure (socket ().shutdown (Socket::shutdown_both, error ()))) + return; + + if (failure (socket ().close (error ()))) + return; +} diff --git a/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicSyncClient.h b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicSyncClient.h new file mode 100644 index 0000000000..ca0624ffa1 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicSyncClient.h @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_TESTPEERLOGICSYNCCLIENT_H_INCLUDED +#define BEAST_TESTPEERLOGICSYNCCLIENT_H_INCLUDED + +class TestPeerLogicSyncClient : public TestPeerLogic +{ +public: + explicit TestPeerLogicSyncClient (Socket& socket); + Role get_role () const noexcept; + Model get_model () const noexcept; + void on_connect (); +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicSyncServer.cpp b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicSyncServer.cpp new file mode 100644 index 0000000000..7be6335d68 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicSyncServer.cpp @@ -0,0 +1,80 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +TestPeerLogicSyncServer::TestPeerLogicSyncServer (Socket& socket) + : TestPeerLogic (socket) +{ +} + +TestPeerBasics::Role TestPeerLogicSyncServer::get_role () const noexcept +{ + return Role::server; +} + +TestPeerBasics::Model TestPeerLogicSyncServer::get_model () const noexcept +{ + return Model::sync; +} + +void TestPeerLogicSyncServer::on_connect () +{ + if (socket ().requires_handshake ()) + { + if (failure (socket ().handshake (get_role (), error ()))) + return; + } + + { + boost::asio::streambuf buf (5); + std::size_t const amount = boost::asio::read_until ( + socket (), buf, "hello", error ()); + + if (failure (error ())) + return; + + if (unexpected (amount == 5, error ())) + return; + + if (unexpected (buf.size () == 5, error ())) + return; + } + + { + std::size_t const amount = boost::asio::write ( + socket (), boost::asio::buffer ("goodbye", 7), error ()); + + if (failure (error ())) + return; + + if (unexpected (amount == 7, error ())) + return; + } + + if (socket ().requires_handshake ()) + { + if (failure (socket ().shutdown (error ()), true)) + return; + } + + if (failure (socket ().shutdown (Socket::shutdown_both, error ()))) + return; + + if (failure (socket ().close (error ()))) + return; +} diff --git a/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicSyncServer.h b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicSyncServer.h new file mode 100644 index 0000000000..c198ea6f62 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerLogicSyncServer.h @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_TESTPEERLOGICSYNCSERVER_H_INCLUDED +#define BEAST_TESTPEERLOGICSYNCSERVER_H_INCLUDED + +class TestPeerLogicSyncServer : public TestPeerLogic +{ +public: + explicit TestPeerLogicSyncServer (Socket& socket); + Role get_role () const noexcept; + Model get_model () const noexcept; + void on_connect (); +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerTestType.h b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerTestType.h new file mode 100644 index 0000000000..e7763b2d58 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerTestType.h @@ -0,0 +1,119 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_TESTPEERTESTTYPE_H_INCLUDED +#define RIPPLE_TESTPEERTESTTYPE_H_INCLUDED + +/** Performs a test of two peers defined by template parameters. +*/ +class TestPeerTestType : public TestPeerTest +{ +public: + /** Test two peers and return the results. + */ + template + static Results run (Arg const& arg, int timeoutSeconds = defaultTimeoutSeconds) + { + Results results; + + results.name = Details::getArgName (arg); + + try + { + TestPeerType server (arg); + + results.name << " / " << server.name (); + + try + { + TestPeerType client (arg); + + results.name << " / " << client.name (); + + try + { + server.start (); + + try + { + client.start (); + + boost::system::error_code const ec = + client.join (timeoutSeconds); + + results.client = Result (ec, client.name ()); + + try + { + boost::system::error_code const ec = + server.join (timeoutSeconds); + + results.server = Result (ec, server.name ()); + + } + catch (...) + { + results.server = Result (make_error ( + errc::exceptioned), server.name ()); + } + } + catch (...) + { + results.client = Result (make_error ( + errc::exceptioned), client.name ()); + } + } + catch (...) + { + results.server = Result (make_error ( + errc::exceptioned), server.name ()); + } + } + catch (...) + { + results.client = Result (make_error ( + errc::exceptioned), "client"); + } + } + catch (...) + { + results.server = Result (make_error ( + errc::exceptioned), "server"); + } + + return results; + } + + //-------------------------------------------------------------------------- + + /** Reports tests of Details against all known logic combinations to a UnitTest. + */ + template + static void test (UnitTest& test, Arg const& arg, + int timeoutSeconds = defaultTimeoutSeconds, + bool beginTestCase = true) + { + run (arg, timeoutSeconds).report (test, beginTestCase); + run (arg, timeoutSeconds).report (test, beginTestCase); + run (arg, timeoutSeconds).report (test, beginTestCase); + run (arg, timeoutSeconds).report (test, beginTestCase); + } +}; + +#endif diff --git a/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerType.h b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerType.h new file mode 100644 index 0000000000..cbef2f81a8 --- /dev/null +++ b/Subtrees/beast/modules/beast_asio/tests/detail/beast_TestPeerType.h @@ -0,0 +1,176 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_TESTPEERTYPE_H_INCLUDED +#define BEAST_TESTPEERTYPE_H_INCLUDED + +template +class TestPeerType + : public DetailsType + , public Logic + , public TestPeer + , public Thread +{ +public: + typedef typename DetailsType::arg_type arg_type; + typedef TestPeerType ThisType; + + TestPeerType (arg_type const& arg) + : DetailsType (arg) + , Logic (get_socket ()) + , Thread (name ()) + { + } + + ~TestPeerType () + { + } + + String name () const + { + return get_model ().name () + "_" + get_role ().name (); + } + + void start () + { + startThread (); + } + + boost::system::error_code join (int timeoutSeconds) + { + if (! wait (timeoutSeconds * 1000)) + { + stopThread (0); + return error (make_error (errc::timeout)); + } + + return error (); + } + + //-------------------------------------------------------------------------- + + void run () + { + if (get_model () == Model::async) + { + if (get_role () == Role::server) + { + run_async_server (); + } + else if (get_role () == Role::client) + { + run_async_client (); + } + else + { + error () = make_error (errc::unexpected); + } + } + else if (get_model () == Model::sync) + { + if (get_role () == Role::server) + { + run_sync_server (); + } + else if (get_role () == Role::client) + { + run_sync_client (); + } + else + { + error () = make_error (errc::unexpected); + } + } + else + { + error () = make_error (errc::unexpected); + } + + get_io_service ().run (); + + notify (); + } + + //-------------------------------------------------------------------------- + + void run_sync_server () + { + do_listen (); + + if (failure (error ())) + return; + + if (failure (get_acceptor ().accept (get_socket (), error ()))) + return; + + this->on_connect (); + + if (failure (error ())) + return ; + } + + void run_async_server () + { + do_listen (); + + if (failure (error ())) + return; + + get_acceptor ().async_accept (get_socket (), boost::bind ( + &Logic::on_connect_async, this, boost::asio::placeholders::error)); + } + + //-------------------------------------------------------------------------- + + void run_sync_client () + { + if (failure (get_native_socket ().connect (get_endpoint (get_role ()), error ()))) + return; + + this->on_connect (); + + if (failure (error ())) + return; + } + + void run_async_client () + { + get_native_socket ().async_connect (get_endpoint (get_role ()), + boost::bind (&Logic::on_connect_async, this, boost::asio::placeholders::error)); + } + + //-------------------------------------------------------------------------- + + void do_listen () + { + if (failure (get_native_acceptor ().open (get_endpoint (get_role ()).protocol (), error ()))) + return; + + if (failure (get_native_acceptor ().set_option (socket_type::reuse_address (true), error ()))) + return; + + if (failure (get_native_acceptor ().bind (get_endpoint (get_role ()), error ()))) + return; + + if (failure (get_native_acceptor ().listen (socket_type::max_connections, error ()))) + return; + } +}; + +#endif diff --git a/Subtrees/beast/modules/beast_core/diagnostic/beast_UnitTest.cpp b/Subtrees/beast/modules/beast_core/diagnostic/beast_UnitTest.cpp index 92c5b3291c..e9724d155b 100644 --- a/Subtrees/beast/modules/beast_core/diagnostic/beast_UnitTest.cpp +++ b/Subtrees/beast/modules/beast_core/diagnostic/beast_UnitTest.cpp @@ -129,16 +129,7 @@ bool UnitTest::expect (bool trueCondition, String const& failureMessage) bool UnitTest::unexpected (bool falseCondition, String const& failureMessage) { - if (! falseCondition) - { - pass (); - } - else - { - fail (failureMessage); - } - - return ! falseCondition; + return expect (! falseCondition, failureMessage); } void UnitTest::pass ()