New beast Socket, SharedHandler, ComposedAsyncOperation APIs

This commit is contained in:
Vinnie Falco
2013-08-21 17:07:21 -07:00
parent b09e975b4c
commit b4855b6ac9
27 changed files with 1753 additions and 2089 deletions

View File

@@ -9,6 +9,7 @@
<PreprocessorDefinitions>_CRTDBG_MAP_ALLOC;_WIN32_WINNT=0x0600;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup />

View File

@@ -142,4 +142,16 @@
#define BEAST_DISABLE_CONTRACT_CHECKS 0
#endif
//------------------------------------------------------------------------------
/** Config: BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES
Setting this option makes Socket-derived classes generate compile errors if
they forget any of the virtual overrides As some Socket-derived classes
intentionally omit member functions that are not applicable, this macro
should only be enabled temporarily when writing your own Socket-derived class,
to make sure that the function signatures match as expected.
*/
#define BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES 0
#endif

View File

@@ -69,7 +69,11 @@
<None Include="..\..\README.md" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\modules\beast_asio\basics\beast_HandlerCall.h" />
<ClInclude Include="..\..\modules\beast_asio\async\beast_ComposedAsyncOperation.h" />
<ClInclude Include="..\..\modules\beast_asio\async\beast_SharedHandler.h" />
<ClInclude Include="..\..\modules\beast_asio\async\beast_SharedHandlerAllocator.h" />
<ClInclude Include="..\..\modules\beast_asio\async\beast_SharedHandlerPtr.h" />
<ClInclude Include="..\..\modules\beast_asio\async\beast_SharedHandlerType.h" />
<ClInclude Include="..\..\modules\beast_asio\basics\beast_BufferType.h" />
<ClInclude Include="..\..\modules\beast_asio\basics\beast_FixedInputBuffer.h" />
<ClInclude Include="..\..\modules\beast_asio\basics\beast_PeerRole.h" />
@@ -78,13 +82,13 @@
<ClInclude Include="..\..\modules\beast_asio\handshake\beast_HandshakeDetectLogicPROXY.h" />
<ClInclude Include="..\..\modules\beast_asio\handshake\beast_HandshakeDetectLogicSSL2.h" />
<ClInclude Include="..\..\modules\beast_asio\handshake\beast_HandshakeDetectLogicSSL3.h" />
<ClInclude Include="..\..\modules\beast_asio\handshake\beast_HandshakeDetectStream.h" />
<ClInclude Include="..\..\modules\beast_asio\handshake\beast_HandshakeDetector.h" />
<ClInclude Include="..\..\modules\beast_asio\handshake\beast_InputParser.h" />
<ClInclude Include="..\..\modules\beast_asio\handshake\beast_PrefilledReadStream.h" />
<ClInclude Include="..\..\modules\beast_asio\sockets\beast_Socket.h" />
<ClInclude Include="..\..\modules\beast_asio\sockets\beast_SocketBase.h" />
<ClInclude Include="..\..\modules\beast_asio\sockets\beast_SocketWrapper.h" />
<ClInclude Include="..\..\modules\beast_asio\sockets\beast_SslContext.h" />
<ClInclude Include="..\..\modules\beast_asio\streams\beast_PrefilledReadStream.h" />
<ClInclude Include="..\..\modules\beast_asio\system\beast_BoostIncludes.h" />
<ClInclude Include="..\..\modules\beast_asio\system\beast_OpenSSLIncludes.h" />
<ClInclude Include="..\..\modules\beast_asio\tests\beast_TestPeer.h" />
@@ -303,7 +307,7 @@
<ClInclude Include="BeastConfig.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\modules\beast_asio\basics\beast_HandlerCall.cpp">
<ClCompile Include="..\..\modules\beast_asio\async\beast_SharedHandler.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -340,6 +344,12 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\system\beast_BoostUnitTests.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\tests\beast_TestPeerLogic.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@@ -361,6 +371,8 @@
<ClCompile Include="..\..\modules\beast_asio\tests\beast_TestPeerLogicProxyClient.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\tests\beast_TestPeerLogicSyncClient.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>

View File

@@ -155,12 +155,12 @@
<Filter Include="beast_asio\basics">
<UniqueIdentifier>{ccdc0c8e-f77a-486e-ba2f-29c10ec97f18}</UniqueIdentifier>
</Filter>
<Filter Include="beast_asio\streams">
<UniqueIdentifier>{dfa79046-33ef-4653-a6f9-83954b76a10f}</UniqueIdentifier>
</Filter>
<Filter Include="beast_asio\handshake">
<UniqueIdentifier>{4856837a-fa72-4252-8e8f-a112c1dbb3d2}</UniqueIdentifier>
</Filter>
<Filter Include="beast_asio\async">
<UniqueIdentifier>{beb81776-4aad-401d-8826-81478dbbf30b}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\modules\beast_core\beast_core.h">
@@ -824,9 +824,6 @@
<ClInclude Include="..\..\modules\beast_core\memory\beast_ByteSwap.h">
<Filter>beast_core\memory</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\streams\beast_PrefilledReadStream.h">
<Filter>beast_asio\streams</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\handshake\beast_HandshakeDetectLogic.h">
<Filter>beast_asio\handshake</Filter>
</ClInclude>
@@ -839,24 +836,39 @@
<ClInclude Include="..\..\modules\beast_asio\handshake\beast_HandshakeDetectLogicSSL3.h">
<Filter>beast_asio\handshake</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\handshake\beast_HandshakeDetectStream.h">
<Filter>beast_asio\handshake</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\handshake\beast_HandshakeDetectLogicPROXY.h">
<Filter>beast_asio\handshake</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\basics\beast_HandlerCall.h">
<Filter>beast_asio\basics</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_core\memory\beast_ContainerDeletePolicy.h">
<Filter>beast_core\memory</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\handshake\beast_InputParser.h">
<Filter>beast_asio\sockets</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\system\beast_OpenSSLIncludes.h">
<Filter>beast_asio\system</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\handshake\beast_HandshakeDetector.h">
<Filter>beast_asio\handshake</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\handshake\beast_PrefilledReadStream.h">
<Filter>beast_asio\handshake</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\async\beast_ComposedAsyncOperation.h">
<Filter>beast_asio\async</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\async\beast_SharedHandler.h">
<Filter>beast_asio\async</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\async\beast_SharedHandlerAllocator.h">
<Filter>beast_asio\async</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\async\beast_SharedHandlerPtr.h">
<Filter>beast_asio\async</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\async\beast_SharedHandlerType.h">
<Filter>beast_asio\async</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_asio\handshake\beast_InputParser.h">
<Filter>beast_asio\handshake</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\modules\beast_core\beast_core.cpp">
@@ -1318,8 +1330,11 @@
<ClCompile Include="..\..\modules\beast_asio\handshake\beast_HandshakeDetectLogicPROXY.cpp">
<Filter>beast_asio\handshake</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\basics\beast_HandlerCall.cpp">
<Filter>beast_asio\basics</Filter>
<ClCompile Include="..\..\modules\beast_asio\system\beast_BoostUnitTests.cpp">
<Filter>beast_asio\system</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\beast_asio\async\beast_SharedHandler.cpp">
<Filter>beast_asio\async</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,100 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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_COMPOSEDASYNCOPERATION_H_INCLUDED
#define BEAST_COMPOSEDASYNCOPERATION_H_INCLUDED
/** Base class for creating composed asynchronous operations.
The composed operation will have its operator() overloads called with
the same context and execution safety guarantees as the original
SharedHandler.
*/
class ComposedAsyncOperation : public SharedHandler
{
protected:
/** Construct the composed operation.
The composed operation will execute in the context of the
SharedHandler. A reference to the SharedHandler is maintained
for the lifetime of the composed operation.
*/
ComposedAsyncOperation (std::size_t size, SharedHandlerPtr const& ptr)
: m_size (size)
, m_ptr (ptr)
{
// Illegal to do anything with handler here, because
// usually it hasn't been assigned by the derived class yet.
}
~ComposedAsyncOperation ()
{
}
void invoke (invoked_type& invoked)
{
boost_asio_handler_invoke_helpers::
invoke (invoked, *m_ptr);
}
void* allocate (std::size_t size)
{
return boost_asio_handler_alloc_helpers::
allocate (size, *m_ptr);
}
void deallocate (void* p, std::size_t size)
{
boost_asio_handler_alloc_helpers::
deallocate (p, size, *m_ptr);
}
/** Override this function as needed.
Usually you will logical-and your own continuation condition. In
the following example, isContinuing is a derived class member:
@code
bool derived::is_continuation ()
{
bool const ourResult = this->isContinuing ()
return ourResult || ComposedAsyncOperation <Handler>::is_contiation ();
}
@endcode
*/
bool is_continuation ()
{
#if BEAST_ASIO_HAS_CONTINUATION_HOOKS
return boost_asio_handler_cont_helpers::
is_continuation (*m_ptr);
#else
return false;
#endif
}
void destroy ()
{
delete this;
}
private:
std::size_t const m_size;
SharedHandlerPtr const m_ptr;
};
#endif

View File

@@ -0,0 +1,47 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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 SharedHandler::operator() ()
{
pure_virtual_called (__FILE__, __LINE__);
}
void SharedHandler::operator() (error_code const&)
{
pure_virtual_called (__FILE__, __LINE__);
}
void SharedHandler::operator() (error_code const&, std::size_t)
{
pure_virtual_called (__FILE__, __LINE__);
}
void SharedHandler::pure_virtual_called (char const* fileName, int lineNumber)
{
// These shouldn't be getting called. But since the object returned
// by most implementations of bind have operator() up to high arity
// levels, it is not generally possible to write a traits test that
// works in all scenarios for detecting a particular signature of a
// handler.
//
// We use Throw here so beast has a chance to dump the stack BEFORE
// the stack is unwound.
//
Throw (std::runtime_error ("pure virtual called"), fileName, lineNumber);
}

View File

@@ -0,0 +1,134 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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_SHAREDHANDLER_H_INCLUDED
#define BEAST_SHAREDHANDLER_H_INCLUDED
template <typename T>
struct SharedHandlerAllocator;
/** Reference counted wrapper that can hold any other boost::asio handler.
This object will match these signatures:
@code
void (void)
void (system::error_code)
void (system::error_code, std::size_t)
@endcode
If the underlying implementation does not support the signature,
undefined behavior will result.
Supports these concepts:
Destructible
*/
class SharedHandler : public SharedObject
{
protected:
typedef boost::system::error_code error_code;
typedef boost::function <void(void)> invoked_type;
SharedHandler () noexcept { }
public:
// For asio::async_result<>
typedef void result_type;
typedef SharedObjectPtr <SharedHandler> Ptr;
virtual void operator() ();
virtual void operator() (error_code const&);
virtual void operator() (error_code const&, std::size_t);
/** Dispatch the Function on our context. */
/*
template <typename Dispatcher, typename Function>
void dispatch (Dispatcher& dispatcher, BOOST_ASIO_MOVE_ARG(Function) function)
{
dispatcher.dispatch (boost::bind (
&SharedHandler::invoke <Function>, this,
BOOST_ASIO_MOVE_CAST(Function)(function)));
}
*/
template <typename Function>
void invoke (BOOST_ASIO_MOVE_ARG(Function) f);
virtual void invoke (invoked_type& invoked) = 0;
virtual void* allocate (std::size_t size) = 0;
virtual void deallocate (void* p, std::size_t size) = 0;
virtual bool is_continuation () = 0;
virtual void destroy () = 0;
static void pure_virtual_called (char const* fileName, int lineNumber);
private:
template <typename Function>
friend void asio_handler_invoke (BOOST_ASIO_MOVE_ARG(Function) f, SharedHandler*);
friend void* asio_handler_allocate (std::size_t, SharedHandler*);
friend void asio_handler_deallocate (void*, std::size_t, SharedHandler*);
friend bool asio_handler_is_continuation (SharedHandler*);
friend struct ContainerDeletePolicy <SharedHandler>;
};
//--------------------------------------------------------------------------
// For SharedObjectPtr <SharedHandler>
template <>
struct ContainerDeletePolicy <SharedHandler>
{
// SharedObjectPtr will use this when
// the reference count drops to zero.
//
inline static void destroy (SharedHandler* handler)
{
handler->destroy ();
}
};
//--------------------------------------------------------------------------
//
// Context execution guarantees
//
template <class Function>
void asio_handler_invoke (BOOST_ASIO_MOVE_ARG(Function) f, SharedHandler* handler)
{
handler->invoke (BOOST_ASIO_MOVE_CAST(Function)(f));
}
inline void* asio_handler_allocate (std::size_t size, SharedHandler* handler)
{
return handler->allocate (size);
}
inline void asio_handler_deallocate (void* p, std::size_t size, SharedHandler* handler)
{
handler->deallocate (p, size);
}
inline bool asio_handler_is_continuation (SharedHandler* handler)
{
return handler->is_continuation ();
}
#endif

View File

@@ -0,0 +1,129 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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_SHAREDHANDLERALLOCATOR_H_INCLUDED
#define BEAST_SHAREDHANDLERALLOCATOR_H_INCLUDED
/** Custom Allocator using the allocation hooks from the Handler.
This class is compatible with std::allocator and can be used in any
boost interface which takes a template parameter of type Allocator.
This includes boost::function and especially boost::asio::streambuf
and relatives. This is vastly more efficient in a variety of situations
especially during an upcall and when using stackful coroutines.
The Allocator holds a reference to the underlying SharedHandler. The
SharedHandler will not be destroyed as long as any Allocator is still
using it.
*/
template <typename T>
struct SharedHandlerAllocator
{
typedef T value_type;
typedef T* pointer;
typedef T& reference;
typedef T const* const_pointer;
typedef T const& const_reference;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
SharedHandlerAllocator (SharedHandler* handler) noexcept
: m_ptr (handler)
{
}
SharedHandlerAllocator (SharedHandlerPtr const& handler) noexcept
: m_ptr (handler)
{
}
template <typename U>
SharedHandlerAllocator (SharedHandlerAllocator <U> const& other)
: m_ptr (other.m_ptr)
{
}
template <typename U>
struct rebind
{
typedef SharedHandlerAllocator <U> other;
};
pointer address (reference x) const
{
return &x;
}
const_pointer address (const_reference x) const
{
return &x;
}
pointer allocate (size_type n) const
{
size_type const bytes = n * sizeof (value_type);
return static_cast <pointer> (m_ptr->allocate (bytes));
}
void deallocate (pointer p, size_type n) const
{
size_type const bytes = n * sizeof (value_type);
m_ptr->deallocate (p, bytes);
}
size_type max_size () const noexcept
{
return std::numeric_limits <size_type>::max () / sizeof (value_type);
}
void construct (pointer p, const_reference val) const
{
::new ((void *)p) value_type (val);
}
void destroy (pointer p) const
{
p->~value_type ();
}
private:
template <typename>
friend struct SharedHandlerAllocator;
friend class SharedHandler;
SharedHandlerPtr m_ptr;
};
//------------------------------------------------------------------------------
template <typename Function>
void SharedHandler::invoke (BOOST_ASIO_MOVE_ARG(Function) f)
{
#if BEAST_USE_HANDLER_ALLOCATIONS
// The allocator will hold a reference to the SharedHandler
// so that we can safely destroy the function object.
invoked_type invoked (BOOST_ASIO_MOVE_CAST(Function)(f),
SharedHandlerAllocator <char> (this));
#else
invoked_type invoked (BOOST_ASIO_MOVE_CAST(Function)(f));
#endif
invoke (invoked);
}
#endif

View File

@@ -0,0 +1,307 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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_SHAREDHANDLERPTR_H_INCLUDED
#define BEAST_SHAREDHANDLERPTR_H_INCLUDED
/** RAII container for a SharedHandler.
This object behaves exactly like a SharedHandler except that it
merely contains a shared pointer to the underlying SharedHandler.
All calls are forwarded to the underlying SharedHandler, and all
of the execution safety guarantees are met by forwarding them through
to the underlying SharedHandler.
*/
class SharedHandlerPtr
{
protected:
typedef boost::system::error_code error_code;
public:
// For asio::async_result<>
typedef void result_type;
/** Construct a null handler.
A null handler cannot be called. It can, however, be checked
for validity by calling isNull, and later assigned.
@see isNull, isNotNull
*/
inline SharedHandlerPtr () noexcept
{
}
/** Construct from an existing SharedHandler.
Ownership of the handler is transferred to the container.
*/
inline SharedHandlerPtr (SharedHandler* handler)
: m_ptr (handler)
{
}
/** Construct a reference from an existing container.
*/
inline SharedHandlerPtr (SharedHandlerPtr const& other) noexcept
: m_ptr (other.m_ptr)
{
}
/** Assign a reference from an existing container. */
inline SharedHandlerPtr& operator= (SharedHandlerPtr const& other) noexcept
{
m_ptr = other.m_ptr;
return *this;
}
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
/** Move-construct a reference from an existing container.
The other container is set to a null handler.
*/
inline SharedHandlerPtr (SharedHandlerPtr&& other) noexcept
: m_ptr (other.m_ptr)
{
other.m_ptr = nullptr;
}
/** Move-assign a reference from an existing container.
The other container is set to a null handler.
*/
inline SharedHandlerPtr& operator= (SharedHandlerPtr&& other) noexcept
{
m_ptr = other.m_ptr;
other.m_ptr = nullptr;
return *this;
}
#endif
/** Returns true if the handler is a null handler. */
inline bool isNull () const noexcept
{
return m_ptr == nullptr;
}
/** Returns true if the handler is not a null handler. */
inline bool isNotNull () const noexcept
{
return m_ptr != nullptr;
}
/** Dereference the container.
This returns a reference to the underlying SharedHandler object.
*/
inline SharedHandler& operator* () const noexcept
{
return *m_ptr;
}
/** SharedHandler member access.
This lets you call functions directly on the SharedHandler.
*/
inline SharedHandler* operator-> () const noexcept
{
return m_ptr.get ();
}
/** Retrieve the SharedHandler as a Context.
This can be used for invoking functions in the context:
@code
template <Function>
void callOnHandler (Function f, SharedHandlerPtr ptr)
{
boost::asio_handler_invoke (f, ptr.get ());
}
@endcode
*/
inline SharedHandler* get () const noexcept
{
return m_ptr.get ();
}
/** Invoke the SharedHandler with signature void(void)
Normally this is called by a dispatcher, you shouldn't call it directly.
*/
inline void operator() () const
{
(*m_ptr)();
}
/** Invoke the SharedHandler with signature void(error_code)
Normally this is called by a dispatcher, you shouldn't call it directly.
*/
inline void operator() (error_code const& ec) const
{
(*m_ptr)(ec);
}
/** Invoke the SharedHandler with signature void(error_code, size_t)
Normally this is called by a dispatcher, you shouldn't call it directly.
*/
inline void operator() (error_code const& ec, std::size_t bytes_transferred) const
{
(*m_ptr)(ec, bytes_transferred);
}
private:
// These ensure that SharedHandlerPtr invocations adhere to
// the asio::io_service execution guarantees of the underlying SharedHandler.
//
template <typename Function>
friend void asio_handler_invoke (BOOST_ASIO_MOVE_ARG(Function) f, SharedHandlerPtr*);
friend void* asio_handler_allocate (std::size_t, SharedHandlerPtr*);
friend void asio_handler_deallocate (void*, std::size_t, SharedHandlerPtr*);
friend bool asio_handler_is_continuation (SharedHandlerPtr*);
SharedHandler::Ptr m_ptr;
};
//--------------------------------------------------------------------------
//
// Context execution guarantees
//
template <class Function>
inline void asio_handler_invoke (BOOST_ASIO_MOVE_ARG(Function) f, SharedHandlerPtr* ptr)
{
boost_asio_handler_invoke_helpers::
invoke <Function, SharedHandler>
(BOOST_ASIO_MOVE_CAST(Function)(f), *ptr->get ());
}
inline void* asio_handler_allocate (std::size_t size, SharedHandlerPtr* ptr)
{
return boost_asio_handler_alloc_helpers::
allocate <SharedHandler> (size, *ptr->get ());
}
inline void asio_handler_deallocate (void* p, std::size_t size, SharedHandlerPtr* ptr)
{
boost_asio_handler_alloc_helpers::
deallocate <SharedHandler> (p, size, *ptr->get ());
}
inline bool asio_handler_is_continuation (SharedHandlerPtr* ptr)
{
#if BEAST_ASIO_HAS_CONTINUATION_HOOKS
return boost_asio_handler_cont_helpers::
is_continuation <SharedHandler> (*ptr->get ());
#else
return false;
#endif
}
//--------------------------------------------------------------------------
//
// Helpers
//
//--------------------------------------------------------------------------
// CompletionHandler
//
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/CompletionHandler.html
//
template <typename CompletionHandler>
SharedHandlerPtr newCompletionHandler (
BOOST_ASIO_MOVE_ARG(CompletionHandler) handler)
{
return newSharedHandlerContainer <PostSharedHandlerType> (
BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler));
}
// AcceptHandler
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/AcceptHandler.html
//
template <typename AcceptHandler>
SharedHandlerPtr newAcceptHandler (
BOOST_ASIO_MOVE_ARG(AcceptHandler) handler)
{
return newSharedHandlerContainer <ErrorSharedHandlerType> (
BOOST_ASIO_MOVE_CAST(AcceptHandler)(handler));
}
// ConnectHandler
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ConnectHandler.html
//
template <typename ConnectHandler>
SharedHandlerPtr newConnectHandler (
BOOST_ASIO_MOVE_ARG(ConnectHandler) handler)
{
return newSharedHandlerContainer <ErrorSharedHandlerType> (
BOOST_ASIO_MOVE_CAST(ConnectHandler)(handler));
}
// ShutdownHandler
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ShutdownHandler.html
//
template <typename ShutdownHandler>
SharedHandlerPtr newShutdownHandler(
BOOST_ASIO_MOVE_ARG(ShutdownHandler) handler)
{
return newSharedHandlerContainer <ErrorSharedHandlerType> (
BOOST_ASIO_MOVE_CAST(ShutdownHandler)(handler));
}
// HandshakeHandler
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/HandshakeHandler.html
//
template <typename HandshakeHandler>
SharedHandlerPtr newHandshakeHandler(
BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler)
{
return newSharedHandlerContainer <ErrorSharedHandlerType> (
BOOST_ASIO_MOVE_CAST(HandshakeHandler)(handler));
}
// ReadHandler
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ReadHandler.html
//
template <typename ReadHandler>
SharedHandlerPtr newReadHandler(
BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
{
return newSharedHandlerContainer <TransferSharedHandlerType> (
BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
}
// WriteHandler
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/WriteHandler.html
//
template <typename WriteHandler>
SharedHandlerPtr newWriteHandler(
BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
{
return newSharedHandlerContainer <TransferSharedHandlerType> (
BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
}
// BufferedHandshakeHandler
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/BufferedHandshakeHandler.html
//
template <typename BufferedHandshakeHandler>
SharedHandlerPtr newBufferedHandshakeHandler(
BOOST_ASIO_MOVE_ARG(BufferedHandshakeHandler) handler)
{
return newSharedHandlerContainer <TransferSharedHandlerType> (
BOOST_ASIO_MOVE_CAST(BufferedHandshakeHandler)(handler));
}
#endif

View File

@@ -0,0 +1,233 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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_SHAREDHANDLERTYPE_H_INCLUDED
#define BEAST_SHAREDHANDLERTYPE_H_INCLUDED
/** An instance of SharedHandler that wraps an existing Handler.
The wrapped handler will meet all the execution guarantees of
the original Handler object.
*/
template <typename Handler>
class SharedHandlerType : public SharedHandler
{
protected:
SharedHandlerType (std::size_t size,
BOOST_ASIO_MOVE_ARG(Handler) handler)
: m_size (size)
, m_handler (BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
}
~SharedHandlerType ()
{
}
void invoke (invoked_type& invoked)
{
boost_asio_handler_invoke_helpers::
invoke <invoked_type, Handler> (invoked, m_handler);
}
void* allocate (std::size_t size)
{
return boost_asio_handler_alloc_helpers::
allocate <Handler> (size, m_handler);
}
void deallocate (void* p, std::size_t size)
{
boost_asio_handler_alloc_helpers::
deallocate <Handler> (p, size, m_handler);
}
bool is_continuation ()
{
#if BEAST_ASIO_HAS_CONTINUATION_HOOKS
return boost_asio_handler_cont_helpers::
is_continuation <Handler> (m_handler);
#else
return false;
#endif
}
// Called by our ContainerDeletePolicy hook to destroy the
// object. We need this because we allocated it using a custom
// allocator. Destruction is tricky, the algorithm is as follows:
//
// First we move-assign the handler to our stack. If the build
// doesn't support move-assignment it will be a copy, still ok.
// We convert 'this' to a pointer to the polymorphic base, to
// ensure that the following direct destructor call will reach
// the most derived class. Finally, we deallocate the memory
// using the handler that is local to the stack.
//
// For this to work we need to make sure regular operator delete
// is never called for our object (it's private). We also need
// the size from the original allocation, which we saved at
// the time of construction.
//
void destroy ()
{
#if BEAST_USE_HANDLER_ALLOCATIONS
Handler local (BOOST_ASIO_MOVE_CAST(Handler)(m_handler));
std::size_t const size (m_size);
SharedHandler* const shared (static_cast <SharedHandler*>(this));
shared->~SharedHandler ();
boost_asio_handler_alloc_helpers::
deallocate <Handler> (shared, size, local);
#else
delete this;
#endif
}
#if BEAST_USE_HANDLER_ALLOCATIONS
// If these somehow get called, bad things will happen
//
void* operator new (std::size_t)
{
return pure_virtual_called (__FILE__, __LINE__);
}
void operator delete (void*)
{
return pure_virtual_called (__FILE__, __LINE__);
}
#endif
protected:
std::size_t const m_size;
Handler m_handler;
};
//--------------------------------------------------------------------------
//
// A SharedHandlerType for this signature:
// void(void)
//
template <typename Handler>
class PostSharedHandlerType : public SharedHandlerType <Handler>
{
public:
PostSharedHandlerType (std::size_t size,
BOOST_ASIO_MOVE_ARG(Handler) handler)
: SharedHandlerType <Handler> (size,
BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
}
protected:
void operator() ()
{
this->m_handler ();
}
};
//--------------------------------------------------------------------------
//
// A SharedHandlerType for this signature:
// void(error_code)
//
template <typename Handler>
class ErrorSharedHandlerType : public SharedHandlerType <Handler>
{
public:
ErrorSharedHandlerType (std::size_t size,
BOOST_ASIO_MOVE_ARG(Handler) handler)
: SharedHandlerType <Handler> (size,
BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
}
protected:
void operator() (boost::system::error_code const& ec)
{
this->m_handler (ec);
}
};
//--------------------------------------------------------------------------
//
// A SharedHandlerType for this signature:
// void(error_code, size_t)
//
template <typename Handler>
class TransferSharedHandlerType : public SharedHandlerType <Handler>
{
public:
TransferSharedHandlerType (std::size_t size,
BOOST_ASIO_MOVE_ARG(Handler) handler)
: SharedHandlerType <Handler> (size,
BOOST_ASIO_MOVE_CAST(Handler)(handler))
{
}
protected:
void operator() (boost::system::error_code const& ec,
std::size_t bytes_transferred)
{
this->m_handler (ec, bytes_transferred);
}
};
//--------------------------------------------------------------------------
//
// These specializations will make sure we don't do
// anything silly like wrap ourselves in our own wrapper...
//
#if 1
template <>
class PostSharedHandlerType <SharedHandler>
{
};
template <>
class ErrorSharedHandlerType <SharedHandler>
{
};
template <>
class TransferSharedHandlerType <SharedHandler>
{
};
#endif
//--------------------------------------------------------------------------
/** Construct a wrapped handler using the context's allocation hooks.
*/
template <template <typename> class Container, typename Handler>
Container <Handler>* newSharedHandlerContainer (BOOST_ASIO_MOVE_ARG(Handler) handler)
{
typedef Container <Handler> ContainerType;
std::size_t const size (sizeof (ContainerType));
#if BEAST_USE_HANDLER_ALLOCATIONS
Handler local (BOOST_ASIO_MOVE_CAST(Handler)(handler));
void* const p (boost_asio_handler_alloc_helpers::
allocate <Handler> (size, local));
return ::new (p) ContainerType (size, BOOST_ASIO_MOVE_CAST(Handler)(local));
#else
void* const p = ::operator new (size);
return ::new (p) ContainerType (size, BOOST_ASIO_MOVE_CAST(Handler)(handler));
#endif
}
#endif

View File

@@ -34,21 +34,48 @@ public:
typedef Buffer value_type;
typedef typename std::vector <Buffer>::const_iterator const_iterator;
/** Construct a null buffer.
This is the equivalent of @ref asio::null_buffers.
*/
BufferType ()
: m_size (0)
{
}
template <class OtherBuffers>
explicit BufferType (OtherBuffers const& buffers)
: m_size (0)
/** Construct a BufferType from an existing BufferSequence.
@see assign
*/
template <class BufferSequence>
BufferType (BufferSequence const& buffers)
{
assign (buffers);
}
/** Assign a BufferType from an existing BufferSequence.
@see assign
*/
template <class BufferSequence>
BufferType <Buffer>& operator= (BufferSequence const& buffers)
{
return assign (buffers);
}
/** Assign a BufferType from an existing BufferSequence
A copy is not made. The data is still owned by the original
BufferSequence object. This merely points to that data.
*/
template <class BufferSequence>
BufferType <Buffer>& assign (BufferSequence const& buffers)
{
m_size = 0;
m_buffers.clear ();
m_buffers.reserve (std::distance (buffers.begin (), buffers.end ()));
BOOST_FOREACH (typename OtherBuffers::value_type buffer, buffers)
BOOST_FOREACH (typename BufferSequence::value_type buffer, buffers)
{
m_size += boost::asio::buffer_size (buffer);
m_buffers.push_back (buffer);
}
return *this;
}
/** Determine the total size of all buffers.
@@ -91,7 +118,10 @@ private:
std::vector <Buffer> m_buffers;
};
/** A single linear read-only buffer. */
typedef boost::asio::const_buffer ConstBuffer;
/** A single linear writable buffer. */
typedef boost::asio::mutable_buffer MutableBuffer;
/** Meets the requirements of ConstBufferSequence */

View File

@@ -1,345 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
//
// Context
//
//------------------------------------------------------------------------------
HandlerCall::Context::Context (Call* call) noexcept
: m_call (call)
{
bassert (m_call != nullptr);
}
HandlerCall::Context::Context () noexcept
: m_call (nullptr)
{
}
HandlerCall::Context::Context (Context const& other) noexcept
: m_call (other.m_call)
{
}
HandlerCall::Context::Context (HandlerCall const& handler) noexcept
: m_call (handler.m_call.get ())
{
}
HandlerCall::Context& HandlerCall::Context::operator= (Context other) noexcept
{
m_call = other.m_call;
return *this;
}
bool HandlerCall::Context::operator== (Call const* call) const noexcept
{
return m_call == call;
}
bool HandlerCall::Context::operator!= (Call const* call) const noexcept
{
return m_call != call;
}
bool HandlerCall::Context::isComposed () const noexcept
{
return m_call->is_continuation ();
}
bool HandlerCall::Context::isNull () const noexcept
{
return m_call == nullptr;
}
bool HandlerCall::Context::isNotNull () const noexcept
{
return m_call != nullptr;
}
bool HandlerCall::Context::operator== (Context other) const noexcept
{
return m_call == other.m_call;
}
bool HandlerCall::Context::operator!= (Context other) const noexcept
{
return m_call != other.m_call;
}
void* HandlerCall::Context::allocate (std::size_t size) const
{
return m_call->allocate (size);
}
void HandlerCall::Context::deallocate (void* p, std::size_t size) const
{
m_call->deallocate (p, size);
}
//------------------------------------------------------------------------------
//
// Call
//
//------------------------------------------------------------------------------
HandlerCall::Call::Call (Context context) noexcept
: m_context (context.isNull () ? Context (this) : context)
, m_is_continuation (false)
, m_is_final_continuation (false)
{
}
HandlerCall::Call::~Call ()
{
}
HandlerCall::Context HandlerCall::Call::getContext () const noexcept
{
return m_context;
}
bool HandlerCall::Call::is_continuation () const noexcept
{
// If this goes off it means someone isn't calling getContext()!
bassert (m_context == this);
return m_is_continuation;
}
void HandlerCall::Call::set_continuation () noexcept
{
// Setting it twice means some code is sloppy!
bassert (! m_is_continuation);
m_is_continuation = true;
}
void HandlerCall::Call::set_final_continuation () noexcept
{
// Soemone called endComposed without calling beginComposed!
bassert (m_is_continuation);
// When true, we will clear
// m_is_continuation on our next completion
m_is_final_continuation = true;
}
void HandlerCall::Call::check_continuation () noexcept
{
if (m_is_final_continuation)
{
bassert (m_is_continuation);
m_is_continuation = false;
m_is_final_continuation = false;
}
}
void HandlerCall::Call::operator() ()
{
check_continuation ();
dispatch ();
}
void HandlerCall::Call::operator() (error_code const& ec)
{
check_continuation ();
dispatch (ec);
}
void HandlerCall::Call::operator() (error_code const& ec, std::size_t bytes_transferred)
{
check_continuation ();
dispatch (ec, bytes_transferred);
}
void HandlerCall::Call::dispatch ()
{
pure_virtual_called ();
}
void HandlerCall::Call::dispatch (error_code const&)
{
pure_virtual_called ();
}
void HandlerCall::Call::dispatch (error_code const&, std::size_t)
{
pure_virtual_called ();
}
void* HandlerCall::Call::pure_virtual_called ()
{
// These shouldn't be getting called. But since the object returned
// by most implementations of bind have operator() up to high arity
// levels, it is not generally possible to write a traits test that
// works in all scenarios for detecting a particular signature of a
// handler.
//
fatal_error ("pure virtual called");
return nullptr;
}
//------------------------------------------------------------------------------
//
// HandlerCall
//
//------------------------------------------------------------------------------
HandlerCall::HandlerCall () noexcept
{
}
HandlerCall::HandlerCall (HandlerCall const& other) noexcept
: m_call (other.m_call)
{
}
HandlerCall& HandlerCall::operator= (HandlerCall const& other) noexcept
{
m_call = other.m_call;
return *this;
}
bool HandlerCall::isNull () const noexcept
{
return m_call == nullptr;
}
bool HandlerCall::isNotNull () const noexcept
{
return m_call != nullptr;
}
HandlerCall::Context HandlerCall::getContext () const noexcept
{
bassert (m_call != nullptr);
return m_call->getContext ();
}
bool HandlerCall::isFinal () const noexcept
{
return m_call->getContext () == m_call.get ();
}
HandlerCall const& HandlerCall::beginComposed () const noexcept
{
// If this goes off it means that your handler is
// already sharing a context with another handler!
// You have to call beginComposed on the original handler.
//
bassert (isFinal ());
m_call->set_continuation ();
return *this;
}
HandlerCall const& HandlerCall::endComposed () const noexcept
{
// If this goes off it means that your handler is
// already sharing a context with another handler!
// You have to call beginComposed on the original handler.
//
bassert (isFinal ());
m_call->set_final_continuation ();
return *this;
}
void HandlerCall::operator() () const
{
(*m_call)();
}
void HandlerCall::operator() (error_code const& ec) const
{
(*m_call)(ec);
}
void HandlerCall::operator() (error_code const& ec, std::size_t bytes_transferred) const
{
(*m_call)(ec, bytes_transferred);
}
//------------------------------------------------------------------------------
//
// Specializations
//
//------------------------------------------------------------------------------
void ContainerDeletePolicy <HandlerCall::Call>::destroy (HandlerCall::Call* call)
{
call->destroy ();
}
//------------------------------------------------------------------------------
void* asio_handler_allocate (std::size_t size, HandlerCall* call)
{
// Always go through the call's context.
return call->getContext ().allocate (size);
}
void* asio_handler_allocate (std::size_t size, HandlerCall::Call* call)
{
// Always go through the call's context.
return call->getContext ().allocate (size);
}
void* asio_handler_allocate (std::size_t size, HandlerCall::Context* context)
{
return context->allocate (size);
}
//------------------------------------------------------------------------------
void asio_handler_deallocate (void* p, std::size_t size, HandlerCall* call)
{
// Always go through the call's context.
call->getContext ().deallocate (p, size);
}
void asio_handler_deallocate (void* p, std::size_t size, HandlerCall::Call* call)
{
// Always go through the call's context.
call->getContext ().deallocate (p, size);
}
void asio_handler_deallocate (void* p, std::size_t size, HandlerCall::Context* context)
{
context->deallocate (p, size);
}
//------------------------------------------------------------------------------
bool asio_handler_is_continuation (HandlerCall* call)
{
return call->getContext().isComposed ();
}
bool asio_handler_is_continuation (HandlerCall::Call* call)
{
return call->getContext().isComposed ();
}
bool asio_handler_is_continuation (HandlerCall::Context*)
{
// Something is horribly wrong if we're trying to
// use a Context as a completion handler?
//
fatal_error ("A function was unexpectedly called.");
return false;
}

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,8 @@
namespace beast
{
#include "basics/beast_HandlerCall.cpp"
#include "async/beast_SharedHandler.cpp"
#include "basics/beast_PeerRole.cpp"
#include "sockets/beast_SocketBase.cpp"
@@ -35,6 +36,7 @@ namespace beast
#include "handshake/beast_HandshakeDetectLogicPROXY.cpp"
#include "tests/beast_PeerTest.cpp"
#include "tests/beast_TestPeerBasics.cpp"
#include "tests/beast_TestPeerLogic.cpp"
#include "tests/beast_TestPeerLogicProxyClient.cpp"
@@ -42,8 +44,8 @@ namespace beast
#include "tests/beast_TestPeerLogicSyncClient.cpp"
#include "tests/beast_TestPeerLogicAsyncServer.cpp"
#include "tests/beast_TestPeerLogicAsyncClient.cpp"
#include "tests/beast_PeerTest.cpp"
#include "tests/beast_TestPeerUnitTests.cpp"
#include "system/beast_BoostUnitTests.cpp"
}

View File

@@ -40,15 +40,36 @@
// Must come before boost includes to fix the bost placeholders.
#include "../beast_core/beast_core.h"
/* This module requires boost and possibly OpenSSL */
// This module requires boost and possibly OpenSSL
#include "system/beast_BoostIncludes.h"
// Checking overrides replaces unimplemented stubs with pure virtuals
#ifndef BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES
# define BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES 0
#endif
#if BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES
# define BEAST_SOCKET_VIRTUAL = 0
#else
# define BEAST_SOCKET_VIRTUAL
#endif
// A potentially dangerous but powerful feature which
// might need to be turned off to see if it fixes anything.
//
#ifndef BEAST_USE_HANDLER_ALLOCATIONS
# define BEAST_USE_HANDLER_ALLOCATIONS 1
#endif
namespace beast
{
// Order matters
#include "async/beast_SharedHandler.h"
#include "async/beast_SharedHandlerType.h"
#include "async/beast_SharedHandlerPtr.h"
#include "async/beast_ComposedAsyncOperation.h"
#include "async/beast_SharedHandlerAllocator.h"
#include "basics/beast_HandlerCall.h"
#include "basics/beast_BufferType.h"
#include "basics/beast_FixedInputBuffer.h"
#include "basics/beast_PeerRole.h"
@@ -63,9 +84,8 @@ namespace beast
#include "handshake/beast_HandshakeDetectLogicPROXY.h"
#include "handshake/beast_HandshakeDetectLogicSSL2.h"
#include "handshake/beast_HandshakeDetectLogicSSL3.h"
#include "handshake/beast_HandshakeDetectStream.h"
#include "streams/beast_PrefilledReadStream.h"
#include "handshake/beast_HandshakeDetector.h"
#include "handshake/beast_PrefilledReadStream.h"
#include "tests/beast_TestPeerBasics.h"
#include "tests/beast_TestPeer.h"

View File

@@ -1,293 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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_HANDSHAKEDETECTSTREAM_H_INCLUDED
#define BEAST_HANDSHAKEDETECTSTREAM_H_INCLUDED
/** A stream that can detect a handshake.
*/
/** @{ */
template <class Logic>
class HandshakeDetectStream
{
protected:
typedef boost::system::error_code error_code;
public:
typedef Logic LogicType;
/** Called when the state is known.
This could be called from any thread, most likely an io_service
thread but don't rely on that.
The Callback must be allocated via operator new.
*/
struct Callback
{
virtual ~Callback () { }
/** Called for synchronous ssl detection.
Note that the storage for the buffers passed to the
callback is owned by the detector class and becomes
invalid when the detector class is destroyed, which is
a common thing to do from inside your callback.
@param ec A modifiable error code that becomes the return
value of handshake.
@param buffers The bytes that were read in.
@param is_ssl True if the sequence is an ssl handshake.
*/
virtual void on_detect (Logic& logic,
error_code& ec, ConstBuffers const& buffers) = 0;
virtual void on_async_detect (Logic& logic,
error_code const& ec, ConstBuffers const& buffers,
HandlerCall const& origHandler) = 0;
};
};
//------------------------------------------------------------------------------
template <typename Stream, typename Logic>
class HandshakeDetectStreamType
: public HandshakeDetectStream <Logic>
, public boost::asio::ssl::stream_base
, public boost::asio::socket_base
{
private:
typedef boost::system::error_code error_code;
typedef HandshakeDetectStreamType <Stream, Logic> this_type;
typedef boost::asio::streambuf buffer_type;
typedef typename boost::remove_reference <Stream>::type stream_type;
public:
typedef typename HandshakeDetectStream <Logic>::Callback CallbackType;
/** This takes ownership of the callback.
The callback must be allocated with operator new.
*/
template <typename Arg>
HandshakeDetectStreamType (CallbackType* callback, Arg& arg)
: m_callback (callback)
, m_next_layer (arg)
, m_stream (m_next_layer)
{
}
// This puts bytes that you already have into the detector buffer
// Any leftovers will be given to the callback.
// A copy of the data is made.
//
template <typename ConstBufferSequence>
void fill (ConstBufferSequence const& buffers)
{
m_buffer.commit (boost::asio::buffer_copy (
m_buffer.prepare (boost::asio::buffer_size (buffers)),
buffers));
}
// basic_io_object
boost::asio::io_service& get_io_service ()
{
return m_next_layer.get_io_service ();
}
// basic_socket
typedef typename stream_type::protocol_type protocol_type;
typedef typename stream_type::lowest_layer_type lowest_layer_type;
lowest_layer_type& lowest_layer ()
{
return m_next_layer.lowest_layer ();
}
lowest_layer_type const& lowest_layer () const
{
return m_next_layer.lowest_layer ();
}
// ssl::stream
error_code handshake (handshake_type type, error_code& ec)
{
return do_handshake (type, ec, ConstBuffers ());
}
template <typename HandshakeHandler>
BEAST_ASIO_INITFN_RESULT_TYPE(HandshakeHandler, void (error_code))
async_handshake (handshake_type type, BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
HandshakeHandler, void (error_code)> init(
BOOST_ASIO_MOVE_CAST(HandshakeHandler)(handler));
// init.handler is copied
m_origHandler = HandlerCall (
BOOST_ASIO_MOVE_CAST(HandshakeHandler)
(HandshakeHandler(init.handler)));
async_do_handshake (type, ConstBuffers ());
return init.result.get();
#else
m_origHandler = HandlerCall (
BOOST_ASIO_MOVE_CAST(HandshakeHandler)(handler));
async_do_handshake (type, ConstBuffers ());
#endif
}
//--------------------------------------------------------------------------
error_code do_handshake (handshake_type, error_code& ec, ConstBuffers const& buffers)
{
ec = error_code ();
// Transfer caller data to our buffer.
m_buffer.commit (boost::asio::buffer_copy (m_buffer.prepare (
boost::asio::buffer_size (buffers)), buffers));
do
{
std::size_t const available = m_buffer.size ();
std::size_t const needed = m_logic.max_needed ();
if (available < needed)
{
buffer_type::mutable_buffers_type buffers (
m_buffer.prepare (needed - available));
m_buffer.commit (m_next_layer.read_some (buffers, ec));
}
if (! ec)
{
m_logic.analyze (m_buffer.data ());
if (m_logic.finished ())
{
// consume what we used (for SSL its 0)
std::size_t const consumed = m_logic.bytes_consumed ();
bassert (consumed <= m_buffer.size ());
m_buffer.consume (consumed);
m_callback->on_detect (m_logic.get (), ec,
ConstBuffers (m_buffer.data ()));
break;
}
// If this fails it means we will never finish
check_postcondition (available < needed);
}
}
while (! ec);
return ec;
}
//--------------------------------------------------------------------------
void async_do_handshake (handshake_type type, ConstBuffers const& buffers)
{
// Get the execution context from the original handler
// and signal the beginning of our composed operation.
//
//m_origHandler.beginComposed ();
m_context = m_origHandler.getContext ();
bassert (m_context.isNotNull ());
// Transfer caller data to our buffer.
// We commit the bytes in on_async_read_some.
//
std::size_t const bytes_transferred (boost::asio::buffer_copy (
m_buffer.prepare (boost::asio::buffer_size (buffers)), buffers));
// bootstrap the asynchronous loop
on_async_read_some (error_code (), bytes_transferred);
}
// asynchronous version of the synchronous loop found in handshake ()
//
void on_async_read_some (error_code const& ec, std::size_t bytes_transferred)
{
if (! ec)
{
m_buffer.commit (bytes_transferred);
std::size_t const available = m_buffer.size ();
std::size_t const needed = m_logic.max_needed ();
if (bytes_transferred > 0)
m_logic.analyze (m_buffer.data ());
if (m_logic.finished ())
{
// consume what we used (for SSL its 0)
std::size_t const consumed = m_logic.bytes_consumed ();
bassert (consumed <= m_buffer.size ());
m_buffer.consume (consumed);
// The composed operation has completed and
// the original handler will eventually get called.
//
//m_origHandler.endComposed ();
m_callback->on_async_detect (m_logic.get (), ec,
ConstBuffers (m_buffer.data ()), m_origHandler);
return;
}
// If this fails it means we will never finish
check_postcondition (available < needed);
buffer_type::mutable_buffers_type buffers (m_buffer.prepare (
needed - available));
// Perform the asynchronous operation using the context
// of the original handler. This ensures that we meet the
// execution safety requirements of the handler.
//
HandlerCall handler (HandlerCall::Read (), m_context,
boost::bind (&this_type::on_async_read_some, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
m_next_layer.async_read_some (buffers, handler);
return;
}
// Error condition
//m_origHandler.endComposed ();
m_callback->on_async_detect (m_logic.get (), ec,
ConstBuffers (m_buffer.data ()), m_origHandler);
}
private:
ScopedPointer <CallbackType> m_callback;
Stream m_next_layer;
buffer_type m_buffer;
boost::asio::buffered_read_stream <stream_type&> m_stream;
HandshakeDetectLogicType <Logic> m_logic;
HandlerCall m_origHandler;
HandlerCall m_origBufferedHandler;
HandlerCall::Context m_context;
};
/** @} */
#endif

View File

@@ -0,0 +1,206 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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_HANDSHAKEDETECTOR_H_INCLUDED
#define BEAST_HANDSHAKEDETECTOR_H_INCLUDED
//------------------------------------------------------------------------------
/** A wrapper to decode the handshake data on a Stream.
Stream must meet these requirements
For detect:
SyncReadStream
For async_detect:
AsyncReadStream
Logic must meet this requirement:
HandshakeDetectLogic
*/
template <typename Stream, typename Logic>
class HandshakeDetectorType
{
protected:
typedef boost::system::error_code error_code;
public:
Logic& getLogic ()
{
return m_logic.get ();
}
//--------------------------------------------------------------------------
/** Synchronous handshake detect.
The bytes from the input sequence in the specified buffer
are used first.
*/
template <typename Allocator>
error_code detect (Stream& stream,
boost::asio::basic_streambuf <Allocator>& buffer)
{
typedef boost::asio::basic_streambuf <Allocator> BufferType;
error_code ec;
do
{
m_logic.analyze (buffer.data ());
if (m_logic.finished ())
{
// consume what we used (for SSL its 0)
std::size_t const consumed = m_logic.bytes_consumed ();
bassert (consumed <= buffer.size ());
buffer.consume (consumed);
break;
}
std::size_t const available = buffer.size ();
std::size_t const needed = m_logic.max_needed ();
// If postcondition fails, loop will never end
if (meets_postcondition (available < needed))
{
typename BufferType::mutable_buffers_type buffers (
buffer.prepare (needed - available));
buffer.commit (stream.read_some (buffers, ec));
}
}
while (! ec);
return ec;
}
//--------------------------------------------------------------------------
/** Asynchronous handshake detect.
The bytes from the input sequence in the specified buffer
are used first.
DetectHandler must have this signature:
void(error_code)
*/
template <typename DetectHandler, typename Allocator>
void async_detect (Stream& stream,
boost::asio::basic_streambuf <Allocator>& buffer,
BOOST_ASIO_MOVE_ARG(DetectHandler) handler)
{
async_detect <Allocator> (stream, buffer, SharedHandlerPtr (
new ErrorSharedHandlerType <DetectHandler> (
BOOST_ASIO_MOVE_CAST(DetectHandler)(handler))));
}
template <typename Allocator>
void async_detect (Stream& stream,
boost::asio::basic_streambuf <Allocator>& buffer,
SharedHandlerPtr handler)
{
typedef AsyncOp <Allocator> OpType;
OpType* const op = new AsyncOp <Allocator> (
m_logic, stream, buffer, handler);
stream.get_io_service ().wrap (SharedHandlerPtr (op))
(error_code (), 0);
}
private:
template <typename Allocator>
struct AsyncOp : ComposedAsyncOperation
{
typedef boost::asio::basic_streambuf <Allocator> BufferType;
AsyncOp (HandshakeDetectLogicType <Logic>& logic, Stream& stream,
BufferType& buffer, SharedHandlerPtr const& handler)
: ComposedAsyncOperation (sizeof (*this), handler)
, m_logic (logic)
, m_stream (stream)
, m_buffer (buffer)
, m_handler (handler)
, m_running (false)
{
}
// Set breakpoint to prove it gets destroyed
~AsyncOp ()
{
}
void operator() (error_code const& ec_, size_t bytes_transferred)
{
m_running = true;
error_code ec (ec_);
if (! ec)
{
m_buffer.commit (bytes_transferred);
m_logic.analyze (m_buffer.data ());
if (!m_logic.finished ())
{
std::size_t const available = m_buffer.size ();
std::size_t const needed = m_logic.max_needed ();
// If postcondition fails, loop will never end
if (meets_postcondition (available < needed))
{
typename BufferType::mutable_buffers_type buffers (
m_buffer.prepare (needed - available));
m_stream.async_read_some (buffers, SharedHandlerPtr (this));
}
return;
}
std::size_t const consumed = m_logic.bytes_consumed ();
m_buffer.consume (consumed);
}
// Finalize with a call to the original handler.
m_stream.get_io_service ().wrap (
BOOST_ASIO_MOVE_CAST (SharedHandlerPtr)(m_handler))
(ec);
}
bool is_continuation ()
{
return m_running
#if BEAST_ASIO_HAS_CONTINUATION_HOOKS
|| boost_asio_handler_cont_helpers::is_continuation (m_handler);
#endif
;
}
private:
HandshakeDetectLogicType <Logic>& m_logic;
Stream& m_stream;
BufferType& m_buffer;
SharedHandlerPtr m_handler;
bool m_running;
};
private:
HandshakeDetectLogicType <Logic> m_logic;
};
#endif

View File

@@ -72,10 +72,10 @@ public:
template <typename ConstBufferSequence>
void fill (ConstBufferSequence const& buffers)
{
using namespace boost;
// We don't assume the caller's buffers will
// remain valid for the lifetime of this object.
//
using namespace boost;
m_buffer.commit (asio::buffer_copy (
m_buffer.prepare (asio::buffer_size (buffers)),
buffers));
@@ -116,76 +116,6 @@ public:
return m_next_layer.close(ec);
}
template <typename ConstBufferSequence>
std::size_t write_some (ConstBufferSequence const& buffers)
{
return m_next_layer.write_some (buffers);
}
template <typename ConstBufferSequence>
std::size_t write_some (ConstBufferSequence const& buffers, error_code& ec)
{
return m_next_layer.write_some (buffers, ec);
}
template <typename MutableBufferSequence>
std::size_t read_some (MutableBufferSequence const& buffers, error_code& ec)
{
ec = error_code ();
if (m_buffer.size () > 0)
{
std::size_t const bytes_transferred = boost::asio::buffer_copy (
buffers, m_buffer.data ());
m_buffer.consume (bytes_transferred);
return bytes_transferred;
}
return m_next_layer.read_some (buffers, ec);
}
template <typename MutableBufferSequence, typename ReadHandler>
BEAST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (error_code, std::size_t))
async_read_some (MutableBufferSequence const& buffers,
BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
{
using namespace boost;
if (m_buffer.size () > 0)
{
std::size_t const bytes_transferred = asio::buffer_copy (
buffers, m_buffer.data ());
m_buffer.consume (bytes_transferred);
#if BEAST_ASIO_HAS_FUTURE_RETURNS
asio::detail::async_result_init <
ReadHandler, void (error_code, std::size_t)> init (
BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
get_io_service ().post (HandlerCall (HandlerCall::Post (),
ReadHandler(init.handler), // handler is copied
error_code (), bytes_transferred));
return init.result.get();
#else
return get_io_service ().post (HandlerCall (HandlerCall::Post (),
BOOST_ASIO_MOVE_CAST(ReadHandler)(handler),
error_code (), bytes_transferred));
#endif
}
return m_next_layer.async_read_some (buffers,
BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
}
template <typename ConstBufferSequence, typename WriteHandler>
BEAST_ASIO_INITFN_RESULT_TYPE(WriteHandler, void (error_code, std::size_t))
async_write_some (ConstBufferSequence const& buffers,
BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
{
return m_next_layer.async_write_some (buffers,
BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
}
template <typename MutableBufferSequence>
std::size_t read_some (MutableBufferSequence const& buffers)
{
@@ -196,6 +126,62 @@ public:
return amount;
}
template <typename MutableBufferSequence>
std::size_t read_some (MutableBufferSequence const& buffers, error_code& ec)
{
if (m_buffer.size () > 0)
{
ec = error_code ();
std::size_t const bytes_transferred = boost::asio::buffer_copy (
buffers, m_buffer.data ());
m_buffer.consume (bytes_transferred);
return bytes_transferred;
}
return m_next_layer.read_some (buffers, ec);
}
template <typename ConstBufferSequence>
std::size_t write_some (ConstBufferSequence const& buffers)
{
error_code ec;
std::size_t const amount = write_some (buffers, ec);
if (ec)
throw_error (ec, __FILE__, __LINE__);
return amount;
}
template <typename ConstBufferSequence>
std::size_t write_some (ConstBufferSequence const& buffers, error_code& ec)
{
return m_next_layer.write_some (buffers, ec);
}
template <typename MutableBufferSequence, typename ReadHandler>
void async_read_some (MutableBufferSequence const& buffers,
BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
{
if (m_buffer.size () > 0)
{
std::size_t const bytes_transferred = boost::asio::buffer_copy (
buffers, m_buffer.data ());
m_buffer.consume (bytes_transferred);
get_io_service ().wrap (
BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) (
error_code (), bytes_transferred);
return;
}
m_next_layer.async_read_some (buffers,
BOOST_ASIO_MOVE_CAST(ReadHandler)(handler));
}
template <typename ConstBufferSequence, typename WriteHandler>
void async_write_some (ConstBufferSequence const& buffers,
BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
{
m_next_layer.async_write_some (buffers,
BOOST_ASIO_MOVE_CAST(WriteHandler)(handler));
}
private:
Stream m_next_layer;
boost::asio::streambuf m_buffer;

View File

@@ -21,6 +21,8 @@ Socket::~Socket ()
{
}
#if ! BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES
//-----------------------------------------------------------------------------
//
// basic_io_object
@@ -28,7 +30,7 @@ Socket::~Socket ()
boost::asio::io_service& Socket::get_io_service ()
{
pure_virtual ();
pure_virtual_called (__FILE__, __LINE__);
return *static_cast <boost::asio::io_service*>(nullptr);
}
@@ -39,29 +41,29 @@ boost::asio::io_service& Socket::get_io_service ()
void* Socket::lowest_layer (char const*) const
{
pure_virtual ();
pure_virtual_called (__FILE__, __LINE__);
return nullptr;
}
void* Socket::native_handle (char const*) const
{
pure_virtual ();
pure_virtual_called (__FILE__, __LINE__);
return nullptr;
}
boost::system::error_code Socket::cancel (boost::system::error_code& ec)
{
return pure_virtual (ec);
return pure_virtual_error (ec, __FILE__, __LINE__);
}
boost::system::error_code Socket::shutdown (shutdown_type, boost::system::error_code& ec)
{
return pure_virtual (ec);
return pure_virtual_error (ec, __FILE__, __LINE__);
}
boost::system::error_code Socket::close (boost::system::error_code& ec)
{
return pure_virtual (ec);
return pure_virtual_error (ec, __FILE__, __LINE__);
}
//------------------------------------------------------------------------------
@@ -71,22 +73,14 @@ boost::system::error_code Socket::close (boost::system::error_code& ec)
boost::system::error_code Socket::accept (Socket&, boost::system::error_code& ec)
{
return pure_virtual (ec);
return pure_virtual_error (ec, __FILE__, __LINE__);
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (boost::system::error_code))
Socket::async_accept (Socket&, HandlerCall const& handler)
void Socket::async_accept (Socket&, SharedHandlerPtr handler)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
HandlerCall, void (boost::system::error_code)> init( handler);
get_io_service ().post (HandlerCall (HandlerCall::Post (),
handler, pure_virtual_error ()));
return init.result.get();
#else
get_io_service ().post (HandlerCall (HandlerCall::Post(),
handler, pure_virtual_error ()));
#endif
get_io_service ().wrap (
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
(pure_virtual_error ());
}
//------------------------------------------------------------------------------
@@ -96,44 +90,30 @@ Socket::async_accept (Socket&, HandlerCall const& handler)
std::size_t Socket::read_some (MutableBuffers const&, boost::system::error_code& ec)
{
pure_virtual (ec);
pure_virtual_called (__FILE__, __LINE__);
ec = pure_virtual_error ();
return 0;
}
std::size_t Socket::write_some (ConstBuffers const&, boost::system::error_code& ec)
{
pure_virtual (ec);
pure_virtual_called (__FILE__, __LINE__);
ec = pure_virtual_error ();
return 0;
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (boost::system::error_code, std::size_t))
Socket::async_read_some (MutableBuffers const&, HandlerCall const& handler)
void Socket::async_read_some (MutableBuffers const&, SharedHandlerPtr handler)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
HandlerCall, void (boost::system::error_code, std::size_t)> init(handler);
get_io_service ().post (HandlerCall (HandlerCall::Post (),
handler, pure_virtual_error (), 0));
return init.result.get();
#else
get_io_service ().post (HandlerCall (HandlerCall::Post (),
handler , pure_virtual_error (), 0));
#endif
get_io_service ().wrap (
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
(pure_virtual_error (), 0);
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (boost::system::error_code, std::size_t))
Socket::async_write_some (ConstBuffers const&, HandlerCall const& handler)
void Socket::async_write_some (ConstBuffers const&, SharedHandlerPtr handler)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
HandlerCall, void (boost::system::error_code, std::size_t)> init(handler);
get_io_service ().post (HandlerCall (HandlerCall::Post (),
handler, pure_virtual_error (), 0));
return init.result.get();
#else
get_io_service ().post (HandlerCall (HandlerCall::Post (),
handler, pure_virtual_error (), 0));
#endif
get_io_service ().wrap (
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
(pure_virtual_error (), 0);
}
//--------------------------------------------------------------------------
@@ -148,22 +128,14 @@ bool Socket::needs_handshake ()
boost::system::error_code Socket::handshake (handshake_type, boost::system::error_code& ec)
{
return pure_virtual (ec);
return pure_virtual_error (ec, __FILE__, __LINE__);
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (boost::system::error_code))
Socket::async_handshake (handshake_type, HandlerCall const& handler)
void Socket::async_handshake (handshake_type, SharedHandlerPtr handler)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
HandlerCall, void (boost::system::error_code)> init( handler);
get_io_service ().post (HandlerCall (HandlerCall::Post (),
handler, pure_virtual_error ()));
return init.result.get();
#else
get_io_service ().post (HandlerCall (HandlerCall::Post(),
handler, pure_virtual_error ()));
#endif
get_io_service ().wrap (
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
(pure_virtual_error ());
}
#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
@@ -171,44 +143,30 @@ Socket::async_handshake (handshake_type, HandlerCall const& handler)
boost::system::error_code Socket::handshake (handshake_type,
ConstBuffers const&, boost::system::error_code& ec)
{
return pure_virtual (ec);
return pure_virtual_error (ec, __FILE__, __LINE__);
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (boost::system::error_code, std::size_t))
Socket::async_handshake (handshake_type, ConstBuffers const&, HandlerCall const& handler)
void Socket::async_handshake (handshake_type, ConstBuffers const&, SharedHandlerPtr handler)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
HandlerCall, void (boost::system::error_code, std::size_t)> init(handler);
get_io_service ().post (HandlerCall (HandlerCall::Post (),
handler, pure_virtual_error (), 0));
return init.result.get();
#else
get_io_service ().post (HandlerCall (HandlerCall::Post (),
handler , pure_virtual_error (), 0));
#endif
get_io_service ().wrap (
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
(pure_virtual_error (), 0);
}
#endif
boost::system::error_code Socket::shutdown (boost::system::error_code& ec)
{
return pure_virtual (ec);
return pure_virtual_error (ec, __FILE__, __LINE__);
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (boost::system::error_code))
Socket::async_shutdown (HandlerCall const& handler)
void Socket::async_shutdown (SharedHandlerPtr handler)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
HandlerCall, void (boost::system::error_code, std::size_t)> init (handler);
get_io_service ().post (HandlerCall (HandlerCall::Post (),
handler, pure_virtual_error ()));
return init.result.get();
#else
get_io_service ().post (HandlerCall (HandlerCall::Post (),
handler , pure_virtual_error ()));
#endif
get_io_service ().wrap (
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
(pure_virtual_error ());
}
//------------------------------------------------------------------------------
#endif

View File

@@ -34,9 +34,6 @@ class Socket
, public boost::asio::ssl::stream_base
, public boost::asio::socket_base
{
protected:
typedef boost::system::error_code error_code;
public:
virtual ~Socket ();
@@ -45,7 +42,8 @@ public:
// basic_io_object
//
virtual boost::asio::io_service& get_io_service ();
virtual boost::asio::io_service& get_io_service ()
BEAST_SOCKET_VIRTUAL;
//--------------------------------------------------------------------------
//
@@ -57,7 +55,7 @@ public:
else a fatal error will occur.
*/
/** @{ */
template <class Object>
template <typename Object>
Object& lowest_layer ()
{
Object* object (this->lowest_layer_ptr <Object> ());
@@ -66,7 +64,7 @@ public:
return *object;
}
template <class Object>
template <typename Object>
Object const& lowest_layer () const
{
Object const* object (this->lowest_layer_ptr <Object> ());
@@ -75,14 +73,14 @@ public:
return *object;
}
template <class Object>
template <typename Object>
Object* lowest_layer_ptr ()
{
return static_cast <Object*> (
this->lowest_layer (typeid (Object).name ()));
}
template <class Object>
template <typename Object>
Object const* lowest_layer_ptr () const
{
return static_cast <Object const*> (
@@ -90,14 +88,15 @@ public:
}
/** @} */
virtual void* lowest_layer (char const* type_name) const;
virtual void* lowest_layer (char const* type_name) const
BEAST_SOCKET_VIRTUAL;
/** Retrieve the underlying object.
Note that you must know the type name for this to work, or
else a fatal error will occur.
*/
/** @{ */
template <class Object>
template <typename Object>
Object& native_handle ()
{
Object* object (this->native_handle_ptr <Object> ());
@@ -106,7 +105,7 @@ public:
return *object;
}
template <class Object>
template <typename Object>
Object const& native_handle () const
{
Object const* object (this->native_handle_ptr <Object> ());
@@ -115,14 +114,14 @@ public:
return *object;
}
template <class Object>
template <typename Object>
Object* native_handle_ptr ()
{
return static_cast <Object*> (
this->native_handle (typeid (Object).name ()));
}
template <class Object>
template <typename Object>
Object const* native_handle_ptr () const
{
return static_cast <Object const*> (
@@ -130,51 +129,54 @@ public:
}
/** @} */
virtual void* native_handle (char const* type_name) const;
virtual void* native_handle (char const* type_name) const
BEAST_SOCKET_VIRTUAL;
void cancel ()
{
error_code ec;
throw_error (cancel (ec));
throw_error (cancel (ec), __FILE__, __LINE__);
}
virtual error_code cancel (error_code& ec);
virtual error_code cancel (error_code& ec)
BEAST_SOCKET_VIRTUAL;
void shutdown (shutdown_type what)
{
error_code ec;
throw_error (shutdown (what, ec));
throw_error (shutdown (what, ec), __FILE__, __LINE__);
}
virtual error_code shutdown (shutdown_type what,
error_code& ec);
error_code& ec)
BEAST_SOCKET_VIRTUAL;
void close ()
{
error_code ec;
throw_error (close (ec));
throw_error (close (ec), __FILE__, __LINE__);
}
virtual error_code close (error_code& ec);
virtual error_code close (error_code& ec)
BEAST_SOCKET_VIRTUAL;
//--------------------------------------------------------------------------
//
// basic_socket_acceptor
//
virtual error_code accept (Socket& peer, error_code& ec);
virtual error_code accept (Socket& peer, error_code& ec)
BEAST_SOCKET_VIRTUAL;
template <class AcceptHandler>
BEAST_ASIO_INITFN_RESULT_TYPE(AcceptHandler, void (error_code))
async_accept (Socket& peer, BOOST_ASIO_MOVE_ARG(AcceptHandler) handler)
template <typename AcceptHandler>
void async_accept (Socket& peer, BOOST_ASIO_MOVE_ARG(AcceptHandler) handler)
{
return async_accept (peer, HandlerCall (HandlerCall::Accept (),
BOOST_ASIO_MOVE_CAST(AcceptHandler)(handler)));
return async_accept (peer,
newAcceptHandler (BOOST_ASIO_MOVE_CAST(AcceptHandler)(handler)));
}
virtual
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code))
async_accept (Socket& peer, HandlerCall const& handler);
virtual void async_accept (Socket& peer, SharedHandlerPtr handler)
BEAST_SOCKET_VIRTUAL;
//--------------------------------------------------------------------------
//
@@ -183,54 +185,56 @@ public:
// SyncReadStream
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/SyncReadStream.html
template <class MutableBufferSequence>
//
template <typename MutableBufferSequence>
std::size_t read_some (MutableBufferSequence const& buffers,
error_code& ec)
{
return read_some (MutableBuffers (buffers), ec);
}
virtual std::size_t read_some (MutableBuffers const& buffers, error_code& ec);
virtual std::size_t read_some (MutableBuffers const& buffers, error_code& ec)
BEAST_SOCKET_VIRTUAL;
// SyncWriteStream
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/SyncWriteStream.html
template <class ConstBufferSequence>
//
template <typename ConstBufferSequence>
std::size_t write_some (ConstBufferSequence const& buffers, error_code &ec)
{
return write_some (ConstBuffers (buffers), ec);
}
virtual std::size_t write_some (ConstBuffers const& buffers, error_code& ec);
virtual std::size_t write_some (ConstBuffers const& buffers, error_code& ec)
BEAST_SOCKET_VIRTUAL;
// AsyncReadStream
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/AsyncReadStream.html
template <class MutableBufferSequence, class ReadHandler>
BEAST_ASIO_INITFN_RESULT_TYPE(ReadHandler, void (error_code, std::size_t))
async_read_some (MutableBufferSequence const& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
//
template <typename MutableBufferSequence, typename ReadHandler>
void async_read_some (MutableBufferSequence const& buffers,
BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
{
return async_read_some (MutableBuffers (buffers),
HandlerCall (HandlerCall::Transfer (),
BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)));
newReadHandler (BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)));
}
virtual
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code, std::size_t))
async_read_some (MutableBuffers const& buffers, HandlerCall const& handler);
virtual void async_read_some (MutableBuffers const& buffers, SharedHandlerPtr handler)
BEAST_SOCKET_VIRTUAL;
// AsyncWriteStream
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/AsyncWriteStream.html
template <class ConstBufferSequence, class WriteHandler>
BEAST_ASIO_INITFN_RESULT_TYPE(WriteHandler, void (error_code, std::size_t))
async_write_some (ConstBufferSequence const& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
//
template <typename ConstBufferSequence, typename WriteHandler>
void async_write_some (ConstBufferSequence const& buffers,
BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
{
return async_write_some (ConstBuffers (buffers),
HandlerCall (HandlerCall::Transfer (),
BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)));
newWriteHandler (BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)));
}
virtual
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code, std::size_t))
async_write_some (ConstBuffers const& buffers, HandlerCall const& handler);
virtual void async_write_some (ConstBuffers const& buffers, SharedHandlerPtr handler)
BEAST_SOCKET_VIRTUAL;
//--------------------------------------------------------------------------
//
@@ -249,7 +253,8 @@ public:
The default version returns false.
*/
virtual bool needs_handshake ();
virtual bool needs_handshake ()
BEAST_SOCKET_VIRTUAL;
// ssl::stream::handshake (1 of 4)
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ssl__stream/handshake/overload1.html
@@ -257,29 +262,27 @@ public:
void handshake (handshake_type type)
{
error_code ec;
throw_error (handshake (type, ec));
throw_error (handshake (type, ec), __FILE__, __LINE__);
}
// ssl::stream::handshake (2 of 4)
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ssl__stream/handshake/overload2.html
//
virtual error_code handshake (handshake_type type,
error_code& ec);
virtual error_code handshake (handshake_type type, error_code& ec)
BEAST_SOCKET_VIRTUAL;
// 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
//
template <typename HandshakeHandler>
BEAST_ASIO_INITFN_RESULT_TYPE(HandshakeHandler, void (error_code))
async_handshake (handshake_type type, BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler)
void async_handshake (handshake_type type, BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler)
{
return async_handshake (type, HandlerCall (HandlerCall::Error (),
BOOST_ASIO_MOVE_CAST(HandshakeHandler)(handler)));
return async_handshake (type,
newHandshakeHandler (BOOST_ASIO_MOVE_CAST(HandshakeHandler)(handler)));
}
virtual
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code))
async_handshake (handshake_type type, HandlerCall const& handler);
virtual void async_handshake (handshake_type type, SharedHandlerPtr handler)
BEAST_SOCKET_VIRTUAL;
//--------------------------------------------------------------------------
@@ -287,17 +290,17 @@ public:
// 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
//
template <class ConstBufferSequence>
template <typename ConstBufferSequence>
void handshake (handshake_type type, ConstBufferSequence const& buffers)
{
error_code ec;
throw_error (handshake (type, buffers, ec));
throw_error (handshake (type, buffers, ec), __FILE__, __LINE__);
}
// ssl::stream::handshake (4 of 4)
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ssl__stream/handshake/overload4.html
//
template <class ConstBufferSequence>
template <typename ConstBufferSequence>
error_code handshake (handshake_type type,
ConstBufferSequence const& buffers, error_code& ec)
{
@@ -305,24 +308,23 @@ public:
}
virtual error_code handshake (handshake_type type,
ConstBuffers const& buffers, error_code& ec);
ConstBuffers const& buffers, error_code& ec)
BEAST_SOCKET_VIRTUAL;
// 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
//
template <class ConstBufferSequence, class BufferedHandshakeHandler>
BEAST_ASIO_INITFN_RESULT_TYPE(BufferedHandshakeHandler, void (error_code, std::size_t))
async_handshake (handshake_type type, ConstBufferSequence const& buffers,
template <typename ConstBufferSequence, typename BufferedHandshakeHandler>
void async_handshake (handshake_type type, ConstBufferSequence const& buffers,
BOOST_ASIO_MOVE_ARG(BufferedHandshakeHandler) handler)
{
return async_handshake (type, ConstBuffers (buffers),
HandlerCall (HandlerCall::Transfer (),
BOOST_ASIO_MOVE_CAST(BufferedHandshakeHandler)(handler)));
newBufferedHandshakeHandler (BOOST_ASIO_MOVE_CAST(BufferedHandshakeHandler)(handler)));
}
virtual
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code, std::size_t))
async_handshake (handshake_type type, ConstBuffers const& buffers, HandlerCall const& handler);
virtual void async_handshake (handshake_type type, ConstBuffers const& buffers,
SharedHandlerPtr handler)
BEAST_SOCKET_VIRTUAL;
#endif
//--------------------------------------------------------------------------
@@ -333,24 +335,24 @@ public:
void shutdown ()
{
error_code ec;
throw_error (shutdown (ec));
throw_error (shutdown (ec), __FILE__, __LINE__);
}
virtual error_code shutdown (error_code& ec);
virtual error_code shutdown (error_code& ec)
BEAST_SOCKET_VIRTUAL;
// ssl::stream::async_shutdown
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ssl__stream/async_shutdown.html
//
template <class ShutdownHandler>
template <typename ShutdownHandler>
void async_shutdown (BOOST_ASIO_MOVE_ARG(ShutdownHandler) handler)
{
return async_shutdown (HandlerCall (HandlerCall::Error (),
BOOST_ASIO_MOVE_CAST(ShutdownHandler)(handler)));
return async_shutdown (
newShutdownHandler (BOOST_ASIO_MOVE_CAST(ShutdownHandler)(handler)));
}
virtual
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code))
async_shutdown (HandlerCall const& handler);
virtual void async_shutdown (SharedHandlerPtr handler)
BEAST_SOCKET_VIRTUAL;
};
#endif

View File

@@ -23,14 +23,20 @@ boost::system::error_code SocketBase::pure_virtual_error ()
boost::system::errc::function_not_supported);
}
void SocketBase::pure_virtual ()
boost::system::error_code SocketBase::pure_virtual_error (error_code& ec,
char const* fileName, int lineNumber)
{
fatal_error ("A beast::Socket function was called on an object that doesn't support the interface");
pure_virtual_called (fileName, lineNumber);
return ec = pure_virtual_error ();
}
boost::system::error_code SocketBase::pure_virtual (boost::system::error_code& ec)
void SocketBase::pure_virtual_called (char const* fileName, int lineNumber)
{
pure_virtual ();
ec = pure_virtual_error ();
return ec;
Throw (std::runtime_error ("pure virtual called"), fileName, lineNumber);
}
void SocketBase::throw_error (error_code const& ec, char const* fileName, int lineNumber)
{
if (ec)
Throw (boost::system::system_error (ec), fileName, lineNumber);
}

View File

@@ -20,21 +20,30 @@
#ifndef BEAST_SOCKETBASE_H_INCLUDED
#define BEAST_SOCKETBASE_H_INCLUDED
/** Implementation details for Socket.
/** Common implementation details for Socket and related classes.
Normally you wont need to use this.
*/
struct SocketBase
{
static boost::system::error_code pure_virtual_error ();
static boost::system::error_code pure_virtual (boost::system::error_code& ec);
static void pure_virtual ();
protected:
typedef boost::system::error_code error_code;
/** Called when the underlying object does not support the interface. */
void throw_error (boost::system::error_code const& ec)
{
if (ec)
Throw (boost::system::system_error (ec), __FILE__, __LINE__);
}
/** The error returned when a pure virtual is called.
This is mostly academic since a pure virtual call generates
a fatal error but in case that gets disabled, this will at
least return a suitable error code.
*/
static error_code pure_virtual_error ();
/** Convenience for taking a reference and returning the error_code. */
static error_code pure_virtual_error (error_code& ec,
char const* fileName, int lineNumber);
/** Called when a function doesn't support the interface. */
static void pure_virtual_called (char const* fileName, int lineNumber);
/** Called when synchronous functions without error parameters get an error. */
static void throw_error (error_code const& ec, char const* fileName, int lineNumber);
};
#endif

View File

@@ -96,8 +96,16 @@ namespace SocketWrapperMemberChecks
struct native_socket
{
typedef void* socket_type;
inline native_socket (Socket&) : m_socket (nullptr) { SocketBase::pure_virtual (); }
inline socket_type& get () { SocketBase::pure_virtual (); return m_socket; }
inline native_socket (Socket&)
: m_socket (nullptr)
{
SocketBase::pure_virtual_called (__FILE__, __LINE__);
}
inline socket_type& get ()
{
SocketBase::pure_virtual_called (__FILE__, __LINE__);
return m_socket;
}
inline socket_type& operator-> () { return get (); }
private:
socket_type m_socket;
@@ -109,7 +117,8 @@ namespace SocketWrapperMemberChecks
typename T::protocol_type::socket> >::type>
{
typedef typename T::protocol_type::socket socket_type;
inline native_socket (Socket& peer) : m_socket_ptr (&peer.native_handle <socket_type> ()) { }
inline native_socket (Socket& peer)
: m_socket_ptr (&peer.native_handle <socket_type> ()) { }
inline socket_type& get () noexcept { return *m_socket_ptr; }
inline socket_type& operator-> () noexcept { return get (); }
private:
@@ -178,11 +187,13 @@ public:
{
using namespace SocketWrapperMemberChecks;
#if 0
// This is the one that doesn't work, (void) arg lists
return get_io_service (
Type <HandshakeHandler> ( (
EnableIf <has_get_io_service <this_layer_type,
io_service ()>::value> ());
#else
// BEAST_DEFINE_IS_CALL_POSSIBLE doesn't seem to
// match (void) argument lists so this is a workaround.
//
return get_io_service (boost::true_type ());
#endif
}
@@ -196,7 +207,7 @@ public:
boost::asio::io_service& get_io_service (
boost::false_type)
{
pure_virtual ();
pure_virtual_called (__FILE__, __LINE__);
return *static_cast <boost::asio::io_service*>(nullptr);
}
@@ -252,7 +263,7 @@ public:
void* lowest_layer (char const*,
boost::false_type) const
{
pure_virtual ();
pure_virtual_called (__FILE__, __LINE__);
return nullptr;
}
@@ -285,7 +296,7 @@ public:
error_code cancel (error_code& ec,
boost::false_type)
{
return pure_virtual (ec);
return pure_virtual_error (ec, __FILE__, __LINE__);
}
//--------------------------------------------------------------------------
@@ -308,7 +319,7 @@ public:
error_code shutdown (shutdown_type, error_code& ec,
boost::false_type)
{
return pure_virtual (ec);
return pure_virtual_error (ec, __FILE__, __LINE__);
}
//--------------------------------------------------------------------------
@@ -330,7 +341,7 @@ public:
error_code close (error_code& ec,
boost::false_type)
{
return pure_virtual (ec);
return pure_virtual_error (ec, __FILE__, __LINE__);
}
//--------------------------------------------------------------------------
@@ -358,47 +369,35 @@ public:
error_code accept (Socket&, error_code& ec,
boost::false_type)
{
return pure_virtual (ec);
return pure_virtual_error (ec, __FILE__, __LINE__);
}
//--------------------------------------------------------------------------
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code))
async_accept (Socket& peer, HandlerCall const& handler)
void async_accept (Socket& peer, SharedHandlerPtr handler)
{
using namespace SocketWrapperMemberChecks;
typedef typename native_socket <this_layer_type>::socket_type socket_type;
return async_accept (peer, handler,
async_accept (peer, BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler),
EnableIf <has_async_accept <this_layer_type,
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code))
(socket_type&, BOOST_ASIO_MOVE_ARG(HandlerCall))>::value> ());
void (socket_type&, BOOST_ASIO_MOVE_ARG(SharedHandlerPtr))>::value> ());
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code))
async_accept (Socket& peer, HandlerCall const& handler,
void async_accept (Socket& peer, BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
boost::true_type)
{
using namespace SocketWrapperMemberChecks;
return m_object.async_accept (
native_socket <this_layer_type> (peer).get (), handler);
m_object.async_accept (
native_socket <this_layer_type> (peer).get (),
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler));
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code))
async_accept (Socket&, HandlerCall const& handler,
void async_accept (Socket&, BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
boost::false_type)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
HandlerCall, void (error_code)> init(handler);
get_io_service ().post (HandlerCall (HandlerCall::Post (),
init.handler, pure_virtual_error ()));
return init.result.get();
#else
get_io_service ().post (HandlerCall (HandlerCall::Post (),
handler, pure_virtual_error ()));
#endif
get_io_service ().wrap (
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
(pure_virtual_error ());
}
//--------------------------------------------------------------------------
@@ -425,7 +424,8 @@ public:
std::size_t read_some (MutableBufferSequence const&, error_code& ec,
boost::false_type)
{
pure_virtual (ec);
pure_virtual_called (__FILE__, __LINE__);
ec = pure_virtual_error ();
return 0;
}
@@ -450,82 +450,63 @@ public:
std::size_t write_some (ConstBufferSequence const&, error_code& ec,
boost::false_type)
{
pure_virtual (ec);
pure_virtual_called (__FILE__, __LINE__);
ec = pure_virtual_error ();
return 0;
}
//--------------------------------------------------------------------------
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code, std::size_t))
async_read_some (MutableBuffers const& buffers, BOOST_ASIO_MOVE_ARG(HandlerCall) handler)
void async_read_some (MutableBuffers const& buffers, SharedHandlerPtr handler)
{
using namespace SocketWrapperMemberChecks;
return async_read_some (buffers, BOOST_ASIO_MOVE_CAST(HandlerCall)(handler),
async_read_some (buffers, BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler),
EnableIf <has_async_read_some <this_layer_type,
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code, std::size_t))
(MutableBuffers const&, BOOST_ASIO_MOVE_ARG(HandlerCall))>::value> ());
void (MutableBuffers const&, BOOST_ASIO_MOVE_ARG(SharedHandlerPtr))>::value> ());
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code, std::size_t))
async_read_some (MutableBuffers const& buffers, HandlerCall const& handler,
void async_read_some (MutableBuffers const& buffers,
BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
boost::true_type)
{
return m_object.async_read_some (buffers, handler);
m_object.async_read_some (buffers,
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler));
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code, std::size_t))
async_read_some (MutableBuffers const&, HandlerCall const& handler,
void async_read_some (MutableBuffers const&,
BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
boost::false_type)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
HandlerCall, void (error_code, std::size_t)> init(handler);
get_io_service ().post (HandlerCall (HandlerCall::Post (),
init.handler, pure_virtual_error (), 0));
return init.result.get();
#else
get_io_service ().post (HandlerCall (HandlerCall::Post (),
handler, pure_virtual_error (), 0));
#endif
get_io_service ().wrap (
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
(pure_virtual_error (), 0);
}
//--------------------------------------------------------------------------
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code, std::size_t))
async_write_some (ConstBuffers const& buffers, HandlerCall const& handler)
void async_write_some (ConstBuffers const& buffers, SharedHandlerPtr handler)
{
using namespace SocketWrapperMemberChecks;
return async_write_some (buffers, handler,
async_write_some (buffers, BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler),
EnableIf <has_async_write_some <this_layer_type,
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code, std::size_t))
(ConstBuffers const&, HandlerCall const&)>::value> ());
void (ConstBuffers const&, BOOST_ASIO_MOVE_ARG(SharedHandlerPtr))>::value> ());
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code, std::size_t))
async_write_some (ConstBuffers const& buffers, HandlerCall const& handler,
void async_write_some (ConstBuffers const& buffers,
BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
boost::true_type)
{
return m_object.async_write_some (buffers, handler);
m_object.async_write_some (buffers,
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler));
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code, std::size_t))
async_write_some (ConstBuffers const&, HandlerCall const& handler,
void async_write_some (ConstBuffers const&,
BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
boost::false_type)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
HandlerCall, void (error_code, std::size_t)> init(handler);
get_io_service ().post (HandlerCall (HandlerCall::Post (),
init.handler, pure_virtual_error (), 0));
return init.result.get();
#else
get_io_service ().post (HandlerCall (HandlerCall::Post (),
handler, pure_virtual_error (), 0));
#endif
get_io_service ().wrap (
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
(pure_virtual_error (), 0);
}
//--------------------------------------------------------------------------
@@ -540,8 +521,7 @@ public:
has_handshake <this_layer_type,
error_code (handshake_type, error_code&)>::value ||
has_async_handshake <this_layer_type,
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code))
(handshake_type, BOOST_ASIO_MOVE_ARG(HandlerCall))>::value;
void (handshake_type, BOOST_ASIO_MOVE_ARG(SharedHandlerPtr))>::value;
}
//--------------------------------------------------------------------------
@@ -563,49 +543,41 @@ public:
error_code handshake (handshake_type, error_code& ec,
boost::false_type)
{
return pure_virtual (ec);
return pure_virtual_error (ec, __FILE__, __LINE__);
}
//--------------------------------------------------------------------------
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code))
async_handshake (handshake_type type, HandlerCall const& handler)
void async_handshake (handshake_type type, SharedHandlerPtr handler)
{
using namespace SocketWrapperMemberChecks;
return async_handshake (type, handler,
async_handshake (type, BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler),
EnableIf <has_async_handshake <this_layer_type,
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code))
(handshake_type, HandlerCall const& handler)>::value> ());
void (handshake_type, BOOST_ASIO_MOVE_ARG(SharedHandlerPtr))>::value> ());
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code))
async_handshake (handshake_type type, HandlerCall const& handler,
void async_handshake (handshake_type type,
BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
boost::true_type)
{
return m_object.async_handshake (type, handler);
m_object.async_handshake (type,
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler));
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code))
async_handshake (handshake_type, HandlerCall const& handler,
void async_handshake (handshake_type, BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
boost::false_type)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
HandlerCall, void (error_code)> init(handler);
get_io_service ().post (HandlerCall (HandlerCall::Post (),
init.handler, pure_virtual_error ()));
return init.result.get();
#else
get_io_service ().post (HandlerCall (HandlerCall::Post (),
handler, pure_virtual_error ()));
#endif
get_io_service ().wrap (
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
(pure_virtual_error ());
}
//--------------------------------------------------------------------------
#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
error_code handshake (handshake_type type, ConstBuffers const& buffers, error_code& ec)
error_code handshake (handshake_type type,
ConstBuffers const& buffers, error_code& ec)
{
using namespace SocketWrapperMemberChecks;
return handshake (type, buffers, ec,
@@ -613,7 +585,8 @@ public:
error_code (handshake_type, ConstBuffers const&, error_code&)>::value> ());
}
error_code handshake (handshake_type type, ConstBuffers const& buffers, error_code& ec,
error_code handshake (handshake_type type,
ConstBuffers const& buffers, error_code& ec,
boost::true_type)
{
return m_object.handshake (type, buffers, ec);
@@ -622,45 +595,37 @@ public:
error_code handshake (handshake_type, ConstBuffers const&, error_code& ec,
boost::false_type)
{
return pure_virtual (ec);
return pure_virtual_error (ec, __FILE__, __LINE__);
}
//--------------------------------------------------------------------------
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code, std::size_t))
async_handshake (handshake_type type, ConstBuffers const& buffers,
HandlerCall const& handler)
void async_handshake (handshake_type type,
ConstBuffers const& buffers, SharedHandlerPtr handler)
{
using namespace SocketWrapperMemberChecks;
return async_handshake (type, buffers, handler,
async_handshake (type, buffers,
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler),
EnableIf <has_async_handshake <this_layer_type,
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code, std::size_t))
(handshake_type, ConstBuffers const&, error_code&)>::value> ());
void (handshake_type, ConstBuffers const&,
BOOST_ASIO_MOVE_ARG(SharedHandlerPtr))>::value> ());
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code, std::size_t))
async_handshake (handshake_type type, ConstBuffers const& buffers, HandlerCall const& handler,
void async_handshake (handshake_type type, ConstBuffers const& buffers,
BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
boost::true_type)
{
return m_object.async_handshake (type, buffers, handler);
m_object.async_handshake (type, buffers,
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler));
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code, std::size_t))
async_handshake (handshake_type, ConstBuffers const&, HandlerCall const& handler,
void async_handshake (handshake_type, ConstBuffers const&,
BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
boost::false_type)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
HandlerCall, void (error_code, std::size_t)> init(handler);
get_io_service ().post (HandlerCall (HandlerCall::Post (),
init.handler, pure_virtual_error (), 0));
return init.result.get();
#else
get_io_service ().post (HandlerCall (HandlerCall::Post (),
handler, pure_virtual_error (), 0));
#endif
get_io_service ().wrap (
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
(pure_virtual_error (), 0);
}
#endif
@@ -684,43 +649,32 @@ public:
error_code shutdown (error_code& ec,
boost::false_type)
{
return pure_virtual (ec);
return pure_virtual_error (ec, __FILE__, __LINE__);
}
//--------------------------------------------------------------------------
void async_shutdown (HandlerCall const& handler)
void async_shutdown (SharedHandlerPtr handler)
{
using namespace SocketWrapperMemberChecks;
return async_shutdown (handler,
async_shutdown (BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler),
EnableIf <has_async_shutdown <this_layer_type,
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code))
(HandlerCall const& handler)>::value> ());
void (BOOST_ASIO_MOVE_ARG(SharedHandlerPtr))>::value> ());
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code))
async_shutdown (HandlerCall const& handler,
void async_shutdown (BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
boost::true_type)
{
return m_object.async_shutdown (handler);
m_object.async_shutdown (
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler));
}
BEAST_ASIO_INITFN_RESULT_TYPE_MEMBER(HandlerCall, void (error_code))
async_shutdown (HandlerCall const& handler,
void async_shutdown (BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
boost::false_type)
{
#if BEAST_ASIO_HAS_FUTURE_RETURNS
boost::asio::detail::async_result_init<
HandlerCall, void (error_code, std::size_t)> init(handler);
get_io_service ().post (HandlerCall (HandlerCall::Post (),
init.handler, pure_virtual_error ()));
return init.result.get();
#else
get_io_service ().post (HandlerCall (HandlerCall::Post (),
handler, pure_virtual_error ()));
#endif
get_io_service ().wrap (
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
(pure_virtual_error ());
}
private:

View File

@@ -38,6 +38,8 @@
# endif
#endif
#include <boost/version.hpp>
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
@@ -46,11 +48,44 @@
#include <boost/function.hpp>
#include <boost/type_traits.hpp>
// Unfortunately, we need to use some boost detail
//
// https://svn.boost.org/trac/boost/ticket/9024
//
#include <boost/asio/detail/handler_alloc_helpers.hpp>
#include <boost/asio/detail/handler_invoke_helpers.hpp>
// Not sure when handler_type was added but it's not in 1.48
#ifndef BEAST_ASIO_HAS_HANDLER_TYPE
# if BOOST_VERSION >= 105400
# define BEAST_ASIO_HAS_HANDLER_TYPE 1
# else
# define BEAST_ASIO_HAS_HANDLER_TYPE 0
# endif
#endif
#if BEAST_ASIO_HAS_HANDLER_TYPE
# include <boost/asio/handler_type.hpp>
# define BEAST_ASIO_HANDLER_TYPE(h, sig) BOOST_ASIO_HANDLER_TYPE(h, sig)
#else
# define BEAST_ASIO_HANDLER_TYPE(h, sig) h
#endif
// Continuation hooks added in 1.54.0
#ifndef BEAST_ASIO_HAS_CONTINUATION_HOOKS
# if BOOST_VERSION >= 105400
# define BEAST_ASIO_HAS_CONTINUATION_HOOKS 1
# else
# define BEAST_ASIO_HAS_CONTINUATION_HOOKS 0
# endif
#endif
#if BEAST_ASIO_HAS_CONTINUATION_HOOKS
# include <boost/asio/detail/handler_cont_helpers.hpp>
#endif
//------------------------------------------------------------------------------
// Configure some options based on the version of boost
#include <boost/version.hpp>
#if (BOOST_VERSION / 100) >= 1054
#if BOOST_VERSION >= 105400
# ifndef BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
# define BEAST_ASIO_HAS_BUFFEREDHANDSHAKE 1
# endif

View File

@@ -0,0 +1,82 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
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.
*/
//==============================================================================
/** Test for showing information about the build of boost.
*/
class BoostUnitTests : public UnitTest
{
public:
struct BoostVersion
{
explicit BoostVersion (int value)
: vmajor (value / 100000)
, vminor ((value / 100) % 100)
, vpatch (value % 100)
{
}
String toString () const noexcept
{
return String (vmajor) + "." +
String (vminor).paddedLeft ('0', 2) + "." +
String (vpatch).paddedLeft ('0', 2);
}
int vmajor;
int vminor;
int vpatch;
};
enum
{
minimumVersion = 104700
};
// To prevent constant conditional expression warning
static int getMinimumVersion ()
{
return minimumVersion;
}
void runTest ()
{
beginTestCase ("version");
BoostVersion version (BOOST_VERSION);
logMessage (String ("BOOST_VERSION = " + version.toString ()));
logMessage (String ("BOOST_LIB_VERSION = '") + BOOST_LIB_VERSION + "'");
if (BOOST_VERSION >= getMinimumVersion ())
{
pass ();
}
else
{
fail (String ("Boost version is below ") +
BoostVersion (minimumVersion).toString ());
}
}
BoostUnitTests () : UnitTest ("boost", "beast")
{
}
};
static BoostUnitTests boostUnitTests;

View File

@@ -104,7 +104,10 @@ bool TestPeerBasics::success (boost::system::error_code const& ec, bool eofIsOka
{
if (eofIsOkay && ec == boost::asio::error::eof)
return true;
return ! ec;
if (! ec)
return true;
breakpoint (ec);
return false;
}
bool TestPeerBasics::failure (boost::system::error_code const& ec, bool eofIsOkay) noexcept
@@ -115,9 +118,14 @@ bool TestPeerBasics::failure (boost::system::error_code const& ec, bool eofIsOka
bool TestPeerBasics::expected (bool condition, boost::system::error_code& ec) noexcept
{
if (condition)
{
ec = boost::system::error_code ();
}
else
{
make_error (errc::unexpected, ec);
breakpoint (ec);
}
return condition;
}
@@ -133,3 +141,15 @@ bool TestPeerBasics::aborted (boost::system::error_code const& ec) noexcept
//------------------------------------------------------------------------------
void TestPeerBasics::breakpoint (boost::system::error_code const& ec)
{
// Set a breakpoint here to catch a failure
std::string const& message = ec.message ();
char const* const c_str = message.c_str ();
breakpoint (c_str);
}
void TestPeerBasics::breakpoint (char const* const)
{
}

View File

@@ -95,6 +95,12 @@ public:
/** Returns true if the error condition indicates an aborted I/O. */
static bool aborted (boost::system::error_code const& ec) noexcept;
/** Provides a place to set a breakpoint to catch a failed condition. */
static void breakpoint (boost::system::error_code const& ec);
/** Forces the variable to exist in the debugger. */
static void breakpoint (char const* const message);
};
#endif