mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Merge commit '86ba8ffca6a6399bb19861e1cd826ec792a33651' as 'src/beast'
This commit is contained in:
100
src/beast/modules/beast_asio/async/ComposedAsyncOperation.h
Normal file
100
src/beast/modules/beast_asio/async/ComposedAsyncOperation.h
Normal 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_ASIO_ASYNC_COMPOSEDASYNCOPERATION_H_INCLUDED
|
||||
#define BEAST_ASIO_ASYNC_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
|
||||
47
src/beast/modules/beast_asio/async/SharedHandler.cpp
Normal file
47
src/beast/modules/beast_asio/async/SharedHandler.cpp
Normal 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);
|
||||
}
|
||||
121
src/beast/modules/beast_asio/async/SharedHandler.h
Normal file
121
src/beast/modules/beast_asio/async/SharedHandler.h
Normal file
@@ -0,0 +1,121 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_ASYNC_SHAREDHANDLER_H_INCLUDED
|
||||
#define BEAST_ASIO_ASYNC_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;
|
||||
#if 0
|
||||
typedef boost::function <void(void)> invoked_type;
|
||||
#else
|
||||
typedef SharedFunction <void(void), SharedHandlerAllocator <char> > invoked_type;
|
||||
#endif
|
||||
|
||||
SharedHandler () noexcept { }
|
||||
|
||||
public:
|
||||
// For asio::async_result<>
|
||||
typedef void result_type;
|
||||
|
||||
typedef SharedPtr <SharedHandler> Ptr;
|
||||
|
||||
virtual void operator() ();
|
||||
virtual void operator() (error_code const&);
|
||||
virtual void operator() (error_code const&, std::size_t);
|
||||
|
||||
template <typename Function>
|
||||
void invoke (BOOST_ASIO_MOVE_ARG(Function) f)
|
||||
#if 0
|
||||
;
|
||||
#else
|
||||
{
|
||||
// The allocator will hold a reference to the SharedHandler
|
||||
// so that we can safely destroy the function object.
|
||||
invoked_type invoked (f,
|
||||
SharedHandlerAllocator <char> (this));
|
||||
invoke (invoked);
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
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*);
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// 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
|
||||
127
src/beast/modules/beast_asio/async/SharedHandlerAllocator.h
Normal file
127
src/beast/modules/beast_asio/async/SharedHandlerAllocator.h
Normal file
@@ -0,0 +1,127 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_ASYNC_SHAREDHANDLERALLOCATOR_H_INCLUDED
|
||||
#define BEAST_ASIO_ASYNC_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;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#if 0
|
||||
template <typename Function>
|
||||
void SharedHandler::invoke (BOOST_ASIO_MOVE_ARG(Function) f)
|
||||
{
|
||||
// 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));
|
||||
invoke (invoked);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
327
src/beast/modules/beast_asio/async/SharedHandlerPtr.h
Normal file
327
src/beast/modules/beast_asio/async/SharedHandlerPtr.h
Normal file
@@ -0,0 +1,327 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_ASYNC_SHAREDHANDLERPTR_H_INCLUDED
|
||||
#define BEAST_ASIO_ASYNC_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
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// void(error_code)
|
||||
template <typename Handler>
|
||||
SharedHandlerPtr newErrorHandler (
|
||||
BOOST_ASIO_MOVE_ARG(Handler) handler)
|
||||
{
|
||||
return newSharedHandlerContainer <ErrorSharedHandlerType> (
|
||||
BOOST_ASIO_MOVE_CAST(Handler)(handler));
|
||||
}
|
||||
|
||||
// void(error_code, size_t)
|
||||
template <typename Handler>
|
||||
SharedHandlerPtr newTransferHandler (
|
||||
BOOST_ASIO_MOVE_ARG(Handler) handler)
|
||||
{
|
||||
return newSharedHandlerContainer <TransferSharedHandlerType> (
|
||||
BOOST_ASIO_MOVE_CAST(Handler)(handler));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// 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
|
||||
222
src/beast/modules/beast_asio/async/SharedHandlerType.h
Normal file
222
src/beast/modules/beast_asio/async/SharedHandlerType.h
Normal file
@@ -0,0 +1,222 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_ASYNC_SHAREDHANDLERTYPE_H_INCLUDED
|
||||
#define BEAST_ASIO_ASYNC_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 SharedObject 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 ()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
// 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__);
|
||||
}
|
||||
|
||||
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));
|
||||
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));
|
||||
}
|
||||
|
||||
#endif
|
||||
102
src/beast/modules/beast_asio/basics/BufferType.h
Normal file
102
src/beast/modules/beast_asio/basics/BufferType.h
Normal file
@@ -0,0 +1,102 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_BASICS_BUFFERTYPE_H_INCLUDED
|
||||
#define BEAST_ASIO_BASICS_BUFFERTYPE_H_INCLUDED
|
||||
|
||||
/** General linear memory buffer.
|
||||
This wraps the underlying buffer type and provides additional methods
|
||||
to create a uniform interface. Specializations allow asio-compatible
|
||||
buffers without having to include boost/asio.h.
|
||||
*/
|
||||
/** @{ */
|
||||
template <bool IsConst>
|
||||
class BufferType
|
||||
{
|
||||
private:
|
||||
typedef typename mpl::IfCond <IsConst,
|
||||
void const*,
|
||||
void*>::type pointer_type;
|
||||
|
||||
typedef typename mpl::IfCond <IsConst,
|
||||
uint8 const,
|
||||
uint8>::type byte_type;
|
||||
|
||||
public:
|
||||
typedef std::size_t size_type;
|
||||
|
||||
BufferType ()
|
||||
: m_data (nullptr)
|
||||
, m_size (0)
|
||||
{
|
||||
}
|
||||
|
||||
template <bool OtherIsConst>
|
||||
BufferType (BufferType <OtherIsConst> const& other)
|
||||
: m_data (other.cast <pointer_type> ())
|
||||
, m_size (other.size ())
|
||||
{
|
||||
}
|
||||
|
||||
BufferType (pointer_type data, std::size_t size) noexcept
|
||||
: m_data (data)
|
||||
, m_size (size)
|
||||
{
|
||||
}
|
||||
|
||||
BufferType& operator= (BufferType const& other) noexcept
|
||||
{
|
||||
m_data = other.cast <pointer_type> ();
|
||||
m_size = other.size ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <bool OtherIsConst>
|
||||
BufferType& operator= (
|
||||
BufferType <OtherIsConst> const& other) noexcept
|
||||
{
|
||||
m_data = other.cast <pointer_type> ();
|
||||
m_size = other.size ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T cast () const noexcept
|
||||
{
|
||||
return static_cast <T> (m_data);
|
||||
}
|
||||
|
||||
size_type size () const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
BufferType operator+ (size_type n) const noexcept
|
||||
{
|
||||
return BufferType (cast <byte_type*> (),
|
||||
size () - std::min (size(), n));
|
||||
}
|
||||
|
||||
private:
|
||||
pointer_type m_data;
|
||||
std::size_t m_size;
|
||||
};
|
||||
/** @} */
|
||||
|
||||
#endif
|
||||
137
src/beast/modules/beast_asio/basics/BuffersType.h
Normal file
137
src/beast/modules/beast_asio/basics/BuffersType.h
Normal file
@@ -0,0 +1,137 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_BUFFERSTYPE_H_INCLUDED
|
||||
#define BEAST_ASIO_BUFFERSTYPE_H_INCLUDED
|
||||
|
||||
/** Storage for a BufferSequence.
|
||||
|
||||
Meets these requirements:
|
||||
BufferSequence
|
||||
ConstBufferSequence (when Buffer is mutable_buffer)
|
||||
MutableBufferSequence (when Buffer is const_buffer)
|
||||
*/
|
||||
template <class Buffer>
|
||||
class BuffersType
|
||||
{
|
||||
public:
|
||||
typedef Buffer value_type;
|
||||
typedef std::vector <Buffer> container_type;
|
||||
typedef typename container_type::const_iterator const_iterator;
|
||||
|
||||
/** Construct a null buffer.
|
||||
This is the equivalent of @ref asio::null_buffers.
|
||||
*/
|
||||
BuffersType ()
|
||||
: m_size (0)
|
||||
{
|
||||
}
|
||||
|
||||
/** Construct from a container.
|
||||
Ownership of the container is transferred, the caller's
|
||||
value becomes undefined, but valid.
|
||||
*/
|
||||
explicit BuffersType (container_type& container)
|
||||
: m_size (0)
|
||||
{
|
||||
m_buffers.swap (container);
|
||||
for (typename container_type::const_iterator iter (m_buffers.begin ());
|
||||
iter != m_buffers.end (); ++iter)
|
||||
//m_size += iter->size ();
|
||||
m_size += boost::asio::buffer_size (*iter);
|
||||
}
|
||||
|
||||
/** Construct a BuffersType from an existing BufferSequence.
|
||||
@see assign
|
||||
*/
|
||||
template <class BufferSequence>
|
||||
BuffersType (BufferSequence const& buffers)
|
||||
{
|
||||
assign (buffers);
|
||||
}
|
||||
|
||||
/** Assign a BuffersType from an existing BufferSequence.
|
||||
@see assign
|
||||
*/
|
||||
template <class BufferSequence>
|
||||
BuffersType <Buffer>& operator= (BufferSequence const& buffers)
|
||||
{
|
||||
return assign (buffers);
|
||||
}
|
||||
|
||||
/** Assign a BuffersType 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>
|
||||
BuffersType <Buffer>& assign (BufferSequence const& buffers)
|
||||
{
|
||||
m_size = 0;
|
||||
m_buffers.clear ();
|
||||
m_buffers.reserve (std::distance (buffers.begin (), buffers.end ()));
|
||||
for (typename BufferSequence::const_iterator iter (
|
||||
buffers.begin ()); iter != buffers.end(); ++ iter)
|
||||
{
|
||||
//m_size += iter->size ();
|
||||
m_size += boost::asio::buffer_size (*iter);
|
||||
m_buffers.push_back (*iter);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Determine the total size of all buffers.
|
||||
This is faster than calling boost::asio::buffer_size.
|
||||
*/
|
||||
std::size_t size () const noexcept
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
const_iterator begin () const noexcept
|
||||
{
|
||||
return m_buffers.begin ();
|
||||
}
|
||||
|
||||
const_iterator end () const noexcept
|
||||
{
|
||||
return m_buffers.end ();
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t m_size;
|
||||
std::vector <Buffer> m_buffers;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** A single linear read-only buffer. */
|
||||
//typedef BufferType <true> ConstBuffer;
|
||||
typedef boost::asio::const_buffer ConstBuffer;
|
||||
|
||||
/** A single linear writable buffer. */
|
||||
//typedef BufferType <false> MutableBuffer;
|
||||
typedef boost::asio::mutable_buffer MutableBuffer;
|
||||
|
||||
/** Meets the requirements of ConstBufferSequence */
|
||||
typedef BuffersType <ConstBuffer> ConstBuffers;
|
||||
|
||||
/** Meets the requirements of MutableBufferSequence */
|
||||
typedef BuffersType <MutableBuffer> MutableBuffers;
|
||||
|
||||
#endif
|
||||
101
src/beast/modules/beast_asio/basics/ContentBodyBuffer.cpp
Normal file
101
src/beast/modules/beast_asio/basics/ContentBodyBuffer.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
ContentBodyBuffer::ContentBodyBuffer (size_type blocksize)
|
||||
: m_blocksize (blocksize)
|
||||
, m_size (0)
|
||||
{
|
||||
}
|
||||
|
||||
ContentBodyBuffer::~ContentBodyBuffer ()
|
||||
{
|
||||
for (Handles::iterator iter (m_handles.begin());
|
||||
iter != m_handles.end(); ++iter)
|
||||
{
|
||||
void* const buffer (*iter);
|
||||
std::free (buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void ContentBodyBuffer::swapWith (ContentBodyBuffer& other)
|
||||
{
|
||||
std::swap (m_blocksize, other.m_blocksize);
|
||||
std::swap (m_size, other.m_size);
|
||||
m_handles.swap (other.m_handles);
|
||||
}
|
||||
|
||||
void ContentBodyBuffer::commit (size_type n)
|
||||
{
|
||||
m_size += n;
|
||||
bassert (m_size <= m_handles.size () * m_blocksize);
|
||||
}
|
||||
|
||||
ConstBuffers ContentBodyBuffer::data () const
|
||||
{
|
||||
size_type n (m_size);
|
||||
std::vector <ConstBuffer> v;
|
||||
v.reserve ((m_size + m_blocksize - 1) / m_blocksize);
|
||||
for (Handles::const_iterator iter (m_handles.begin());
|
||||
iter != m_handles.end() && n > 0; ++iter)
|
||||
{
|
||||
size_type const amount (std::min (n, m_blocksize));
|
||||
v.push_back (MutableBuffer (*iter, amount));
|
||||
n -= amount;
|
||||
}
|
||||
return ConstBuffers (v);
|
||||
}
|
||||
|
||||
ContentBodyBuffer::size_type ContentBodyBuffer::size () const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
MutableBuffers ContentBodyBuffer::prepare (size_type n)
|
||||
{
|
||||
reserve (n);
|
||||
std::vector <MutableBuffer> v;
|
||||
size_type offset (m_size % m_blocksize);
|
||||
for (Handles::iterator iter = m_handles.begin () + (m_size / m_blocksize);
|
||||
iter != m_handles.end () && n > 0; ++iter)
|
||||
{
|
||||
size_type const amount (std::min (n, m_blocksize - offset));
|
||||
v.push_back (MutableBuffer (*iter, amount));
|
||||
n -= amount;
|
||||
offset = 0;
|
||||
}
|
||||
return MutableBuffers (v);
|
||||
}
|
||||
|
||||
void ContentBodyBuffer::reserve (size_type n)
|
||||
{
|
||||
size_type count ((m_size + n + m_blocksize - 1) / m_blocksize);
|
||||
if (count > m_handles.size ())
|
||||
for (count -= m_handles.size (); count-- > 0;)
|
||||
m_handles.push_back (std::malloc (m_blocksize));
|
||||
}
|
||||
|
||||
void ContentBodyBuffer::shrink_to_fit ()
|
||||
{
|
||||
size_type const count ((m_size + m_blocksize - 1) / m_blocksize);
|
||||
while (m_handles.size () > count)
|
||||
{
|
||||
std::free (m_handles.back ());
|
||||
m_handles.erase (m_handles.end () - 1);
|
||||
}
|
||||
}
|
||||
78
src/beast/modules/beast_asio/basics/ContentBodyBuffer.h
Normal file
78
src/beast/modules/beast_asio/basics/ContentBodyBuffer.h
Normal file
@@ -0,0 +1,78 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_BASICS_CONTENTBODYBUFFER_H_INCLUDED
|
||||
#define BEAST_ASIO_BASICS_CONTENTBODYBUFFER_H_INCLUDED
|
||||
|
||||
/** Dynamic storage optimized for a large Content-Body of unknown size.
|
||||
This comes at the expense of discontiguous storage of the segments.
|
||||
We derive from SharedObject to make transfer of ownership inexpensive.
|
||||
*/
|
||||
class ContentBodyBuffer
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
defaultBlocksize = 32 * 1024
|
||||
};
|
||||
|
||||
typedef std::size_t size_type;
|
||||
typedef ConstBuffers const_buffers_tyoe;
|
||||
typedef MutableBuffers mutable_buffers_type;
|
||||
|
||||
explicit ContentBodyBuffer (size_type blocksize = defaultBlocksize);
|
||||
|
||||
~ContentBodyBuffer ();
|
||||
|
||||
/** Swap the contents of this buffer with another.
|
||||
This is the preferred way to transfer ownership.
|
||||
*/
|
||||
void swapWith (ContentBodyBuffer& other);
|
||||
|
||||
/** Move bytes from the output to the input sequence.
|
||||
This will invalidate references to buffers.
|
||||
*/
|
||||
void commit (size_type n);
|
||||
|
||||
/** Returns a buffer to the input sequence. */
|
||||
ConstBuffers data () const;
|
||||
|
||||
/** Returns the size of the input sequence. */
|
||||
size_type size () const;
|
||||
|
||||
/** Reserve space in the output sequence.
|
||||
This also returns a buffer suitable for writing.
|
||||
*/
|
||||
MutableBuffers prepare (size_type n);
|
||||
|
||||
/** Reserve space in the output sequence. */
|
||||
void reserve (size_type n);
|
||||
|
||||
/** Release memory while preserving the input sequence. */
|
||||
void shrink_to_fit ();
|
||||
|
||||
private:
|
||||
typedef std::vector <void*> Handles;
|
||||
|
||||
size_type m_blocksize;
|
||||
size_type m_size;
|
||||
Handles m_handles;
|
||||
};
|
||||
|
||||
#endif
|
||||
193
src/beast/modules/beast_asio/basics/FixedInputBuffer.h
Normal file
193
src/beast/modules/beast_asio/basics/FixedInputBuffer.h
Normal file
@@ -0,0 +1,193 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_BASICS_FIXEDINPUTBUFFER_H_INCLUDED
|
||||
#define BEAST_ASIO_BASICS_FIXEDINPUTBUFFER_H_INCLUDED
|
||||
|
||||
/** Represents a small, fixed size buffer.
|
||||
This provides a convenient interface for doing a bytewise
|
||||
verification/reject test on a handshake protocol.
|
||||
*/
|
||||
/** @{ */
|
||||
class FixedInputBuffer
|
||||
{
|
||||
protected:
|
||||
struct CtorParams
|
||||
{
|
||||
CtorParams (uint8 const* begin_, std::size_t bytes_)
|
||||
: begin (begin_)
|
||||
, bytes (bytes_)
|
||||
{
|
||||
}
|
||||
|
||||
uint8 const* begin;
|
||||
std::size_t bytes;
|
||||
};
|
||||
|
||||
FixedInputBuffer (CtorParams const& params)
|
||||
: m_begin (params.begin)
|
||||
, m_iter (m_begin)
|
||||
, m_end (m_begin + params.bytes)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
FixedInputBuffer (FixedInputBuffer const& other)
|
||||
: m_begin (other.m_begin)
|
||||
, m_iter (other.m_iter)
|
||||
, m_end (other.m_end)
|
||||
{
|
||||
}
|
||||
|
||||
FixedInputBuffer& operator= (FixedInputBuffer const& other)
|
||||
{
|
||||
m_begin = other.m_begin;
|
||||
m_iter = other.m_iter;
|
||||
m_end = other.m_end;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Returns the number of bytes consumed
|
||||
std::size_t used () const noexcept
|
||||
{
|
||||
return m_iter - m_begin;
|
||||
}
|
||||
|
||||
// Returns the size of what's remaining
|
||||
std::size_t size () const noexcept
|
||||
{
|
||||
return m_end - m_iter;
|
||||
}
|
||||
|
||||
void const* peek (std::size_t bytes)
|
||||
{
|
||||
return peek_impl (bytes, nullptr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool peek (T* t) const noexcept
|
||||
{
|
||||
return peek_impl (sizeof (T), t) != nullptr;
|
||||
}
|
||||
|
||||
bool consume (std::size_t bytes) noexcept
|
||||
{
|
||||
return read_impl (bytes, nullptr) != nullptr;
|
||||
}
|
||||
|
||||
bool read (std::size_t bytes) noexcept
|
||||
{
|
||||
return read_impl (bytes, nullptr) != nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool read (T* t) noexcept
|
||||
{
|
||||
return read_impl (sizeof (T), t) != nullptr;
|
||||
}
|
||||
|
||||
uint8 operator[] (std::size_t index) const noexcept
|
||||
{
|
||||
bassert (index >= 0 && index < size ());
|
||||
return m_iter [index];
|
||||
}
|
||||
|
||||
// Reads an integraltype in network byte order
|
||||
template <typename IntegerType>
|
||||
bool readNetworkInteger (IntegerType* value)
|
||||
{
|
||||
// Must be an integral type!
|
||||
// not available in all versions of std:: unfortunately
|
||||
//static_bassert (std::is_integral <IntegerType>::value);
|
||||
IntegerType networkValue;
|
||||
if (! read (&networkValue))
|
||||
return false;
|
||||
*value = fromNetworkByteOrder (networkValue);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
void const* peek_impl (std::size_t bytes, void* buffer) const noexcept
|
||||
{
|
||||
if (size () >= bytes)
|
||||
{
|
||||
if (buffer != nullptr)
|
||||
memcpy (buffer, m_iter, bytes);
|
||||
return m_iter;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void const* read_impl (std::size_t bytes, void* buffer) noexcept
|
||||
{
|
||||
if (size () >= bytes)
|
||||
{
|
||||
if (buffer != nullptr)
|
||||
memcpy (buffer, m_iter, bytes);
|
||||
void const* data = m_iter;
|
||||
m_iter += bytes;
|
||||
return data;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
uint8 const* m_begin;
|
||||
uint8 const* m_iter;
|
||||
uint8 const* m_end;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <int Bytes>
|
||||
class FixedInputBufferSize : public FixedInputBuffer
|
||||
{
|
||||
protected:
|
||||
struct SizedCtorParams
|
||||
{
|
||||
template <typename ConstBufferSequence, typename Storage>
|
||||
SizedCtorParams (ConstBufferSequence const& buffers, Storage& storage)
|
||||
{
|
||||
MutableBuffer buffer (boost::asio::buffer (storage));
|
||||
data = boost::asio::buffer_cast <uint8 const*> (buffer);
|
||||
bytes = boost::asio::buffer_copy (buffer, buffers);
|
||||
}
|
||||
|
||||
operator CtorParams () const noexcept
|
||||
{
|
||||
return CtorParams (data, bytes);
|
||||
}
|
||||
|
||||
uint8 const* data;
|
||||
std::size_t bytes;
|
||||
};
|
||||
|
||||
public:
|
||||
template <typename ConstBufferSequence>
|
||||
explicit FixedInputBufferSize (ConstBufferSequence const& buffers)
|
||||
: FixedInputBuffer (SizedCtorParams (buffers, m_storage))
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
boost::array <uint8, Bytes> m_storage;
|
||||
MutableBuffer m_buffer;
|
||||
};
|
||||
|
||||
#endif
|
||||
44
src/beast/modules/beast_asio/basics/PeerRole.cpp
Normal file
44
src/beast/modules/beast_asio/basics/PeerRole.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
PeerRole::PeerRole (role_t role)
|
||||
: m_role (role)
|
||||
{
|
||||
}
|
||||
|
||||
String PeerRole::name () const noexcept
|
||||
{
|
||||
if (m_role == server)
|
||||
return "server";
|
||||
return "client";
|
||||
}
|
||||
|
||||
bool PeerRole::operator== (role_t role) const noexcept
|
||||
{
|
||||
return m_role == role;
|
||||
}
|
||||
|
||||
#if 0
|
||||
PeerRole::operator Socket::handshake_type () const noexcept
|
||||
{
|
||||
if (m_role == server)
|
||||
return Socket::server;
|
||||
return Socket::client;
|
||||
}
|
||||
#endif
|
||||
40
src/beast/modules/beast_asio/basics/PeerRole.h
Normal file
40
src/beast/modules/beast_asio/basics/PeerRole.h
Normal file
@@ -0,0 +1,40 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_BASICS_PEERROLE_H_INCLUDED
|
||||
#define BEAST_ASIO_BASICS_PEERROLE_H_INCLUDED
|
||||
|
||||
/** Identifies if the peer is a client or a server. */
|
||||
struct PeerRole
|
||||
{
|
||||
enum role_t
|
||||
{
|
||||
client,
|
||||
server
|
||||
};
|
||||
|
||||
PeerRole (role_t role);
|
||||
String name () const noexcept;
|
||||
bool operator== (role_t role) const noexcept;
|
||||
|
||||
private:
|
||||
role_t m_role;
|
||||
};
|
||||
|
||||
#endif
|
||||
28
src/beast/modules/beast_asio/basics/SSLContext.cpp
Normal file
28
src/beast/modules/beast_asio/basics/SSLContext.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
SSLContext::SSLContext (ContextType& context)
|
||||
: m_context (context)
|
||||
{
|
||||
}
|
||||
|
||||
SSLContext::~SSLContext ()
|
||||
{
|
||||
}
|
||||
|
||||
61
src/beast/modules/beast_asio/basics/SSLContext.h
Normal file
61
src/beast/modules/beast_asio/basics/SSLContext.h
Normal file
@@ -0,0 +1,61 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_BASICS_SSLCONTEXT_H_INCLUDED
|
||||
#define BEAST_ASIO_BASICS_SSLCONTEXT_H_INCLUDED
|
||||
|
||||
/** Simple base class for passing a context around.
|
||||
This lets derived classes hide their implementation from the headers.
|
||||
*/
|
||||
class SSLContext : public Uncopyable
|
||||
{
|
||||
public:
|
||||
virtual ~SSLContext ();
|
||||
|
||||
// Saves typing
|
||||
typedef boost::asio::ssl::context ContextType;
|
||||
|
||||
inline ContextType& get () noexcept
|
||||
{
|
||||
return m_context;
|
||||
}
|
||||
|
||||
inline ContextType const& get () const noexcept
|
||||
{
|
||||
return m_context;
|
||||
}
|
||||
|
||||
// implicit conversion
|
||||
inline operator ContextType& () noexcept
|
||||
{
|
||||
return get ();
|
||||
}
|
||||
|
||||
inline operator ContextType const& () const noexcept
|
||||
{
|
||||
return get ();
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit SSLContext (ContextType& context);
|
||||
|
||||
ContextType& m_context;
|
||||
};
|
||||
|
||||
#endif
|
||||
75
src/beast/modules/beast_asio/beast_asio.cpp
Normal file
75
src/beast/modules/beast_asio/beast_asio.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include "BeastConfig.h"
|
||||
|
||||
#include "system/OpenSSLIncludes.h"
|
||||
|
||||
#include "beast_asio.h"
|
||||
|
||||
namespace beast
|
||||
{
|
||||
|
||||
#include "async/SharedHandler.cpp"
|
||||
|
||||
#include "basics/ContentBodyBuffer.cpp"
|
||||
#include "basics/PeerRole.cpp"
|
||||
#include "basics/SSLContext.cpp"
|
||||
|
||||
#include "sockets/SocketBase.cpp"
|
||||
#include "sockets/Socket.cpp"
|
||||
|
||||
#include "protocol/HandshakeDetectLogicPROXY.cpp"
|
||||
|
||||
# include "parsehttp/http_parser.h"
|
||||
# include "http/HTTPParserImpl.h"
|
||||
#include "http/HTTPParser.cpp"
|
||||
#include "http/UniformResourceLocator.cpp"
|
||||
#include "http/HTTPClientType.cpp"
|
||||
#include "http/HTTPField.cpp"
|
||||
#include "http/HTTPHeaders.cpp"
|
||||
#include "http/HTTPMessage.cpp"
|
||||
#include "http/HTTPResponse.cpp"
|
||||
#include "http/HTTPVersion.cpp"
|
||||
|
||||
#include "tests/PeerTest.cpp"
|
||||
#include "tests/TestPeerBasics.cpp"
|
||||
#include "tests/TestPeerLogic.cpp"
|
||||
#include "tests/TestPeerLogicProxyClient.cpp"
|
||||
#include "tests/TestPeerLogicSyncServer.cpp"
|
||||
#include "tests/TestPeerLogicSyncClient.cpp"
|
||||
#include "tests/TestPeerLogicAsyncServer.cpp"
|
||||
#include "tests/TestPeerLogicAsyncClient.cpp"
|
||||
#include "tests/TestPeerUnitTests.cpp"
|
||||
|
||||
#include "system/BoostUnitTests.cpp"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4127) // conditional expression is constant
|
||||
#pragma warning (disable: 4244) // integer conversion, possible loss of data
|
||||
#endif
|
||||
#include "parsehttp/http_parser.c"
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
111
src/beast/modules/beast_asio/beast_asio.h
Normal file
111
src/beast/modules/beast_asio/beast_asio.h
Normal file
@@ -0,0 +1,111 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_H_INCLUDED
|
||||
#define BEAST_ASIO_H_INCLUDED
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/* If you fail to make sure that all your compile units are building Beast with
|
||||
the same set of option flags, then there's a risk that different compile
|
||||
units will treat the classes as having different memory layouts, leading to
|
||||
very nasty memory corruption errors when they all get linked together.
|
||||
That's why it's best to always include the BeastConfig.h file before any
|
||||
beast headers.
|
||||
*/
|
||||
#ifndef BEAST_BEASTCONFIG_H_INCLUDED
|
||||
# ifdef _MSC_VER
|
||||
# pragma message ("Have you included your BeastConfig.h file before including the Beast headers?")
|
||||
# else
|
||||
# warning "Have you included your BeastConfig.h file before including the Beast headers?"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Must come before boost includes to fix the bost placeholders.
|
||||
#include "../beast_core/beast_core.h"
|
||||
|
||||
// This module requires boost and possibly OpenSSL
|
||||
#include "system/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
|
||||
|
||||
namespace beast
|
||||
{
|
||||
|
||||
// Order matters
|
||||
# include "async/SharedHandler.h"
|
||||
# include "async/SharedHandlerType.h"
|
||||
# include "async/SharedHandlerPtr.h"
|
||||
# include "async/ComposedAsyncOperation.h"
|
||||
#include "async/SharedHandlerAllocator.h"
|
||||
|
||||
# include "basics/BufferType.h"
|
||||
# include "basics/BuffersType.h"
|
||||
#include "basics/ContentBodyBuffer.h"
|
||||
#include "basics/FixedInputBuffer.h"
|
||||
#include "basics/PeerRole.h"
|
||||
#include "basics/SSLContext.h"
|
||||
|
||||
# include "sockets/SocketBase.h"
|
||||
# include "sockets/Socket.h"
|
||||
# include "sockets/SocketWrapper.h"
|
||||
#include "sockets/SocketWrapperStrand.h"
|
||||
|
||||
# include "http/HTTPVersion.h"
|
||||
# include "http/HTTPField.h"
|
||||
# include "http/HTTPHeaders.h"
|
||||
# include "http/HTTPMessage.h"
|
||||
# include "http/HTTPResponse.h"
|
||||
# include "http/HTTPParser.h"
|
||||
# include "http/UniformResourceLocator.h"
|
||||
#include "http/HTTPClientType.h"
|
||||
|
||||
# include "protocol/InputParser.h"
|
||||
# include "protocol/HandshakeDetectLogic.h"
|
||||
#include "protocol/HandshakeDetectLogicPROXY.h"
|
||||
#include "protocol/HandshakeDetectLogicSSL2.h"
|
||||
#include "protocol/HandshakeDetectLogicSSL3.h"
|
||||
#include "protocol/HandshakeDetector.h"
|
||||
#include "protocol/PrefilledReadStream.h"
|
||||
|
||||
#include "tests/TestPeerBasics.h"
|
||||
#include "tests/TestPeer.h"
|
||||
#include "tests/TestPeerDetails.h"
|
||||
#include "tests/TestPeerLogic.h"
|
||||
#include "tests/TestPeerLogicSyncServer.h"
|
||||
#include "tests/TestPeerLogicSyncClient.h"
|
||||
#include "tests/TestPeerLogicProxyClient.h"
|
||||
#include "tests/TestPeerLogicAsyncServer.h"
|
||||
#include "tests/TestPeerLogicAsyncClient.h"
|
||||
#include "tests/TestPeerType.h"
|
||||
#include "tests/TestPeerDetailsTcp.h"
|
||||
#include "tests/PeerTest.h"
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
838
src/beast/modules/beast_asio/http/HTTPClientType.cpp
Normal file
838
src/beast/modules/beast_asio/http/HTTPClientType.cpp
Normal file
@@ -0,0 +1,838 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
class HTTPClientType : public HTTPClientBase, public Uncopyable
|
||||
{
|
||||
private:
|
||||
using HTTPClientBase::Listener;
|
||||
|
||||
typedef boost::system::error_code error_code;
|
||||
|
||||
class ListenerHandler
|
||||
{
|
||||
public:
|
||||
ListenerHandler ()
|
||||
: m_owner (nullptr)
|
||||
, m_listener (nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ListenerHandler (HTTPClientType* owner, Listener* listener = nullptr)
|
||||
: m_owner (owner)
|
||||
, m_listener (listener)
|
||||
{
|
||||
}
|
||||
|
||||
ListenerHandler (ListenerHandler const& other)
|
||||
: m_owner (other.m_owner)
|
||||
, m_listener (other.m_listener)
|
||||
{
|
||||
}
|
||||
|
||||
ListenerHandler& operator= (ListenerHandler const& other)
|
||||
{
|
||||
m_owner = other.m_owner;
|
||||
m_listener = other.m_listener;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void operator() (error_code)
|
||||
{
|
||||
if (m_listener != nullptr)
|
||||
m_listener->onHTTPRequestComplete (
|
||||
*m_owner, m_owner->result ());
|
||||
}
|
||||
|
||||
private:
|
||||
HTTPClientType* m_owner;
|
||||
Listener* m_listener;
|
||||
};
|
||||
|
||||
public:
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
HTTPClientType (
|
||||
double timeoutSeconds,
|
||||
std::size_t messageLimitBytes,
|
||||
std::size_t bufferSize)
|
||||
: m_timeoutSeconds (timeoutSeconds)
|
||||
, m_messageLimitBytes (messageLimitBytes)
|
||||
, m_bufferSize (bufferSize)
|
||||
{
|
||||
}
|
||||
|
||||
~HTTPClientType ()
|
||||
{
|
||||
m_async_op = nullptr;
|
||||
}
|
||||
|
||||
Result const& result () const
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
|
||||
Result const& get (UniformResourceLocator const& url)
|
||||
{
|
||||
boost::asio::io_service io_service;
|
||||
async_get (io_service, nullptr, url);
|
||||
io_service.run ();
|
||||
cancel ();
|
||||
return result ();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void async_get (boost::asio::io_service& io_service, Listener* listener,
|
||||
UniformResourceLocator const& url)
|
||||
{
|
||||
async_get (io_service, url, ListenerHandler (this, listener));
|
||||
}
|
||||
|
||||
// Handler signature is void(error_code)
|
||||
//
|
||||
template <typename Handler>
|
||||
void async_get (boost::asio::io_service& io_service,
|
||||
UniformResourceLocator const& url,
|
||||
BOOST_ASIO_MOVE_ARG(Handler) handler)
|
||||
{
|
||||
async_get (io_service, url, newErrorHandler (
|
||||
BOOST_ASIO_MOVE_CAST(Handler)(handler)));
|
||||
}
|
||||
|
||||
void async_get (boost::asio::io_service& io_service,
|
||||
UniformResourceLocator const& url, SharedHandlerPtr handler)
|
||||
{
|
||||
// This automatically dispatches
|
||||
m_async_op = new AsyncGetOp (
|
||||
*this, io_service, url, handler,
|
||||
m_timeoutSeconds, m_messageLimitBytes, m_bufferSize);
|
||||
}
|
||||
|
||||
void cancel ()
|
||||
{
|
||||
if (m_async_op != nullptr)
|
||||
{
|
||||
m_async_op->cancel ();
|
||||
m_async_op = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** Helper function to get a const_buffer from a String. */
|
||||
static boost::asio::const_buffers_1 stringBuffer (String const& s)
|
||||
{
|
||||
return boost::asio::const_buffers_1 (s.getCharPointer (), s.length ());
|
||||
}
|
||||
|
||||
/** Helper function to fill out a Query from a URL. */
|
||||
template <typename Query>
|
||||
static Query queryFromURL (UniformResourceLocator const& url)
|
||||
{
|
||||
if (url.port () != 0)
|
||||
{
|
||||
return Query (
|
||||
url.host().toStdString(),
|
||||
url.port_string().toStdString(),
|
||||
Query::numeric_service);
|
||||
}
|
||||
|
||||
return Query (
|
||||
url.host().toStdString(),
|
||||
url.scheme().toStdString());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
class AsyncGetOp : public ComposedAsyncOperation
|
||||
{
|
||||
private:
|
||||
typedef boost::asio::ip::tcp Protocol;
|
||||
typedef boost::system::error_code error_code;
|
||||
|
||||
typedef Protocol::resolver resolver;
|
||||
typedef resolver::query query;
|
||||
typedef resolver::iterator iterator;
|
||||
typedef iterator::value_type resolver_entry;
|
||||
typedef Protocol::socket socket;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
enum State
|
||||
{
|
||||
stateStart,
|
||||
stateResolveComplete,
|
||||
stateConnectComplete,
|
||||
stateHandshakeComplete,
|
||||
stateWriteComplete,
|
||||
stateShutdownComplete
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
struct TimerHandler : SharedHandlerPtr
|
||||
{
|
||||
explicit TimerHandler (AsyncGetOp* owner)
|
||||
: SharedHandlerPtr (owner)
|
||||
, m_owner (owner)
|
||||
{
|
||||
}
|
||||
void operator() (error_code const& ec)
|
||||
{
|
||||
m_owner->timerCompletion (ec);
|
||||
}
|
||||
|
||||
AsyncGetOp* m_owner;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
public:
|
||||
AsyncGetOp (HTTPClientType& owner,
|
||||
boost::asio::io_service& io_service,
|
||||
UniformResourceLocator const& url,
|
||||
SharedHandlerPtr const& handler,
|
||||
double timeoutSeconds,
|
||||
std::size_t messageLimitBytes,
|
||||
std::size_t bufferSize)
|
||||
: ComposedAsyncOperation (sizeof (*this), handler)
|
||||
, m_owner (owner)
|
||||
, m_io_service (io_service)
|
||||
, m_strand (m_io_service)
|
||||
, m_url (url)
|
||||
, m_handler (handler)
|
||||
, m_timer (io_service)
|
||||
, m_resolver (io_service)
|
||||
, m_socket (io_service)
|
||||
, m_context (boost::asio::ssl::context::sslv23)
|
||||
, m_buffer (bufferSize)
|
||||
, m_parser (HTTPParser::typeResponse)
|
||||
, m_timer_canceled (false)
|
||||
, m_timer_expired (false)
|
||||
, m_messageLimitBytes (messageLimitBytes)
|
||||
, m_bytesReceived (0)
|
||||
{
|
||||
m_context.set_default_verify_paths ();
|
||||
m_context.set_options (
|
||||
boost::asio::ssl::context::no_sslv2 |
|
||||
boost::asio::ssl::context::single_dh_use |
|
||||
boost::asio::ssl::context::default_workarounds);
|
||||
//m_context.set_verify_mode (boost::asio::ssl::verify_peer);
|
||||
|
||||
if (timeoutSeconds > 0)
|
||||
{
|
||||
m_timer.expires_from_now (
|
||||
boost::posix_time::milliseconds (
|
||||
long (timeoutSeconds * 1000)));
|
||||
|
||||
++m_io_pending;
|
||||
m_timer.async_wait (TimerHandler (this));
|
||||
}
|
||||
|
||||
// Count as pending i/o
|
||||
++m_io_pending;
|
||||
m_io_service.dispatch (
|
||||
m_strand.wrap (StartHandler (this)));
|
||||
}
|
||||
|
||||
~AsyncGetOp ()
|
||||
{
|
||||
}
|
||||
|
||||
// Cancel all pending I/O, if any, and block until
|
||||
// there are no more completion handler calls pending.
|
||||
//
|
||||
void cancel ()
|
||||
{
|
||||
cancel_all ();
|
||||
m_done.wait ();
|
||||
}
|
||||
|
||||
private:
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
// Counts a pending i/o as canceled
|
||||
//
|
||||
void cancel_io ()
|
||||
{
|
||||
bassert (m_io_pending.get () > 0);
|
||||
if (--m_io_pending == 0)
|
||||
m_done.signal ();
|
||||
}
|
||||
|
||||
// Cancels the deadline timer.
|
||||
//
|
||||
void cancel_timer ()
|
||||
{
|
||||
m_timer_canceled = true;
|
||||
error_code ec;
|
||||
m_timer.cancel (ec);
|
||||
}
|
||||
|
||||
// Called to notify the original handler the operation is complete.
|
||||
//
|
||||
void complete (error_code const& ec)
|
||||
{
|
||||
m_owner.m_result.error = ec;
|
||||
|
||||
cancel_timer ();
|
||||
|
||||
bassert (m_io_pending.get () > 0);
|
||||
|
||||
cancel_io ();
|
||||
|
||||
// We call the handler directly since we know
|
||||
// we are already in the right context, and
|
||||
// because we need to do some things afterwards.
|
||||
//
|
||||
m_handler->operator() (ec);
|
||||
}
|
||||
|
||||
// Called every time an async operation completes.
|
||||
// The return value indicates if the handler should
|
||||
// stop additional activity and return immediately.
|
||||
//
|
||||
bool io_complete (error_code const& ec)
|
||||
{
|
||||
if (m_timer_expired ||
|
||||
ec == boost::asio::error::operation_aborted)
|
||||
{
|
||||
cancel_io ();
|
||||
return true;
|
||||
}
|
||||
else if (ec != 0 && ec != boost::asio::error::eof)
|
||||
{
|
||||
complete (ec);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cancels/closes all i/o objects.
|
||||
//
|
||||
void cancel_all ()
|
||||
{
|
||||
cancel_timer ();
|
||||
m_resolver.cancel ();
|
||||
error_code ec;
|
||||
m_socket.close (ec);
|
||||
}
|
||||
|
||||
// Called when the deadline timer expires or is canceled.
|
||||
//
|
||||
void timerCompletion (error_code ec)
|
||||
{
|
||||
if (ec == boost::asio::error::operation_aborted)
|
||||
{
|
||||
bassert (m_timer_canceled);
|
||||
return cancel_io ();
|
||||
}
|
||||
|
||||
check_invariant (ec == 0);
|
||||
|
||||
// Handle the case where the timer completion has already
|
||||
// been queued for dispatch but we have finished the operation
|
||||
// and queued the completion handler for dispatch.
|
||||
//
|
||||
if (! m_timer_canceled)
|
||||
{
|
||||
m_timer_expired = true;
|
||||
|
||||
ec = error_code (boost::asio::error::timed_out,
|
||||
boost::asio::error::get_system_category ());
|
||||
|
||||
complete (ec);
|
||||
|
||||
io_complete (ec);
|
||||
|
||||
m_resolver.cancel ();
|
||||
m_socket.close (ec);
|
||||
}
|
||||
else
|
||||
{
|
||||
cancel_io ();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
struct StartHandler : SharedHandlerPtr
|
||||
{
|
||||
explicit StartHandler (AsyncGetOp* owner)
|
||||
: SharedHandlerPtr (owner)
|
||||
, m_owner (owner)
|
||||
{
|
||||
}
|
||||
|
||||
void operator() ()
|
||||
{
|
||||
m_owner->start_complete ();
|
||||
}
|
||||
|
||||
AsyncGetOp* m_owner;
|
||||
};
|
||||
|
||||
struct ResolveHandler : SharedHandlerPtr
|
||||
{
|
||||
explicit ResolveHandler (AsyncGetOp* owner)
|
||||
: SharedHandlerPtr (owner)
|
||||
, m_owner (owner)
|
||||
{
|
||||
}
|
||||
|
||||
void operator() (error_code const& ec, iterator iter)
|
||||
{
|
||||
m_owner->resolve_complete (ec, iter);
|
||||
}
|
||||
|
||||
AsyncGetOp* m_owner;
|
||||
};
|
||||
|
||||
struct ConnectHandler : SharedHandlerPtr
|
||||
{
|
||||
explicit ConnectHandler (AsyncGetOp* owner)
|
||||
: SharedHandlerPtr (owner)
|
||||
, m_owner (owner)
|
||||
{
|
||||
}
|
||||
|
||||
void operator() (error_code const& ec)
|
||||
{
|
||||
m_owner->connect_complete (ec);
|
||||
}
|
||||
|
||||
AsyncGetOp* m_owner;
|
||||
};
|
||||
|
||||
struct HandshakeHandler : SharedHandlerPtr
|
||||
{
|
||||
explicit HandshakeHandler (AsyncGetOp* owner)
|
||||
: SharedHandlerPtr (owner)
|
||||
, m_owner (owner)
|
||||
{
|
||||
}
|
||||
|
||||
void operator() (error_code const& ec)
|
||||
{
|
||||
m_owner->handshake_complete (ec);
|
||||
}
|
||||
|
||||
AsyncGetOp* m_owner;
|
||||
};
|
||||
|
||||
struct WriteHandler : SharedHandlerPtr
|
||||
{
|
||||
explicit WriteHandler (AsyncGetOp* owner)
|
||||
: SharedHandlerPtr (owner)
|
||||
, m_owner (owner)
|
||||
{
|
||||
}
|
||||
|
||||
void operator() (error_code const& ec, std::size_t bytes_transferred)
|
||||
{
|
||||
m_owner->write_complete (ec, bytes_transferred);
|
||||
}
|
||||
|
||||
AsyncGetOp* m_owner;
|
||||
};
|
||||
|
||||
struct ReadHandler : SharedHandlerPtr
|
||||
{
|
||||
explicit ReadHandler (AsyncGetOp* owner)
|
||||
: SharedHandlerPtr (owner)
|
||||
, m_owner (owner)
|
||||
{
|
||||
}
|
||||
|
||||
void operator() (error_code const& ec, std::size_t bytes_transferred)
|
||||
{
|
||||
m_owner->read_complete (ec, bytes_transferred);
|
||||
}
|
||||
|
||||
AsyncGetOp* m_owner;
|
||||
};
|
||||
|
||||
struct ShutdownHandler : SharedHandlerPtr
|
||||
{
|
||||
explicit ShutdownHandler (AsyncGetOp* owner)
|
||||
: SharedHandlerPtr (owner)
|
||||
, m_owner (owner)
|
||||
{
|
||||
}
|
||||
|
||||
void operator() (error_code const& ec)
|
||||
{
|
||||
m_owner->shutdown_complete (ec);
|
||||
}
|
||||
|
||||
AsyncGetOp* m_owner;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void async_read_some ()
|
||||
{
|
||||
boost::asio::mutable_buffers_1 buf (
|
||||
m_buffer.getData (), m_buffer.getSize ());
|
||||
|
||||
m_stream->async_read_some (buf,
|
||||
m_strand.wrap (ReadHandler (this)));
|
||||
}
|
||||
|
||||
// Called when the HTTP parser returns an error
|
||||
void parse_error ()
|
||||
{
|
||||
//unsigned char const http_errno (m_parser.error ());
|
||||
String const http_errmsg (m_parser.message ());
|
||||
|
||||
// VFALCO TODO put the parser error in ec
|
||||
error_code ec (
|
||||
boost::system::errc::invalid_argument,
|
||||
boost::system::system_category ());
|
||||
|
||||
complete (ec);
|
||||
}
|
||||
|
||||
// Called to create an error when the message is over the limit
|
||||
error_code message_limit_error ()
|
||||
{
|
||||
// VFALCO TODO Make a suitable error code
|
||||
return error_code (
|
||||
boost::system::errc::invalid_argument,
|
||||
boost::system::system_category ());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
void start_complete ()
|
||||
{
|
||||
query q (queryFromURL <query> (m_url));
|
||||
m_resolver.async_resolve (q,
|
||||
m_strand.wrap (ResolveHandler (this)));
|
||||
}
|
||||
|
||||
void resolve_complete (error_code ec, iterator iter)
|
||||
{
|
||||
if (io_complete (ec))
|
||||
return;
|
||||
|
||||
resolver_entry const entry (*iter);
|
||||
m_socket.async_connect (entry.endpoint (),
|
||||
m_strand.wrap (ConnectHandler (this)));
|
||||
}
|
||||
|
||||
void connect_complete (error_code ec)
|
||||
{
|
||||
if (io_complete (ec))
|
||||
return;
|
||||
|
||||
if (m_url.scheme () == "https")
|
||||
{
|
||||
typedef boost::asio::ssl::stream <socket&> ssl_stream;
|
||||
m_stream = new SocketWrapper <ssl_stream> (m_socket, m_context);
|
||||
/*
|
||||
m_stream->set_verify_mode (
|
||||
boost::asio::ssl::verify_peer |
|
||||
boost::asio::ssl::verify_fail_if_no_peer_cert);
|
||||
*/
|
||||
m_stream->async_handshake (
|
||||
Socket::client, HandshakeHandler (this));
|
||||
return;
|
||||
}
|
||||
|
||||
m_stream = new SocketWrapper <socket&> (m_socket);
|
||||
handshake_complete (ec);
|
||||
}
|
||||
|
||||
void handshake_complete (error_code ec)
|
||||
{
|
||||
if (io_complete (ec))
|
||||
return;
|
||||
|
||||
m_get_string =
|
||||
"GET " + m_url.path() + " HTTP/1.1\r\n" +
|
||||
"Host: " + m_url.host() + "\r\n" +
|
||||
"Accept: */*\r\n" +
|
||||
"Connection: close\r\n\r\n";
|
||||
|
||||
boost::asio::async_write (
|
||||
*m_stream, stringBuffer (m_get_string),
|
||||
m_strand.wrap (WriteHandler (this)));
|
||||
++m_io_pending;
|
||||
|
||||
async_read_some ();
|
||||
}
|
||||
|
||||
void write_complete (error_code ec, std::size_t)
|
||||
{
|
||||
if (io_complete (ec))
|
||||
return;
|
||||
|
||||
if (! m_stream->needs_handshake ())
|
||||
{
|
||||
m_socket.shutdown (socket::shutdown_send, ec);
|
||||
if (ec != 0)
|
||||
return complete (ec);
|
||||
}
|
||||
|
||||
// deduct one i/o since we aren't issuing any new one
|
||||
cancel_io ();
|
||||
}
|
||||
|
||||
void read_complete (error_code ec, std::size_t bytes_transferred)
|
||||
{
|
||||
m_bytesReceived += bytes_transferred;
|
||||
if (m_bytesReceived > m_messageLimitBytes)
|
||||
ec = message_limit_error ();
|
||||
|
||||
if (io_complete (ec))
|
||||
return;
|
||||
|
||||
std::size_t const bytes_parsed (m_parser.process (
|
||||
m_buffer.getData (), bytes_transferred));
|
||||
|
||||
if (m_parser.error ())
|
||||
{
|
||||
parse_error ();
|
||||
return;
|
||||
}
|
||||
|
||||
if (bytes_parsed != bytes_transferred)
|
||||
{
|
||||
// VFALCO TODO put an appropriate error in ec
|
||||
ec = error_code (
|
||||
boost::system::errc::invalid_argument,
|
||||
boost::system::system_category ());
|
||||
return complete (ec);
|
||||
}
|
||||
|
||||
if (ec == boost::asio::error::eof)
|
||||
{
|
||||
m_parser.process_eof ();
|
||||
}
|
||||
|
||||
if (m_parser.finished ())
|
||||
{
|
||||
m_state = stateShutdownComplete;
|
||||
if (m_stream->needs_handshake ())
|
||||
m_stream->async_shutdown (ShutdownHandler (this));
|
||||
else
|
||||
shutdown_complete (error_code ());
|
||||
return;
|
||||
}
|
||||
|
||||
async_read_some ();
|
||||
}
|
||||
|
||||
void shutdown_complete (error_code ec)
|
||||
{
|
||||
if (io_complete (ec))
|
||||
return;
|
||||
|
||||
m_owner.m_result.response = m_parser.response ();
|
||||
if (ec == boost::asio::error::eof)
|
||||
ec = error_code ();
|
||||
|
||||
return complete (ec);
|
||||
}
|
||||
|
||||
private:
|
||||
WaitableEvent m_done;
|
||||
Atomic <int> m_io_pending;
|
||||
HTTPClientType& m_owner;
|
||||
boost::asio::io_service& m_io_service;
|
||||
boost::asio::io_service& m_strand;
|
||||
UniformResourceLocator m_url;
|
||||
SharedHandlerPtr m_handler;
|
||||
boost::asio::deadline_timer m_timer;
|
||||
resolver m_resolver;
|
||||
socket m_socket;
|
||||
ScopedPointer <Socket> m_stream;
|
||||
boost::asio::ssl::context m_context;
|
||||
MemoryBlock m_buffer;
|
||||
State m_state;
|
||||
HTTPParser m_parser;
|
||||
String m_get_string;
|
||||
bool m_timer_canceled;
|
||||
bool m_timer_expired;
|
||||
std::size_t m_messageLimitBytes;
|
||||
std::size_t m_bytesReceived;
|
||||
};
|
||||
|
||||
double m_timeoutSeconds;
|
||||
std::size_t m_messageLimitBytes;
|
||||
std::size_t m_bufferSize;
|
||||
boost::asio::io_service m_io_service;
|
||||
SharedPtr <AsyncGetOp> m_async_op;
|
||||
Result m_result;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
HTTPClientBase* HTTPClientBase::New (
|
||||
double timeoutSeconds, std::size_t messageLimitBytes, std::size_t bufferSize)
|
||||
{
|
||||
ScopedPointer <HTTPClientBase> object (new HTTPClientType
|
||||
(timeoutSeconds, messageLimitBytes, bufferSize));
|
||||
return object.release ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class HTTPClientTests
|
||||
: public UnitTest
|
||||
, public HTTPClientBase::Listener
|
||||
{
|
||||
public:
|
||||
typedef boost::system::error_code error_code;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
class IoServiceThread : protected Thread
|
||||
{
|
||||
public:
|
||||
explicit IoServiceThread (String name = "io_service")
|
||||
: Thread (name)
|
||||
{
|
||||
}
|
||||
|
||||
~IoServiceThread ()
|
||||
{
|
||||
join ();
|
||||
}
|
||||
|
||||
boost::asio::io_service& get_io_service ()
|
||||
{
|
||||
return m_service;
|
||||
}
|
||||
|
||||
void start ()
|
||||
{
|
||||
startThread ();
|
||||
}
|
||||
|
||||
void join ()
|
||||
{
|
||||
this->waitForThreadToExit ();
|
||||
}
|
||||
|
||||
private:
|
||||
void run ()
|
||||
{
|
||||
m_service.run ();
|
||||
}
|
||||
|
||||
private:
|
||||
boost::asio::io_service m_service;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void log (HTTPMessage const& m)
|
||||
{
|
||||
for (std::size_t i = 0; i < m.headers().size(); ++i)
|
||||
{
|
||||
HTTPField const f (m.headers()[i]);
|
||||
String s;
|
||||
s = "[ '" + f.name() +
|
||||
"' , '" + f.value() + "' ]";
|
||||
logMessage (s);
|
||||
}
|
||||
}
|
||||
|
||||
void log (HTTPClientBase::Result const& result)
|
||||
{
|
||||
if (result.error != 0)
|
||||
{
|
||||
logMessage (String (
|
||||
"HTTPClient error: '" + result.error.message() + "'"));
|
||||
}
|
||||
else if (! result.response.empty ())
|
||||
{
|
||||
logMessage (String ("Status: ") +
|
||||
String::fromNumber (result.response->status()));
|
||||
|
||||
log (*result.response);
|
||||
}
|
||||
else
|
||||
{
|
||||
logMessage ("HTTPClient: no response");
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void onHTTPRequestComplete (
|
||||
HTTPClientBase const&, HTTPClientBase::Result const& result)
|
||||
{
|
||||
log (result);
|
||||
}
|
||||
|
||||
void testSync (String const& s, double timeoutSeconds)
|
||||
{
|
||||
ScopedPointer <HTTPClientBase> client (
|
||||
HTTPClientBase::New (timeoutSeconds));
|
||||
|
||||
log (client->get (ParsedURL (s).url ()));
|
||||
}
|
||||
|
||||
void testAsync (String const& s, double timeoutSeconds)
|
||||
{
|
||||
IoServiceThread t;
|
||||
ScopedPointer <HTTPClientBase> client (
|
||||
HTTPClientBase::New (timeoutSeconds));
|
||||
|
||||
client->async_get (t.get_io_service (), this,
|
||||
ParsedURL (s).url ());
|
||||
|
||||
t.start ();
|
||||
t.join ();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void runTest ()
|
||||
{
|
||||
beginTestCase ("HTTPClient::get");
|
||||
|
||||
testSync (
|
||||
"http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference.html",
|
||||
5);
|
||||
|
||||
testAsync (
|
||||
"http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference.html",
|
||||
5);
|
||||
|
||||
testAsync (
|
||||
"https://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference.html",
|
||||
5);
|
||||
|
||||
pass ();
|
||||
}
|
||||
|
||||
HTTPClientTests () : UnitTest ("HttpClient", "beast", runManual)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static HTTPClientTests httpClientTests;
|
||||
|
||||
|
||||
65
src/beast/modules/beast_asio/http/HTTPClientType.h
Normal file
65
src/beast/modules/beast_asio/http/HTTPClientType.h
Normal file
@@ -0,0 +1,65 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_HTTPCLIENTTYPE_H_INCLUDED
|
||||
#define BEAST_ASIO_HTTPCLIENTTYPE_H_INCLUDED
|
||||
|
||||
class HTTPClientBase
|
||||
{
|
||||
public:
|
||||
struct Result
|
||||
{
|
||||
boost::system::error_code error;
|
||||
SharedPtr <HTTPResponse> response;
|
||||
};
|
||||
|
||||
class Listener
|
||||
{
|
||||
public:
|
||||
virtual void onHTTPRequestComplete (
|
||||
HTTPClientBase const& client,
|
||||
Result const& result) = 0;
|
||||
};
|
||||
|
||||
static HTTPClientBase* New (
|
||||
double timeoutSeconds = 30,
|
||||
std::size_t messageLimitBytes = 256 * 1024,
|
||||
std::size_t bufferSize = 16 * 1024);
|
||||
|
||||
virtual ~HTTPClientBase () { }
|
||||
|
||||
virtual Result const& result () const = 0;
|
||||
|
||||
virtual Result const& get (
|
||||
UniformResourceLocator const& url) = 0;
|
||||
|
||||
virtual void async_get (boost::asio::io_service& io_service,
|
||||
Listener* listener,
|
||||
UniformResourceLocator const& url) = 0;
|
||||
|
||||
/** Cancel any pending asynchronous operations.
|
||||
This must be called before destroying the container if there are
|
||||
any pending asynchronous operations. This routine does nothing if
|
||||
there are no pending operations. The call will block until all
|
||||
pending i/o is canceled.
|
||||
*/
|
||||
virtual void cancel () = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
51
src/beast/modules/beast_asio/http/HTTPField.cpp
Normal file
51
src/beast/modules/beast_asio/http/HTTPField.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
HTTPField::HTTPField ()
|
||||
{
|
||||
}
|
||||
|
||||
HTTPField::HTTPField (String name_, String value_)
|
||||
: m_name (name_)
|
||||
, m_value (value_)
|
||||
{
|
||||
}
|
||||
|
||||
HTTPField::HTTPField (HTTPField const& other)
|
||||
: m_name (other.m_name)
|
||||
, m_value (other.m_value)
|
||||
{
|
||||
}
|
||||
|
||||
HTTPField& HTTPField::operator= (HTTPField const& other)
|
||||
{
|
||||
m_name = other.m_name;
|
||||
m_value = other.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
String HTTPField::name () const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
String HTTPField::value () const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
42
src/beast/modules/beast_asio/http/HTTPField.h
Normal file
42
src/beast/modules/beast_asio/http/HTTPField.h
Normal file
@@ -0,0 +1,42 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_HTTPFIELD_H_INCLUDED
|
||||
#define BEAST_ASIO_HTTPFIELD_H_INCLUDED
|
||||
|
||||
/** A single header.
|
||||
The header is a field/value pair.
|
||||
Time complexity of copies is constant.
|
||||
*/
|
||||
class HTTPField
|
||||
{
|
||||
public:
|
||||
HTTPField ();
|
||||
HTTPField (String name_, String value_);
|
||||
HTTPField (HTTPField const& other);
|
||||
HTTPField& operator= (HTTPField const& other);
|
||||
String name () const;
|
||||
String value () const;
|
||||
|
||||
private:
|
||||
String m_name;
|
||||
String m_value;
|
||||
};
|
||||
|
||||
#endif
|
||||
74
src/beast/modules/beast_asio/http/HTTPHeaders.cpp
Normal file
74
src/beast/modules/beast_asio/http/HTTPHeaders.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
HTTPHeaders::HTTPHeaders ()
|
||||
{
|
||||
}
|
||||
|
||||
HTTPHeaders::HTTPHeaders (StringPairArray& fields)
|
||||
{
|
||||
m_fields.swapWith (fields);
|
||||
}
|
||||
|
||||
HTTPHeaders::HTTPHeaders (StringPairArray const& fields)
|
||||
: m_fields (fields)
|
||||
{
|
||||
}
|
||||
|
||||
HTTPHeaders::HTTPHeaders (HTTPHeaders const& other)
|
||||
: m_fields (other.m_fields)
|
||||
{
|
||||
}
|
||||
|
||||
HTTPHeaders& HTTPHeaders::operator= (HTTPHeaders const& other)
|
||||
{
|
||||
m_fields = other.m_fields;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool HTTPHeaders::empty () const
|
||||
{
|
||||
return m_fields.size () == 0;
|
||||
}
|
||||
|
||||
std::size_t HTTPHeaders::size () const
|
||||
{
|
||||
return m_fields.size ();
|
||||
}
|
||||
|
||||
HTTPField HTTPHeaders::at (std::size_t index) const
|
||||
{
|
||||
return HTTPField (m_fields.getAllKeys () [index],
|
||||
m_fields.getAllValues () [index]);
|
||||
}
|
||||
|
||||
HTTPField HTTPHeaders::operator[] (std::size_t index) const
|
||||
{
|
||||
return at (index);
|
||||
}
|
||||
|
||||
String HTTPHeaders::get (String const& field) const
|
||||
{
|
||||
return m_fields [field];
|
||||
}
|
||||
|
||||
String HTTPHeaders::operator[] (String const& field) const
|
||||
{
|
||||
return get (field);
|
||||
}
|
||||
68
src/beast/modules/beast_asio/http/HTTPHeaders.h
Normal file
68
src/beast/modules/beast_asio/http/HTTPHeaders.h
Normal file
@@ -0,0 +1,68 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_HTTPHEADERS_H_INCLUDED
|
||||
#define BEAST_ASIO_HTTPHEADERS_H_INCLUDED
|
||||
|
||||
/** A set of HTTP headers. */
|
||||
class HTTPHeaders
|
||||
{
|
||||
public:
|
||||
/** Construct an empty set of headers. */
|
||||
HTTPHeaders ();
|
||||
|
||||
/** Construct headers taking ownership of a field array.
|
||||
The callers value is overwritten.
|
||||
*/
|
||||
HTTPHeaders (StringPairArray& fields);
|
||||
|
||||
/** Construct a copy of headers from an array.*/
|
||||
HTTPHeaders (StringPairArray const& fields);
|
||||
|
||||
/** Construct a copy of headers. */
|
||||
HTTPHeaders (HTTPHeaders const& other);
|
||||
|
||||
/** Assign a copy of headers. */
|
||||
HTTPHeaders& operator= (HTTPHeaders const& other);
|
||||
|
||||
/** Returns `true` if the container is empty. */
|
||||
bool empty () const;
|
||||
|
||||
/** Returns the number of fields in the container. */
|
||||
std::size_t size () const;
|
||||
|
||||
/** Random access to fields by index. */
|
||||
/** @{ */
|
||||
HTTPField at (std::size_t index) const;
|
||||
HTTPField operator[] (std::size_t index) const;
|
||||
/** @} */
|
||||
|
||||
/** Associative access to fields by name.
|
||||
If the field is not present, an empty string is returned.
|
||||
*/
|
||||
/** @{ */
|
||||
String get (String const& field) const;
|
||||
String operator[] (String const& field) const;
|
||||
/** @} */
|
||||
|
||||
private:
|
||||
StringPairArray m_fields;
|
||||
};
|
||||
|
||||
#endif
|
||||
42
src/beast/modules/beast_asio/http/HTTPMessage.cpp
Normal file
42
src/beast/modules/beast_asio/http/HTTPMessage.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
HTTPMessage::HTTPMessage (HTTPVersion const& version_,
|
||||
StringPairArray& fields,
|
||||
ContentBodyBuffer& body)
|
||||
: m_version (version_)
|
||||
, m_headers (fields)
|
||||
{
|
||||
m_body.swapWith (body);
|
||||
}
|
||||
|
||||
HTTPVersion const& HTTPMessage::version () const
|
||||
{
|
||||
return m_version;
|
||||
}
|
||||
|
||||
HTTPHeaders const& HTTPMessage::headers () const
|
||||
{
|
||||
return m_headers;
|
||||
}
|
||||
|
||||
ContentBodyBuffer const& HTTPMessage::body () const
|
||||
{
|
||||
return m_body;
|
||||
}
|
||||
60
src/beast/modules/beast_asio/http/HTTPMessage.h
Normal file
60
src/beast/modules/beast_asio/http/HTTPMessage.h
Normal file
@@ -0,0 +1,60 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_HTTPMESSAGE_H_INCLUDED
|
||||
#define BEAST_ASIO_HTTPMESSAGE_H_INCLUDED
|
||||
|
||||
/** A complete HTTP message.
|
||||
|
||||
This provides the information common to all HTTP messages, including
|
||||
the version, content body, and headers.
|
||||
Derived classes provide the request or response specific data.
|
||||
|
||||
Because a single HTTP message can be a fairly expensive object to
|
||||
make copies of, this is a SharedObject.
|
||||
|
||||
@see HTTPRequest, HTTPResponse
|
||||
*/
|
||||
class HTTPMessage : public SharedObject
|
||||
{
|
||||
public:
|
||||
/** Construct the common HTTP message parts from values.
|
||||
Ownership of the fields and body parameters are
|
||||
transferred from the caller.
|
||||
*/
|
||||
HTTPMessage (HTTPVersion const& version_,
|
||||
StringPairArray& fields,
|
||||
ContentBodyBuffer& body);
|
||||
|
||||
/** Returns the HTTP version of this message. */
|
||||
HTTPVersion const& version () const;
|
||||
|
||||
/** Returns the set of HTTP headers associated with this message. */
|
||||
HTTPHeaders const& headers () const;
|
||||
|
||||
/** Returns the content-body. */
|
||||
ContentBodyBuffer const& body () const;
|
||||
|
||||
private:
|
||||
HTTPVersion m_version;
|
||||
HTTPHeaders m_headers;
|
||||
ContentBodyBuffer m_body;
|
||||
};
|
||||
|
||||
#endif
|
||||
79
src/beast/modules/beast_asio/http/HTTPParser.cpp
Normal file
79
src/beast/modules/beast_asio/http/HTTPParser.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
HTTPParser::HTTPParser (Type type)
|
||||
: m_type (type)
|
||||
, m_impl (new HTTPParserImpl (
|
||||
(type == typeResponse) ? HTTP_RESPONSE : HTTP_REQUEST))
|
||||
{
|
||||
}
|
||||
|
||||
HTTPParser::~HTTPParser ()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned char HTTPParser::error () const
|
||||
{
|
||||
return m_impl->http_errno ();
|
||||
}
|
||||
|
||||
String HTTPParser::message () const
|
||||
{
|
||||
return m_impl->http_errno_message ();
|
||||
}
|
||||
|
||||
std::size_t HTTPParser::process (void const* buf, std::size_t bytes)
|
||||
{
|
||||
std::size_t const bytes_used (m_impl->process (buf, bytes));
|
||||
|
||||
if (m_impl->finished ())
|
||||
{
|
||||
if (m_type == typeResponse)
|
||||
{
|
||||
m_response = new HTTPResponse (
|
||||
m_impl->version (),
|
||||
m_impl->fields (),
|
||||
m_impl->body (),
|
||||
m_impl->status_code ());
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_request = new HTTPRequest (
|
||||
}
|
||||
}
|
||||
|
||||
return bytes_used;
|
||||
}
|
||||
|
||||
void HTTPParser::process_eof ()
|
||||
{
|
||||
m_impl->process_eof ();
|
||||
}
|
||||
|
||||
bool HTTPParser::finished () const
|
||||
{
|
||||
return m_impl->finished();
|
||||
}
|
||||
|
||||
SharedPtr <HTTPResponse> const& HTTPParser::response ()
|
||||
{
|
||||
bassert (m_type == typeResponse);
|
||||
|
||||
return m_response;
|
||||
}
|
||||
74
src/beast/modules/beast_asio/http/HTTPParser.h
Normal file
74
src/beast/modules/beast_asio/http/HTTPParser.h
Normal file
@@ -0,0 +1,74 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_HTTPPARSER_H_INCLUDED
|
||||
#define BEAST_ASIO_HTTPPARSER_H_INCLUDED
|
||||
|
||||
class HTTPParserImpl;
|
||||
|
||||
/** A parser for HTTPRequest and HTTPResponse objects. */
|
||||
class HTTPParser
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
typeRequest,
|
||||
typeResponse
|
||||
};
|
||||
|
||||
/** Construct a new parser for the specified HTTPMessage type. */
|
||||
explicit HTTPParser (Type type);
|
||||
|
||||
/** Destroy the parser. */
|
||||
~HTTPParser ();
|
||||
|
||||
/** Returns a non zero error code if parsing fails. */
|
||||
unsigned char error () const;
|
||||
|
||||
/** Returns the error message text when error is non zero. */
|
||||
String message () const;
|
||||
|
||||
/** Parse the buffer and return the amount used.
|
||||
Typically it is an error when this returns less than
|
||||
the amount passed in.
|
||||
*/
|
||||
std::size_t process (void const* buf, std::size_t bytes);
|
||||
|
||||
/** Notify the parser that eof was received.
|
||||
*/
|
||||
void process_eof ();
|
||||
|
||||
/** Returns `true` when parsing is successful and complete. */
|
||||
bool finished () const;
|
||||
|
||||
/** Return the HTTPResponse object produce from the parsing.
|
||||
Only valid after finished returns `true`.
|
||||
*/
|
||||
SharedPtr <HTTPResponse> const& response ();
|
||||
|
||||
//SharedPtr <HTTPRequest> const& request ();
|
||||
|
||||
private:
|
||||
Type m_type;
|
||||
ScopedPointer <HTTPParserImpl> m_impl;
|
||||
SharedPtr <HTTPResponse> m_response;
|
||||
//SharedPtr <HTTPRequest> m_request;
|
||||
};
|
||||
|
||||
#endif
|
||||
256
src/beast/modules/beast_asio/http/HTTPParserImpl.h
Normal file
256
src/beast/modules/beast_asio/http/HTTPParserImpl.h
Normal file
@@ -0,0 +1,256 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_HTTPPARSERIMPL_H_INCLUDED
|
||||
#define BEAST_HTTPPARSERIMPL_H_INCLUDED
|
||||
|
||||
class HTTPParserImpl
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
stringReservation = 256
|
||||
};
|
||||
|
||||
explicit HTTPParserImpl (enum http_parser_type type)
|
||||
: m_finished (false)
|
||||
, m_was_value (false)
|
||||
{
|
||||
m_settings.on_message_begin = &HTTPParserImpl::on_message_begin;
|
||||
m_settings.on_url = &HTTPParserImpl::on_url;
|
||||
m_settings.on_status_complete = &HTTPParserImpl::on_status_complete;
|
||||
m_settings.on_header_field = &HTTPParserImpl::on_header_field;
|
||||
m_settings.on_header_value = &HTTPParserImpl::on_header_value;
|
||||
m_settings.on_headers_complete = &HTTPParserImpl::on_headers_complete;
|
||||
m_settings.on_body = &HTTPParserImpl::on_body;
|
||||
m_settings.on_message_complete = &HTTPParserImpl::on_message_complete;
|
||||
|
||||
m_field.reserve (stringReservation);
|
||||
m_value.reserve (stringReservation);
|
||||
|
||||
http_parser_init (&m_parser, type);
|
||||
m_parser.data = this;
|
||||
}
|
||||
|
||||
~HTTPParserImpl ()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned char error () const
|
||||
{
|
||||
return m_parser.http_errno;
|
||||
}
|
||||
|
||||
String message () const
|
||||
{
|
||||
return String (http_errno_name (static_cast <
|
||||
enum http_errno> (m_parser.http_errno)));
|
||||
}
|
||||
|
||||
std::size_t process (void const* buf, std::size_t bytes)
|
||||
{
|
||||
return http_parser_execute (&m_parser,
|
||||
&m_settings, static_cast <char const*> (buf), bytes);
|
||||
}
|
||||
|
||||
void process_eof ()
|
||||
{
|
||||
http_parser_execute (&m_parser, &m_settings, nullptr, 0);
|
||||
}
|
||||
|
||||
bool finished () const
|
||||
{
|
||||
return m_finished;
|
||||
}
|
||||
|
||||
HTTPVersion version () const
|
||||
{
|
||||
return HTTPVersion (
|
||||
m_parser.http_major, m_parser.http_minor);
|
||||
}
|
||||
|
||||
// Only for HTTPResponse!
|
||||
unsigned short status_code () const
|
||||
{
|
||||
return m_parser.status_code;
|
||||
}
|
||||
|
||||
// Only for HTTPRequest!
|
||||
unsigned char method () const
|
||||
{
|
||||
return m_parser.method;
|
||||
}
|
||||
|
||||
unsigned char http_errno () const
|
||||
{
|
||||
return m_parser.http_errno;
|
||||
}
|
||||
|
||||
String http_errno_message () const
|
||||
{
|
||||
return String (http_errno_name (
|
||||
static_cast <enum http_errno> (
|
||||
m_parser.http_errno)));
|
||||
}
|
||||
|
||||
bool upgrade () const
|
||||
{
|
||||
return m_parser.upgrade != 0;
|
||||
}
|
||||
|
||||
StringPairArray& fields ()
|
||||
{
|
||||
return m_fields;
|
||||
}
|
||||
|
||||
ContentBodyBuffer& body ()
|
||||
{
|
||||
return m_body;
|
||||
}
|
||||
|
||||
private:
|
||||
void addFieldValue ()
|
||||
{
|
||||
if (m_field.size () > 0 && m_value.size () > 0)
|
||||
m_fields.set (m_field, m_value);
|
||||
m_field.resize (0);
|
||||
m_value.resize (0);
|
||||
}
|
||||
|
||||
int onMessageBegin ()
|
||||
{
|
||||
int ec (0);
|
||||
return ec;
|
||||
}
|
||||
|
||||
int onUrl (char const*, std::size_t)
|
||||
{
|
||||
int ec (0);
|
||||
// This is for HTTP Request
|
||||
return ec;
|
||||
}
|
||||
|
||||
int onStatusComplete ()
|
||||
{
|
||||
int ec (0);
|
||||
return ec;
|
||||
}
|
||||
|
||||
int onHeaderField (char const* at, std::size_t length)
|
||||
{
|
||||
int ec (0);
|
||||
if (m_was_value)
|
||||
{
|
||||
addFieldValue ();
|
||||
m_was_value = false;
|
||||
}
|
||||
m_field.append (at, length);
|
||||
return ec;
|
||||
}
|
||||
|
||||
int onHeaderValue (char const* at, std::size_t length)
|
||||
{
|
||||
int ec (0);
|
||||
m_value.append (at, length);
|
||||
m_was_value = true;
|
||||
return ec;
|
||||
}
|
||||
|
||||
int onHeadersComplete ()
|
||||
{
|
||||
int ec (0);
|
||||
addFieldValue ();
|
||||
return ec;
|
||||
}
|
||||
|
||||
int onBody (char const* at, std::size_t length)
|
||||
{
|
||||
m_body.commit (boost::asio::buffer_copy (m_body.prepare (length),
|
||||
boost::asio::buffer (at, length)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int onMessageComplete ()
|
||||
{
|
||||
int ec (0);
|
||||
m_finished = true;
|
||||
return ec;
|
||||
}
|
||||
|
||||
private:
|
||||
static int on_message_begin (http_parser* parser)
|
||||
{
|
||||
return static_cast <HTTPParserImpl*> (parser->data)->
|
||||
onMessageBegin ();
|
||||
}
|
||||
|
||||
static int on_url (http_parser* parser, const char *at, size_t length)
|
||||
{
|
||||
return static_cast <HTTPParserImpl*> (parser->data)->
|
||||
onUrl (at, length);
|
||||
}
|
||||
|
||||
static int on_status_complete (http_parser* parser)
|
||||
{
|
||||
return static_cast <HTTPParserImpl*> (parser->data)->
|
||||
onStatusComplete ();
|
||||
}
|
||||
|
||||
static int on_header_field (http_parser* parser, const char *at, size_t length)
|
||||
{
|
||||
return static_cast <HTTPParserImpl*> (parser->data)->
|
||||
onHeaderField (at, length);
|
||||
}
|
||||
|
||||
static int on_header_value (http_parser* parser, const char *at, size_t length)
|
||||
{
|
||||
return static_cast <HTTPParserImpl*> (parser->data)->
|
||||
onHeaderValue (at, length);
|
||||
}
|
||||
|
||||
static int on_headers_complete (http_parser* parser)
|
||||
{
|
||||
return static_cast <HTTPParserImpl*> (parser->data)->
|
||||
onHeadersComplete ();
|
||||
}
|
||||
|
||||
static int on_body (http_parser* parser, const char *at, size_t length)
|
||||
{
|
||||
return static_cast <HTTPParserImpl*> (parser->data)->
|
||||
onBody (at, length);
|
||||
}
|
||||
|
||||
static int on_message_complete (http_parser* parser)
|
||||
{
|
||||
return static_cast <HTTPParserImpl*> (parser->data)->
|
||||
onMessageComplete ();
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_finished;
|
||||
http_parser_settings m_settings;
|
||||
http_parser m_parser;
|
||||
StringPairArray m_fields;
|
||||
bool m_was_value;
|
||||
std::string m_field;
|
||||
std::string m_value;
|
||||
ContentBodyBuffer m_body;
|
||||
};
|
||||
|
||||
#endif
|
||||
33
src/beast/modules/beast_asio/http/HTTPResponse.cpp
Normal file
33
src/beast/modules/beast_asio/http/HTTPResponse.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
HTTPResponse::HTTPResponse (
|
||||
HTTPVersion const& version_,
|
||||
StringPairArray& fields,
|
||||
ContentBodyBuffer& body,
|
||||
unsigned short status_)
|
||||
: HTTPMessage (version_, fields, body)
|
||||
, m_status (status_)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned short HTTPResponse::status () const
|
||||
{
|
||||
return m_status;
|
||||
}
|
||||
42
src/beast/modules/beast_asio/http/HTTPResponse.h
Normal file
42
src/beast/modules/beast_asio/http/HTTPResponse.h
Normal file
@@ -0,0 +1,42 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_HTTPRESPONSE_H_INCLUDED
|
||||
#define BEAST_ASIO_HTTPRESPONSE_H_INCLUDED
|
||||
|
||||
class HTTPResponse : public HTTPMessage
|
||||
{
|
||||
public:
|
||||
/** Construct a complete response from values.
|
||||
Ownership of the fields and body parameters are
|
||||
transferred from the caller.
|
||||
*/
|
||||
HTTPResponse (
|
||||
HTTPVersion const& version_,
|
||||
StringPairArray& fields,
|
||||
ContentBodyBuffer& body,
|
||||
unsigned short status_);
|
||||
|
||||
unsigned short status () const;
|
||||
|
||||
private:
|
||||
unsigned short m_status;
|
||||
};
|
||||
|
||||
#endif
|
||||
93
src/beast/modules/beast_asio/http/HTTPVersion.cpp
Normal file
93
src/beast/modules/beast_asio/http/HTTPVersion.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
HTTPVersion::HTTPVersion ()
|
||||
: m_major (0)
|
||||
, m_minor (0)
|
||||
{
|
||||
}
|
||||
|
||||
HTTPVersion::HTTPVersion (unsigned short major_, unsigned short minor_)
|
||||
: m_major (major_)
|
||||
, m_minor (minor_)
|
||||
{
|
||||
}
|
||||
|
||||
HTTPVersion::HTTPVersion (HTTPVersion const& other)
|
||||
: m_major (other.m_major)
|
||||
, m_minor (other.m_minor)
|
||||
{
|
||||
}
|
||||
|
||||
HTTPVersion& HTTPVersion::operator= (HTTPVersion const& other)
|
||||
{
|
||||
m_major = other.m_major;
|
||||
m_minor = other.m_minor;
|
||||
return *this;
|
||||
}
|
||||
|
||||
String HTTPVersion::toString () const
|
||||
{
|
||||
return String::fromNumber (major ()) + "." +
|
||||
String::fromNumber (minor ());
|
||||
}
|
||||
|
||||
unsigned short HTTPVersion::major () const
|
||||
{
|
||||
return m_major;
|
||||
}
|
||||
|
||||
unsigned short HTTPVersion::minor () const
|
||||
{
|
||||
return m_minor;
|
||||
}
|
||||
|
||||
bool HTTPVersion::operator== (HTTPVersion const& rhs) const
|
||||
{
|
||||
return (m_major == rhs.m_major) && (m_minor == rhs.m_minor);
|
||||
}
|
||||
|
||||
bool HTTPVersion::operator!= (HTTPVersion const& rhs) const
|
||||
{
|
||||
return (m_major != rhs.m_major) || (m_minor != rhs.m_minor);
|
||||
}
|
||||
|
||||
bool HTTPVersion::operator> (HTTPVersion const& rhs) const
|
||||
{
|
||||
return (m_major > rhs.m_major) ||
|
||||
((m_major == rhs.m_major) && (m_minor > rhs.m_minor));
|
||||
}
|
||||
|
||||
bool HTTPVersion::operator>= (HTTPVersion const& rhs) const
|
||||
{
|
||||
return (m_major > rhs.m_major) ||
|
||||
((m_major == rhs.m_major) && (m_minor >= rhs.m_minor));
|
||||
}
|
||||
|
||||
bool HTTPVersion::operator< (HTTPVersion const& rhs) const
|
||||
{
|
||||
return (m_major < rhs.m_major) ||
|
||||
((m_major == rhs.m_major) && (m_minor < rhs.m_minor));
|
||||
}
|
||||
|
||||
bool HTTPVersion::operator<= (HTTPVersion const& rhs) const
|
||||
{
|
||||
return (m_major < rhs.m_major) ||
|
||||
((m_major == rhs.m_major) && (m_minor <= rhs.m_minor));
|
||||
}
|
||||
46
src/beast/modules/beast_asio/http/HTTPVersion.h
Normal file
46
src/beast/modules/beast_asio/http/HTTPVersion.h
Normal file
@@ -0,0 +1,46 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_HTTPVERSION_H_INCLUDED
|
||||
#define BEAST_ASIO_HTTPVERSION_H_INCLUDED
|
||||
|
||||
/** The HTTP version. This is the major.minor version number. */
|
||||
class HTTPVersion
|
||||
{
|
||||
public:
|
||||
HTTPVersion ();
|
||||
HTTPVersion (unsigned short major_, unsigned short minor_);
|
||||
HTTPVersion (HTTPVersion const& other);
|
||||
HTTPVersion& operator= (HTTPVersion const& other);
|
||||
String toString () const;
|
||||
unsigned short major () const;
|
||||
unsigned short minor () const;
|
||||
bool operator== (HTTPVersion const& rhs) const;
|
||||
bool operator!= (HTTPVersion const& rhs) const;
|
||||
bool operator> (HTTPVersion const& rhs) const;
|
||||
bool operator>= (HTTPVersion const& rhs) const;
|
||||
bool operator< (HTTPVersion const& rhs) const;
|
||||
bool operator<= (HTTPVersion const& rhs) const;
|
||||
|
||||
private:
|
||||
unsigned short m_major;
|
||||
unsigned short m_minor;;
|
||||
};
|
||||
|
||||
#endif
|
||||
299
src/beast/modules/beast_asio/http/UniformResourceLocator.cpp
Normal file
299
src/beast/modules/beast_asio/http/UniformResourceLocator.cpp
Normal file
@@ -0,0 +1,299 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
UniformResourceLocator::UniformResourceLocator ()
|
||||
: m_port (0)
|
||||
{
|
||||
}
|
||||
|
||||
UniformResourceLocator::UniformResourceLocator (
|
||||
String scheme_,
|
||||
String host_,
|
||||
uint16 port_,
|
||||
String port_string_,
|
||||
String path_,
|
||||
String query_,
|
||||
String fragment_,
|
||||
String userinfo_)
|
||||
: m_scheme (scheme_)
|
||||
, m_host (host_)
|
||||
, m_port (port_)
|
||||
, m_port_string (port_string_)
|
||||
, m_path (path_)
|
||||
, m_query (query_)
|
||||
, m_fragment (fragment_)
|
||||
, m_userinfo (userinfo_)
|
||||
{
|
||||
}
|
||||
|
||||
UniformResourceLocator::UniformResourceLocator (UniformResourceLocator const& other)
|
||||
: m_scheme (other.m_scheme)
|
||||
, m_host (other.m_host)
|
||||
, m_port (other.m_port)
|
||||
, m_port_string (other.m_port_string)
|
||||
, m_path (other.m_path)
|
||||
, m_query (other.m_query)
|
||||
, m_fragment (other.m_fragment)
|
||||
, m_userinfo (other.m_userinfo)
|
||||
{
|
||||
}
|
||||
|
||||
UniformResourceLocator& UniformResourceLocator::operator= (UniformResourceLocator const& other)
|
||||
{
|
||||
m_scheme = other.m_scheme;
|
||||
m_host = other.m_host;
|
||||
m_port = other.m_port;
|
||||
m_port_string = other.m_port_string;
|
||||
m_path = other.m_path;
|
||||
m_query = other.m_query;
|
||||
m_fragment = other.m_fragment;
|
||||
m_userinfo = other.m_userinfo;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
String UniformResourceLocator::scheme () const
|
||||
{
|
||||
return m_scheme;
|
||||
}
|
||||
|
||||
String UniformResourceLocator::host () const
|
||||
{
|
||||
return m_host;
|
||||
}
|
||||
|
||||
String UniformResourceLocator::port_string () const
|
||||
{
|
||||
return m_port_string;
|
||||
}
|
||||
|
||||
uint16 UniformResourceLocator::port () const
|
||||
{
|
||||
return m_port;
|
||||
}
|
||||
|
||||
String UniformResourceLocator::path () const
|
||||
{
|
||||
return m_path;
|
||||
}
|
||||
|
||||
String UniformResourceLocator::query () const
|
||||
{
|
||||
return m_query;
|
||||
}
|
||||
|
||||
String UniformResourceLocator::fragment () const
|
||||
{
|
||||
return m_fragment;
|
||||
}
|
||||
|
||||
String UniformResourceLocator::userinfo () const
|
||||
{
|
||||
return m_userinfo;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
From
|
||||
http://en.wikipedia.org/wiki/URI_scheme
|
||||
|
||||
<scheme name> : <hierarchical part> [ ? <query> ] [ # <fragment> ]
|
||||
|
||||
e.g.
|
||||
|
||||
foo://username:password@example.com:8042/over/there/index.dtb?type=animal&name=narwhal#nose
|
||||
*/
|
||||
String UniformResourceLocator::full () const
|
||||
{
|
||||
String s;
|
||||
|
||||
s = scheme () + "://";
|
||||
|
||||
if (userinfo () != String::empty)
|
||||
s = userinfo () + "@";
|
||||
|
||||
s = s + host ();
|
||||
|
||||
if (port () != 0)
|
||||
s = s + ":" + String::fromNumber (port ());
|
||||
|
||||
s = s + path ();
|
||||
|
||||
if (query () != String::empty)
|
||||
s = "?" + query ();
|
||||
|
||||
if (fragment () != String::empty)
|
||||
s = "#" + fragment ();
|
||||
|
||||
return s;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
ParsedURL::ParsedURL ()
|
||||
: m_error (0)
|
||||
{
|
||||
}
|
||||
|
||||
ParsedURL::ParsedURL (String const& url)
|
||||
{
|
||||
std::string const ss (url.toStdString ());
|
||||
std::size_t const buflen (ss.size ());
|
||||
char const* const buf (ss.c_str ());
|
||||
|
||||
http_parser_url u;
|
||||
|
||||
m_error = http_parser_parse_url (buf, buflen, false, &u);
|
||||
|
||||
String scheme_;
|
||||
String host_;
|
||||
uint16 port_ (0);
|
||||
String port_string_;
|
||||
String path_;
|
||||
String query_;
|
||||
String fragment_;
|
||||
String userinfo_;
|
||||
|
||||
if (m_error == 0)
|
||||
{
|
||||
if ((u.field_set & (1<<UF_SCHEMA)) != 0)
|
||||
{
|
||||
scheme_ = String (
|
||||
buf + u.field_data [UF_SCHEMA].off,
|
||||
u.field_data [UF_SCHEMA].len);
|
||||
}
|
||||
|
||||
if ((u.field_set & (1<<UF_HOST)) != 0)
|
||||
{
|
||||
host_ = String (
|
||||
buf + u.field_data [UF_HOST].off,
|
||||
u.field_data [UF_HOST].len);
|
||||
}
|
||||
|
||||
if ((u.field_set & (1<<UF_PORT)) != 0)
|
||||
{
|
||||
port_ = u.port;
|
||||
port_string_ = String (
|
||||
buf + u.field_data [UF_PORT].off,
|
||||
u.field_data [UF_PORT].len);
|
||||
}
|
||||
else
|
||||
{
|
||||
port_ = 0;
|
||||
}
|
||||
|
||||
if ((u.field_set & (1<<UF_PATH)) != 0)
|
||||
{
|
||||
path_ = String (
|
||||
buf + u.field_data [UF_PATH].off,
|
||||
u.field_data [UF_PATH].len);
|
||||
}
|
||||
|
||||
if ((u.field_set & (1<<UF_QUERY)) != 0)
|
||||
{
|
||||
query_ = String (
|
||||
buf + u.field_data [UF_QUERY].off,
|
||||
u.field_data [UF_QUERY].len);
|
||||
}
|
||||
|
||||
if ((u.field_set & (1<<UF_FRAGMENT)) != 0)
|
||||
{
|
||||
fragment_ = String (
|
||||
buf + u.field_data [UF_FRAGMENT].off,
|
||||
u.field_data [UF_FRAGMENT].len);
|
||||
}
|
||||
|
||||
if ((u.field_set & (1<<UF_USERINFO)) != 0)
|
||||
{
|
||||
userinfo_ = String (
|
||||
buf + u.field_data [UF_USERINFO].off,
|
||||
u.field_data [UF_USERINFO].len);
|
||||
}
|
||||
|
||||
m_url = UniformResourceLocator (
|
||||
scheme_,
|
||||
host_,
|
||||
port_,
|
||||
port_string_,
|
||||
path_,
|
||||
query_,
|
||||
fragment_,
|
||||
userinfo_);
|
||||
}
|
||||
}
|
||||
|
||||
ParsedURL::ParsedURL (int error, UniformResourceLocator const& url)
|
||||
: m_error (error)
|
||||
, m_url (url)
|
||||
{
|
||||
}
|
||||
|
||||
ParsedURL::ParsedURL (ParsedURL const& other)
|
||||
: m_error (other.m_error)
|
||||
, m_url (other.m_url)
|
||||
{
|
||||
}
|
||||
|
||||
ParsedURL& ParsedURL::operator= (ParsedURL const& other)
|
||||
{
|
||||
m_error = other.m_error;
|
||||
m_url = other.m_url;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int ParsedURL::error () const
|
||||
{
|
||||
return m_error;
|
||||
}
|
||||
|
||||
UniformResourceLocator ParsedURL::url () const
|
||||
{
|
||||
return m_url;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class ParsedURLTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
void checkURL (String const& url)
|
||||
{
|
||||
ParsedURL result (url);
|
||||
expect (result.error () == 0);
|
||||
expect (result.url ().full () == url);
|
||||
}
|
||||
|
||||
void testURL ()
|
||||
{
|
||||
beginTestCase ("parse URL");
|
||||
|
||||
checkURL ("http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference.html");
|
||||
}
|
||||
|
||||
void runTest ()
|
||||
{
|
||||
testURL ();
|
||||
}
|
||||
|
||||
ParsedURLTests () : UnitTest ("ParsedURL", "beast", runManual)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static ParsedURLTests parsedURLTests;
|
||||
123
src/beast/modules/beast_asio/http/UniformResourceLocator.h
Normal file
123
src/beast/modules/beast_asio/http/UniformResourceLocator.h
Normal file
@@ -0,0 +1,123 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_PROTOCOL_UNIFORMRESOURCELOCATOR_H_INCLUDED
|
||||
#define BEAST_ASIO_PROTOCOL_UNIFORMRESOURCELOCATOR_H_INCLUDED
|
||||
|
||||
/** A URL.
|
||||
The accompanying robust parser is hardened against all forms of attack.
|
||||
*/
|
||||
class UniformResourceLocator
|
||||
{
|
||||
public:
|
||||
/** Construct an empty URL. */
|
||||
explicit UniformResourceLocator ();
|
||||
|
||||
/** Construct a URL from it's components. */
|
||||
UniformResourceLocator (
|
||||
String schema_,
|
||||
String host_,
|
||||
uint16 port_,
|
||||
String port_string_,
|
||||
String path_,
|
||||
String query_ = "",
|
||||
String fragment_ = "",
|
||||
String userinfo_ = "");
|
||||
|
||||
/** Copy construct a URL. */
|
||||
UniformResourceLocator (UniformResourceLocator const& other);
|
||||
|
||||
/** Copy assign a URL. */
|
||||
UniformResourceLocator& operator= (UniformResourceLocator const& other);
|
||||
|
||||
/** Returns the scheme of the URL.
|
||||
If no scheme was specified, the string will be empty.
|
||||
*/
|
||||
String scheme () const;
|
||||
|
||||
/** Returns the host of the URL.
|
||||
If no host was specified, the string will be empty.
|
||||
*/
|
||||
String host () const;
|
||||
|
||||
/** Returns the port number as an integer.
|
||||
If no port was specified, the value will be zero.
|
||||
*/
|
||||
uint16 port () const;
|
||||
|
||||
/** Returns the port number as a string.
|
||||
If no port was specified, the string will be empty.
|
||||
*/
|
||||
String port_string () const;
|
||||
|
||||
/** Returns the path of the URL.
|
||||
If no path was specified, the string will be empty.
|
||||
*/
|
||||
String path () const;
|
||||
|
||||
/** Returns the query parameters portion of the URL.
|
||||
If no query parameters were present, the string will be empty.
|
||||
*/
|
||||
String query () const;
|
||||
|
||||
/** Returns the URL fragment, if any. */
|
||||
String fragment () const;
|
||||
|
||||
/** Returns the user information, if any. */
|
||||
String userinfo () const;
|
||||
|
||||
/** Retrieve the full URL as a single string. */
|
||||
String full () const;
|
||||
|
||||
private:
|
||||
String m_scheme;
|
||||
String m_host;
|
||||
uint16 m_port;
|
||||
String m_port_string;
|
||||
String m_path;
|
||||
String m_query;
|
||||
String m_fragment;
|
||||
String m_userinfo;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Parses a String containing a URL.
|
||||
*/
|
||||
class ParsedURL
|
||||
{
|
||||
public:
|
||||
ParsedURL ();
|
||||
explicit ParsedURL (String const& url);
|
||||
ParsedURL (int error, UniformResourceLocator const& url);
|
||||
ParsedURL (ParsedURL const& other);
|
||||
ParsedURL& operator= (ParsedURL const& other);
|
||||
|
||||
/** Zero for success, else a non zero value indicating failure. */
|
||||
int error () const;
|
||||
|
||||
/** The parsed URL if there was no error. */
|
||||
UniformResourceLocator url () const;
|
||||
|
||||
private:
|
||||
int m_error;
|
||||
UniformResourceLocator m_url;
|
||||
};
|
||||
|
||||
#endif
|
||||
14
src/beast/modules/beast_asio/parsehttp/.gitignore
vendored
Normal file
14
src/beast/modules/beast_asio/parsehttp/.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/out/
|
||||
core
|
||||
tags
|
||||
*.o
|
||||
test
|
||||
test_g
|
||||
test_fast
|
||||
url_parser
|
||||
parsertrace
|
||||
parsertrace_g
|
||||
*.mk
|
||||
*.Makefile
|
||||
*.so.*
|
||||
*.a
|
||||
7
src/beast/modules/beast_asio/parsehttp/.mailmap
Normal file
7
src/beast/modules/beast_asio/parsehttp/.mailmap
Normal file
@@ -0,0 +1,7 @@
|
||||
# update AUTHORS with:
|
||||
# git log --all --reverse --format='%aN <%aE>' | perl -ne 'BEGIN{print "# Authors ordered by first contribution.\n"} print unless $h{$_}; $h{$_} = 1' > AUTHORS
|
||||
Ryan Dahl <ry@tinyclouds.org>
|
||||
Salman Haq <salman.haq@asti-usa.com>
|
||||
Simon Zimmermann <simonz05@gmail.com>
|
||||
Thomas LE ROUX <thomas@november-eleven.fr> LE ROUX Thomas <thomas@procheo.fr>
|
||||
Thomas LE ROUX <thomas@november-eleven.fr> Thomas LE ROUX <thomas@procheo.fr>
|
||||
13
src/beast/modules/beast_asio/parsehttp/.travis.yml
Normal file
13
src/beast/modules/beast_asio/parsehttp/.travis.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
language: c
|
||||
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
|
||||
script:
|
||||
- "make"
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
irc:
|
||||
- "irc.freenode.net#libuv"
|
||||
41
src/beast/modules/beast_asio/parsehttp/AUTHORS
Normal file
41
src/beast/modules/beast_asio/parsehttp/AUTHORS
Normal file
@@ -0,0 +1,41 @@
|
||||
# Authors ordered by first contribution.
|
||||
Ryan Dahl <ry@tinyclouds.org>
|
||||
Jeremy Hinegardner <jeremy@hinegardner.org>
|
||||
Sergey Shepelev <temotor@gmail.com>
|
||||
Joe Damato <ice799@gmail.com>
|
||||
tomika <tomika_nospam@freemail.hu>
|
||||
Phoenix Sol <phoenix@burninglabs.com>
|
||||
Cliff Frey <cliff@meraki.com>
|
||||
Ewen Cheslack-Postava <ewencp@cs.stanford.edu>
|
||||
Santiago Gala <sgala@apache.org>
|
||||
Tim Becker <tim.becker@syngenio.de>
|
||||
Jeff Terrace <jterrace@gmail.com>
|
||||
Ben Noordhuis <info@bnoordhuis.nl>
|
||||
Nathan Rajlich <nathan@tootallnate.net>
|
||||
Mark Nottingham <mnot@mnot.net>
|
||||
Aman Gupta <aman@tmm1.net>
|
||||
Tim Becker <tim.becker@kuriositaet.de>
|
||||
Sean Cunningham <sean.cunningham@mandiant.com>
|
||||
Peter Griess <pg@std.in>
|
||||
Salman Haq <salman.haq@asti-usa.com>
|
||||
Cliff Frey <clifffrey@gmail.com>
|
||||
Jon Kolb <jon@b0g.us>
|
||||
Fouad Mardini <f.mardini@gmail.com>
|
||||
Paul Querna <pquerna@apache.org>
|
||||
Felix Geisendörfer <felix@debuggable.com>
|
||||
koichik <koichik@improvement.jp>
|
||||
Andre Caron <andre.l.caron@gmail.com>
|
||||
Ivo Raisr <ivosh@ivosh.net>
|
||||
James McLaughlin <jamie@lacewing-project.org>
|
||||
David Gwynne <loki@animata.net>
|
||||
Thomas LE ROUX <thomas@november-eleven.fr>
|
||||
Randy Rizun <rrizun@ortivawireless.com>
|
||||
Andre Louis Caron <andre.louis.caron@usherbrooke.ca>
|
||||
Simon Zimmermann <simonz05@gmail.com>
|
||||
Erik Dubbelboer <erik@dubbelboer.com>
|
||||
Martell Malone <martellmalone@gmail.com>
|
||||
Bertrand Paquet <bpaquet@octo.com>
|
||||
BogDan Vatra <bogdan@kde.org>
|
||||
Peter Faiman <peter@thepicard.org>
|
||||
Corey Richardson <corey@octayn.net>
|
||||
Tóth Tamás <tomika_nospam@freemail.hu>
|
||||
4
src/beast/modules/beast_asio/parsehttp/CONTRIBUTIONS
Normal file
4
src/beast/modules/beast_asio/parsehttp/CONTRIBUTIONS
Normal file
@@ -0,0 +1,4 @@
|
||||
Contributors must agree to the Contributor License Agreement before patches
|
||||
can be accepted.
|
||||
|
||||
http://spreadsheets2.google.com/viewform?hl=en&formkey=dDJXOGUwbzlYaWM4cHN1MERwQS1CSnc6MQ
|
||||
23
src/beast/modules/beast_asio/parsehttp/LICENSE-MIT
Normal file
23
src/beast/modules/beast_asio/parsehttp/LICENSE-MIT
Normal file
@@ -0,0 +1,23 @@
|
||||
http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright
|
||||
Igor Sysoev.
|
||||
|
||||
Additional changes are licensed under the same terms as NGINX and
|
||||
copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
105
src/beast/modules/beast_asio/parsehttp/Makefile
Normal file
105
src/beast/modules/beast_asio/parsehttp/Makefile
Normal file
@@ -0,0 +1,105 @@
|
||||
# Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
|
||||
PLATFORM ?= $(shell sh -c 'uname -s | tr "[A-Z]" "[a-z]"')
|
||||
SONAME ?= libhttp_parser.so.2.1
|
||||
|
||||
CC?=gcc
|
||||
AR?=ar
|
||||
|
||||
CPPFLAGS += -I.
|
||||
CPPFLAGS_DEBUG = $(CPPFLAGS) -DHTTP_PARSER_STRICT=1
|
||||
CPPFLAGS_DEBUG += $(CPPFLAGS_DEBUG_EXTRA)
|
||||
CPPFLAGS_FAST = $(CPPFLAGS) -DHTTP_PARSER_STRICT=0
|
||||
CPPFLAGS_FAST += $(CPPFLAGS_FAST_EXTRA)
|
||||
|
||||
CFLAGS += -Wall -Wextra -Werror
|
||||
CFLAGS_DEBUG = $(CFLAGS) -O0 -g $(CFLAGS_DEBUG_EXTRA)
|
||||
CFLAGS_FAST = $(CFLAGS) -O3 $(CFLAGS_FAST_EXTRA)
|
||||
CFLAGS_LIB = $(CFLAGS_FAST) -fPIC
|
||||
|
||||
LDFLAGS_LIB = $(LDFLAGS) -shared
|
||||
|
||||
ifneq (darwin,$(PLATFORM))
|
||||
# TODO(bnoordhuis) The native SunOS linker expects -h rather than -soname...
|
||||
LDFLAGS_LIB += -Wl,-soname=$(SONAME)
|
||||
endif
|
||||
|
||||
test: test_g test_fast
|
||||
./test_g
|
||||
./test_fast
|
||||
|
||||
test_g: http_parser_g.o test_g.o
|
||||
$(CC) $(CFLAGS_DEBUG) $(LDFLAGS) http_parser_g.o test_g.o -o $@
|
||||
|
||||
test_g.o: test.c http_parser.h Makefile
|
||||
$(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) -c test.c -o $@
|
||||
|
||||
http_parser_g.o: http_parser.c http_parser.h Makefile
|
||||
$(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) -c http_parser.c -o $@
|
||||
|
||||
test_fast: http_parser.o test.o http_parser.h
|
||||
$(CC) $(CFLAGS_FAST) $(LDFLAGS) http_parser.o test.o -o $@
|
||||
|
||||
test.o: test.c http_parser.h Makefile
|
||||
$(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) -c test.c -o $@
|
||||
|
||||
http_parser.o: http_parser.c http_parser.h Makefile
|
||||
$(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) -c http_parser.c
|
||||
|
||||
test-run-timed: test_fast
|
||||
while(true) do time ./test_fast > /dev/null; done
|
||||
|
||||
test-valgrind: test_g
|
||||
valgrind ./test_g
|
||||
|
||||
libhttp_parser.o: http_parser.c http_parser.h Makefile
|
||||
$(CC) $(CPPFLAGS_FAST) $(CFLAGS_LIB) -c http_parser.c -o libhttp_parser.o
|
||||
|
||||
library: libhttp_parser.o
|
||||
$(CC) $(LDFLAGS_LIB) -o $(SONAME) $<
|
||||
|
||||
package: http_parser.o
|
||||
$(AR) rcs libhttp_parser.a http_parser.o
|
||||
|
||||
url_parser: http_parser.o contrib/url_parser.c
|
||||
$(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) $^ -o $@
|
||||
|
||||
url_parser_g: http_parser_g.o contrib/url_parser.c
|
||||
$(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) $^ -o $@
|
||||
|
||||
parsertrace: http_parser.o contrib/parsertrace.c
|
||||
$(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) $^ -o parsertrace
|
||||
|
||||
parsertrace_g: http_parser_g.o contrib/parsertrace.c
|
||||
$(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) $^ -o parsertrace_g
|
||||
|
||||
tags: http_parser.c http_parser.h test.c
|
||||
ctags $^
|
||||
|
||||
clean:
|
||||
rm -f *.o *.a tags test test_fast test_g \
|
||||
http_parser.tar libhttp_parser.so.* \
|
||||
url_parser url_parser_g parsertrace parsertrace_g
|
||||
|
||||
contrib/url_parser.c: http_parser.h
|
||||
contrib/parsertrace.c: http_parser.h
|
||||
|
||||
.PHONY: clean package test-run test-run-timed test-valgrind
|
||||
180
src/beast/modules/beast_asio/parsehttp/README.md
Normal file
180
src/beast/modules/beast_asio/parsehttp/README.md
Normal file
@@ -0,0 +1,180 @@
|
||||
HTTP Parser
|
||||
===========
|
||||
|
||||
[](https://travis-ci.org/joyent/http-parser)
|
||||
|
||||
This is a parser for HTTP messages written in C. It parses both requests and
|
||||
responses. The parser is designed to be used in performance HTTP
|
||||
applications. It does not make any syscalls nor allocations, it does not
|
||||
buffer data, it can be interrupted at anytime. Depending on your
|
||||
architecture, it only requires about 40 bytes of data per message
|
||||
stream (in a web server that is per connection).
|
||||
|
||||
Features:
|
||||
|
||||
* No dependencies
|
||||
* Handles persistent streams (keep-alive).
|
||||
* Decodes chunked encoding.
|
||||
* Upgrade support
|
||||
* Defends against buffer overflow attacks.
|
||||
|
||||
The parser extracts the following information from HTTP messages:
|
||||
|
||||
* Header fields and values
|
||||
* Content-Length
|
||||
* Request method
|
||||
* Response status code
|
||||
* Transfer-Encoding
|
||||
* HTTP version
|
||||
* Request URL
|
||||
* Message body
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
One `http_parser` object is used per TCP connection. Initialize the struct
|
||||
using `http_parser_init()` and set the callbacks. That might look something
|
||||
like this for a request parser:
|
||||
|
||||
http_parser_settings settings;
|
||||
settings.on_url = my_url_callback;
|
||||
settings.on_header_field = my_header_field_callback;
|
||||
/* ... */
|
||||
|
||||
http_parser *parser = malloc(sizeof(http_parser));
|
||||
http_parser_init(parser, HTTP_REQUEST);
|
||||
parser->data = my_socket;
|
||||
|
||||
When data is received on the socket execute the parser and check for errors.
|
||||
|
||||
size_t len = 80*1024, nparsed;
|
||||
char buf[len];
|
||||
ssize_t recved;
|
||||
|
||||
recved = recv(fd, buf, len, 0);
|
||||
|
||||
if (recved < 0) {
|
||||
/* Handle error. */
|
||||
}
|
||||
|
||||
/* Start up / continue the parser.
|
||||
* Note we pass recved==0 to signal that EOF has been recieved.
|
||||
*/
|
||||
nparsed = http_parser_execute(parser, &settings, buf, recved);
|
||||
|
||||
if (parser->upgrade) {
|
||||
/* handle new protocol */
|
||||
} else if (nparsed != recved) {
|
||||
/* Handle error. Usually just close the connection. */
|
||||
}
|
||||
|
||||
HTTP needs to know where the end of the stream is. For example, sometimes
|
||||
servers send responses without Content-Length and expect the client to
|
||||
consume input (for the body) until EOF. To tell http_parser about EOF, give
|
||||
`0` as the forth parameter to `http_parser_execute()`. Callbacks and errors
|
||||
can still be encountered during an EOF, so one must still be prepared
|
||||
to receive them.
|
||||
|
||||
Scalar valued message information such as `status_code`, `method`, and the
|
||||
HTTP version are stored in the parser structure. This data is only
|
||||
temporally stored in `http_parser` and gets reset on each new message. If
|
||||
this information is needed later, copy it out of the structure during the
|
||||
`headers_complete` callback.
|
||||
|
||||
The parser decodes the transfer-encoding for both requests and responses
|
||||
transparently. That is, a chunked encoding is decoded before being sent to
|
||||
the on_body callback.
|
||||
|
||||
|
||||
The Special Problem of Upgrade
|
||||
------------------------------
|
||||
|
||||
HTTP supports upgrading the connection to a different protocol. An
|
||||
increasingly common example of this is the Web Socket protocol which sends
|
||||
a request like
|
||||
|
||||
GET /demo HTTP/1.1
|
||||
Upgrade: WebSocket
|
||||
Connection: Upgrade
|
||||
Host: example.com
|
||||
Origin: http://example.com
|
||||
WebSocket-Protocol: sample
|
||||
|
||||
followed by non-HTTP data.
|
||||
|
||||
(See http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75 for more
|
||||
information the Web Socket protocol.)
|
||||
|
||||
To support this, the parser will treat this as a normal HTTP message without a
|
||||
body. Issuing both on_headers_complete and on_message_complete callbacks. However
|
||||
http_parser_execute() will stop parsing at the end of the headers and return.
|
||||
|
||||
The user is expected to check if `parser->upgrade` has been set to 1 after
|
||||
`http_parser_execute()` returns. Non-HTTP data begins at the buffer supplied
|
||||
offset by the return value of `http_parser_execute()`.
|
||||
|
||||
|
||||
Callbacks
|
||||
---------
|
||||
|
||||
During the `http_parser_execute()` call, the callbacks set in
|
||||
`http_parser_settings` will be executed. The parser maintains state and
|
||||
never looks behind, so buffering the data is not necessary. If you need to
|
||||
save certain data for later usage, you can do that from the callbacks.
|
||||
|
||||
There are two types of callbacks:
|
||||
|
||||
* notification `typedef int (*http_cb) (http_parser*);`
|
||||
Callbacks: on_message_begin, on_headers_complete, on_message_complete.
|
||||
* data `typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);`
|
||||
Callbacks: (requests only) on_uri,
|
||||
(common) on_header_field, on_header_value, on_body;
|
||||
|
||||
Callbacks must return 0 on success. Returning a non-zero value indicates
|
||||
error to the parser, making it exit immediately.
|
||||
|
||||
In case you parse HTTP message in chunks (i.e. `read()` request line
|
||||
from socket, parse, read half headers, parse, etc) your data callbacks
|
||||
may be called more than once. Http-parser guarantees that data pointer is only
|
||||
valid for the lifetime of callback. You can also `read()` into a heap allocated
|
||||
buffer to avoid copying memory around if this fits your application.
|
||||
|
||||
Reading headers may be a tricky task if you read/parse headers partially.
|
||||
Basically, you need to remember whether last header callback was field or value
|
||||
and apply following logic:
|
||||
|
||||
(on_header_field and on_header_value shortened to on_h_*)
|
||||
------------------------ ------------ --------------------------------------------
|
||||
| State (prev. callback) | Callback | Description/action |
|
||||
------------------------ ------------ --------------------------------------------
|
||||
| nothing (first call) | on_h_field | Allocate new buffer and copy callback data |
|
||||
| | | into it |
|
||||
------------------------ ------------ --------------------------------------------
|
||||
| value | on_h_field | New header started. |
|
||||
| | | Copy current name,value buffers to headers |
|
||||
| | | list and allocate new buffer for new name |
|
||||
------------------------ ------------ --------------------------------------------
|
||||
| field | on_h_field | Previous name continues. Reallocate name |
|
||||
| | | buffer and append callback data to it |
|
||||
------------------------ ------------ --------------------------------------------
|
||||
| field | on_h_value | Value for current header started. Allocate |
|
||||
| | | new buffer and copy callback data to it |
|
||||
------------------------ ------------ --------------------------------------------
|
||||
| value | on_h_value | Value continues. Reallocate value buffer |
|
||||
| | | and append callback data to it |
|
||||
------------------------ ------------ --------------------------------------------
|
||||
|
||||
|
||||
Parsing URLs
|
||||
------------
|
||||
|
||||
A simplistic zero-copy URL parser is provided as `http_parser_parse_url()`.
|
||||
Users of this library may wish to use it to parse URLs constructed from
|
||||
consecutive `on_url` callbacks.
|
||||
|
||||
See examples of reading in headers:
|
||||
|
||||
* [partial example](http://gist.github.com/155877) in C
|
||||
* [from http-parser tests](http://github.com/joyent/http-parser/blob/37a0ff8/test.c#L403) in C
|
||||
* [from Node library](http://github.com/joyent/node/blob/842eaf4/src/http.js#L284) in Javascript
|
||||
156
src/beast/modules/beast_asio/parsehttp/contrib/parsertrace.c
Normal file
156
src/beast/modules/beast_asio/parsehttp/contrib/parsertrace.c
Normal file
@@ -0,0 +1,156 @@
|
||||
/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev
|
||||
*
|
||||
* Additional changes are licensed under the same terms as NGINX and
|
||||
* copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* Dump what the parser finds to stdout as it happen */
|
||||
|
||||
#include "http_parser.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int on_message_begin(http_parser* _) {
|
||||
(void)_;
|
||||
printf("\n***MESSAGE BEGIN***\n\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int on_headers_complete(http_parser* _) {
|
||||
(void)_;
|
||||
printf("\n***HEADERS COMPLETE***\n\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int on_message_complete(http_parser* _) {
|
||||
(void)_;
|
||||
printf("\n***MESSAGE COMPLETE***\n\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int on_url(http_parser* _, const char* at, size_t length) {
|
||||
(void)_;
|
||||
printf("Url: %.*s\n", (int)length, at);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int on_header_field(http_parser* _, const char* at, size_t length) {
|
||||
(void)_;
|
||||
printf("Header field: %.*s\n", (int)length, at);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int on_header_value(http_parser* _, const char* at, size_t length) {
|
||||
(void)_;
|
||||
printf("Header value: %.*s\n", (int)length, at);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int on_body(http_parser* _, const char* at, size_t length) {
|
||||
(void)_;
|
||||
printf("Body: %.*s\n", (int)length, at);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void usage(const char* name) {
|
||||
fprintf(stderr,
|
||||
"Usage: %s $type $filename\n"
|
||||
" type: -x, where x is one of {r,b,q}\n"
|
||||
" parses file as a Response, reQuest, or Both\n",
|
||||
name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
enum http_parser_type file_type;
|
||||
|
||||
if (argc != 3) {
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
char* type = argv[1];
|
||||
if (type[0] != '-') {
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
switch (type[1]) {
|
||||
/* in the case of "-", type[1] will be NUL */
|
||||
case 'r':
|
||||
file_type = HTTP_RESPONSE;
|
||||
break;
|
||||
case 'q':
|
||||
file_type = HTTP_REQUEST;
|
||||
break;
|
||||
case 'b':
|
||||
file_type = HTTP_BOTH;
|
||||
break;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
}
|
||||
|
||||
char* filename = argv[2];
|
||||
FILE* file = fopen(filename, "r");
|
||||
if (file == NULL) {
|
||||
perror("fopen");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
long file_length = ftell(file);
|
||||
if (file_length == -1) {
|
||||
perror("ftell");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
char* data = malloc(file_length);
|
||||
if (fread(data, 1, file_length, file) != (size_t)file_length) {
|
||||
fprintf(stderr, "couldn't read entire file\n");
|
||||
free(data);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
http_parser_settings settings;
|
||||
memset(&settings, 0, sizeof(settings));
|
||||
settings.on_message_begin = on_message_begin;
|
||||
settings.on_url = on_url;
|
||||
settings.on_header_field = on_header_field;
|
||||
settings.on_header_value = on_header_value;
|
||||
settings.on_headers_complete = on_headers_complete;
|
||||
settings.on_body = on_body;
|
||||
settings.on_message_complete = on_message_complete;
|
||||
|
||||
http_parser parser;
|
||||
http_parser_init(&parser, file_type);
|
||||
size_t nparsed = http_parser_execute(&parser, &settings, data, file_length);
|
||||
free(data);
|
||||
|
||||
if (nparsed != (size_t)file_length) {
|
||||
fprintf(stderr,
|
||||
"Error: %s (%s)\n",
|
||||
http_errno_description(HTTP_PARSER_ERRNO(&parser)),
|
||||
http_errno_name(HTTP_PARSER_ERRNO(&parser)));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
44
src/beast/modules/beast_asio/parsehttp/contrib/url_parser.c
Normal file
44
src/beast/modules/beast_asio/parsehttp/contrib/url_parser.c
Normal file
@@ -0,0 +1,44 @@
|
||||
#include "http_parser.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
void
|
||||
dump_url (const char *url, const struct http_parser_url *u)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
printf("\tfield_set: 0x%x, port: %u\n", u->field_set, u->port);
|
||||
for (i = 0; i < UF_MAX; i++) {
|
||||
if ((u->field_set & (1 << i)) == 0) {
|
||||
printf("\tfield_data[%u]: unset\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("\tfield_data[%u]: off: %u len: %u part: \"%.*s\n",
|
||||
i,
|
||||
u->field_data[i].off,
|
||||
u->field_data[i].len,
|
||||
u->field_data[i].len,
|
||||
url + u->field_data[i].off);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
if (argc != 3) {
|
||||
printf("Syntax : %s connect|get url\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
struct http_parser_url u;
|
||||
int len = strlen(argv[2]);
|
||||
int connect = strcmp("connect", argv[1]) == 0 ? 1 : 0;
|
||||
printf("Parsing %s, connect %d\n", argv[2], connect);
|
||||
|
||||
int result = http_parser_parse_url(argv[2], len, connect, &u);
|
||||
if (result != 0) {
|
||||
printf("Parse error : %d\n", result);
|
||||
return result;
|
||||
}
|
||||
printf("Parse ok, result : \n");
|
||||
dump_url(argv[2], &u);
|
||||
return 0;
|
||||
}
|
||||
2199
src/beast/modules/beast_asio/parsehttp/http_parser.c
Normal file
2199
src/beast/modules/beast_asio/parsehttp/http_parser.c
Normal file
File diff suppressed because it is too large
Load Diff
111
src/beast/modules/beast_asio/parsehttp/http_parser.gyp
Normal file
111
src/beast/modules/beast_asio/parsehttp/http_parser.gyp
Normal file
@@ -0,0 +1,111 @@
|
||||
# This file is used with the GYP meta build system.
|
||||
# http://code.google.com/p/gyp/
|
||||
# To build try this:
|
||||
# svn co http://gyp.googlecode.com/svn/trunk gyp
|
||||
# ./gyp/gyp -f make --depth=`pwd` http_parser.gyp
|
||||
# ./out/Debug/test
|
||||
{
|
||||
'target_defaults': {
|
||||
'default_configuration': 'Debug',
|
||||
'configurations': {
|
||||
# TODO: hoist these out and put them somewhere common, because
|
||||
# RuntimeLibrary MUST MATCH across the entire project
|
||||
'Debug': {
|
||||
'defines': [ 'DEBUG', '_DEBUG' ],
|
||||
'cflags': [ '-Wall', '-Wextra', '-O0', '-g', '-ftrapv' ],
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
'RuntimeLibrary': 1, # static debug
|
||||
},
|
||||
},
|
||||
},
|
||||
'Release': {
|
||||
'defines': [ 'NDEBUG' ],
|
||||
'cflags': [ '-Wall', '-Wextra', '-O3' ],
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
'RuntimeLibrary': 0, # static release
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
},
|
||||
'VCLibrarianTool': {
|
||||
},
|
||||
'VCLinkerTool': {
|
||||
'GenerateDebugInformation': 'true',
|
||||
},
|
||||
},
|
||||
'conditions': [
|
||||
['OS == "win"', {
|
||||
'defines': [
|
||||
'WIN32'
|
||||
],
|
||||
}]
|
||||
],
|
||||
},
|
||||
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'http_parser',
|
||||
'type': 'static_library',
|
||||
'include_dirs': [ '.' ],
|
||||
'direct_dependent_settings': {
|
||||
'defines': [ 'HTTP_PARSER_STRICT=0' ],
|
||||
'include_dirs': [ '.' ],
|
||||
},
|
||||
'defines': [ 'HTTP_PARSER_STRICT=0' ],
|
||||
'sources': [ './http_parser.c', ],
|
||||
'conditions': [
|
||||
['OS=="win"', {
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
# Compile as C++. http_parser.c is actually C99, but C++ is
|
||||
# close enough in this case.
|
||||
'CompileAs': 2,
|
||||
},
|
||||
},
|
||||
}]
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
'target_name': 'http_parser_strict',
|
||||
'type': 'static_library',
|
||||
'include_dirs': [ '.' ],
|
||||
'direct_dependent_settings': {
|
||||
'defines': [ 'HTTP_PARSER_STRICT=1' ],
|
||||
'include_dirs': [ '.' ],
|
||||
},
|
||||
'defines': [ 'HTTP_PARSER_STRICT=1' ],
|
||||
'sources': [ './http_parser.c', ],
|
||||
'conditions': [
|
||||
['OS=="win"', {
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
# Compile as C++. http_parser.c is actually C99, but C++ is
|
||||
# close enough in this case.
|
||||
'CompileAs': 2,
|
||||
},
|
||||
},
|
||||
}]
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
'target_name': 'test-nonstrict',
|
||||
'type': 'executable',
|
||||
'dependencies': [ 'http_parser' ],
|
||||
'sources': [ 'test.c' ]
|
||||
},
|
||||
|
||||
{
|
||||
'target_name': 'test-strict',
|
||||
'type': 'executable',
|
||||
'dependencies': [ 'http_parser_strict' ],
|
||||
'sources': [ 'test.c' ]
|
||||
}
|
||||
]
|
||||
}
|
||||
318
src/beast/modules/beast_asio/parsehttp/http_parser.h
Normal file
318
src/beast/modules/beast_asio/parsehttp/http_parser.h
Normal file
@@ -0,0 +1,318 @@
|
||||
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef http_parser_h
|
||||
#define http_parser_h
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Also update SONAME in the Makefile whenever you change these. */
|
||||
#define HTTP_PARSER_VERSION_MAJOR 2
|
||||
#define HTTP_PARSER_VERSION_MINOR 1
|
||||
#define HTTP_PARSER_VERSION_PATCH 0
|
||||
|
||||
#include <sys/types.h>
|
||||
#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600)
|
||||
#include <BaseTsd.h>
|
||||
#include <stddef.h>
|
||||
typedef __int8 int8_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef __int16 int16_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef __int32 int32_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
|
||||
* faster
|
||||
*/
|
||||
#ifndef HTTP_PARSER_STRICT
|
||||
# define HTTP_PARSER_STRICT 1
|
||||
#endif
|
||||
|
||||
/* Maximium header size allowed */
|
||||
#define HTTP_MAX_HEADER_SIZE (80*1024)
|
||||
|
||||
|
||||
typedef struct http_parser http_parser;
|
||||
typedef struct http_parser_settings http_parser_settings;
|
||||
|
||||
|
||||
/* Callbacks should return non-zero to indicate an error. The parser will
|
||||
* then halt execution.
|
||||
*
|
||||
* The one exception is on_headers_complete. In a HTTP_RESPONSE parser
|
||||
* returning '1' from on_headers_complete will tell the parser that it
|
||||
* should not expect a body. This is used when receiving a response to a
|
||||
* HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
|
||||
* chunked' headers that indicate the presence of a body.
|
||||
*
|
||||
* http_data_cb does not return data chunks. It will be call arbitrarally
|
||||
* many times for each string. E.G. you might get 10 callbacks for "on_url"
|
||||
* each providing just a few characters more data.
|
||||
*/
|
||||
typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
|
||||
typedef int (*http_cb) (http_parser*);
|
||||
|
||||
|
||||
/* Request Methods */
|
||||
#define HTTP_METHOD_MAP(XX) \
|
||||
XX(0, DELETE, DELETE) \
|
||||
XX(1, GET, GET) \
|
||||
XX(2, HEAD, HEAD) \
|
||||
XX(3, POST, POST) \
|
||||
XX(4, PUT, PUT) \
|
||||
/* pathological */ \
|
||||
XX(5, CONNECT, CONNECT) \
|
||||
XX(6, OPTIONS, OPTIONS) \
|
||||
XX(7, TRACE, TRACE) \
|
||||
/* webdav */ \
|
||||
XX(8, COPY, COPY) \
|
||||
XX(9, LOCK, LOCK) \
|
||||
XX(10, MKCOL, MKCOL) \
|
||||
XX(11, MOVE, MOVE) \
|
||||
XX(12, PROPFIND, PROPFIND) \
|
||||
XX(13, PROPPATCH, PROPPATCH) \
|
||||
XX(14, SEARCH, SEARCH) \
|
||||
XX(15, UNLOCK, UNLOCK) \
|
||||
/* subversion */ \
|
||||
XX(16, REPORT, REPORT) \
|
||||
XX(17, MKACTIVITY, MKACTIVITY) \
|
||||
XX(18, CHECKOUT, CHECKOUT) \
|
||||
XX(19, MERGE, MERGE) \
|
||||
/* upnp */ \
|
||||
XX(20, MSEARCH, M-SEARCH) \
|
||||
XX(21, NOTIFY, NOTIFY) \
|
||||
XX(22, SUBSCRIBE, SUBSCRIBE) \
|
||||
XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \
|
||||
/* RFC-5789 */ \
|
||||
XX(24, PATCH, PATCH) \
|
||||
XX(25, PURGE, PURGE) \
|
||||
|
||||
enum http_method
|
||||
{
|
||||
#define XX(num, name, string) HTTP_##name = num,
|
||||
HTTP_METHOD_MAP(XX)
|
||||
#undef XX
|
||||
};
|
||||
|
||||
|
||||
enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
|
||||
|
||||
|
||||
/* Flag values for http_parser.flags field */
|
||||
enum flags
|
||||
{ F_CHUNKED = 1 << 0
|
||||
, F_CONNECTION_KEEP_ALIVE = 1 << 1
|
||||
, F_CONNECTION_CLOSE = 1 << 2
|
||||
, F_TRAILING = 1 << 3
|
||||
, F_UPGRADE = 1 << 4
|
||||
, F_SKIPBODY = 1 << 5
|
||||
};
|
||||
|
||||
|
||||
/* Map for errno-related constants
|
||||
*
|
||||
* The provided argument should be a macro that takes 2 arguments.
|
||||
*/
|
||||
#define HTTP_ERRNO_MAP(XX) \
|
||||
/* No error */ \
|
||||
XX(OK, "success") \
|
||||
\
|
||||
/* Callback-related errors */ \
|
||||
XX(CB_message_begin, "the on_message_begin callback failed") \
|
||||
XX(CB_status_complete, "the on_status_complete callback failed") \
|
||||
XX(CB_url, "the on_url callback failed") \
|
||||
XX(CB_header_field, "the on_header_field callback failed") \
|
||||
XX(CB_header_value, "the on_header_value callback failed") \
|
||||
XX(CB_headers_complete, "the on_headers_complete callback failed") \
|
||||
XX(CB_body, "the on_body callback failed") \
|
||||
XX(CB_message_complete, "the on_message_complete callback failed") \
|
||||
\
|
||||
/* Parsing-related errors */ \
|
||||
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
|
||||
XX(HEADER_OVERFLOW, \
|
||||
"too many header bytes seen; overflow detected") \
|
||||
XX(CLOSED_CONNECTION, \
|
||||
"data received after completed connection: close message") \
|
||||
XX(INVALID_VERSION, "invalid HTTP version") \
|
||||
XX(INVALID_STATUS, "invalid HTTP status code") \
|
||||
XX(INVALID_METHOD, "invalid HTTP method") \
|
||||
XX(INVALID_URL, "invalid URL") \
|
||||
XX(INVALID_HOST, "invalid host") \
|
||||
XX(INVALID_PORT, "invalid port") \
|
||||
XX(INVALID_PATH, "invalid path") \
|
||||
XX(INVALID_QUERY_STRING, "invalid query string") \
|
||||
XX(INVALID_FRAGMENT, "invalid fragment") \
|
||||
XX(LF_EXPECTED, "LF character expected") \
|
||||
XX(INVALID_HEADER_TOKEN, "invalid character in header") \
|
||||
XX(INVALID_CONTENT_LENGTH, \
|
||||
"invalid character in content-length header") \
|
||||
XX(INVALID_CHUNK_SIZE, \
|
||||
"invalid character in chunk size header") \
|
||||
XX(INVALID_CONSTANT, "invalid constant string") \
|
||||
XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
|
||||
XX(STRICT, "strict mode assertion failed") \
|
||||
XX(PAUSED, "parser is paused") \
|
||||
XX(UNKNOWN, "an unknown error occurred")
|
||||
|
||||
|
||||
/* Define HPE_* values for each errno value above */
|
||||
#define HTTP_ERRNO_GEN(n, s) HPE_##n,
|
||||
enum http_errno {
|
||||
HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
|
||||
};
|
||||
#undef HTTP_ERRNO_GEN
|
||||
|
||||
|
||||
/* Get an http_errno value from an http_parser */
|
||||
#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
|
||||
|
||||
|
||||
struct http_parser {
|
||||
/** PRIVATE **/
|
||||
unsigned char type : 2; /* enum http_parser_type */
|
||||
unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */
|
||||
unsigned char state; /* enum state from http_parser.c */
|
||||
unsigned char header_state; /* enum header_state from http_parser.c */
|
||||
unsigned char index; /* index into current matcher */
|
||||
|
||||
uint32_t nread; /* # bytes read in various scenarios */
|
||||
uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
|
||||
|
||||
/** READ-ONLY **/
|
||||
unsigned short http_major;
|
||||
unsigned short http_minor;
|
||||
unsigned short status_code; /* responses only */
|
||||
unsigned char method; /* requests only */
|
||||
unsigned char http_errno : 7;
|
||||
|
||||
/* 1 = Upgrade header was present and the parser has exited because of that.
|
||||
* 0 = No upgrade header present.
|
||||
* Should be checked when http_parser_execute() returns in addition to
|
||||
* error checking.
|
||||
*/
|
||||
unsigned char upgrade : 1;
|
||||
|
||||
/** PUBLIC **/
|
||||
void *data; /* A pointer to get hook to the "connection" or "socket" object */
|
||||
};
|
||||
|
||||
|
||||
struct http_parser_settings {
|
||||
http_cb on_message_begin;
|
||||
http_data_cb on_url;
|
||||
http_cb on_status_complete;
|
||||
http_data_cb on_header_field;
|
||||
http_data_cb on_header_value;
|
||||
http_cb on_headers_complete;
|
||||
http_data_cb on_body;
|
||||
http_cb on_message_complete;
|
||||
};
|
||||
|
||||
|
||||
enum http_parser_url_fields
|
||||
{ UF_SCHEMA = 0
|
||||
, UF_HOST = 1
|
||||
, UF_PORT = 2
|
||||
, UF_PATH = 3
|
||||
, UF_QUERY = 4
|
||||
, UF_FRAGMENT = 5
|
||||
, UF_USERINFO = 6
|
||||
, UF_MAX = 7
|
||||
};
|
||||
|
||||
|
||||
/* Result structure for http_parser_parse_url().
|
||||
*
|
||||
* Callers should index into field_data[] with UF_* values iff field_set
|
||||
* has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
|
||||
* because we probably have padding left over), we convert any port to
|
||||
* a uint16_t.
|
||||
*/
|
||||
struct http_parser_url {
|
||||
uint16_t field_set; /* Bitmask of (1 << UF_*) values */
|
||||
uint16_t port; /* Converted UF_PORT string */
|
||||
|
||||
struct {
|
||||
uint16_t off; /* Offset into buffer in which field starts */
|
||||
uint16_t len; /* Length of run in buffer */
|
||||
} field_data[UF_MAX];
|
||||
};
|
||||
|
||||
|
||||
/* Returns the library version. Bits 16-23 contain the major version number,
|
||||
* bits 8-15 the minor version number and bits 0-7 the patch level.
|
||||
* Usage example:
|
||||
*
|
||||
* unsigned long version = http_parser_version();
|
||||
* unsigned major = (version >> 16) & 255;
|
||||
* unsigned minor = (version >> 8) & 255;
|
||||
* unsigned patch = version & 255;
|
||||
* printf("http_parser v%u.%u.%u\n", major, minor, version);
|
||||
*/
|
||||
unsigned long http_parser_version(void);
|
||||
|
||||
void http_parser_init(http_parser *parser, enum http_parser_type type);
|
||||
|
||||
|
||||
size_t http_parser_execute(http_parser *parser,
|
||||
const http_parser_settings *settings,
|
||||
const char *data,
|
||||
size_t len);
|
||||
|
||||
|
||||
/* If http_should_keep_alive() in the on_headers_complete or
|
||||
* on_message_complete callback returns 0, then this should be
|
||||
* the last message on the connection.
|
||||
* If you are the server, respond with the "Connection: close" header.
|
||||
* If you are the client, close the connection.
|
||||
*/
|
||||
int http_should_keep_alive(const http_parser *parser);
|
||||
|
||||
/* Returns a string version of the HTTP method. */
|
||||
const char *http_method_str(enum http_method m);
|
||||
|
||||
/* Return a string name of the given error */
|
||||
const char *http_errno_name(enum http_errno err);
|
||||
|
||||
/* Return a string description of the given error */
|
||||
const char *http_errno_description(enum http_errno err);
|
||||
|
||||
/* Parse a URL; return nonzero on failure */
|
||||
int http_parser_parse_url(const char *buf, size_t buflen,
|
||||
int is_connect,
|
||||
struct http_parser_url *u);
|
||||
|
||||
/* Pause or un-pause the parser; a nonzero value pauses */
|
||||
void http_parser_pause(http_parser *parser, int paused);
|
||||
|
||||
/* Checks if this is the final chunk of the body. */
|
||||
int http_body_is_final(const http_parser *parser);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
3439
src/beast/modules/beast_asio/parsehttp/test.c
Normal file
3439
src/beast/modules/beast_asio/parsehttp/test.c
Normal file
File diff suppressed because it is too large
Load Diff
141
src/beast/modules/beast_asio/protocol/HandshakeDetectLogic.h
Normal file
141
src/beast/modules/beast_asio/protocol/HandshakeDetectLogic.h
Normal file
@@ -0,0 +1,141 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGIC_H_INCLUDED
|
||||
#define BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGIC_H_INCLUDED
|
||||
|
||||
class HandshakeDetectLogic
|
||||
{
|
||||
public:
|
||||
HandshakeDetectLogic ()
|
||||
: m_finished (false)
|
||||
, m_success (false)
|
||||
{
|
||||
}
|
||||
|
||||
/** How many bytes maximum we might need.
|
||||
|
||||
This is the largest number of bytes that the detector
|
||||
might need in order to come to a conclusion about
|
||||
whether or not the handshake is a match. Depending
|
||||
on the data, it could come to that conclusion sooner
|
||||
though.
|
||||
|
||||
Use read_some instead of read so that the detect logic
|
||||
can reject the handshake sooner if possible.
|
||||
*/
|
||||
virtual std::size_t max_needed () = 0;
|
||||
|
||||
/** How many bytes the handshake consumes.
|
||||
If the detector processes the entire handshake this will
|
||||
be non zero. The SSL detector would return 0, since we
|
||||
want all the existing bytes to be passed on.
|
||||
*/
|
||||
virtual std::size_t bytes_consumed () = 0;
|
||||
|
||||
/** Return true if we have enough data to form a conclusion.
|
||||
*/
|
||||
bool finished () const noexcept
|
||||
{
|
||||
return m_finished;
|
||||
}
|
||||
|
||||
/** Return true if we came to a conclusion and the data matched.
|
||||
*/
|
||||
bool success () const noexcept
|
||||
{
|
||||
return m_finished && m_success;
|
||||
}
|
||||
|
||||
protected:
|
||||
void conclude (bool success = true)
|
||||
{
|
||||
m_finished = true;
|
||||
m_success = success;
|
||||
}
|
||||
|
||||
void fail ()
|
||||
{
|
||||
conclude (false);
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_finished;
|
||||
bool m_success;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Wraps the logic and exports it as an abstract interface.
|
||||
*/
|
||||
template <typename Logic>
|
||||
class HandshakeDetectLogicType
|
||||
{
|
||||
public:
|
||||
typedef Logic LogicType;
|
||||
typedef typename Logic::arg_type arg_type;
|
||||
|
||||
explicit HandshakeDetectLogicType (arg_type const& arg = arg_type ())
|
||||
: m_logic (arg)
|
||||
{
|
||||
}
|
||||
|
||||
LogicType& get ()
|
||||
{
|
||||
return m_logic;
|
||||
}
|
||||
|
||||
std::size_t max_needed ()
|
||||
{
|
||||
return m_logic.max_needed ();
|
||||
}
|
||||
|
||||
std::size_t bytes_consumed ()
|
||||
{
|
||||
return m_logic.bytes_consumed ();
|
||||
}
|
||||
|
||||
bool finished ()
|
||||
{
|
||||
return m_logic.finished ();
|
||||
}
|
||||
|
||||
/** If finished is true, this tells us if the handshake was detected.
|
||||
*/
|
||||
bool success ()
|
||||
{
|
||||
return m_logic.success ();
|
||||
}
|
||||
|
||||
/** Analyze the buffer to match the Handshake.
|
||||
Returns `true` if the analysis is complete.
|
||||
*/
|
||||
template <typename ConstBufferSequence>
|
||||
bool analyze (ConstBufferSequence const& buffer)
|
||||
{
|
||||
bassert (! m_logic.finished ());
|
||||
m_logic.analyze (buffer);
|
||||
return m_logic.finished ();
|
||||
}
|
||||
|
||||
private:
|
||||
Logic m_logic;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICPROXY_H_INCLUDED
|
||||
#define BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICPROXY_H_INCLUDED
|
||||
|
||||
/** Handshake detector for the PROXY protcol
|
||||
|
||||
http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt
|
||||
*/
|
||||
class HandshakeDetectLogicPROXY : public HandshakeDetectLogic
|
||||
{
|
||||
public:
|
||||
typedef int arg_type;
|
||||
|
||||
enum
|
||||
{
|
||||
// This is for version 1. The largest number of bytes
|
||||
// that we could possibly need to parse a valid handshake.
|
||||
// We will reject it much sooner if there's an illegal value.
|
||||
//
|
||||
maxBytesNeeded = 107 // including CRLF, no null term
|
||||
};
|
||||
|
||||
struct ProxyInfo
|
||||
{
|
||||
typedef InputParser::IPv4Address IPv4Address;
|
||||
|
||||
String protocol; // "TCP4", "TCP6", "UNKNOWN"
|
||||
|
||||
IPv4Address sourceAddress;
|
||||
IPv4Address destAddress;
|
||||
|
||||
uint16 sourcePort;
|
||||
uint16 destPort;
|
||||
};
|
||||
|
||||
explicit HandshakeDetectLogicPROXY (arg_type const&)
|
||||
: m_consumed (0)
|
||||
{
|
||||
}
|
||||
|
||||
ProxyInfo const& getInfo () const noexcept
|
||||
{
|
||||
return m_info;
|
||||
}
|
||||
|
||||
std::size_t max_needed ()
|
||||
{
|
||||
return maxBytesNeeded;
|
||||
}
|
||||
|
||||
std::size_t bytes_consumed ()
|
||||
{
|
||||
return m_consumed;
|
||||
}
|
||||
|
||||
template <typename ConstBufferSequence>
|
||||
void analyze (ConstBufferSequence const& buffer)
|
||||
{
|
||||
FixedInputBufferSize <maxBytesNeeded> in (buffer);
|
||||
|
||||
InputParser::State state;
|
||||
|
||||
analyze_input (in, state);
|
||||
|
||||
if (state.passed ())
|
||||
{
|
||||
m_consumed = in.used ();
|
||||
conclude (true);
|
||||
}
|
||||
else if (state.failed ())
|
||||
{
|
||||
conclude (false);
|
||||
}
|
||||
}
|
||||
|
||||
void analyze_input (FixedInputBuffer& in, InputParser::State& state)
|
||||
{
|
||||
using namespace InputParser;
|
||||
|
||||
if (! match (in, "PROXY ", state))
|
||||
return;
|
||||
|
||||
if (match (in, "TCP4 "))
|
||||
{
|
||||
m_info.protocol = "TCP4";
|
||||
|
||||
if (! read (in, m_info.sourceAddress, state))
|
||||
return;
|
||||
|
||||
if (! match (in, " ", state))
|
||||
return;
|
||||
|
||||
if (! read (in, m_info.destAddress, state))
|
||||
return;
|
||||
|
||||
if (! match (in, " ", state))
|
||||
return;
|
||||
|
||||
UInt16Str sourcePort;
|
||||
if (! read (in, sourcePort, state))
|
||||
return;
|
||||
m_info.sourcePort = sourcePort.value;
|
||||
|
||||
if (! match (in, " ", state))
|
||||
return;
|
||||
|
||||
UInt16Str destPort;
|
||||
if (! read (in, destPort, state))
|
||||
return;
|
||||
m_info.destPort = destPort.value;
|
||||
|
||||
if (! match (in, "\r\n", state))
|
||||
return;
|
||||
|
||||
state = State::pass;
|
||||
return;
|
||||
}
|
||||
else if (match (in, "TCP6 "))
|
||||
{
|
||||
m_info.protocol = "TCP6";
|
||||
|
||||
state = State::fail;
|
||||
return;
|
||||
}
|
||||
else if (match (in, "UNKNOWN "))
|
||||
{
|
||||
m_info.protocol = "UNKNOWN";
|
||||
|
||||
state = State::fail;
|
||||
return;
|
||||
}
|
||||
|
||||
state = State::fail;
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t m_consumed;
|
||||
ProxyInfo m_info;
|
||||
};
|
||||
|
||||
#endif
|
||||
108
src/beast/modules/beast_asio/protocol/HandshakeDetectLogicSSL2.h
Normal file
108
src/beast/modules/beast_asio/protocol/HandshakeDetectLogicSSL2.h
Normal file
@@ -0,0 +1,108 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICSSL2_H_INCLUDED
|
||||
#define BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICSSL2_H_INCLUDED
|
||||
|
||||
// Handshake for SSL 2
|
||||
//
|
||||
// http://tools.ietf.org/html/rfc5246#appendix-E.2
|
||||
//
|
||||
// uint8 V2CipherSpec[3];
|
||||
// struct {
|
||||
// uint16 msg_length;
|
||||
// uint8 msg_type;
|
||||
// Version version; Should be 'ProtocolVersion'?
|
||||
// uint16 cipher_spec_length;
|
||||
// uint16 session_id_length;
|
||||
// uint16 challenge_length;
|
||||
// ...
|
||||
//
|
||||
class HandshakeDetectLogicSSL2 : public HandshakeDetectLogic
|
||||
{
|
||||
public:
|
||||
typedef int arg_type;
|
||||
|
||||
explicit HandshakeDetectLogicSSL2 (arg_type const&)
|
||||
{
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
bytesNeeded = 3
|
||||
};
|
||||
|
||||
std::size_t max_needed ()
|
||||
{
|
||||
return bytesNeeded;
|
||||
}
|
||||
|
||||
std::size_t bytes_consumed ()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename ConstBufferSequence>
|
||||
void analyze (ConstBufferSequence const& buffer)
|
||||
{
|
||||
FixedInputBufferSize <bytesNeeded> in (buffer);
|
||||
|
||||
{
|
||||
uint8 byte;
|
||||
if (! in.peek (&byte))
|
||||
return;
|
||||
|
||||
// First byte must have the high bit set
|
||||
//
|
||||
if((byte & 0x80) != 0x80)
|
||||
return fail ();
|
||||
}
|
||||
|
||||
// The remaining bits contain the
|
||||
// length of the following data in bytes.
|
||||
//
|
||||
uint16 msg_length;
|
||||
if (! in.readNetworkInteger(&msg_length))
|
||||
return;
|
||||
|
||||
// sizeof (msg_type +
|
||||
// Version (ProtcolVersion?) +
|
||||
// cipher_spec_length +
|
||||
// session_id_length +
|
||||
// challenge_length)
|
||||
//
|
||||
// Should be 9 or greater.
|
||||
//
|
||||
if (msg_length < 9)
|
||||
return fail ();
|
||||
|
||||
uint8 msg_type;
|
||||
if (! in.read (&msg_type))
|
||||
return;
|
||||
|
||||
// The msg_type must be 0x01 for a version 2 ClientHello
|
||||
//
|
||||
if (msg_type != 0x01)
|
||||
return fail ();
|
||||
|
||||
conclude ();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICSSL3_H_INCLUDED
|
||||
#define BEAST_ASIO_HANDSHAKE_HANDSHAKEDETECTLOGICSSL3_H_INCLUDED
|
||||
|
||||
// Handshake for SSL 3 (Also TLS 1.0 and 1.1)
|
||||
//
|
||||
// http://www.ietf.org/rfc/rfc2246.txt
|
||||
//
|
||||
// Section 7.4. Handshake protocol
|
||||
//
|
||||
class HandshakeDetectLogicSSL3 : public HandshakeDetectLogic
|
||||
{
|
||||
public:
|
||||
typedef int arg_type; // dummy
|
||||
|
||||
explicit HandshakeDetectLogicSSL3 (arg_type const&)
|
||||
{
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
bytesNeeded = 6
|
||||
};
|
||||
|
||||
std::size_t max_needed ()
|
||||
{
|
||||
return bytesNeeded;
|
||||
}
|
||||
|
||||
std::size_t bytes_consumed ()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename ConstBufferSequence>
|
||||
void analyze (ConstBufferSequence const& buffer)
|
||||
{
|
||||
uint16 version;
|
||||
FixedInputBufferSize <bytesNeeded> in (buffer);
|
||||
|
||||
uint8 msg_type;
|
||||
if (! in.read (&msg_type))
|
||||
return;
|
||||
|
||||
// msg_type must be 0x16 = "SSL Handshake"
|
||||
//
|
||||
if (msg_type != 0x16)
|
||||
return fail ();
|
||||
|
||||
if (! in.read (&version))
|
||||
return;
|
||||
version = fromNetworkByteOrder (version);
|
||||
|
||||
uint16 length;
|
||||
if (! in.read (&length))
|
||||
return;
|
||||
|
||||
length = fromNetworkByteOrder (length);
|
||||
|
||||
conclude ();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
206
src/beast/modules/beast_asio/protocol/HandshakeDetector.h
Normal file
206
src/beast/modules/beast_asio/protocol/HandshakeDetector.h
Normal 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_ASIO_HANDSHAKE_HANDSHAKEDETECTOR_H_INCLUDED
|
||||
#define BEAST_ASIO_HANDSHAKE_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> BuffersType;
|
||||
|
||||
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 BuffersType::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> BuffersType;
|
||||
|
||||
AsyncOp (HandshakeDetectLogicType <Logic>& logic, Stream& stream,
|
||||
BuffersType& 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 BuffersType::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;
|
||||
BuffersType& m_buffer;
|
||||
SharedHandlerPtr m_handler;
|
||||
bool m_running;
|
||||
};
|
||||
|
||||
private:
|
||||
HandshakeDetectLogicType <Logic> m_logic;
|
||||
};
|
||||
|
||||
#endif
|
||||
387
src/beast/modules/beast_asio/protocol/InputParser.h
Normal file
387
src/beast/modules/beast_asio/protocol/InputParser.h
Normal file
@@ -0,0 +1,387 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_HANDSHAKE_INPUTPARSER_H_INCLUDED
|
||||
#define BEAST_ASIO_HANDSHAKE_INPUTPARSER_H_INCLUDED
|
||||
|
||||
namespace InputParser
|
||||
{
|
||||
|
||||
/** Tri-valued parsing state.
|
||||
This is convertible to bool which means continue.
|
||||
Or you can use stop() to decide if you should return.
|
||||
After a stop you can use failed () to determine if parsing failed.
|
||||
*/
|
||||
struct State : SafeBool <State>
|
||||
{
|
||||
enum State_t
|
||||
{
|
||||
pass, // passed the parse
|
||||
fail, // failed the parse
|
||||
more // didn't fail but need more bytes
|
||||
};
|
||||
|
||||
State () : m_state (more) { }
|
||||
|
||||
State (State_t state) : m_state (state) { }
|
||||
|
||||
/** Implicit construction from bool.
|
||||
If condition is true then the parse passes, else need more.
|
||||
*/
|
||||
State (bool condition) : m_state (condition ? pass : more) { }
|
||||
|
||||
State& operator= (State_t state) { m_state = state; return *this; }
|
||||
|
||||
bool eof () const noexcept { return m_state == more; }
|
||||
bool stop () const noexcept { return m_state != pass; }
|
||||
bool passed () const noexcept { return m_state == pass; }
|
||||
bool failed () const noexcept { return m_state == fail; }
|
||||
bool asBoolean () const noexcept { return m_state == pass; } // for SafeBool<>
|
||||
|
||||
private:
|
||||
State_t m_state;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Shortcut to save typing.
|
||||
typedef FixedInputBuffer& Input;
|
||||
|
||||
/** Specializations implement the get() function. */
|
||||
template <class T>
|
||||
struct Get;
|
||||
|
||||
/** Specializations implement the match() function.
|
||||
Default implementation of match tries to read it into a local.
|
||||
*/
|
||||
template <class T>
|
||||
struct Match
|
||||
{
|
||||
static State func (Input in, T other)
|
||||
{
|
||||
T t;
|
||||
State state = Get <T>::func (in, t);
|
||||
if (state.passed ())
|
||||
{
|
||||
if (t == other)
|
||||
return State::pass;
|
||||
return State::fail;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
/** Specializations implement the peek() function.
|
||||
Default implementation of peek reads and rewinds.
|
||||
*/
|
||||
template <class T>
|
||||
struct Peek
|
||||
{
|
||||
static State func (Input in, T& t)
|
||||
{
|
||||
Input dup (in);
|
||||
return Get <T>::func (dup, t);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Free Functions
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// match a block of data in memory
|
||||
//
|
||||
static State match_buffer (Input in, void const* buffer, std::size_t bytes)
|
||||
{
|
||||
bassert (bytes > 0);
|
||||
if (in.size () <= 0)
|
||||
return State::more;
|
||||
|
||||
std::size_t const have = std::min (in.size (), bytes);
|
||||
void const* data = in.peek (have);
|
||||
bassert (data != nullptr);
|
||||
|
||||
int const compare = memcmp (data, buffer, have);
|
||||
if (compare != 0)
|
||||
return State::fail;
|
||||
in.consume (have);
|
||||
|
||||
return have == bytes;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// match
|
||||
//
|
||||
|
||||
// Returns the state
|
||||
template <class T>
|
||||
State match (Input in, T t)
|
||||
{
|
||||
return Match <T>::func (in, t);
|
||||
}
|
||||
|
||||
// Stores the state in the argument and returns true if its a pass
|
||||
template <class T>
|
||||
bool match (Input in, T t, State& state)
|
||||
{
|
||||
return (state = match (in, t)).passed ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// peek
|
||||
//
|
||||
|
||||
// Returns the state
|
||||
template <class T>
|
||||
State peek (Input in, T& t)
|
||||
{
|
||||
return Peek <T>::func (in, t);
|
||||
}
|
||||
|
||||
// Stores the state in the argument and returns true if its a pass
|
||||
template <class T>
|
||||
bool peek (Input in, T& t, State& state)
|
||||
{
|
||||
return (state = peek (in, t)).passed ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// read
|
||||
//
|
||||
|
||||
// Returns the state
|
||||
template <class T>
|
||||
State read (Input in, T& t)
|
||||
{
|
||||
return Get <T>::func (in, t);
|
||||
}
|
||||
|
||||
// Stores the state in the argument and returns true if its a pass
|
||||
template <class T>
|
||||
bool read (Input in, T& t, State& state)
|
||||
{
|
||||
return (state = read (in, t)).passed ();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Specializations for basic types
|
||||
//
|
||||
|
||||
template <>
|
||||
struct Match <char const*>
|
||||
{
|
||||
static State func (Input in, char const* text)
|
||||
{
|
||||
return InputParser::match_buffer (in, text, strlen (text));
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Special types and their specializations
|
||||
//
|
||||
|
||||
struct Digit
|
||||
{
|
||||
int value;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Get <Digit>
|
||||
{
|
||||
static State func (Input in, Digit& t)
|
||||
{
|
||||
char c;
|
||||
if (! in.peek (&c))
|
||||
return State::more;
|
||||
if (! std::isdigit (c))
|
||||
return State::fail;
|
||||
in.consume (1);
|
||||
t.value = c - '0';
|
||||
return State::pass;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// An unsigned 32 bit number expressed as a string
|
||||
struct UInt32Str
|
||||
{
|
||||
uint32 value;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Get <UInt32Str>
|
||||
{
|
||||
static State func (Input in, UInt32Str& t)
|
||||
{
|
||||
State state;
|
||||
uint32 value (0);
|
||||
|
||||
Digit digit;
|
||||
// have to have at least one digit
|
||||
if (! read (in, digit, state))
|
||||
return state;
|
||||
value = digit.value;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
state = peek (in, digit);
|
||||
|
||||
if (state.failed ())
|
||||
{
|
||||
t.value = value;
|
||||
return State::pass;
|
||||
}
|
||||
else if (state.eof ())
|
||||
{
|
||||
t.value = value;
|
||||
return state;
|
||||
}
|
||||
|
||||
// can't have a digit following a zero
|
||||
if (value == 0)
|
||||
return State::fail;
|
||||
|
||||
uint32 newValue = (value * 10) + digit.value;
|
||||
|
||||
// overflow
|
||||
if (newValue < value)
|
||||
return State::fail;
|
||||
|
||||
value = newValue;
|
||||
}
|
||||
|
||||
return State::fail;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// An unsigned 16 bit number expressed as a string
|
||||
struct UInt16Str
|
||||
{
|
||||
uint16 value;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Get <UInt16Str>
|
||||
{
|
||||
static State func (Input in, UInt16Str& t)
|
||||
{
|
||||
UInt32Str v;
|
||||
State state = read (in, v);
|
||||
if (state.passed ())
|
||||
{
|
||||
if (v.value <= 65535)
|
||||
{
|
||||
t.value = uint16(v.value);
|
||||
return State::pass;
|
||||
}
|
||||
return State::fail;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// An unsigned 8 bit number expressed as a string
|
||||
struct UInt8Str
|
||||
{
|
||||
uint8 value;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Get <UInt8Str>
|
||||
{
|
||||
static State func (Input in, UInt8Str& t)
|
||||
{
|
||||
UInt32Str v;
|
||||
State state = read (in, v);
|
||||
if (state.passed ())
|
||||
{
|
||||
if (v.value <= 255)
|
||||
{
|
||||
t.value = uint8(v.value);
|
||||
return State::pass;
|
||||
}
|
||||
return State::fail;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// An dotted IPv4 address
|
||||
struct IPv4Address
|
||||
{
|
||||
uint8 value [4];
|
||||
|
||||
String toString () const
|
||||
{
|
||||
return String::fromNumber <int> (value [0]) + "." +
|
||||
String::fromNumber <int> (value [1]) + "." +
|
||||
String::fromNumber <int> (value [2]) + "." +
|
||||
String::fromNumber <int> (value [3]);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Get <IPv4Address>
|
||||
{
|
||||
static State func (Input in, IPv4Address& t)
|
||||
{
|
||||
State state;
|
||||
UInt8Str digit [4];
|
||||
if (! read (in, digit [0], state))
|
||||
return state;
|
||||
if (! match (in, ".", state))
|
||||
return state;
|
||||
if (! read (in, digit [1], state))
|
||||
return state;
|
||||
if (! match (in, ".", state))
|
||||
return state;
|
||||
if (! read (in, digit [2], state))
|
||||
return state;
|
||||
if (! match (in, ".", state))
|
||||
return state;
|
||||
if (! read (in, digit [3], state))
|
||||
return state;
|
||||
|
||||
t.value [0] = digit [0].value;
|
||||
t.value [1] = digit [1].value;
|
||||
t.value [2] = digit [2].value;
|
||||
t.value [3] = digit [3].value;
|
||||
|
||||
return State::pass;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
197
src/beast/modules/beast_asio/protocol/PrefilledReadStream.h
Normal file
197
src/beast/modules/beast_asio/protocol/PrefilledReadStream.h
Normal file
@@ -0,0 +1,197 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_HANDSHAKE_PREFILLEDREADSTREAM_H_INCLUDED
|
||||
#define BEAST_ASIO_HANDSHAKE_PREFILLEDREADSTREAM_H_INCLUDED
|
||||
|
||||
/** Front-ends a stream with a provided block of data.
|
||||
|
||||
When read operations are performed on this object, bytes will first be
|
||||
returned from the buffer provided on construction. When those bytes
|
||||
are exhausted, read operations will then pass through to the underlying
|
||||
stream.
|
||||
|
||||
Write operations are all simply passed through.
|
||||
*/
|
||||
template <typename Stream>
|
||||
class PrefilledReadStream : public Uncopyable
|
||||
{
|
||||
protected:
|
||||
typedef boost::system::error_code error_code;
|
||||
|
||||
void throw_error (error_code const& ec, char const* fileName, int lineNumber)
|
||||
{
|
||||
Throw (boost::system::system_error (ec), fileName, lineNumber);
|
||||
}
|
||||
|
||||
public:
|
||||
typedef typename boost::remove_reference <Stream>::type next_layer_type;
|
||||
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
|
||||
|
||||
/** Single argument constructor for when we are wrapped in something.
|
||||
arg is passed through to the next layer's constructor.
|
||||
*/
|
||||
template <typename Arg>
|
||||
explicit PrefilledReadStream (Arg& arg)
|
||||
: m_next_layer (arg)
|
||||
{
|
||||
}
|
||||
|
||||
/** Construct with the buffer, and argument passed through.
|
||||
This creates a copy of the data. The argument is passed through
|
||||
to the constructor of Stream.
|
||||
*/
|
||||
template <typename Arg, typename ConstBufferSequence>
|
||||
PrefilledReadStream (Arg& arg, ConstBufferSequence const& buffers)
|
||||
: m_next_layer (arg)
|
||||
{
|
||||
fill (buffers);
|
||||
}
|
||||
|
||||
/** Place some input into the prefilled buffer.
|
||||
Note that this is in no way thread safe. The only reason this function
|
||||
is here is for the case when you can't pass the buffer through the
|
||||
constructor because there is another object wrapping this stream.
|
||||
*/
|
||||
template <typename ConstBufferSequence>
|
||||
void fill (ConstBufferSequence const& buffers)
|
||||
{
|
||||
// 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));
|
||||
}
|
||||
|
||||
next_layer_type& next_layer()
|
||||
{
|
||||
return m_next_layer;
|
||||
}
|
||||
|
||||
next_layer_type const& next_layer() const
|
||||
{
|
||||
return m_next_layer;
|
||||
}
|
||||
|
||||
lowest_layer_type& lowest_layer()
|
||||
{
|
||||
return m_next_layer.lowest_layer();
|
||||
}
|
||||
|
||||
const lowest_layer_type& lowest_layer() const
|
||||
{
|
||||
return m_next_layer.lowest_layer();
|
||||
}
|
||||
|
||||
boost::asio::io_service& get_io_service()
|
||||
{
|
||||
return m_next_layer.get_io_service();
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
error_code ec;
|
||||
if (close(ec))
|
||||
throw_error (ec, __FILE__, __LINE__);
|
||||
return ec;
|
||||
}
|
||||
|
||||
error_code close (error_code& ec)
|
||||
{
|
||||
// VFALCO NOTE This is questionable. We can't
|
||||
// call m_next_layer.close() because Stream might not
|
||||
// support that function. For example, ssl::stream has no close()
|
||||
//
|
||||
return lowest_layer ().close(ec);
|
||||
}
|
||||
|
||||
template <typename MutableBufferSequence>
|
||||
std::size_t read_some (MutableBufferSequence const& buffers)
|
||||
{
|
||||
error_code ec;
|
||||
std::size_t const amount = read_some (buffers, ec);
|
||||
if (ec)
|
||||
throw_error (ec, __FILE__, __LINE__);
|
||||
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;
|
||||
};
|
||||
|
||||
#endif
|
||||
199
src/beast/modules/beast_asio/sockets/Socket.cpp
Normal file
199
src/beast/modules/beast_asio/sockets/Socket.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
Socket::~Socket ()
|
||||
{
|
||||
}
|
||||
|
||||
#if ! BEAST_COMPILER_CHECKS_SOCKET_OVERRIDES
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Socket
|
||||
//
|
||||
|
||||
void* Socket::this_layer_ptr (char const*) const
|
||||
{
|
||||
pure_virtual_called (__FILE__, __LINE__);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// native_handle
|
||||
//
|
||||
|
||||
bool Socket::native_handle (char const*, void*)
|
||||
{
|
||||
pure_virtual_called (__FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// basic_io_object
|
||||
//
|
||||
|
||||
boost::asio::io_service& Socket::get_io_service ()
|
||||
{
|
||||
pure_virtual_called (__FILE__, __LINE__);
|
||||
return *static_cast <boost::asio::io_service*>(nullptr);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// basic_socket
|
||||
//
|
||||
|
||||
void* Socket::lowest_layer_ptr (char const*) const
|
||||
{
|
||||
pure_virtual_called (__FILE__, __LINE__);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
boost::system::error_code Socket::cancel (boost::system::error_code& ec)
|
||||
{
|
||||
return pure_virtual_error (ec, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
boost::system::error_code Socket::shutdown (shutdown_type, boost::system::error_code& ec)
|
||||
{
|
||||
return pure_virtual_error (ec, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
boost::system::error_code Socket::close (boost::system::error_code& ec)
|
||||
{
|
||||
return pure_virtual_error (ec, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// basic_socket_acceptor
|
||||
//
|
||||
|
||||
boost::system::error_code Socket::accept (Socket&, boost::system::error_code& ec)
|
||||
{
|
||||
return pure_virtual_error (ec, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
void Socket::async_accept (Socket&, SharedHandlerPtr handler)
|
||||
{
|
||||
get_io_service ().wrap (
|
||||
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
|
||||
(pure_virtual_error ());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// basic_stream_socket
|
||||
//
|
||||
|
||||
std::size_t Socket::read_some (MutableBuffers const&, boost::system::error_code& 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_called (__FILE__, __LINE__);
|
||||
ec = pure_virtual_error ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Socket::async_read_some (MutableBuffers const&, SharedHandlerPtr handler)
|
||||
{
|
||||
get_io_service ().wrap (
|
||||
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
|
||||
(pure_virtual_error (), 0);
|
||||
}
|
||||
|
||||
void Socket::async_write_some (ConstBuffers const&, SharedHandlerPtr handler)
|
||||
{
|
||||
get_io_service ().wrap (
|
||||
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
|
||||
(pure_virtual_error (), 0);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// ssl::stream
|
||||
//
|
||||
|
||||
void* Socket::next_layer_ptr (char const*) const
|
||||
{
|
||||
pure_virtual_called (__FILE__, __LINE__);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool Socket::needs_handshake ()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Socket::set_verify_mode (int)
|
||||
{
|
||||
pure_virtual_called (__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
boost::system::error_code Socket::handshake (handshake_type, boost::system::error_code& ec)
|
||||
{
|
||||
return pure_virtual_error (ec, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
void Socket::async_handshake (handshake_type, SharedHandlerPtr handler)
|
||||
{
|
||||
get_io_service ().wrap (
|
||||
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
|
||||
(pure_virtual_error ());
|
||||
}
|
||||
|
||||
#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
|
||||
|
||||
boost::system::error_code Socket::handshake (handshake_type,
|
||||
ConstBuffers const&, boost::system::error_code& ec)
|
||||
{
|
||||
return pure_virtual_error (ec, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
void Socket::async_handshake (handshake_type, ConstBuffers const&, SharedHandlerPtr handler)
|
||||
{
|
||||
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_error (ec, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
void Socket::async_shutdown (SharedHandlerPtr handler)
|
||||
{
|
||||
get_io_service ().wrap (
|
||||
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
|
||||
(pure_virtual_error ());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#endif
|
||||
436
src/beast/modules/beast_asio/sockets/Socket.h
Normal file
436
src/beast/modules/beast_asio/sockets/Socket.h
Normal file
@@ -0,0 +1,436 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_SOCKETS_SOCKET_H_INCLUDED
|
||||
#define BEAST_ASIO_SOCKETS_SOCKET_H_INCLUDED
|
||||
|
||||
/** A high level socket abstraction.
|
||||
|
||||
This combines the capabilities of multiple socket interfaces such
|
||||
as listening, connecting, streaming, and handshaking. It brings
|
||||
everything together into a single abstract interface.
|
||||
|
||||
When member functions are called and the underlying implementation does
|
||||
not support the operation, a fatal error is generated.
|
||||
*/
|
||||
class Socket
|
||||
: public SocketBase
|
||||
, public boost::asio::ssl::stream_base
|
||||
, public boost::asio::socket_base
|
||||
{
|
||||
public:
|
||||
virtual ~Socket ();
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Socket
|
||||
//
|
||||
|
||||
/** Retrieve the underlying object.
|
||||
|
||||
@note If the type doesn't match, nullptr is returned or an
|
||||
exception is thrown if trying to acquire a reference.
|
||||
*/
|
||||
/** @{ */
|
||||
template <typename Object>
|
||||
Object& this_layer ()
|
||||
{
|
||||
Object* object (this->this_layer_ptr <Object> ());
|
||||
if (object == nullptr)
|
||||
Throw (std::bad_cast (), __FILE__, __LINE__);
|
||||
return *object;
|
||||
}
|
||||
|
||||
template <typename Object>
|
||||
Object const& this_layer () const
|
||||
{
|
||||
Object const* object (this->this_layer_ptr <Object> ());
|
||||
if (object == nullptr)
|
||||
Throw (std::bad_cast (), __FILE__, __LINE__);
|
||||
return *object;
|
||||
}
|
||||
|
||||
template <typename Object>
|
||||
Object* this_layer_ptr ()
|
||||
{
|
||||
return static_cast <Object*> (
|
||||
this->this_layer_ptr (typeid (Object).name ()));
|
||||
}
|
||||
|
||||
template <typename Object>
|
||||
Object const* this_layer_ptr () const
|
||||
{
|
||||
return static_cast <Object const*> (
|
||||
this->this_layer_ptr (typeid (Object).name ()));
|
||||
}
|
||||
/** @} */
|
||||
|
||||
virtual void* this_layer_ptr (char const* type_name) const
|
||||
BEAST_SOCKET_VIRTUAL;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// native_handle
|
||||
//
|
||||
|
||||
/** Retrieve the native representation of the object.
|
||||
|
||||
Since we dont know the return type, and because almost every
|
||||
asio implementation passes the result by value, you need to provide
|
||||
a pointer to a default-constructed object of the matching type.
|
||||
|
||||
@note If the type doesn't match, an exception is thrown.
|
||||
*/
|
||||
template <typename Handle>
|
||||
void native_handle (Handle* dest)
|
||||
{
|
||||
if (! native_handle (typeid (Handle).name (), dest))
|
||||
Throw (std::bad_cast (), __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
virtual bool native_handle (char const* type_name, void* dest)
|
||||
BEAST_SOCKET_VIRTUAL;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// basic_io_object
|
||||
//
|
||||
|
||||
virtual boost::asio::io_service& get_io_service ()
|
||||
BEAST_SOCKET_VIRTUAL;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// basic_socket
|
||||
//
|
||||
|
||||
/** Retrieve the lowest layer object.
|
||||
|
||||
@note If the type doesn't match, nullptr is returned or an
|
||||
exception is thrown if trying to acquire a reference.
|
||||
*/
|
||||
/** @{ */
|
||||
template <typename Object>
|
||||
Object& lowest_layer ()
|
||||
{
|
||||
Object* object (this->lowest_layer_ptr <Object> ());
|
||||
if (object == nullptr)
|
||||
Throw (std::bad_cast (), __FILE__, __LINE__);
|
||||
return *object;
|
||||
}
|
||||
|
||||
template <typename Object>
|
||||
Object const& lowest_layer () const
|
||||
{
|
||||
Object const* object (this->lowest_layer_ptr <Object> ());
|
||||
if (object == nullptr)
|
||||
Throw (std::bad_cast (), __FILE__, __LINE__);
|
||||
return *object;
|
||||
}
|
||||
|
||||
template <typename Object>
|
||||
Object* lowest_layer_ptr ()
|
||||
{
|
||||
return static_cast <Object*> (
|
||||
this->lowest_layer_ptr (typeid (Object).name ()));
|
||||
}
|
||||
|
||||
template <typename Object>
|
||||
Object const* lowest_layer_ptr () const
|
||||
{
|
||||
return static_cast <Object const*> (
|
||||
this->lowest_layer_ptr (typeid (Object).name ()));
|
||||
}
|
||||
/** @} */
|
||||
|
||||
virtual void* lowest_layer_ptr (char const* type_name) const
|
||||
BEAST_SOCKET_VIRTUAL;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void cancel ()
|
||||
{
|
||||
error_code ec;
|
||||
throw_error (cancel (ec), __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
virtual error_code cancel (error_code& ec)
|
||||
BEAST_SOCKET_VIRTUAL;
|
||||
|
||||
void shutdown (shutdown_type what)
|
||||
{
|
||||
error_code ec;
|
||||
throw_error (shutdown (what, ec), __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
virtual error_code shutdown (shutdown_type what,
|
||||
error_code& ec)
|
||||
BEAST_SOCKET_VIRTUAL;
|
||||
|
||||
void close ()
|
||||
{
|
||||
error_code ec;
|
||||
throw_error (close (ec), __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
virtual error_code close (error_code& ec)
|
||||
BEAST_SOCKET_VIRTUAL;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// basic_socket_acceptor
|
||||
//
|
||||
|
||||
virtual error_code accept (Socket& peer, error_code& ec)
|
||||
BEAST_SOCKET_VIRTUAL;
|
||||
|
||||
template <typename AcceptHandler>
|
||||
void async_accept (Socket& peer, BOOST_ASIO_MOVE_ARG(AcceptHandler) handler)
|
||||
{
|
||||
return async_accept (peer,
|
||||
newAcceptHandler (BOOST_ASIO_MOVE_CAST(AcceptHandler)(handler)));
|
||||
}
|
||||
|
||||
virtual void async_accept (Socket& peer, SharedHandlerPtr handler)
|
||||
BEAST_SOCKET_VIRTUAL;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// basic_stream_socket
|
||||
//
|
||||
|
||||
// SyncReadStream
|
||||
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/SyncReadStream.html
|
||||
//
|
||||
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)
|
||||
BEAST_SOCKET_VIRTUAL;
|
||||
|
||||
// SyncWriteStream
|
||||
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/SyncWriteStream.html
|
||||
//
|
||||
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)
|
||||
BEAST_SOCKET_VIRTUAL;
|
||||
|
||||
// AsyncReadStream
|
||||
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/AsyncReadStream.html
|
||||
//
|
||||
template <typename MutableBufferSequence, typename ReadHandler>
|
||||
void async_read_some (MutableBufferSequence const& buffers,
|
||||
BOOST_ASIO_MOVE_ARG(ReadHandler) handler)
|
||||
{
|
||||
return async_read_some (MutableBuffers (buffers),
|
||||
newReadHandler (BOOST_ASIO_MOVE_CAST(ReadHandler)(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 <typename ConstBufferSequence, typename WriteHandler>
|
||||
void async_write_some (ConstBufferSequence const& buffers,
|
||||
BOOST_ASIO_MOVE_ARG(WriteHandler) handler)
|
||||
{
|
||||
return async_write_some (ConstBuffers (buffers),
|
||||
newWriteHandler (BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)));
|
||||
}
|
||||
|
||||
virtual void async_write_some (ConstBuffers const& buffers, SharedHandlerPtr handler)
|
||||
BEAST_SOCKET_VIRTUAL;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// ssl::stream
|
||||
//
|
||||
|
||||
/** Retrieve the next layer object.
|
||||
|
||||
@note If the type doesn't match, nullptr is returned or an
|
||||
exception is thrown if trying to acquire a reference.
|
||||
*/
|
||||
/** @{ */
|
||||
template <typename Object>
|
||||
Object& next_layer ()
|
||||
{
|
||||
Object* object (this->next_layer_ptr <Object> ());
|
||||
if (object == nullptr)
|
||||
Throw (std::bad_cast (), __FILE__, __LINE__);
|
||||
return *object;
|
||||
}
|
||||
|
||||
template <typename Object>
|
||||
Object const& next_layer () const
|
||||
{
|
||||
Object const* object (this->next_layer_ptr <Object> ());
|
||||
if (object == nullptr)
|
||||
Throw (std::bad_cast (), __FILE__, __LINE__);
|
||||
return *object;
|
||||
}
|
||||
|
||||
template <typename Object>
|
||||
Object* next_layer_ptr ()
|
||||
{
|
||||
return static_cast <Object*> (
|
||||
this->next_layer_ptr (typeid (Object).name ()));
|
||||
}
|
||||
|
||||
template <typename Object>
|
||||
Object const* next_layer_ptr () const
|
||||
{
|
||||
return static_cast <Object const*> (
|
||||
this->next_layer_ptr (typeid (Object).name ()));
|
||||
}
|
||||
/** @} */
|
||||
|
||||
virtual void* next_layer_ptr (char const* type_name) const
|
||||
BEAST_SOCKET_VIRTUAL;
|
||||
|
||||
/** Determines if the underlying stream requires a handshake.
|
||||
|
||||
If needs_handshake is true, it will be necessary to call handshake or
|
||||
async_handshake after the connection is established. Furthermore it
|
||||
will be necessary to call the shutdown member from the
|
||||
HandshakeInterface to close the connection. Do not close the underlying
|
||||
socket or else the closure will not be graceful. Only one side should
|
||||
initiate the handshaking shutdon. The other side should observe it.
|
||||
Which side does what is up to the user.
|
||||
|
||||
The default version returns false.
|
||||
*/
|
||||
virtual bool needs_handshake ()
|
||||
BEAST_SOCKET_VIRTUAL;
|
||||
|
||||
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ssl__verify_mode.html
|
||||
//
|
||||
virtual void set_verify_mode (int verify_mode) = 0;
|
||||
|
||||
// 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
|
||||
//
|
||||
void handshake (handshake_type type)
|
||||
{
|
||||
error_code 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)
|
||||
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>
|
||||
void async_handshake (handshake_type type, BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler)
|
||||
{
|
||||
return async_handshake (type,
|
||||
newHandshakeHandler (BOOST_ASIO_MOVE_CAST(HandshakeHandler)(handler)));
|
||||
}
|
||||
|
||||
virtual void async_handshake (handshake_type type, SharedHandlerPtr handler)
|
||||
BEAST_SOCKET_VIRTUAL;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
#if BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
|
||||
// ssl::stream::handshake (3 of 4)
|
||||
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ssl__stream/handshake/overload3.html
|
||||
//
|
||||
template <typename ConstBufferSequence>
|
||||
void handshake (handshake_type type, ConstBufferSequence const& buffers)
|
||||
{
|
||||
error_code 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 <typename ConstBufferSequence>
|
||||
error_code handshake (handshake_type type,
|
||||
ConstBufferSequence const& buffers, error_code& ec)
|
||||
{
|
||||
return handshake (type, ConstBuffers (buffers), ec);
|
||||
}
|
||||
|
||||
virtual error_code handshake (handshake_type type,
|
||||
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 <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),
|
||||
newBufferedHandshakeHandler (BOOST_ASIO_MOVE_CAST(BufferedHandshakeHandler)(handler)));
|
||||
}
|
||||
|
||||
virtual void async_handshake (handshake_type type, ConstBuffers const& buffers,
|
||||
SharedHandlerPtr handler)
|
||||
BEAST_SOCKET_VIRTUAL;
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// ssl::stream::shutdown
|
||||
// http://www.boost.org/doc/libs/1_54_0/doc/html/boost_asio/reference/ssl__stream/shutdown.html
|
||||
//
|
||||
void shutdown ()
|
||||
{
|
||||
error_code ec;
|
||||
throw_error (shutdown (ec), __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
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 <typename ShutdownHandler>
|
||||
void async_shutdown (BOOST_ASIO_MOVE_ARG(ShutdownHandler) handler)
|
||||
{
|
||||
return async_shutdown (
|
||||
newShutdownHandler (BOOST_ASIO_MOVE_CAST(ShutdownHandler)(handler)));
|
||||
}
|
||||
|
||||
virtual void async_shutdown (SharedHandlerPtr handler)
|
||||
BEAST_SOCKET_VIRTUAL;
|
||||
};
|
||||
|
||||
#endif
|
||||
42
src/beast/modules/beast_asio/sockets/SocketBase.cpp
Normal file
42
src/beast/modules/beast_asio/sockets/SocketBase.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
boost::system::error_code SocketBase::pure_virtual_error ()
|
||||
{
|
||||
return boost::system::errc::make_error_code (
|
||||
boost::system::errc::function_not_supported);
|
||||
}
|
||||
|
||||
boost::system::error_code SocketBase::pure_virtual_error (error_code& ec,
|
||||
char const* fileName, int lineNumber)
|
||||
{
|
||||
pure_virtual_called (fileName, lineNumber);
|
||||
return ec = pure_virtual_error ();
|
||||
}
|
||||
|
||||
void SocketBase::pure_virtual_called (char const* fileName, int lineNumber)
|
||||
{
|
||||
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);
|
||||
}
|
||||
49
src/beast/modules/beast_asio/sockets/SocketBase.h
Normal file
49
src/beast/modules/beast_asio/sockets/SocketBase.h
Normal file
@@ -0,0 +1,49 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_SOCKETS_SOCKETBASE_H_INCLUDED
|
||||
#define BEAST_ASIO_SOCKETS_SOCKETBASE_H_INCLUDED
|
||||
|
||||
/** Common implementation details for Socket and related classes.
|
||||
Normally you wont need to use this.
|
||||
*/
|
||||
struct SocketBase
|
||||
{
|
||||
protected:
|
||||
typedef boost::system::error_code error_code;
|
||||
|
||||
/** 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
|
||||
838
src/beast/modules/beast_asio/sockets/SocketWrapper.h
Normal file
838
src/beast/modules/beast_asio/sockets/SocketWrapper.h
Normal file
@@ -0,0 +1,838 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_SOCKETS_SOCKETWRAPPER_H_INCLUDED
|
||||
#define BEAST_ASIO_SOCKETS_SOCKETWRAPPER_H_INCLUDED
|
||||
|
||||
/** Wraps a reference to any object and exports all availble interfaces.
|
||||
|
||||
If the object does not support an interface, calling those
|
||||
member functions will behave as if a pure virtual was called.
|
||||
|
||||
Note that only a reference to the underlying is stored. Management
|
||||
of the lifetime of the object is controlled by the caller.
|
||||
|
||||
Examples of the type of Object:
|
||||
|
||||
asio::ip::tcp::socket
|
||||
asio::ip::tcp::socket&
|
||||
asio::ssl::stream <asio::ip::tcp::socket>
|
||||
asio::ssl::stream <asio::ip::tcp::socket&>
|
||||
explain arg must be an io_context
|
||||
explain SocketWrapper will create and take ownership of the tcp::socket
|
||||
explain this_layer_type will be tcp::socket
|
||||
explain next_layer () returns a asio::ip::tcp::socket&
|
||||
explain lowest_layer () returns a asio::ip::tcp::socket&
|
||||
|
||||
asio::ssl::stream <asio::buffered_stream <asio::ip::tcp::socket> > >
|
||||
This makes my head explode
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
namespace SocketWrapperMemberChecks
|
||||
{
|
||||
template <bool Enable>
|
||||
struct EnableIf : boost::false_type { };
|
||||
|
||||
template <>
|
||||
struct EnableIf <true> : boost::true_type { };
|
||||
|
||||
BEAST_DEFINE_IS_CALL_POSSIBLE(has_get_io_service, get_io_service);
|
||||
|
||||
BEAST_DEFINE_IS_CALL_POSSIBLE(has_lowest_layer, lowest_layer);
|
||||
BEAST_DEFINE_IS_CALL_POSSIBLE(has_cancel, cancel);
|
||||
BEAST_DEFINE_IS_CALL_POSSIBLE(has_shutdown, shutdown);
|
||||
BEAST_DEFINE_IS_CALL_POSSIBLE(has_close, close);
|
||||
|
||||
BEAST_DEFINE_IS_CALL_POSSIBLE(has_accept, accept);
|
||||
BEAST_DEFINE_IS_CALL_POSSIBLE(has_async_accept, async_accept);
|
||||
|
||||
BEAST_DEFINE_IS_CALL_POSSIBLE(has_read_some, read_some);
|
||||
BEAST_DEFINE_IS_CALL_POSSIBLE(has_write_some, write_some);
|
||||
BEAST_DEFINE_IS_CALL_POSSIBLE(has_async_read_some, async_read_some);
|
||||
BEAST_DEFINE_IS_CALL_POSSIBLE(has_async_write_some, async_write_some);
|
||||
|
||||
BEAST_DEFINE_IS_CALL_POSSIBLE(has_set_verify_mode, set_verify_mode);
|
||||
BEAST_DEFINE_IS_CALL_POSSIBLE(has_handshake, handshake);
|
||||
BEAST_DEFINE_IS_CALL_POSSIBLE(has_async_handshake, async_handshake);
|
||||
BEAST_DEFINE_IS_CALL_POSSIBLE(has_async_shutdown, async_shutdown);
|
||||
|
||||
// Extracts the underlying socket type from the protocol of another asio object
|
||||
template <typename T, typename Enable = void>
|
||||
struct native_socket
|
||||
{
|
||||
typedef void* socket_type;
|
||||
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;
|
||||
};
|
||||
|
||||
// Enabled if T::protocol_type::socket exists as a type
|
||||
template <typename T>
|
||||
struct native_socket <T, typename boost::enable_if <boost::is_class <
|
||||
typename T::protocol_type::socket> >::type>
|
||||
{
|
||||
typedef typename T::protocol_type::socket socket_type;
|
||||
inline native_socket (Socket& peer)
|
||||
: m_socket_ptr (&peer.this_layer <socket_type> ())
|
||||
{
|
||||
}
|
||||
inline socket_type& get () noexcept
|
||||
{
|
||||
return *m_socket_ptr;
|
||||
}
|
||||
inline socket_type& operator-> () noexcept
|
||||
{
|
||||
return get ();
|
||||
}
|
||||
private:
|
||||
socket_type* m_socket_ptr;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename Object>
|
||||
class SocketWrapper
|
||||
: public Socket
|
||||
, public Uncopyable
|
||||
{
|
||||
public:
|
||||
template <typename Arg>
|
||||
explicit SocketWrapper (Arg& arg)
|
||||
: m_object (arg)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Arg1, typename Arg2>
|
||||
SocketWrapper (Arg1& arg1, Arg2& arg2)
|
||||
: m_object (arg1, arg2)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// SocketWrapper
|
||||
//
|
||||
|
||||
/** The type of the object being wrapped. */
|
||||
typedef typename boost::remove_reference <Object>::type this_layer_type;
|
||||
|
||||
/** Get a reference to this layer. */
|
||||
this_layer_type& this_layer () noexcept
|
||||
{
|
||||
return m_object;
|
||||
}
|
||||
|
||||
/** Get a const reference to this layer. */
|
||||
this_layer_type const& this_layer () const noexcept
|
||||
{
|
||||
return m_object;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Socket
|
||||
//
|
||||
|
||||
void* this_layer_ptr (char const* type_name) const
|
||||
{
|
||||
char const* const name (typeid (this_layer_type).name ());
|
||||
if (strcmp (name, type_name) == 0)
|
||||
return const_cast <void*> (static_cast <void const*> (&m_object));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// native_handle
|
||||
//
|
||||
|
||||
#if 0
|
||||
// This is a potential work-around for the problem with
|
||||
// the has_type_native_handle_type template, but requires
|
||||
// Boost 1.54 or later.
|
||||
//
|
||||
// This include will be needed:
|
||||
//
|
||||
// boost/tti/has_type.hpp
|
||||
//
|
||||
//
|
||||
BOOST_TTI_HAS_TYPE(native_handle_type)
|
||||
|
||||
#else
|
||||
template <class T>
|
||||
struct has_type_native_handle_type
|
||||
{
|
||||
typedef char yes;
|
||||
typedef struct {char dummy[2];} no;
|
||||
template <class C> static yes f(typename C::native_handle_type*);
|
||||
template <class C> static no f(...);
|
||||
#ifdef _MSC_VER
|
||||
static bool const value = sizeof(f<T>(0)) == 1;
|
||||
#else
|
||||
// This line fails to compile under Visual Studio 2012
|
||||
static bool const value = sizeof(has_type_native_handle_type<T>::f<T>(0)) == 1;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
template <typename T, bool Exists = has_type_native_handle_type <T>::value >
|
||||
struct extract_native_handle_type
|
||||
{
|
||||
typedef typename T::native_handle_type type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct extract_native_handle_type <T, false>
|
||||
{
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
// This will be void if native_handle_type doesn't exist in Object
|
||||
typedef typename extract_native_handle_type <this_layer_type>::type native_handle_type;
|
||||
|
||||
bool native_handle (char const* type_name, void* dest)
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
return native_handle (type_name, dest,
|
||||
EnableIf <has_type_native_handle_type <this_layer_type>::value> ());
|
||||
}
|
||||
|
||||
bool native_handle (char const* type_name, void* dest,
|
||||
boost::true_type)
|
||||
{
|
||||
char const* const name (typeid (typename this_layer_type::native_handle_type).name ());
|
||||
if (strcmp (name, type_name) == 0)
|
||||
{
|
||||
native_handle_type* const p (reinterpret_cast <native_handle_type*> (dest));
|
||||
*p = m_object.native_handle ();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool native_handle (char const*, void*,
|
||||
boost::false_type)
|
||||
{
|
||||
pure_virtual_called (__FILE__, __LINE__);
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// basic_io_object
|
||||
//
|
||||
|
||||
boost::asio::io_service& get_io_service ()
|
||||
{
|
||||
#if 0
|
||||
// Apparently has_get_io_service always results in false
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
return get_io_service (
|
||||
EnableIf <has_get_io_service <this_layer_type,
|
||||
boost::asio::io_service&()>::value> ());
|
||||
#else
|
||||
return get_io_service (boost::true_type ());
|
||||
#endif
|
||||
}
|
||||
|
||||
boost::asio::io_service& get_io_service (
|
||||
boost::true_type)
|
||||
{
|
||||
return m_object.get_io_service ();
|
||||
}
|
||||
|
||||
boost::asio::io_service& get_io_service (
|
||||
boost::false_type)
|
||||
{
|
||||
pure_virtual_called (__FILE__, __LINE__);
|
||||
return *static_cast <boost::asio::io_service*>(nullptr);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// basic_socket
|
||||
//
|
||||
|
||||
/*
|
||||
To forward the lowest_layer_type type, we need to make sure it
|
||||
exists in Object. This is a little more tricky than just figuring
|
||||
out if Object has a particular member function.
|
||||
|
||||
The problem is boost::asio::basic_socket_acceptor, which doesn't
|
||||
have lowest_layer () or lowest_layer_type ().
|
||||
*/
|
||||
|
||||
template <class T>
|
||||
struct has_type_lowest_layer_type
|
||||
{
|
||||
typedef char yes;
|
||||
typedef struct {char dummy[2];} no;
|
||||
template <class C> static yes f(typename C::lowest_layer_type*);
|
||||
template <class C> static no f(...);
|
||||
#ifdef _MSC_VER
|
||||
static bool const value = sizeof(f<T>(0)) == 1;
|
||||
#else
|
||||
// This line fails to compile under Visual Studio 2012
|
||||
static bool const value = sizeof(has_type_lowest_layer_type<T>::f<T>(0)) == 1;
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename T, bool Exists = has_type_lowest_layer_type <T>::value >
|
||||
struct extract_lowest_layer_type
|
||||
{
|
||||
typedef typename T::lowest_layer_type type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct extract_lowest_layer_type <T, false>
|
||||
{
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
// This will be void if lowest_layer_type doesn't exist in Object
|
||||
typedef typename extract_lowest_layer_type <this_layer_type>::type lowest_layer_type;
|
||||
|
||||
void* lowest_layer_ptr (char const* type_name) const
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
return lowest_layer_ptr (type_name,
|
||||
EnableIf <has_type_lowest_layer_type <this_layer_type>::value> ());
|
||||
}
|
||||
|
||||
void* lowest_layer_ptr (char const* type_name,
|
||||
boost::true_type) const
|
||||
{
|
||||
char const* const name (typeid (typename this_layer_type::lowest_layer_type).name ());
|
||||
if (strcmp (name, type_name) == 0)
|
||||
return const_cast <void*> (static_cast <void const*> (&m_object.lowest_layer ()));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* lowest_layer_ptr (char const*,
|
||||
boost::false_type) const
|
||||
{
|
||||
pure_virtual_called (__FILE__, __LINE__);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
error_code cancel (error_code& ec)
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
return cancel (ec,
|
||||
EnableIf <has_cancel <this_layer_type,
|
||||
error_code (error_code&)>::value> ());
|
||||
}
|
||||
|
||||
error_code cancel (error_code& ec,
|
||||
boost::true_type)
|
||||
{
|
||||
return m_object.cancel (ec);
|
||||
}
|
||||
|
||||
error_code cancel (error_code& ec,
|
||||
boost::false_type)
|
||||
{
|
||||
return pure_virtual_error (ec, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
error_code shutdown (shutdown_type what, error_code& ec)
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
return shutdown (what, ec,
|
||||
EnableIf <has_shutdown <this_layer_type,
|
||||
error_code (shutdown_type, error_code&)>::value> ());
|
||||
}
|
||||
|
||||
|
||||
error_code shutdown (shutdown_type what, error_code& ec,
|
||||
boost::true_type)
|
||||
{
|
||||
return m_object.shutdown (what, ec);
|
||||
}
|
||||
|
||||
error_code shutdown (shutdown_type, error_code& ec,
|
||||
boost::false_type)
|
||||
{
|
||||
return pure_virtual_error (ec, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
error_code close (error_code& ec)
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
return close (ec,
|
||||
EnableIf <has_close <this_layer_type,
|
||||
error_code (error_code&)>::value> ());
|
||||
}
|
||||
|
||||
error_code close (error_code& ec,
|
||||
boost::true_type)
|
||||
{
|
||||
return m_object.close (ec);
|
||||
}
|
||||
|
||||
error_code close (error_code& ec,
|
||||
boost::false_type)
|
||||
{
|
||||
return pure_virtual_error (ec, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// basic_socket_acceptor
|
||||
//
|
||||
|
||||
error_code accept (Socket& peer, error_code& ec)
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
typedef typename native_socket <this_layer_type>::socket_type socket_type;
|
||||
return accept (peer, ec,
|
||||
EnableIf <has_accept <this_layer_type,
|
||||
error_code (socket_type&, error_code&)>::value> ());
|
||||
}
|
||||
|
||||
error_code accept (Socket& peer, error_code& ec,
|
||||
boost::true_type)
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
return m_object.accept (
|
||||
native_socket <this_layer_type> (peer).get (), ec);
|
||||
}
|
||||
|
||||
error_code accept (Socket&, error_code& ec,
|
||||
boost::false_type)
|
||||
{
|
||||
return pure_virtual_error (ec, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void async_accept (Socket& peer, SharedHandlerPtr handler)
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
typedef typename native_socket <this_layer_type>::socket_type socket_type;
|
||||
async_accept (peer, BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler),
|
||||
EnableIf <has_async_accept <this_layer_type,
|
||||
void (socket_type&, BOOST_ASIO_MOVE_ARG(SharedHandlerPtr))>::value> ());
|
||||
}
|
||||
|
||||
void async_accept (Socket& peer, BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
|
||||
boost::true_type)
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
m_object.async_accept (
|
||||
native_socket <this_layer_type> (peer).get (),
|
||||
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler));
|
||||
}
|
||||
|
||||
void async_accept (Socket&, BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
|
||||
boost::false_type)
|
||||
{
|
||||
get_io_service ().wrap (
|
||||
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
|
||||
(pure_virtual_error ());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// basic_stream_socket
|
||||
//
|
||||
|
||||
std::size_t read_some (MutableBuffers const& buffers, error_code& ec)
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
return read_some (buffers, ec,
|
||||
EnableIf <has_read_some <this_layer_type,
|
||||
std::size_t (MutableBuffers const&, error_code&)>::value> ());
|
||||
}
|
||||
|
||||
template <typename MutableBufferSequence>
|
||||
std::size_t read_some (MutableBufferSequence const& buffers, error_code& ec,
|
||||
boost::true_type)
|
||||
{
|
||||
return m_object.read_some (buffers, ec);
|
||||
}
|
||||
|
||||
template <typename MutableBufferSequence>
|
||||
std::size_t read_some (MutableBufferSequence const&, error_code& ec,
|
||||
boost::false_type)
|
||||
{
|
||||
pure_virtual_called (__FILE__, __LINE__);
|
||||
ec = pure_virtual_error ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
std::size_t write_some (ConstBuffers const& buffers, error_code& ec)
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
return write_some (buffers, ec,
|
||||
EnableIf <has_write_some <this_layer_type,
|
||||
std::size_t (ConstBuffers const&, error_code&)>::value> ());
|
||||
}
|
||||
|
||||
template <typename ConstBufferSequence>
|
||||
std::size_t write_some (ConstBufferSequence const& buffers, error_code& ec,
|
||||
boost::true_type)
|
||||
{
|
||||
return m_object.write_some (buffers, ec);
|
||||
}
|
||||
|
||||
template <typename ConstBufferSequence>
|
||||
std::size_t write_some (ConstBufferSequence const&, error_code& ec,
|
||||
boost::false_type)
|
||||
{
|
||||
pure_virtual_called (__FILE__, __LINE__);
|
||||
ec = pure_virtual_error ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void async_read_some (MutableBuffers const& buffers, SharedHandlerPtr handler)
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
async_read_some (buffers, BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler),
|
||||
EnableIf <has_async_read_some <this_layer_type,
|
||||
void (MutableBuffers const&, BOOST_ASIO_MOVE_ARG(SharedHandlerPtr))>::value> ());
|
||||
}
|
||||
|
||||
void async_read_some (MutableBuffers const& buffers,
|
||||
BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
|
||||
boost::true_type)
|
||||
{
|
||||
m_object.async_read_some (buffers,
|
||||
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler));
|
||||
}
|
||||
|
||||
void async_read_some (MutableBuffers const&,
|
||||
BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
|
||||
boost::false_type)
|
||||
{
|
||||
get_io_service ().wrap (
|
||||
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
|
||||
(pure_virtual_error (), 0);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void async_write_some (ConstBuffers const& buffers, SharedHandlerPtr handler)
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
async_write_some (buffers, BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler),
|
||||
EnableIf <has_async_write_some <this_layer_type,
|
||||
void (ConstBuffers const&, BOOST_ASIO_MOVE_ARG(SharedHandlerPtr))>::value> ());
|
||||
}
|
||||
|
||||
void async_write_some (ConstBuffers const& buffers,
|
||||
BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
|
||||
boost::true_type)
|
||||
{
|
||||
m_object.async_write_some (buffers,
|
||||
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler));
|
||||
}
|
||||
|
||||
void async_write_some (ConstBuffers const&,
|
||||
BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
|
||||
boost::false_type)
|
||||
{
|
||||
get_io_service ().wrap (
|
||||
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
|
||||
(pure_virtual_error (), 0);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// ssl::stream
|
||||
//
|
||||
|
||||
template <class T>
|
||||
struct has_type_next_layer_type
|
||||
{
|
||||
typedef char yes;
|
||||
typedef struct {char dummy[2];} no;
|
||||
template <class C> static yes f(typename C::next_layer_type*);
|
||||
template <class C> static no f(...);
|
||||
#ifdef _MSC_VER
|
||||
static bool const value = sizeof(f<T>(0)) == 1;
|
||||
#else
|
||||
// This line fails to compile under Visual Studio 2012
|
||||
static bool const value = sizeof(has_type_next_layer_type<T>::f<T>(0)) == 1;
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename T, bool Exists = has_type_next_layer_type <T>::value >
|
||||
struct extract_next_layer_type
|
||||
{
|
||||
typedef typename T::next_layer_type type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct extract_next_layer_type <T, false>
|
||||
{
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
// This will be void if next_layer_type doesn't exist in Object
|
||||
typedef typename extract_next_layer_type <this_layer_type>::type next_layer_type;
|
||||
|
||||
void* next_layer_ptr (char const* type_name) const
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
return next_layer_ptr (type_name,
|
||||
EnableIf <has_type_next_layer_type <this_layer_type>::value> ());
|
||||
}
|
||||
|
||||
void* next_layer_ptr (char const* type_name,
|
||||
boost::true_type) const
|
||||
{
|
||||
char const* const name (typeid (typename this_layer_type::next_layer_type).name ());
|
||||
if (strcmp (name, type_name) == 0)
|
||||
return const_cast <void*> (static_cast <void const*> (&m_object.next_layer ()));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* next_layer_ptr (char const*,
|
||||
boost::false_type) const
|
||||
{
|
||||
pure_virtual_called (__FILE__, __LINE__);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
bool needs_handshake ()
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
return
|
||||
has_handshake <this_layer_type,
|
||||
error_code (handshake_type, error_code&)>::value ||
|
||||
has_async_handshake <this_layer_type,
|
||||
void (handshake_type, BOOST_ASIO_MOVE_ARG(SharedHandlerPtr))>::value;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void set_verify_mode (int verify_mode)
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
set_verify_mode (verify_mode,
|
||||
EnableIf <has_set_verify_mode <this_layer_type,
|
||||
void (int)>::value> ());
|
||||
|
||||
}
|
||||
|
||||
void set_verify_mode (int verify_mode,
|
||||
boost::true_type)
|
||||
{
|
||||
m_object.set_verify_mode (verify_mode);
|
||||
}
|
||||
|
||||
void set_verify_mode (int,
|
||||
boost::false_type)
|
||||
{
|
||||
pure_virtual_called (__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
error_code handshake (handshake_type type, error_code& ec)
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
return handshake (type, ec,
|
||||
EnableIf <has_handshake <this_layer_type,
|
||||
error_code (handshake_type, error_code&)>::value> ());
|
||||
}
|
||||
|
||||
error_code handshake (handshake_type type, error_code& ec,
|
||||
boost::true_type)
|
||||
{
|
||||
return m_object.handshake (type, ec);
|
||||
}
|
||||
|
||||
error_code handshake (handshake_type, error_code& ec,
|
||||
boost::false_type)
|
||||
{
|
||||
return pure_virtual_error (ec, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void async_handshake (handshake_type type, SharedHandlerPtr handler)
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
async_handshake (type, BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler),
|
||||
EnableIf <has_async_handshake <this_layer_type,
|
||||
void (handshake_type, BOOST_ASIO_MOVE_ARG(SharedHandlerPtr))>::value> ());
|
||||
}
|
||||
|
||||
void async_handshake (handshake_type type,
|
||||
BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
|
||||
boost::true_type)
|
||||
{
|
||||
m_object.async_handshake (type,
|
||||
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler));
|
||||
}
|
||||
|
||||
void async_handshake (handshake_type, BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
|
||||
boost::false_type)
|
||||
{
|
||||
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)
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
return handshake (type, buffers, ec,
|
||||
EnableIf <has_handshake <this_layer_type,
|
||||
error_code (handshake_type, ConstBuffers const&, error_code&)>::value> ());
|
||||
}
|
||||
|
||||
error_code handshake (handshake_type type,
|
||||
ConstBuffers const& buffers, error_code& ec,
|
||||
boost::true_type)
|
||||
{
|
||||
return m_object.handshake (type, buffers, ec);
|
||||
}
|
||||
|
||||
error_code handshake (handshake_type, ConstBuffers const&, error_code& ec,
|
||||
boost::false_type)
|
||||
{
|
||||
return pure_virtual_error (ec, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void async_handshake (handshake_type type,
|
||||
ConstBuffers const& buffers, SharedHandlerPtr handler)
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
async_handshake (type, buffers,
|
||||
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler),
|
||||
EnableIf <has_async_handshake <this_layer_type,
|
||||
void (handshake_type, ConstBuffers const&,
|
||||
BOOST_ASIO_MOVE_ARG(SharedHandlerPtr))>::value> ());
|
||||
}
|
||||
|
||||
void async_handshake (handshake_type type, ConstBuffers const& buffers,
|
||||
BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
|
||||
boost::true_type)
|
||||
{
|
||||
m_object.async_handshake (type, buffers,
|
||||
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler));
|
||||
}
|
||||
|
||||
void async_handshake (handshake_type, ConstBuffers const&,
|
||||
BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
|
||||
boost::false_type)
|
||||
{
|
||||
get_io_service ().wrap (
|
||||
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
|
||||
(pure_virtual_error (), 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
error_code shutdown (error_code& ec)
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
return shutdown (ec,
|
||||
EnableIf <has_shutdown <this_layer_type,
|
||||
error_code (error_code&)>::value> ());
|
||||
}
|
||||
|
||||
error_code shutdown (error_code& ec,
|
||||
boost::true_type)
|
||||
{
|
||||
return m_object.shutdown (ec);
|
||||
}
|
||||
|
||||
error_code shutdown (error_code& ec,
|
||||
boost::false_type)
|
||||
{
|
||||
return pure_virtual_error (ec, __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void async_shutdown (SharedHandlerPtr handler)
|
||||
{
|
||||
using namespace detail::SocketWrapperMemberChecks;
|
||||
async_shutdown (BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler),
|
||||
EnableIf <has_async_shutdown <this_layer_type,
|
||||
void (BOOST_ASIO_MOVE_ARG(SharedHandlerPtr))>::value> ());
|
||||
}
|
||||
|
||||
void async_shutdown (BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
|
||||
boost::true_type)
|
||||
{
|
||||
m_object.async_shutdown (
|
||||
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler));
|
||||
}
|
||||
|
||||
void async_shutdown (BOOST_ASIO_MOVE_ARG(SharedHandlerPtr) handler,
|
||||
boost::false_type)
|
||||
{
|
||||
get_io_service ().wrap (
|
||||
BOOST_ASIO_MOVE_CAST(SharedHandlerPtr)(handler))
|
||||
(pure_virtual_error ());
|
||||
}
|
||||
|
||||
private:
|
||||
Object m_object;
|
||||
};
|
||||
|
||||
#endif
|
||||
66
src/beast/modules/beast_asio/sockets/SocketWrapperStrand.h
Normal file
66
src/beast/modules/beast_asio/sockets/SocketWrapperStrand.h
Normal file
@@ -0,0 +1,66 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_SOCKETS_SOCKETWRAPPERSTRAND_H_INCLUDED
|
||||
#define BEAST_ASIO_SOCKETS_SOCKETWRAPPERSTRAND_H_INCLUDED
|
||||
|
||||
/** Wraps the async I/O of a SocketWrapper with an io_service::strand
|
||||
To use this in a chain of wrappers, customize the Base type.
|
||||
*/
|
||||
template <typename Object, typename Base = SocketWrapper <Object> >
|
||||
class SocketWrapperStrand
|
||||
: public Base
|
||||
{
|
||||
public:
|
||||
template <typename Arg>
|
||||
SocketWrapperStrand (Arg& arg)
|
||||
: Base (arg)
|
||||
, m_strand (this->get_io_service ())
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Arg1, typename Arg2>
|
||||
SocketWrapperStrand (Arg1& arg1, Arg2& arg2)
|
||||
: Base (arg1, arg2)
|
||||
, m_strand (this->get_io_service ())
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// basic_stream_socket
|
||||
//
|
||||
|
||||
void async_read_some (MutableBuffers const& buffers, SharedHandlerPtr handler)
|
||||
{
|
||||
this->Base::async_read_some (buffers,
|
||||
newReadHandler (m_strand.wrap (handler)));
|
||||
}
|
||||
|
||||
void async_write_some (MutableBuffers const& buffers, SharedHandlerPtr handler)
|
||||
{
|
||||
this->Base::async_write_some (buffers,
|
||||
newWriteHandler (m_strand.wrap (handler)));
|
||||
}
|
||||
|
||||
protected:
|
||||
boost::asio::io_service::strand m_strand;
|
||||
};
|
||||
|
||||
#endif
|
||||
81
src/beast/modules/beast_asio/system/BoostIncludes.h
Normal file
81
src/beast/modules/beast_asio/system/BoostIncludes.h
Normal file
@@ -0,0 +1,81 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_SYSTEM_BOOSTINCLUDES_H_INCLUDED
|
||||
#define BEAST_ASIO_SYSTEM_BOOSTINCLUDES_H_INCLUDED
|
||||
|
||||
// Make sure we take care of fixing boost::bind oddities first.
|
||||
#if !defined(BEAST_CORE_H_INCLUDED)
|
||||
#error beast_core.h must be included before including this file
|
||||
#endif
|
||||
|
||||
// These should have already been set in your project, but
|
||||
// if you forgot then we will be optimistic and choose the latest.
|
||||
//
|
||||
#if BEAST_WIN32
|
||||
# ifndef _WIN32_WINNT
|
||||
# pragma message ("Warning: _WIN32_WINNT was not set in your project")
|
||||
# define _WIN32_WINNT 0x0600
|
||||
# endif
|
||||
# ifndef _VARIADIC_MAX
|
||||
# define _VARIADIC_MAX 10
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// Unfortunately, we use some boost detail elements
|
||||
//
|
||||
// https://svn.boost.org/trac/boost/ticket/9024
|
||||
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
#include <boost/asio/detail/handler_alloc_helpers.hpp>
|
||||
#include <boost/asio/detail/handler_invoke_helpers.hpp>
|
||||
|
||||
// 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
|
||||
#if BOOST_VERSION >= 105400
|
||||
# ifndef BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
|
||||
# define BEAST_ASIO_HAS_BUFFEREDHANDSHAKE 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef BEAST_ASIO_HAS_BUFFEREDHANDSHAKE
|
||||
# define BEAST_ASIO_HAS_BUFFEREDHANDSHAKE 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
82
src/beast/modules/beast_asio/system/BoostUnitTests.cpp
Normal file
82
src/beast/modules/beast_asio/system/BoostUnitTests.cpp
Normal 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;
|
||||
40
src/beast/modules/beast_asio/system/OpenSSLIncludes.h
Normal file
40
src/beast/modules/beast_asio/system/OpenSSLIncludes.h
Normal file
@@ -0,0 +1,40 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_SYSTEM_OPENSSLINCLUDES_H_INCLUDED
|
||||
#define BEAST_ASIO_SYSTEM_OPENSSLINCLUDES_H_INCLUDED
|
||||
|
||||
#define OPENSSL_THREAD_DEFINES
|
||||
#include <openssl/opensslconf.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Configure our settings based on what we find
|
||||
//
|
||||
#if defined(OPENSSL_THREADS)
|
||||
# ifndef BEAST_OPENSSL_MULTITHREADED
|
||||
# define BEAST_OPENSSL_MULTITHREADED 1
|
||||
# endif
|
||||
#else
|
||||
# ifndef BEAST_OPENSSL_MULTITHREADED
|
||||
# define BEAST_OPENSSL_MULTITHREADED 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
100
src/beast/modules/beast_asio/tests/PeerTest.cpp
Normal file
100
src/beast/modules/beast_asio/tests/PeerTest.cpp
Normal 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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
PeerTest::Result::Result ()
|
||||
: m_ec (TestPeerBasics::make_error (TestPeerBasics::errc::skipped))
|
||||
, m_message (m_ec.message ())
|
||||
{
|
||||
}
|
||||
|
||||
PeerTest::Result::Result (boost::system::error_code const& ec, String const& prefix)
|
||||
: m_ec (ec)
|
||||
, m_message ((prefix == String::empty) ? ec.message ()
|
||||
: prefix + ": " + ec.message ())
|
||||
{
|
||||
}
|
||||
|
||||
PeerTest::Result::Result (std::exception const& e, String const& prefix)
|
||||
: m_ec (TestPeerBasics::make_error (TestPeerBasics::errc::exceptioned))
|
||||
, m_message ((prefix == String::empty) ? e.what ()
|
||||
: prefix + ": " + e.what ())
|
||||
{
|
||||
}
|
||||
|
||||
bool PeerTest::Result::operator== (Result const& other) const noexcept
|
||||
{
|
||||
return m_ec == other.m_ec;
|
||||
}
|
||||
|
||||
bool PeerTest::Result::operator!= (Result const& other) const noexcept
|
||||
{
|
||||
return m_ec != other.m_ec;
|
||||
}
|
||||
|
||||
bool PeerTest::Result::failed () const noexcept
|
||||
{
|
||||
return TestPeerBasics::failure (m_ec);
|
||||
}
|
||||
|
||||
bool PeerTest::Result::timedout () const noexcept
|
||||
{
|
||||
return m_ec == TestPeerBasics::make_error (TestPeerBasics::errc::timeout);
|
||||
}
|
||||
|
||||
String PeerTest::Result::message () const noexcept
|
||||
{
|
||||
return m_message;
|
||||
}
|
||||
|
||||
bool PeerTest::Result::report (UnitTest& test, bool reportPassingTests) const
|
||||
{
|
||||
bool const success = test.unexpected (failed (), message ());
|
||||
if (reportPassingTests && success)
|
||||
test.logMessage (String ("pass ") + message());
|
||||
return success;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
PeerTest::Results::Results ()
|
||||
: name ("unknown")
|
||||
{
|
||||
}
|
||||
|
||||
bool PeerTest::Results::operator== (Results const& other) const noexcept
|
||||
{
|
||||
return (client == other.client) && (server == other.server);
|
||||
}
|
||||
|
||||
bool PeerTest::Results::operator!= (Results const& other) const noexcept
|
||||
{
|
||||
return (client != other.client) || (server != other.server);
|
||||
}
|
||||
|
||||
bool PeerTest::Results::report (UnitTest& test, bool beginTestCase) const
|
||||
{
|
||||
if (beginTestCase)
|
||||
test.beginTestCase (name);
|
||||
bool success = true;
|
||||
if (! client.report (test))
|
||||
success = false;
|
||||
if (! server.report (test))
|
||||
success = false;
|
||||
return success;
|
||||
}
|
||||
239
src/beast/modules/beast_asio/tests/PeerTest.h
Normal file
239
src/beast/modules/beast_asio/tests/PeerTest.h
Normal file
@@ -0,0 +1,239 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_TESTS_PEERTEST_H_INCLUDED
|
||||
#define BEAST_ASIO_TESTS_PEERTEST_H_INCLUDED
|
||||
|
||||
/** Performs a test of two peers defined by template parameters.
|
||||
*/
|
||||
class PeerTest
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
/** How long to wait before aborting a peer and reporting a timeout.
|
||||
|
||||
@note Aborting synchronous logics may cause undefined behavior.
|
||||
*/
|
||||
defaultTimeoutSeconds = 30
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** Holds the test results for one peer.
|
||||
*/
|
||||
class Result
|
||||
{
|
||||
public:
|
||||
/** Default constructor indicates the test was skipped.
|
||||
*/
|
||||
Result ();
|
||||
|
||||
/** Construct from an error code.
|
||||
The prefix is prepended to the error message.
|
||||
*/
|
||||
explicit Result (boost::system::error_code const& ec, String const& prefix = "");
|
||||
explicit Result (std::exception const& e, String const& prefix = "");
|
||||
|
||||
/** Returns true if the error codes match (message is ignored).
|
||||
*/
|
||||
bool operator== (Result const& other) const noexcept;
|
||||
bool operator!= (Result const& other) const noexcept;
|
||||
|
||||
/** Returns true if the peer failed.
|
||||
*/
|
||||
bool failed () const noexcept;
|
||||
|
||||
/** Convenience for determining if the peer timed out.
|
||||
*/
|
||||
bool timedout () const noexcept;
|
||||
|
||||
/** Provides a descriptive message.
|
||||
This is suitable to pass to UnitTest::fail.
|
||||
*/
|
||||
String message () const noexcept;
|
||||
|
||||
/** Report the result to a UnitTest object.
|
||||
A return value of true indicates success.
|
||||
*/
|
||||
bool report (UnitTest& test, bool reportPassingTests = false) const;
|
||||
|
||||
private:
|
||||
boost::system::error_code m_ec;
|
||||
String m_message;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** Holds the results for both peers in a test.
|
||||
*/
|
||||
struct Results
|
||||
{
|
||||
String name; // A descriptive name for this test case.
|
||||
Result client;
|
||||
Result server;
|
||||
|
||||
Results ();
|
||||
|
||||
/** Determines if client and server results match. */
|
||||
bool operator== (Results const& other) const noexcept;
|
||||
bool operator!= (Results const& other) const noexcept;
|
||||
|
||||
/** Report the results to a UnitTest object.
|
||||
A return value of true indicates success.
|
||||
@param beginTestCase `true` to call test.beginTestCase for you
|
||||
*/
|
||||
bool report (UnitTest& test, bool beginTestCase = true) const;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** Test two peers and return the results.
|
||||
*/
|
||||
template <typename Details, typename ClientLogic, typename ServerLogic, typename ClientArg, typename ServerArg>
|
||||
static Results run (ClientArg const& clientArg, ServerArg const& serverArg, int timeoutSeconds = defaultTimeoutSeconds)
|
||||
{
|
||||
Results results;
|
||||
|
||||
if (Process::isRunningUnderDebugger ())
|
||||
timeoutSeconds = -1;
|
||||
|
||||
try
|
||||
{
|
||||
TestPeerType <ServerLogic, Details> server (serverArg);
|
||||
|
||||
results.name = server.name () + Details::getArgName (serverArg);
|
||||
|
||||
try
|
||||
{
|
||||
TestPeerType <ClientLogic, Details> client (clientArg);
|
||||
|
||||
results.name << " / " + client.name () + Details::getArgName (clientArg);
|
||||
|
||||
try
|
||||
{
|
||||
server.start (timeoutSeconds);
|
||||
|
||||
try
|
||||
{
|
||||
client.start (timeoutSeconds);
|
||||
|
||||
boost::system::error_code const ec = client.join ();
|
||||
|
||||
results.client = Result (ec, client.name ());
|
||||
|
||||
try
|
||||
{
|
||||
boost::system::error_code const ec = server.join ();
|
||||
|
||||
results.server = Result (ec, server.name ());
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
results.server = Result (e, server.name ());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
results.server = Result (TestPeerBasics::make_error (
|
||||
TestPeerBasics::errc::exceptioned), server.name ());
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
results.server = Result (e, client.name ());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
results.client = Result (TestPeerBasics::make_error (
|
||||
TestPeerBasics::errc::exceptioned), client.name ());
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
results.server = Result (e, server.name ());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
results.server = Result (TestPeerBasics::make_error (
|
||||
TestPeerBasics::errc::exceptioned), server.name ());
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
results.server = Result (e, "client");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
results.client = Result (TestPeerBasics::make_error (
|
||||
TestPeerBasics::errc::exceptioned), "client");
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
results.server = Result (e, "server");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
results.server = Result (TestPeerBasics::make_error (
|
||||
TestPeerBasics::errc::exceptioned), "server");
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
template <typename Details, typename ClientLogic, typename ServerLogic, class Arg>
|
||||
static Results run (Arg const& arg, int timeoutSeconds = defaultTimeoutSeconds)
|
||||
{
|
||||
return run <Details, ClientLogic, ServerLogic, Arg, Arg> (arg, arg, timeoutSeconds);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** Reports tests of Details for all known asynchronous logic combinations to a UnitTest.
|
||||
*/
|
||||
template <typename Details, class Arg>
|
||||
static void report_async (UnitTest& test, Arg const& arg,
|
||||
int timeoutSeconds = defaultTimeoutSeconds,
|
||||
bool beginTestCase = true)
|
||||
{
|
||||
run <Details, TestPeerLogicAsyncClient, TestPeerLogicAsyncServer>
|
||||
(arg, timeoutSeconds).report (test, beginTestCase);
|
||||
}
|
||||
|
||||
/** Reports tests of Details against all known logic combinations to a UnitTest.
|
||||
*/
|
||||
template <typename Details, class Arg>
|
||||
static void report (UnitTest& test, Arg const& arg,
|
||||
int timeoutSeconds = defaultTimeoutSeconds,
|
||||
bool beginTestCase = true)
|
||||
{
|
||||
run <Details, TestPeerLogicSyncClient, TestPeerLogicSyncServer>
|
||||
(arg, timeoutSeconds).report (test, beginTestCase);
|
||||
|
||||
run <Details, TestPeerLogicAsyncClient, TestPeerLogicSyncServer>
|
||||
(arg, timeoutSeconds).report (test, beginTestCase);
|
||||
|
||||
run <Details, TestPeerLogicSyncClient, TestPeerLogicAsyncServer>
|
||||
(arg, timeoutSeconds).report (test, beginTestCase);
|
||||
|
||||
report_async <Details> (test, arg, timeoutSeconds, beginTestCase);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
53
src/beast/modules/beast_asio/tests/TestPeer.h
Normal file
53
src/beast/modules/beast_asio/tests/TestPeer.h
Normal file
@@ -0,0 +1,53 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_TESTS_TESTPEER_H_INCLUDED
|
||||
#define BEAST_ASIO_TESTS_TESTPEER_H_INCLUDED
|
||||
|
||||
/** An abstract peer for unit tests.
|
||||
*/
|
||||
class TestPeer : public TestPeerBasics
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
// This should be long enough to go about your business.
|
||||
defaultTimeout = 10
|
||||
};
|
||||
|
||||
virtual ~TestPeer () { }
|
||||
|
||||
/** Get the name of this peer. */
|
||||
virtual String name () const = 0;
|
||||
|
||||
/** Start the peer.
|
||||
If timeoutSeconds is 0 or less, the wait is infinite.
|
||||
@param timeoutSeconds How long until the peer should be
|
||||
considered timed out.
|
||||
*/
|
||||
virtual void start (int timeoutSeconds = defaultTimeout) = 0;
|
||||
|
||||
/** Wait for the peer to finish.
|
||||
|
||||
@return Any error code generated during the server operation.
|
||||
*/
|
||||
virtual boost::system::error_code join () = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
155
src/beast/modules/beast_asio/tests/TestPeerBasics.cpp
Normal file
155
src/beast/modules/beast_asio/tests/TestPeerBasics.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
TestPeerBasics::Model::Model (model_t model)
|
||||
: m_model (model)
|
||||
{
|
||||
}
|
||||
|
||||
String TestPeerBasics::Model::name () const noexcept
|
||||
{
|
||||
if (m_model == async)
|
||||
return "async";
|
||||
return "sync";
|
||||
}
|
||||
|
||||
bool TestPeerBasics::Model::operator== (model_t model) const noexcept
|
||||
{
|
||||
return m_model == model;
|
||||
}
|
||||
|
||||
boost::asio::ssl::stream_base::handshake_type
|
||||
TestPeerBasics::to_handshake_type (PeerRole const& role)
|
||||
{
|
||||
if (role == PeerRole::client)
|
||||
return boost::asio::ssl::stream_base::client;
|
||||
return boost::asio::ssl::stream_base::server;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
boost::system::error_category const& TestPeerBasics::test_category () noexcept
|
||||
{
|
||||
struct test_category_type : boost::system::error_category
|
||||
{
|
||||
char const* name () const noexcept
|
||||
{
|
||||
return "TestPeer";
|
||||
}
|
||||
|
||||
std::string message (int ev) const
|
||||
{
|
||||
switch (ev)
|
||||
{
|
||||
case errc::none: return "No error";
|
||||
case errc::timeout: return "The timeout expired before the test could complete";
|
||||
case errc::unexpected: return "An unexpected test result was encountered";
|
||||
case errc::exceptioned: return "An unexpected exception was thrown";
|
||||
case errc::skipped: return "The test was skipped because of previous errors";
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return "An unknown error";
|
||||
}
|
||||
|
||||
boost::system::error_condition default_error_condition (int ev) const noexcept
|
||||
{
|
||||
return boost::system::error_condition (ev, *this);
|
||||
}
|
||||
|
||||
bool equivalent (int ev, boost::system::error_condition const& condition) const noexcept
|
||||
{
|
||||
return default_error_condition (ev) == condition;
|
||||
}
|
||||
|
||||
bool equivalent (boost::system::error_code const& code, int ev) const noexcept
|
||||
{
|
||||
return *this == code.category() && code.value() == ev;
|
||||
}
|
||||
};
|
||||
|
||||
static test_category_type category;
|
||||
|
||||
return category;
|
||||
}
|
||||
|
||||
boost::system::error_code TestPeerBasics::make_error (errc::errc_t ev) noexcept
|
||||
{
|
||||
return boost::system::error_code (ev, test_category ());
|
||||
}
|
||||
|
||||
boost::system::error_code TestPeerBasics::make_error (errc::errc_t ev, boost::system::error_code& ec) noexcept
|
||||
{
|
||||
return ec = make_error (ev);
|
||||
}
|
||||
|
||||
bool TestPeerBasics::success (boost::system::error_code const& ec, bool eofIsOkay) noexcept
|
||||
{
|
||||
if (eofIsOkay && ec == boost::asio::error::eof)
|
||||
return true;
|
||||
if (! ec)
|
||||
return true;
|
||||
breakpoint (ec);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TestPeerBasics::failure (boost::system::error_code const& ec, bool eofIsOkay) noexcept
|
||||
{
|
||||
return ! success (ec, eofIsOkay);
|
||||
}
|
||||
|
||||
bool TestPeerBasics::expected (bool condition, boost::system::error_code& ec) noexcept
|
||||
{
|
||||
if (condition)
|
||||
{
|
||||
ec = boost::system::error_code ();
|
||||
}
|
||||
else
|
||||
{
|
||||
make_error (errc::unexpected, ec);
|
||||
breakpoint (ec);
|
||||
}
|
||||
return condition;
|
||||
}
|
||||
|
||||
bool TestPeerBasics::unexpected (bool condition, boost::system::error_code& ec) noexcept
|
||||
{
|
||||
return ! expected (condition, ec);
|
||||
}
|
||||
|
||||
bool TestPeerBasics::aborted (boost::system::error_code const& ec) noexcept
|
||||
{
|
||||
return ec == boost::asio::error::operation_aborted;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
106
src/beast/modules/beast_asio/tests/TestPeerBasics.h
Normal file
106
src/beast/modules/beast_asio/tests/TestPeerBasics.h
Normal file
@@ -0,0 +1,106 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_TESTS_TESTPEERBASICS_H_INCLUDED
|
||||
#define BEAST_ASIO_TESTS_TESTPEERBASICS_H_INCLUDED
|
||||
|
||||
/** Common declarations for TestPeer.
|
||||
|
||||
@see TestPeer
|
||||
*/
|
||||
class TestPeerBasics
|
||||
{
|
||||
public:
|
||||
/** Selects between synchronous or asynchronous networking i/o usage. */
|
||||
struct Model
|
||||
{
|
||||
enum model_t
|
||||
{
|
||||
sync,
|
||||
async
|
||||
};
|
||||
|
||||
Model (model_t model);
|
||||
String name () const noexcept;
|
||||
bool operator== (model_t model) const noexcept;
|
||||
|
||||
private:
|
||||
model_t m_model;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/** Convert a PeerRole to boost::asio::ssl::stream_base_handshake_type */
|
||||
static boost::asio::ssl::stream_base::handshake_type to_handshake_type (PeerRole const& role);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// Custom error codes for distinguishing test conditions
|
||||
struct errc
|
||||
{
|
||||
enum errc_t
|
||||
{
|
||||
none = 0,
|
||||
timeout, // The peer join timeout expired
|
||||
unexpected, // An expected condition was false
|
||||
exceptioned, // An exception occurred
|
||||
skipped // Test skipped due to previous errors
|
||||
};
|
||||
};
|
||||
|
||||
/** Returns the category that represents TestPeer errors.
|
||||
*/
|
||||
static boost::system::error_category const& test_category () noexcept;
|
||||
|
||||
/** Creates a test error_code from the give code value.
|
||||
*/
|
||||
static boost::system::error_code make_error (errc::errc_t ev) noexcept;
|
||||
|
||||
/** Sets the passed error_code to a test error and returns it.
|
||||
*/
|
||||
static boost::system::error_code make_error (errc::errc_t ev,
|
||||
boost::system::error_code& ec) noexcept;
|
||||
|
||||
/** Returns true if the error code indicates success.
|
||||
*/
|
||||
static bool success (boost::system::error_code const& ec, bool eofIsOkay = false) noexcept;
|
||||
|
||||
/** Returns false if the error code indicates failure.
|
||||
*/
|
||||
static bool failure (boost::system::error_code const& ec, bool eofIsOkay = false) noexcept;
|
||||
|
||||
/** Set the error based on a failed condition and return the success.
|
||||
*/
|
||||
static bool expected (bool condition, boost::system::error_code& ec) noexcept;
|
||||
|
||||
/** Set the error based on a passed condition and return the success.
|
||||
*/
|
||||
static bool unexpected (bool condition, boost::system::error_code& ec) noexcept;
|
||||
|
||||
/** 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
|
||||
45
src/beast/modules/beast_asio/tests/TestPeerDetails.h
Normal file
45
src/beast/modules/beast_asio/tests/TestPeerDetails.h
Normal file
@@ -0,0 +1,45 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_TESTS_TESTPEERDETAILS_H_INCLUDED
|
||||
#define BEAST_ASIO_TESTS_TESTPEERDETAILS_H_INCLUDED
|
||||
|
||||
/** Base class of all detail objects.
|
||||
*/
|
||||
class TestPeerDetails
|
||||
{
|
||||
public:
|
||||
virtual ~TestPeerDetails () { }
|
||||
|
||||
virtual String name () = 0;
|
||||
|
||||
virtual Socket& get_socket () = 0;
|
||||
|
||||
virtual Socket& get_acceptor () = 0;
|
||||
|
||||
boost::asio::io_service& get_io_service ()
|
||||
{
|
||||
return m_io_service;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::asio::io_service m_io_service;
|
||||
};
|
||||
|
||||
#endif
|
||||
108
src/beast/modules/beast_asio/tests/TestPeerDetailsTcp.h
Normal file
108
src/beast/modules/beast_asio/tests/TestPeerDetailsTcp.h
Normal file
@@ -0,0 +1,108 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_TESTS_TESTPEERDETAILSTCP_H_INCLUDED
|
||||
#define BEAST_ASIO_TESTS_TESTPEERDETAILSTCP_H_INCLUDED
|
||||
|
||||
/** Some predefined Detail classes for TestPeer
|
||||
*/
|
||||
struct TcpDetails : public TestPeerDetails
|
||||
{
|
||||
protected:
|
||||
typedef boost::asio::ip::tcp protocol_type;
|
||||
typedef protocol_type::socket socket_type;
|
||||
typedef protocol_type::acceptor acceptor_type;
|
||||
typedef protocol_type::endpoint endpoint_type;
|
||||
typedef protocol_type::resolver resolver_type;
|
||||
|
||||
public:
|
||||
typedef protocol_type arg_type;
|
||||
typedef socket_type native_socket_type;
|
||||
typedef acceptor_type native_acceptor_type;
|
||||
|
||||
explicit TcpDetails (arg_type protocol)
|
||||
: m_protocol (protocol)
|
||||
, m_socket (get_io_service ())
|
||||
, m_acceptor (get_io_service ())
|
||||
, m_socket_wrapper (m_socket)
|
||||
, m_acceptor_wrapper (m_acceptor)
|
||||
{
|
||||
}
|
||||
|
||||
static String getArgName (arg_type arg)
|
||||
{
|
||||
if (arg == protocol_type::v4 ())
|
||||
return ".tcpv4";
|
||||
else if (arg == protocol_type::v6 ())
|
||||
return ".tcpv6";
|
||||
return ".tcp?";
|
||||
}
|
||||
|
||||
String name ()
|
||||
{
|
||||
return getArgName (m_protocol);
|
||||
}
|
||||
|
||||
Socket& get_socket ()
|
||||
{
|
||||
return m_socket_wrapper;
|
||||
}
|
||||
|
||||
Socket& get_acceptor ()
|
||||
{
|
||||
return m_acceptor_wrapper;
|
||||
}
|
||||
|
||||
socket_type& get_native_socket ()
|
||||
{
|
||||
return m_socket;
|
||||
}
|
||||
|
||||
acceptor_type& get_native_acceptor ()
|
||||
{
|
||||
return m_acceptor;
|
||||
}
|
||||
|
||||
endpoint_type get_endpoint (PeerRole role)
|
||||
{
|
||||
if (m_protocol == protocol_type::v4 ())
|
||||
{
|
||||
if (role == PeerRole::server)
|
||||
return endpoint_type (m_protocol, 1053);
|
||||
else
|
||||
return endpoint_type (boost::asio::ip::address_v4::loopback (), 1053);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (role == PeerRole::server)
|
||||
return endpoint_type (m_protocol, 1052);
|
||||
else
|
||||
return endpoint_type (boost::asio::ip::address_v6 ().from_string ("::1"), 1052);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
protocol_type m_protocol;
|
||||
socket_type m_socket;
|
||||
acceptor_type m_acceptor;
|
||||
SocketWrapper <socket_type&> m_socket_wrapper;
|
||||
SocketWrapper <acceptor_type&> m_acceptor_wrapper;
|
||||
};
|
||||
|
||||
#endif
|
||||
63
src/beast/modules/beast_asio/tests/TestPeerLogic.cpp
Normal file
63
src/beast/modules/beast_asio/tests/TestPeerLogic.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
TestPeerLogic::TestPeerLogic (Socket& socket)
|
||||
: m_socket (&socket)
|
||||
{
|
||||
}
|
||||
|
||||
TestPeerLogic::error_code& TestPeerLogic::error () noexcept
|
||||
{
|
||||
return m_ec;
|
||||
}
|
||||
|
||||
TestPeerLogic::error_code const& TestPeerLogic::error () const noexcept
|
||||
{
|
||||
return m_ec;
|
||||
}
|
||||
|
||||
TestPeerLogic::error_code const& TestPeerLogic::error (error_code const& ec) noexcept
|
||||
{
|
||||
return m_ec = ec;
|
||||
}
|
||||
|
||||
Socket& TestPeerLogic::socket () noexcept
|
||||
{
|
||||
return *m_socket;
|
||||
}
|
||||
|
||||
void TestPeerLogic::on_connect ()
|
||||
{
|
||||
pure_virtual ();
|
||||
}
|
||||
|
||||
void TestPeerLogic::on_connect_async (error_code const&)
|
||||
{
|
||||
pure_virtual ();
|
||||
}
|
||||
|
||||
void TestPeerLogic::finished ()
|
||||
{
|
||||
pure_virtual ();
|
||||
}
|
||||
|
||||
void TestPeerLogic::pure_virtual ()
|
||||
{
|
||||
fatal_error ("A TestPeerLogic function was called incorrectly");
|
||||
}
|
||||
57
src/beast/modules/beast_asio/tests/TestPeerLogic.h
Normal file
57
src/beast/modules/beast_asio/tests/TestPeerLogic.h
Normal file
@@ -0,0 +1,57 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_TESTS_TESTPEERLOGIC_H_INCLUDED
|
||||
#define BEAST_ASIO_TESTS_TESTPEERLOGIC_H_INCLUDED
|
||||
|
||||
/** Interface for implementing the logic part of a peer test.
|
||||
*/
|
||||
class TestPeerLogic : public TestPeerBasics
|
||||
{
|
||||
public:
|
||||
typedef boost::system::error_code error_code;
|
||||
|
||||
explicit TestPeerLogic (Socket& socket);
|
||||
|
||||
error_code& error () noexcept;
|
||||
error_code const& error () const noexcept;
|
||||
error_code const& error (error_code const& ec) noexcept; // assigns to m_ec
|
||||
|
||||
Socket& socket () noexcept;
|
||||
|
||||
virtual PeerRole get_role () const noexcept = 0;
|
||||
|
||||
virtual Model get_model () const noexcept = 0;
|
||||
|
||||
virtual void on_connect ();
|
||||
|
||||
virtual void on_connect_async (error_code const&);
|
||||
|
||||
// asynchronous logic classes
|
||||
// must call this when they are done
|
||||
virtual void finished ();
|
||||
|
||||
static void pure_virtual ();
|
||||
|
||||
private:
|
||||
error_code m_ec;
|
||||
Socket* m_socket;
|
||||
};
|
||||
|
||||
#endif
|
||||
155
src/beast/modules/beast_asio/tests/TestPeerLogicAsyncClient.cpp
Normal file
155
src/beast/modules/beast_asio/tests/TestPeerLogicAsyncClient.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
TestPeerLogicAsyncClient::TestPeerLogicAsyncClient (Socket& socket)
|
||||
: TestPeerLogic (socket)
|
||||
{
|
||||
}
|
||||
|
||||
PeerRole TestPeerLogicAsyncClient::get_role () const noexcept
|
||||
{
|
||||
return PeerRole::client;
|
||||
}
|
||||
|
||||
TestPeerBasics::Model TestPeerLogicAsyncClient::get_model () const noexcept
|
||||
{
|
||||
return Model::async;
|
||||
}
|
||||
|
||||
void TestPeerLogicAsyncClient::on_connect_async (error_code const& ec)
|
||||
{
|
||||
if (aborted (ec) || failure (error (ec)))
|
||||
return finished ();
|
||||
|
||||
if (socket ().needs_handshake ())
|
||||
{
|
||||
socket ().async_handshake (Socket::client,
|
||||
boost::bind (&TestPeerLogicAsyncClient::on_handshake, this,
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
else
|
||||
{
|
||||
on_handshake (ec);
|
||||
}
|
||||
}
|
||||
|
||||
void TestPeerLogicAsyncClient::on_handshake (error_code const& ec)
|
||||
{
|
||||
if (aborted (ec) || failure (error (ec)))
|
||||
return finished ();
|
||||
|
||||
boost::asio::async_write (socket (), boost::asio::buffer ("hello", 5),
|
||||
boost::bind (&TestPeerLogicAsyncClient::on_write, this,
|
||||
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
void TestPeerLogicAsyncClient::on_write (error_code const& ec, std::size_t bytes_transferred)
|
||||
{
|
||||
if (aborted (ec) || failure (error (ec)))
|
||||
return finished ();
|
||||
|
||||
if (unexpected (bytes_transferred == 5, error ()))
|
||||
return finished ();
|
||||
|
||||
boost::asio::async_read_until (socket (), m_buf, std::string ("goodbye"),
|
||||
boost::bind (&TestPeerLogicAsyncClient::on_read, this,
|
||||
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
void TestPeerLogicAsyncClient::on_read (error_code const& ec, std::size_t bytes_transferred)
|
||||
{
|
||||
if (aborted (ec) || failure (error (ec)))
|
||||
return finished ();
|
||||
|
||||
if (unexpected (bytes_transferred == 7, error ()))
|
||||
return finished ();
|
||||
|
||||
// should check the data here?
|
||||
m_buf.consume (bytes_transferred);
|
||||
|
||||
// Fire up a 1 byte read, to wait for the server to
|
||||
// shut down its end of the connection.
|
||||
boost::asio::async_read (socket (), m_buf.prepare (1),
|
||||
boost::bind (&TestPeerLogicAsyncClient::on_read_final, this,
|
||||
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
void TestPeerLogicAsyncClient::on_read_final (error_code const& ec, std::size_t)
|
||||
{
|
||||
if (aborted (ec))
|
||||
return finished ();
|
||||
|
||||
// An eof is the normal case. The server should have closed shop.
|
||||
//
|
||||
if (ec == boost::asio::error::eof)
|
||||
{
|
||||
if (socket ().needs_handshake ())
|
||||
{
|
||||
socket ().async_shutdown (boost::bind (&TestPeerLogicAsyncClient::on_shutdown, this,
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
else
|
||||
{
|
||||
// on_shutdown will call finished ()
|
||||
error_code ec;
|
||||
on_shutdown (socket ().shutdown (Socket::shutdown_both, ec));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we don't get eof, then there should be some other
|
||||
// error in there. We don't expect the server to send more bytes!
|
||||
//
|
||||
// This statement will do the following:
|
||||
//
|
||||
// error (ec) save ec into our error state
|
||||
// success () return true if ec represents success
|
||||
// unexpected () changes error() to 'unexpected' result if
|
||||
// success() returned true
|
||||
//
|
||||
unexpected (success (error (ec)), error ());
|
||||
|
||||
return finished ();
|
||||
}
|
||||
}
|
||||
|
||||
void TestPeerLogicAsyncClient::on_shutdown (error_code const& ec)
|
||||
{
|
||||
if (! aborted (ec))
|
||||
{
|
||||
if (success (error (ec), true))
|
||||
{
|
||||
if (socket ().needs_handshake ())
|
||||
{
|
||||
socket ().shutdown (Socket::shutdown_both, error ());
|
||||
}
|
||||
|
||||
if (! error ())
|
||||
{
|
||||
if (success (socket ().close (error ())))
|
||||
{
|
||||
// doing nothing here is intended,
|
||||
// as the calls to success() may set error()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
finished ();
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_TESTS_TESTPEERLOGICASYNCCLIENT_H_INCLUDED
|
||||
#define BEAST_ASIO_TESTS_TESTPEERLOGICASYNCCLIENT_H_INCLUDED
|
||||
|
||||
class TestPeerLogicAsyncClient : public TestPeerLogic
|
||||
{
|
||||
public:
|
||||
explicit TestPeerLogicAsyncClient (Socket& socket);
|
||||
PeerRole get_role () const noexcept;
|
||||
Model get_model () const noexcept;
|
||||
void on_connect_async (error_code const& ec);
|
||||
void on_handshake (error_code const& ec);
|
||||
void on_write (error_code const& ec, std::size_t bytes_transferred);
|
||||
void on_read (error_code const& ec, std::size_t bytes_transferred);
|
||||
void on_read_final (error_code const& ec, std::size_t);
|
||||
void on_shutdown (error_code const& ec);
|
||||
private:
|
||||
boost::asio::streambuf m_buf;
|
||||
};
|
||||
|
||||
#endif
|
||||
117
src/beast/modules/beast_asio/tests/TestPeerLogicAsyncServer.cpp
Normal file
117
src/beast/modules/beast_asio/tests/TestPeerLogicAsyncServer.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
TestPeerLogicAsyncServer::TestPeerLogicAsyncServer (Socket& socket)
|
||||
: TestPeerLogic (socket)
|
||||
{
|
||||
}
|
||||
|
||||
PeerRole TestPeerLogicAsyncServer::get_role () const noexcept
|
||||
{
|
||||
return PeerRole::server;
|
||||
}
|
||||
|
||||
TestPeerBasics::Model TestPeerLogicAsyncServer::get_model () const noexcept
|
||||
{
|
||||
return Model::async;
|
||||
}
|
||||
|
||||
void TestPeerLogicAsyncServer::on_connect_async (error_code const& ec)
|
||||
{
|
||||
if (aborted (ec) || failure (error (ec)))
|
||||
return finished ();
|
||||
|
||||
if (socket ().needs_handshake ())
|
||||
{
|
||||
socket ().async_handshake (Socket::server,
|
||||
boost::bind (&TestPeerLogicAsyncServer::on_handshake, this,
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
else
|
||||
{
|
||||
on_handshake (ec);
|
||||
}
|
||||
}
|
||||
|
||||
void TestPeerLogicAsyncServer::on_handshake (error_code const& ec)
|
||||
{
|
||||
if (aborted (ec) || failure (error (ec)))
|
||||
return finished ();
|
||||
|
||||
boost::asio::async_read_until (socket (), m_buf, std::string ("hello"),
|
||||
boost::bind (&TestPeerLogicAsyncServer::on_read, this,
|
||||
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
void TestPeerLogicAsyncServer::on_read (error_code const& ec, std::size_t bytes_transferred)
|
||||
{
|
||||
if (aborted (ec) || failure (error (ec)))
|
||||
return finished ();
|
||||
|
||||
if (unexpected (bytes_transferred == 5, error ()))
|
||||
return finished ();
|
||||
|
||||
boost::asio::async_write (socket (), boost::asio::buffer ("goodbye", 7),
|
||||
boost::bind (&TestPeerLogicAsyncServer::on_write, this,
|
||||
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
|
||||
void TestPeerLogicAsyncServer::on_write (error_code const& ec, std::size_t bytes_transferred)
|
||||
{
|
||||
if (aborted (ec) || failure (error (ec)))
|
||||
return finished ();
|
||||
|
||||
if (unexpected (bytes_transferred == 7, error ()))
|
||||
return finished ();
|
||||
|
||||
if (socket ().needs_handshake ())
|
||||
{
|
||||
socket ().async_shutdown (boost::bind (&TestPeerLogicAsyncServer::on_shutdown, this,
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
else
|
||||
{
|
||||
// on_shutdown will call finished ()
|
||||
// we need another instance of ec so we can call on_shutdown()
|
||||
error_code ec;
|
||||
on_shutdown (socket ().shutdown (Socket::shutdown_both, ec));
|
||||
}
|
||||
}
|
||||
|
||||
void TestPeerLogicAsyncServer::on_shutdown (error_code const& ec)
|
||||
{
|
||||
if (! aborted (ec))
|
||||
{
|
||||
if (success (error (ec), true))
|
||||
{
|
||||
if (socket ().needs_handshake ())
|
||||
{
|
||||
socket ().shutdown (Socket::shutdown_both, error ());
|
||||
}
|
||||
|
||||
if (success (socket ().close (error ())))
|
||||
{
|
||||
// doing nothing here is intended,
|
||||
// as the calls to success() may set error()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
finished ();
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_TESTS_TESTPEERLOGICASYNCSERVER_H_INCLUDED
|
||||
#define BEAST_ASIO_TESTS_TESTPEERLOGICASYNCSERVER_H_INCLUDED
|
||||
|
||||
class TestPeerLogicAsyncServer : public TestPeerLogic
|
||||
{
|
||||
public:
|
||||
explicit TestPeerLogicAsyncServer (Socket& socket);
|
||||
PeerRole get_role () const noexcept;
|
||||
Model get_model () const noexcept;
|
||||
void on_connect_async (error_code const& ec);
|
||||
void on_handshake (error_code const& ec);
|
||||
void on_read (error_code const& ec, std::size_t bytes_transferred);
|
||||
void on_write (error_code const& ec, std::size_t bytes_transferred);
|
||||
void on_shutdown (error_code const& ec);
|
||||
private:
|
||||
boost::asio::streambuf m_buf;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
TestPeerLogicProxyClient::TestPeerLogicProxyClient (Socket& socket)
|
||||
: TestPeerLogicSyncClient (socket)
|
||||
{
|
||||
}
|
||||
|
||||
void TestPeerLogicProxyClient::on_pre_handshake ()
|
||||
{
|
||||
//ProxyHandshakeParser h;
|
||||
|
||||
static std::string line (
|
||||
"PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n"
|
||||
// 56 chars
|
||||
);
|
||||
|
||||
boost::asio::write (socket (), boost::asio::buffer (line), error ());
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_TESTS_TESTPEERLOGICPROXYCLIENT_H_INCLUDED
|
||||
#define BEAST_ASIO_TESTS_TESTPEERLOGICPROXYCLIENT_H_INCLUDED
|
||||
|
||||
/** A synchronous client logic that sends a PROXY protocol pre-handshake. */
|
||||
class TestPeerLogicProxyClient : public TestPeerLogicSyncClient
|
||||
{
|
||||
public:
|
||||
explicit TestPeerLogicProxyClient (Socket& socket);
|
||||
void on_pre_handshake ();
|
||||
};
|
||||
|
||||
#endif
|
||||
108
src/beast/modules/beast_asio/tests/TestPeerLogicSyncClient.cpp
Normal file
108
src/beast/modules/beast_asio/tests/TestPeerLogicSyncClient.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
TestPeerLogicSyncClient::TestPeerLogicSyncClient (Socket& socket)
|
||||
: TestPeerLogic (socket)
|
||||
{
|
||||
}
|
||||
|
||||
PeerRole TestPeerLogicSyncClient::get_role () const noexcept
|
||||
{
|
||||
return PeerRole::client;
|
||||
}
|
||||
|
||||
TestPeerBasics::Model TestPeerLogicSyncClient::get_model () const noexcept
|
||||
{
|
||||
return Model::sync;
|
||||
}
|
||||
|
||||
void TestPeerLogicSyncClient::on_connect ()
|
||||
{
|
||||
{
|
||||
// pre-handshake hook is optional
|
||||
on_pre_handshake ();
|
||||
if (failure (error ()))
|
||||
return ;
|
||||
}
|
||||
|
||||
if (socket ().needs_handshake ())
|
||||
{
|
||||
if (failure (socket ().handshake (to_handshake_type (get_role ()), error ())))
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
std::size_t const amount = boost::asio::write (
|
||||
socket (), boost::asio::buffer ("hello", 5), error ());
|
||||
|
||||
if (failure (error ()))
|
||||
return;
|
||||
|
||||
if (unexpected (amount == 5, error ()))
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
char data [7];
|
||||
|
||||
size_t const amount = boost::asio::read (
|
||||
socket (), boost::asio::buffer (data, 7), error ());
|
||||
|
||||
if (failure (error ()))
|
||||
return;
|
||||
|
||||
if (unexpected (amount == 7, error ()))
|
||||
return;
|
||||
|
||||
if (unexpected (memcmp (&data, "goodbye", 7) == 0, error ()))
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for 1 byte which should never come. Instead,
|
||||
// the server should close its end and we will get eof
|
||||
{
|
||||
char data [1];
|
||||
boost::asio::read (socket (), boost::asio::buffer (data, 1), error ());
|
||||
|
||||
if (error () == boost::asio::error::eof)
|
||||
{
|
||||
error () = error_code ();
|
||||
}
|
||||
else if (unexpected (failure (error ()), error ()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (socket ().needs_handshake ())
|
||||
{
|
||||
if (failure (socket ().shutdown (error ()), true))
|
||||
return;
|
||||
}
|
||||
|
||||
if (failure (socket ().shutdown (Socket::shutdown_both, error ())))
|
||||
return;
|
||||
|
||||
if (failure (socket ().close (error ())))
|
||||
return;
|
||||
}
|
||||
|
||||
void TestPeerLogicSyncClient::on_pre_handshake ()
|
||||
{
|
||||
}
|
||||
33
src/beast/modules/beast_asio/tests/TestPeerLogicSyncClient.h
Normal file
33
src/beast/modules/beast_asio/tests/TestPeerLogicSyncClient.h
Normal file
@@ -0,0 +1,33 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_TESTS_TESTPEERLOGICSYNCCLIENT_H_INCLUDED
|
||||
#define BEAST_ASIO_TESTS_TESTPEERLOGICSYNCCLIENT_H_INCLUDED
|
||||
|
||||
class TestPeerLogicSyncClient : public TestPeerLogic
|
||||
{
|
||||
public:
|
||||
explicit TestPeerLogicSyncClient (Socket& socket);
|
||||
PeerRole get_role () const noexcept;
|
||||
Model get_model () const noexcept;
|
||||
void on_connect ();
|
||||
virtual void on_pre_handshake ();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,80 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
TestPeerLogicSyncServer::TestPeerLogicSyncServer (Socket& socket)
|
||||
: TestPeerLogic (socket)
|
||||
{
|
||||
}
|
||||
|
||||
PeerRole TestPeerLogicSyncServer::get_role () const noexcept
|
||||
{
|
||||
return PeerRole::server;
|
||||
}
|
||||
|
||||
TestPeerBasics::Model TestPeerLogicSyncServer::get_model () const noexcept
|
||||
{
|
||||
return Model::sync;
|
||||
}
|
||||
|
||||
void TestPeerLogicSyncServer::on_connect ()
|
||||
{
|
||||
if (socket ().needs_handshake ())
|
||||
{
|
||||
if (failure (socket ().handshake (to_handshake_type (get_role ()), error ())))
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
boost::asio::streambuf buf (5);
|
||||
std::size_t const amount = boost::asio::read_until (
|
||||
socket (), buf, "hello", error ());
|
||||
|
||||
if (failure (error ()))
|
||||
return;
|
||||
|
||||
if (unexpected (amount == 5, error ()))
|
||||
return;
|
||||
|
||||
if (unexpected (buf.size () == 5, error ()))
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
std::size_t const amount = boost::asio::write (
|
||||
socket (), boost::asio::buffer ("goodbye", 7), error ());
|
||||
|
||||
if (failure (error ()))
|
||||
return;
|
||||
|
||||
if (unexpected (amount == 7, error ()))
|
||||
return;
|
||||
}
|
||||
|
||||
if (socket ().needs_handshake ())
|
||||
{
|
||||
if (failure (socket ().shutdown (error ()), true))
|
||||
return;
|
||||
}
|
||||
|
||||
if (failure (socket ().shutdown (Socket::shutdown_both, error ())))
|
||||
return;
|
||||
|
||||
if (failure (socket ().close (error ())))
|
||||
return;
|
||||
}
|
||||
32
src/beast/modules/beast_asio/tests/TestPeerLogicSyncServer.h
Normal file
32
src/beast/modules/beast_asio/tests/TestPeerLogicSyncServer.h
Normal file
@@ -0,0 +1,32 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_TESTS_TESTPEERLOGICSYNCSERVER_H_INCLUDED
|
||||
#define BEAST_ASIO_TESTS_TESTPEERLOGICSYNCSERVER_H_INCLUDED
|
||||
|
||||
class TestPeerLogicSyncServer : public TestPeerLogic
|
||||
{
|
||||
public:
|
||||
explicit TestPeerLogicSyncServer (Socket& socket);
|
||||
PeerRole get_role () const noexcept;
|
||||
Model get_model () const noexcept;
|
||||
void on_connect ();
|
||||
};
|
||||
|
||||
#endif
|
||||
395
src/beast/modules/beast_asio/tests/TestPeerType.h
Normal file
395
src/beast/modules/beast_asio/tests/TestPeerType.h
Normal file
@@ -0,0 +1,395 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_ASIO_TESTS_TESTPEERTYPE_H_INCLUDED
|
||||
#define BEAST_ASIO_TESTS_TESTPEERTYPE_H_INCLUDED
|
||||
|
||||
template <typename Logic, typename Details>
|
||||
class TestPeerType
|
||||
: public Details
|
||||
, public Logic
|
||||
, public TestPeer
|
||||
, public Thread
|
||||
{
|
||||
protected:
|
||||
// TestPeerDetails
|
||||
using Details::get_socket;
|
||||
using Details::get_acceptor;
|
||||
using Details::get_io_service;
|
||||
|
||||
// Details
|
||||
typedef typename Details::protocol_type protocol_type;
|
||||
typedef typename Details::socket_type socket_type;
|
||||
typedef typename Details::acceptor_type acceptor_type;
|
||||
typedef typename Details::endpoint_type endpoint_type;
|
||||
typedef typename Details::resolver_type resolver_type;
|
||||
|
||||
using Details::get_native_socket;
|
||||
using Details::get_native_acceptor;
|
||||
using Details::get_endpoint;
|
||||
|
||||
// TestPeerLogic
|
||||
typedef typename Logic::error_code error_code;
|
||||
using Logic::error;
|
||||
using Logic::socket;
|
||||
using Logic::get_role;
|
||||
using Logic::get_model;
|
||||
using Logic::on_connect;
|
||||
using Logic::on_connect_async;
|
||||
using Logic::pure_virtual;
|
||||
|
||||
typedef TestPeerType <Logic, Details> This;
|
||||
|
||||
public:
|
||||
// Details
|
||||
typedef typename Details::arg_type arg_type;
|
||||
typedef typename Details::native_socket_type native_socket_type;
|
||||
typedef typename Details::native_acceptor_type native_acceptor_type;
|
||||
|
||||
TestPeerType (arg_type const& arg)
|
||||
: Details (arg)
|
||||
, Logic (get_socket ())
|
||||
, Thread (name ())
|
||||
, m_timer (get_io_service ())
|
||||
, m_timer_set (false)
|
||||
, m_timed_out (false)
|
||||
{
|
||||
}
|
||||
|
||||
~TestPeerType ()
|
||||
{
|
||||
}
|
||||
|
||||
String name () const
|
||||
{
|
||||
return get_model ().name () + "_" + get_role ().name ();
|
||||
}
|
||||
|
||||
bool is_async () const noexcept
|
||||
{
|
||||
return get_model () == Model::async;
|
||||
}
|
||||
|
||||
void start (int timeoutSeconds)
|
||||
{
|
||||
if (is_async ())
|
||||
{
|
||||
if (timeoutSeconds > 0)
|
||||
{
|
||||
m_timer.expires_from_now (
|
||||
boost::posix_time::seconds (timeoutSeconds));
|
||||
|
||||
m_timer.async_wait (boost::bind (&This::on_deadline,
|
||||
this, boost::asio::placeholders::error));
|
||||
|
||||
m_timer_set = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't set the timer, so infinite wait.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Save the value for when join() is called later.
|
||||
//
|
||||
m_timeoutSeconds = timeoutSeconds;
|
||||
}
|
||||
|
||||
startThread ();
|
||||
|
||||
// For server roles block until the thread is litening.
|
||||
//
|
||||
if (get_role () == PeerRole::server)
|
||||
m_listening.wait ();
|
||||
}
|
||||
|
||||
error_code join ()
|
||||
{
|
||||
if (is_async ())
|
||||
{
|
||||
// If the timer expired, then all our i/o should be
|
||||
// aborted and the thread will exit. So we will wait
|
||||
// for the thread for an infinite amount of time to
|
||||
// prevent undefined behavior. If an asynchronous logic
|
||||
// fails to end when the deadline timer expires, it
|
||||
// means there's a bug in the logic code.
|
||||
//
|
||||
m_join.wait ();
|
||||
|
||||
// The wait was satisfied but now the thread is still on
|
||||
// it's way out of the thread function, so block until
|
||||
// we know its done.
|
||||
//
|
||||
stopThread ();
|
||||
|
||||
// If we timed out then always report the custom error
|
||||
if (m_timed_out)
|
||||
return error (make_error (errc::timeout));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_timeoutSeconds > 0)
|
||||
{
|
||||
// Wait for the thread to finish
|
||||
//
|
||||
if (! m_join.wait (m_timeoutSeconds * 1000))
|
||||
{
|
||||
// Uh oh, we timed out! This is bad.
|
||||
// The synchronous model requires that the thread
|
||||
// be forcibly killed, which can result in undefined
|
||||
// behavior. It's best not to perform tests with
|
||||
// synchronous Logic objects that are supposed to time out.
|
||||
|
||||
// Force the thread to be killed, without waiting.
|
||||
stopThread (0);
|
||||
|
||||
error () = make_error (errc::timeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
stopThread ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// They requested an infinite wait.
|
||||
//
|
||||
m_join.wait ();
|
||||
|
||||
stopThread ();
|
||||
}
|
||||
}
|
||||
|
||||
return error ();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void run ()
|
||||
{
|
||||
if (is_async ())
|
||||
{
|
||||
if (get_role () == PeerRole::server)
|
||||
{
|
||||
run_async_server ();
|
||||
}
|
||||
else if (get_role () == PeerRole::client)
|
||||
{
|
||||
run_async_client ();
|
||||
}
|
||||
else
|
||||
{
|
||||
error () = make_error (errc::unexpected);
|
||||
}
|
||||
}
|
||||
else if (get_model () == Model::sync)
|
||||
{
|
||||
if (get_role () == PeerRole::server)
|
||||
{
|
||||
run_sync_server ();
|
||||
}
|
||||
else if (get_role () == PeerRole::client)
|
||||
{
|
||||
run_sync_client ();
|
||||
}
|
||||
else
|
||||
{
|
||||
error () = make_error (errc::unexpected);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error () = make_error (errc::unexpected);
|
||||
}
|
||||
|
||||
get_io_service ().run ();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void run_sync_server ()
|
||||
{
|
||||
do_listen ();
|
||||
|
||||
if (failure (error ()))
|
||||
return finished ();
|
||||
|
||||
if (failure (get_acceptor ().accept (get_socket (), error ())))
|
||||
return finished ();
|
||||
|
||||
if (failure (get_acceptor ().close (error ())))
|
||||
return finished ();
|
||||
|
||||
this->on_connect ();
|
||||
|
||||
finished ();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void on_accept (error_code const& ec)
|
||||
{
|
||||
if (failure (ec))
|
||||
return finished ();
|
||||
|
||||
// Close the acceptor down so we don't block the io_service forever
|
||||
//
|
||||
// VFALCO NOTE what difference between cancel and close?
|
||||
#if 0
|
||||
if (failure (get_acceptor ().close (error ())))
|
||||
return finished ();
|
||||
#endif
|
||||
|
||||
this->on_connect_async (ec);
|
||||
}
|
||||
|
||||
void run_async_server ()
|
||||
{
|
||||
do_listen ();
|
||||
|
||||
if (failure (error ()))
|
||||
return finished ();
|
||||
|
||||
get_acceptor ().async_accept (get_socket (), boost::bind (
|
||||
&This::on_accept, this, boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void run_sync_client ()
|
||||
{
|
||||
if (failure (get_native_socket ().connect (get_endpoint (get_role ()), error ())))
|
||||
return finished ();
|
||||
|
||||
this->on_connect ();
|
||||
|
||||
finished ();
|
||||
}
|
||||
|
||||
void run_async_client ()
|
||||
{
|
||||
get_native_socket ().async_connect (get_endpoint (get_role ()),
|
||||
boost::bind (&Logic::on_connect_async, this, boost::asio::placeholders::error));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void do_listen ()
|
||||
{
|
||||
if (failure (get_native_acceptor ().open (
|
||||
get_endpoint (get_role ()).protocol (), error ())))
|
||||
return;
|
||||
|
||||
// VFALCO TODO Figure out how to not hard code boost::asio::socket_base
|
||||
if (failure (get_native_acceptor ().set_option (
|
||||
boost::asio::socket_base::reuse_address (true), error ())))
|
||||
return;
|
||||
|
||||
if (failure (get_native_acceptor ().bind (get_endpoint (get_role ()), error ())))
|
||||
return;
|
||||
|
||||
// VFALCO TODO Figure out how to not hard code boost::asio::socket_base
|
||||
if (failure (get_native_acceptor ().listen (
|
||||
boost::asio::socket_base::max_connections, error ())))
|
||||
return;
|
||||
|
||||
m_listening.signal ();
|
||||
}
|
||||
|
||||
void on_deadline (error_code const& ec)
|
||||
{
|
||||
m_timer_set = false;
|
||||
|
||||
if (ec != boost::asio::error::operation_aborted)
|
||||
{
|
||||
// We expect that ec represents no error, since the
|
||||
// timer expired and the operation wasn't aborted.
|
||||
//
|
||||
// If by some chance there is an error in ec we will
|
||||
// report that as an unexpected test condition instead
|
||||
// of a timeout.
|
||||
//
|
||||
if (expected (! ec, error ()))
|
||||
m_timed_out = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The timer was canceled because the Logic
|
||||
// called finished(), so we do nothing here.
|
||||
}
|
||||
|
||||
finished ();
|
||||
}
|
||||
|
||||
void finished ()
|
||||
{
|
||||
// If the server errors out it will come through
|
||||
// here so signal the listening event and unblock
|
||||
// the main thread.
|
||||
//
|
||||
if (get_role () == PeerRole::server)
|
||||
m_listening.signal ();
|
||||
|
||||
if (m_timer_set)
|
||||
{
|
||||
error_code ec;
|
||||
std::size_t const amount = m_timer.cancel (ec);
|
||||
|
||||
// The Logic should not have any I/O pending when
|
||||
// it calls finished, so amount should be zero.
|
||||
//
|
||||
unexpected (amount == 0, ec);
|
||||
}
|
||||
|
||||
// The logic should close the socket at the end of
|
||||
// its operations, unless it encounters an error.
|
||||
// Therefore, we will clean everything up and squelch
|
||||
// any errors, so that io_service::run() will return.
|
||||
//
|
||||
{
|
||||
error_code ec;
|
||||
this->get_socket ().close (ec);
|
||||
}
|
||||
|
||||
// The acceptor will not have closed if the client
|
||||
// never established the connection, so do it here.
|
||||
{
|
||||
error_code ec;
|
||||
this->get_acceptor ().close (ec);
|
||||
}
|
||||
|
||||
// Wake up the thread blocked on join()
|
||||
m_join.signal ();
|
||||
}
|
||||
|
||||
private:
|
||||
WaitableEvent m_listening;
|
||||
WaitableEvent m_join;
|
||||
|
||||
// for async peers
|
||||
boost::asio::deadline_timer m_timer;
|
||||
bool m_timer_set;
|
||||
bool m_timed_out;
|
||||
|
||||
// for sync peers
|
||||
int m_timeoutSeconds;
|
||||
};
|
||||
|
||||
#endif
|
||||
51
src/beast/modules/beast_asio/tests/TestPeerUnitTests.cpp
Normal file
51
src/beast/modules/beast_asio/tests/TestPeerUnitTests.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
/** UnitTest for the TestPeer family of objects.
|
||||
*/
|
||||
class TestPeerUnitTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
|
||||
template <typename Details, typename Arg >
|
||||
void testDetails (Arg const& arg = Arg ())
|
||||
{
|
||||
PeerTest::report <Details> (*this, arg, timeoutSeconds);
|
||||
}
|
||||
|
||||
void runTest ()
|
||||
{
|
||||
typedef boost::asio::ip::tcp protocol;
|
||||
testDetails <TcpDetails, TcpDetails::arg_type> (protocol::v4 ());
|
||||
testDetails <TcpDetails, TcpDetails::arg_type> (protocol::v6 ());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
enum
|
||||
{
|
||||
timeoutSeconds = 10
|
||||
};
|
||||
|
||||
TestPeerUnitTests () : UnitTest ("TestPeer", "beast")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static TestPeerUnitTests testPeerUnitTests;
|
||||
1
src/beast/modules/beast_boost/.gitignore
vendored
Normal file
1
src/beast/modules/beast_boost/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/boost-subtree
|
||||
324
src/beast/modules/beast_core/beast_core.cpp
Normal file
324
src/beast/modules/beast_core/beast_core.cpp
Normal file
@@ -0,0 +1,324 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#if defined BEAST_CORE_H_INCLUDED
|
||||
/* When you add this cpp file to your project, you mustn't include it in a file where you've
|
||||
already included any other headers - just put it inside a file on its own, possibly with your config
|
||||
flags preceding it, but don't include anything else. That also includes avoiding any automatic prefix
|
||||
header files that the compiler may be using.
|
||||
*/
|
||||
#error "Incorrect use of BEAST cpp file"
|
||||
#endif
|
||||
|
||||
// Your project must contain a BeastConfig.h file with your project-specific settings in it,
|
||||
// and your header search path must make it accessible to the module's files.
|
||||
#include "BeastConfig.h"
|
||||
|
||||
//==============================================================================
|
||||
#include "native/beast_BasicNativeHeaders.h"
|
||||
#include "beast_core.h"
|
||||
|
||||
#include <locale>
|
||||
#include <cctype>
|
||||
|
||||
#if ! BEAST_BSD
|
||||
#include <sys/timeb.h>
|
||||
#endif
|
||||
|
||||
#if ! BEAST_ANDROID
|
||||
#include <cwctype>
|
||||
#endif
|
||||
|
||||
#if BEAST_WINDOWS
|
||||
#include <ctime>
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#if ! BEAST_MINGW
|
||||
#include <Dbghelp.h>
|
||||
|
||||
#if ! BEAST_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||
#pragma comment (lib, "DbgHelp.lib")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BEAST_MINGW
|
||||
#include <ws2spi.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
#if BEAST_LINUX || BEAST_ANDROID
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/errno.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#if BEAST_LINUX
|
||||
#include <langinfo.h>
|
||||
#endif
|
||||
|
||||
#include <pwd.h>
|
||||
#include <fcntl.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/time.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#if ! BEAST_ANDROID && ! BEAST_BSD
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BEAST_MAC || BEAST_IOS
|
||||
#include <xlocale.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
#if BEAST_ANDROID
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// If the MSVC debug heap headers were included, disable
|
||||
// the macros during the juce include since they conflict.
|
||||
#ifdef _CRTDBG_MAP_ALLOC
|
||||
#pragma push_macro("calloc")
|
||||
#pragma push_macro("free")
|
||||
#pragma push_macro("malloc")
|
||||
#pragma push_macro("realloc")
|
||||
#pragma push_macro("_recalloc")
|
||||
#pragma push_macro("_aligned_free")
|
||||
#pragma push_macro("_aligned_malloc")
|
||||
#pragma push_macro("_aligned_offset_malloc")
|
||||
#pragma push_macro("_aligned_realloc")
|
||||
#pragma push_macro("_aligned_recalloc")
|
||||
#pragma push_macro("_aligned_offset_realloc")
|
||||
#pragma push_macro("_aligned_offset_recalloc")
|
||||
#pragma push_macro("_aligned_msize")
|
||||
#undef calloc
|
||||
#undef free
|
||||
#undef malloc
|
||||
#undef realloc
|
||||
#undef _recalloc
|
||||
#undef _aligned_free
|
||||
#undef _aligned_malloc
|
||||
#undef _aligned_offset_malloc
|
||||
#undef _aligned_realloc
|
||||
#undef _aligned_recalloc
|
||||
#undef _aligned_offset_realloc
|
||||
#undef _aligned_offset_recalloc
|
||||
#undef _aligned_msize
|
||||
#endif
|
||||
|
||||
namespace beast
|
||||
{
|
||||
|
||||
#include "containers/beast_AbstractFifo.cpp"
|
||||
#include "containers/beast_DynamicObject.cpp"
|
||||
#include "containers/beast_NamedValueSet.cpp"
|
||||
#include "containers/beast_PropertySet.cpp"
|
||||
#include "containers/beast_Variant.cpp"
|
||||
#include "containers/DynamicArray.cpp"
|
||||
#include "containers/DynamicList.cpp"
|
||||
#include "containers/HashMap.cpp"
|
||||
|
||||
#include "diagnostic/beast_Debug.cpp"
|
||||
#include "diagnostic/beast_Error.cpp"
|
||||
#include "diagnostic/beast_FatalError.cpp"
|
||||
#include "diagnostic/beast_FPUFlags.cpp"
|
||||
#include "diagnostic/beast_LeakChecked.cpp"
|
||||
#include "diagnostic/beast_ProtectedCall.cpp"
|
||||
#include "diagnostic/beast_SemanticVersion.cpp"
|
||||
#include "diagnostic/beast_UnitTest.cpp"
|
||||
#include "diagnostic/beast_UnitTestUtilities.cpp"
|
||||
|
||||
#include "files/beast_DirectoryIterator.cpp"
|
||||
#include "files/beast_File.cpp"
|
||||
#include "files/beast_FileInputStream.cpp"
|
||||
#include "files/beast_FileOutputStream.cpp"
|
||||
#include "files/beast_FileSearchPath.cpp"
|
||||
#include "files/beast_RandomAccessFile.cpp"
|
||||
#include "files/beast_TemporaryFile.cpp"
|
||||
|
||||
#include "json/beast_JSON.cpp"
|
||||
|
||||
#include "logging/beast_FileLogger.cpp"
|
||||
#include "logging/beast_Logger.cpp"
|
||||
|
||||
#include "maths/beast_BigInteger.cpp"
|
||||
#include "maths/beast_Expression.cpp"
|
||||
#include "maths/beast_MurmurHash.cpp"
|
||||
#include "maths/beast_Random.cpp"
|
||||
|
||||
#include "memory/beast_MemoryBlock.cpp"
|
||||
#include "memory/beast_FifoFreeStoreWithTLS.cpp"
|
||||
#include "memory/beast_FifoFreeStoreWithoutTLS.cpp"
|
||||
#include "memory/beast_GlobalPagedFreeStore.cpp"
|
||||
#include "memory/beast_PagedFreeStore.cpp"
|
||||
|
||||
#include "misc/beast_Main.cpp"
|
||||
#include "misc/beast_Result.cpp"
|
||||
#include "misc/beast_Uuid.cpp"
|
||||
|
||||
#include "network/beast_MACAddress.cpp"
|
||||
#include "network/beast_NamedPipe.cpp"
|
||||
#include "network/beast_Socket.cpp"
|
||||
#include "network/beast_URL.cpp"
|
||||
#include "network/beast_IPAddress.cpp"
|
||||
|
||||
#include "streams/beast_BufferedInputStream.cpp"
|
||||
#include "streams/beast_FileInputSource.cpp"
|
||||
#include "streams/beast_InputStream.cpp"
|
||||
#include "streams/beast_MemoryInputStream.cpp"
|
||||
#include "streams/beast_MemoryOutputStream.cpp"
|
||||
#include "streams/beast_OutputStream.cpp"
|
||||
#include "streams/beast_SubregionStream.cpp"
|
||||
|
||||
#include "system/SystemStats.cpp"
|
||||
|
||||
#include "text/beast_CharacterFunctions.cpp"
|
||||
#include "text/beast_LexicalCast.cpp"
|
||||
#include "text/beast_Identifier.cpp"
|
||||
#include "text/beast_LocalisedStrings.cpp"
|
||||
#include "text/beast_String.cpp"
|
||||
#include "text/beast_StringArray.cpp"
|
||||
#include "text/beast_StringPairArray.cpp"
|
||||
#include "text/beast_StringPool.cpp"
|
||||
#include "text/beast_TextDiff.cpp"
|
||||
|
||||
#include "thread/impl/TrackedMutex.cpp"
|
||||
#include "thread/beast_DeadlineTimer.cpp"
|
||||
#include "thread/beast_InterruptibleThread.cpp"
|
||||
#include "thread/beast_Semaphore.cpp"
|
||||
#include "thread/beast_CallQueue.cpp"
|
||||
#include "thread/beast_Listeners.cpp"
|
||||
#include "thread/beast_ManualCallQueue.cpp"
|
||||
#include "thread/beast_ParallelFor.cpp"
|
||||
#include "thread/beast_ThreadGroup.cpp"
|
||||
#include "thread/beast_ThreadWithCallQueue.cpp"
|
||||
#include "thread/beast_Workers.cpp"
|
||||
|
||||
#include "threads/beast_ChildProcess.cpp"
|
||||
#include "threads/beast_ReadWriteLock.cpp"
|
||||
#include "threads/beast_ReadWriteMutex.cpp"
|
||||
#include "threads/beast_SpinDelay.cpp"
|
||||
#include "threads/beast_Thread.cpp"
|
||||
#include "threads/beast_ThreadPool.cpp"
|
||||
#include "threads/beast_TimeSliceThread.cpp"
|
||||
|
||||
#include "time/beast_PerformanceCounter.cpp"
|
||||
#include "time/beast_PerformedAtExit.cpp"
|
||||
#include "time/beast_RelativeTime.cpp"
|
||||
#include "time/beast_Time.cpp"
|
||||
|
||||
#include "xml/beast_XmlDocument.cpp"
|
||||
#include "xml/beast_XmlElement.cpp"
|
||||
|
||||
#include "zip/beast_GZIPDecompressorInputStream.cpp"
|
||||
#include "zip/beast_GZIPCompressorOutputStream.cpp"
|
||||
#include "zip/beast_ZipFile.cpp"
|
||||
|
||||
#if BEAST_MAC || BEAST_IOS
|
||||
#include "native/beast_osx_ObjCHelpers.h"
|
||||
#endif
|
||||
|
||||
#if BEAST_WINDOWS
|
||||
#include "native/beast_win32_FPUFlags.cpp"
|
||||
#else
|
||||
#include "native/beast_posix_FPUFlags.cpp"
|
||||
#endif
|
||||
|
||||
#if BEAST_ANDROID
|
||||
#include "native/beast_android_JNIHelpers.h"
|
||||
#endif
|
||||
|
||||
#if ! BEAST_WINDOWS
|
||||
#include "native/beast_posix_SharedCode.h"
|
||||
#include "native/beast_posix_NamedPipe.cpp"
|
||||
#endif
|
||||
|
||||
#if BEAST_MAC || BEAST_IOS
|
||||
#include "native/beast_mac_Files.mm"
|
||||
#include "native/beast_mac_Network.mm"
|
||||
#include "native/beast_mac_Strings.mm"
|
||||
#include "native/beast_mac_SystemStats.mm"
|
||||
#include "native/beast_mac_Threads.mm"
|
||||
|
||||
#elif BEAST_WINDOWS
|
||||
#include "native/beast_win32_ComSmartPtr.h"
|
||||
#include "native/beast_win32_Files.cpp"
|
||||
#include "native/beast_win32_Network.cpp"
|
||||
#include "native/beast_win32_Registry.cpp"
|
||||
#include "native/beast_win32_SystemStats.cpp"
|
||||
#include "native/beast_win32_Threads.cpp"
|
||||
|
||||
#elif BEAST_LINUX
|
||||
#include "native/beast_linux_Files.cpp"
|
||||
#include "native/beast_linux_Network.cpp"
|
||||
#include "native/beast_linux_SystemStats.cpp"
|
||||
#include "native/beast_linux_Threads.cpp"
|
||||
|
||||
#elif BEAST_BSD
|
||||
#include "native/beast_bsd_Files.cpp"
|
||||
#include "native/beast_bsd_Network.cpp"
|
||||
#include "native/beast_bsd_SystemStats.cpp"
|
||||
#include "native/beast_bsd_Threads.cpp"
|
||||
|
||||
#elif BEAST_ANDROID
|
||||
#include "native/beast_android_Files.cpp"
|
||||
#include "native/beast_android_Misc.cpp"
|
||||
#include "native/beast_android_Network.cpp"
|
||||
#include "native/beast_android_SystemStats.cpp"
|
||||
#include "native/beast_android_Threads.cpp"
|
||||
|
||||
#endif
|
||||
|
||||
#include "threads/beast_HighResolutionTimer.cpp"
|
||||
|
||||
}
|
||||
|
||||
#ifdef _CRTDBG_MAP_ALLOC
|
||||
#pragma pop_macro("calloc")
|
||||
#pragma pop_macro("free")
|
||||
#pragma pop_macro("malloc")
|
||||
#pragma pop_macro("realloc")
|
||||
#pragma pop_macro("_recalloc")
|
||||
#pragma pop_macro("_aligned_free")
|
||||
#pragma pop_macro("_aligned_malloc")
|
||||
#pragma pop_macro("_aligned_offset_malloc")
|
||||
#pragma pop_macro("_aligned_realloc")
|
||||
#pragma pop_macro("_aligned_recalloc")
|
||||
#pragma pop_macro("_aligned_offset_realloc")
|
||||
#pragma pop_macro("_aligned_offset_recalloc")
|
||||
#pragma pop_macro("_aligned_msize")
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Must be outside the namespace
|
||||
#include "system/BoostPlaceholdersFix.cpp"
|
||||
453
src/beast/modules/beast_core/beast_core.h
Normal file
453
src/beast/modules/beast_core/beast_core.h
Normal file
@@ -0,0 +1,453 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.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_CORE_H_INCLUDED
|
||||
#define BEAST_CORE_H_INCLUDED
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
|
||||
@mainpage Beast: A C++ library for peer to peer and client server development.
|
||||
|
||||
### Version 1.0
|
||||
|
||||
Copyright 2008, 2013 by Vinnie Falco \<vinnie.falco@gmail.com\> ([e-mail][0])
|
||||
|
||||
Beast is a source code collection of individual modules containing
|
||||
functionality for a variety of applications, with an emphasis on building
|
||||
concurrent systems. Beast incorporates parts of [JUCE][3] (Jules' Utility
|
||||
Class Extensions), available from [Raw Material Software][4]. Beast has no
|
||||
external dependencies
|
||||
|
||||
Beast is hosted on Github at [https://github.com/vinniefalco/Beast][1]
|
||||
|
||||
The online documentation is at [http://vinniefalco.github.com/Beast][2]
|
||||
|
||||
## Platforms
|
||||
|
||||
All platforms supported by JUCE are also supported by Beast. Currently these
|
||||
platforms include:
|
||||
|
||||
- **Windows**: Applications and VST/RTAS/NPAPI/ActiveX plugins can be built
|
||||
using MS Visual Studio. The results are all fully compatible with Windows
|
||||
XP, Vista or Windows 7.
|
||||
|
||||
- **Mac OS X**: Applications and VST/AudioUnit/RTAS/NPAPI plugins with Xcode.
|
||||
|
||||
- **GNU/Linux**: Applications and plugins can be built for any kernel 2.6 or
|
||||
later.
|
||||
|
||||
- **FreeBSD**: Kernel version 8.4 or higher required.
|
||||
|
||||
- **iOS**: Native iPhone and iPad apps.
|
||||
|
||||
- **Android**: Supported.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
This documentation assumes that the reader has a working knowledge of JUCE.
|
||||
Some modules built on external libraries assume that the reader understands
|
||||
the operation of those external libraries. Certain modules assume that the
|
||||
reader understands additional domain-specific information. Modules with
|
||||
additional prerequisites are marked in the documentation.
|
||||
|
||||
## External Modules
|
||||
|
||||
Some modules bring in functionality provided by external libraries. For
|
||||
example, the @ref beast_bzip2 module provides the compression and decompression
|
||||
algorithms in [bZip2][7]. Usage of these external library modules is optional.
|
||||
They come with complete source code, as well as options for using either
|
||||
system or user provided variants of the external libraries: it is not
|
||||
necessary to download additional source code packages to use these modules.
|
||||
|
||||
External code incorporated into Beast is covered by separate licenses. See
|
||||
the licensing information and notes in the corresponding source files for
|
||||
copyright information and terms of use.
|
||||
|
||||
## Integration
|
||||
|
||||
Beast requires recent versions of JUCE. It won't work with versions 1.53 or
|
||||
earlier. To use the library it is necessary to first download JUCE to a
|
||||
location where your development environment can find it. Or, you can use your
|
||||
existing installation of JUCE.
|
||||
|
||||
This library uses the same modularized organizational structure as JUCE. To
|
||||
use a module, first add a path to the list of includes searched by your
|
||||
development environment or project, which points to the Beast directory. Then,
|
||||
add the single corresponding .c or .cpp file to your existing project which
|
||||
already uses JUCE. For example, to use the @ref beast_core module, add the file
|
||||
beast_core.cpp to your project. Some modules depend on other modules.
|
||||
|
||||
To use a module, include the appropriate header from within your source code.
|
||||
For example, to access classes in the @ref beast_concurrent module, use this:
|
||||
|
||||
@code
|
||||
|
||||
#include "modules/beast_concurrent/beast_concurrent.h"
|
||||
|
||||
@endcode
|
||||
|
||||
Then add the corresponding file beast_concurrent.cpp to your build.
|
||||
|
||||
## AppConfig
|
||||
|
||||
Some Beast features can be controlled at compilation time through
|
||||
preprocessor directives. The available choices of compilation options are
|
||||
described in AppConfig.h, located in the AppConfigTemplate directory. Copy
|
||||
the provided settings into your existing AppConfig.h (a file used by JUCE
|
||||
convention).
|
||||
|
||||
## License
|
||||
|
||||
This library contains portions of other open source products covered by
|
||||
separate licenses. Please see the corresponding source files for specific
|
||||
terms.
|
||||
|
||||
Beast is provided under the terms of The ISC License:
|
||||
|
||||
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.
|
||||
|
||||
Some files contain portions of these external projects, licensed separately:
|
||||
|
||||
- [bZip2][7] is Copyright (C) 1996-2010 Julian R Seward. All rights
|
||||
reserved. See the corresponding file LICENSE for licensing terms.
|
||||
|
||||
- [Soci][13] is Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton, and
|
||||
various others noted in the corresponding source files. Soci is distributed
|
||||
under the [Boost Software License, Version 1.0][14].
|
||||
|
||||
- [SQLite][15], placed in the public domain.
|
||||
|
||||
[0]: mailto:vinnie.falco@gmail.com "Vinnie Falco (Email)"
|
||||
[1]: https://github.com/vinniefalco/Beast "Beast Project"
|
||||
[2]: http://vinniefalco.github.com/Beast/ "Beast Documentation"
|
||||
[3]: http://rawmaterialsoftware.com/juce.php "JUCE"
|
||||
[4]: http://rawmaterialsoftware.com/ "Raw Material Software"
|
||||
[5]: http://www.gnu.org/licenses/gpl-2.0.html "GNU General Public License, version 2"
|
||||
[6]: http://rawmaterialsoftware.com/jucelicense.php "JUCE Licenses"
|
||||
[7]: http://www.bzip.org/ "bZip2: Home"
|
||||
[8]: http://freetype.org/ "The FreeType Project"
|
||||
[9]: http://www.freetype.org/FTL.TXT "The FreeType Project License"
|
||||
[10]: http://www.lua.org/ "The Programming Language Lua"
|
||||
[11]: http://opensource.org/licenses/ISC "The ISC License"
|
||||
[12]: https://github.com/vinniefalco/LuaBridge
|
||||
[13]: http://soci.sourceforge.net/ "SOCI"
|
||||
[14]: http://www.boost.org/LICENSE_1_0.txt "Boost Software License, Version 1.0"
|
||||
[15]: http://sqlite.org/ "SQLite Home Page"
|
||||
[16]: http://developer.kde.org/~wheeler/taglib.html "TagLib"
|
||||
[17]: http://www.gnu.org/licenses/lgpl-2.1.html "Gnu Lesser General Public License, version 2.1"
|
||||
[18]: http://www.mozilla.org/MPL/1.1/ "Mozilla Public License"
|
||||
|
||||
@copyright Copyright 2008-2013 by Vinnie Falco \<vinnie.falco@gmail.com\> ([e-mail][0])
|
||||
@copyright Provided under the [ISC LIcense][11]
|
||||
*/
|
||||
|
||||
# include "system/BeforeBoost.h"
|
||||
# include "system/BoostIncludes.h"
|
||||
#include "system/FunctionalIncludes.h"
|
||||
|
||||
#include "system/StandardHeader.h"
|
||||
|
||||
#if BEAST_MSVC
|
||||
# pragma warning (disable: 4251) // (DLL build warning, must be disabled before pushing the warning state)
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable: 4786) // (long class name warning)
|
||||
# ifdef __INTEL_COMPILER
|
||||
# pragma warning (disable: 1125)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// If the MSVC debug heap headers were included, disable
|
||||
// the macros during the juce include since they conflict.
|
||||
#ifdef _CRTDBG_MAP_ALLOC
|
||||
#pragma push_macro("calloc")
|
||||
#pragma push_macro("free")
|
||||
#pragma push_macro("malloc")
|
||||
#pragma push_macro("realloc")
|
||||
#pragma push_macro("_recalloc")
|
||||
#pragma push_macro("_aligned_free")
|
||||
#pragma push_macro("_aligned_malloc")
|
||||
#pragma push_macro("_aligned_offset_malloc")
|
||||
#pragma push_macro("_aligned_realloc")
|
||||
#pragma push_macro("_aligned_recalloc")
|
||||
#pragma push_macro("_aligned_offset_realloc")
|
||||
#pragma push_macro("_aligned_offset_recalloc")
|
||||
#pragma push_macro("_aligned_msize")
|
||||
#undef calloc
|
||||
#undef free
|
||||
#undef malloc
|
||||
#undef realloc
|
||||
#undef _recalloc
|
||||
#undef _aligned_free
|
||||
#undef _aligned_malloc
|
||||
#undef _aligned_offset_malloc
|
||||
#undef _aligned_realloc
|
||||
#undef _aligned_recalloc
|
||||
#undef _aligned_offset_realloc
|
||||
#undef _aligned_offset_recalloc
|
||||
#undef _aligned_msize
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// New header-only library modeled more closely according to boost
|
||||
#include "../../beast/intrusive/ForwardList.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace beast
|
||||
{
|
||||
|
||||
class InputStream;
|
||||
class OutputStream;
|
||||
class FileInputStream;
|
||||
class FileOutputStream;
|
||||
|
||||
extern BEAST_API bool BEAST_CALLTYPE beast_isRunningUnderDebugger();
|
||||
extern BEAST_API void BEAST_CALLTYPE logAssertion (char const* file, int line) noexcept;
|
||||
|
||||
// Order matters, since headers don't have their own #include lines.
|
||||
// Add new includes to the bottom.
|
||||
|
||||
#include "diagnostic/ContractChecks.h"
|
||||
#include "memory/beast_Uncopyable.h"
|
||||
#include "memory/beast_Memory.h"
|
||||
#include "maths/beast_MathsFunctions.h"
|
||||
#include "memory/beast_ByteOrder.h"
|
||||
#include "memory/beast_Atomic.h"
|
||||
#include "text/beast_CharacterFunctions.h"
|
||||
|
||||
#if BEAST_MSVC
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable: 4514 4996)
|
||||
#endif
|
||||
#include "text/beast_CharPointer_UTF8.h"
|
||||
#include "text/beast_CharPointer_UTF16.h"
|
||||
#include "text/beast_CharPointer_UTF32.h"
|
||||
#include "text/beast_CharPointer_ASCII.h"
|
||||
#if BEAST_MSVC
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
# include "containers/detail/removecv.h"
|
||||
#include "containers/detail/copyconst.h"
|
||||
#include "system/PlatformDefs.h"
|
||||
#include "system/TargetPlatform.h"
|
||||
#include "diagnostic/beast_Throw.h"
|
||||
#include "system/Functional.h"
|
||||
#include "memory/beast_AtomicCounter.h"
|
||||
#include "memory/beast_AtomicFlag.h"
|
||||
#include "memory/beast_AtomicPointer.h"
|
||||
#include "memory/beast_AtomicState.h"
|
||||
#include "containers/List.h"
|
||||
#include "containers/beast_LockFreeStack.h"
|
||||
#include "threads/beast_SpinDelay.h"
|
||||
#include "memory/beast_StaticObject.h"
|
||||
|
||||
#include "text/StringCharPointerType.h"
|
||||
#include "text/StringFromNumber.h"
|
||||
#include "text/beast_String.h"
|
||||
#include "time/beast_PerformedAtExit.h"
|
||||
#include "diagnostic/beast_LeakChecked.h"
|
||||
#include "time/beast_RelativeTime.h"
|
||||
#include "time/beast_Time.h"
|
||||
#include "memory/beast_HeapBlock.h"
|
||||
#include "threads/beast_ScopedLock.h"
|
||||
#include "threads/beast_CriticalSection.h"
|
||||
#include "containers/beast_ElementComparator.h"
|
||||
#include "containers/beast_ArrayAllocationBase.h"
|
||||
#include "containers/beast_Array.h"
|
||||
#include "misc/beast_Result.h"
|
||||
#include "text/beast_StringArray.h"
|
||||
#include "memory/beast_MemoryBlock.h"
|
||||
#include "files/beast_File.h"
|
||||
#include "time/beast_PerformanceCounter.h"
|
||||
|
||||
#include "memory/beast_MemoryAlignment.h"
|
||||
#include "memory/beast_CacheLine.h"
|
||||
#include "threads/beast_ReadWriteMutex.h"
|
||||
#include "threads/beast_SharedData.h"
|
||||
#include "diagnostic/beast_SafeBool.h"
|
||||
#include "threads/beast_WaitableEvent.h"
|
||||
#include "threads/beast_Thread.h"
|
||||
#include "threads/beast_SpinLock.h"
|
||||
#include "threads/beast_ThreadLocalValue.h"
|
||||
#include "thread/MutexTraits.h"
|
||||
#include "thread/TrackedMutex.h"
|
||||
#include "diagnostic/beast_FatalError.h"
|
||||
#include "diagnostic/beast_Error.h"
|
||||
#include "diagnostic/beast_Debug.h"
|
||||
#include "text/beast_LexicalCast.h"
|
||||
#include "memory/beast_ContainerDeletePolicy.h"
|
||||
#include "memory/beast_ByteSwap.h"
|
||||
#include "maths/beast_Math.h"
|
||||
#include "maths/beast_uint24.h"
|
||||
#include "logging/beast_Logger.h"
|
||||
#include "diagnostic/beast_FPUFlags.h"
|
||||
#include "memory/SharedObject.h"
|
||||
#include "memory/SharedPtr.h"
|
||||
#include "functional/SharedFunction.h"
|
||||
#include "diagnostic/beast_ProtectedCall.h"
|
||||
#include "containers/beast_AbstractFifo.h"
|
||||
#include "text/beast_Identifier.h"
|
||||
#include "containers/beast_Variant.h"
|
||||
#include "containers/beast_LinkedListPointer.h"
|
||||
#include "containers/beast_NamedValueSet.h"
|
||||
#include "containers/beast_DynamicObject.h"
|
||||
#include "maths/beast_BigInteger.h"
|
||||
#include "maths/beast_Random.h"
|
||||
#include "containers/beast_LockFreeQueue.h"
|
||||
#include "containers/beast_OwnedArray.h"
|
||||
#include "text/beast_StringPairArray.h"
|
||||
#include "containers/beast_PropertySet.h"
|
||||
#include "containers/beast_SharedObjectArray.h"
|
||||
#include "containers/beast_ScopedValueSetter.h"
|
||||
#include "containers/beast_SharedTable.h"
|
||||
#include "containers/beast_SortedLookupTable.h"
|
||||
#include "containers/beast_SortedSet.h"
|
||||
#include "maths/beast_Range.h"
|
||||
#include "containers/beast_SparseSet.h"
|
||||
# include "containers/DynamicList.h"
|
||||
# include "containers/DynamicArray.h"
|
||||
#include "containers/HashMap.h"
|
||||
#include "memory/beast_ScopedPointer.h"
|
||||
#include "files/beast_DirectoryIterator.h"
|
||||
#include "streams/beast_InputStream.h"
|
||||
#include "files/beast_FileInputStream.h"
|
||||
#include "streams/beast_InputSource.h"
|
||||
#include "streams/beast_FileInputSource.h"
|
||||
#include "text/beast_NewLine.h"
|
||||
#include "streams/beast_OutputStream.h"
|
||||
#include "files/beast_FileOutputStream.h"
|
||||
#include "files/beast_FileSearchPath.h"
|
||||
#include "files/beast_MemoryMappedFile.h"
|
||||
#include "files/beast_RandomAccessFile.h"
|
||||
#include "files/beast_TemporaryFile.h"
|
||||
#include "json/beast_JSON.h"
|
||||
#include "logging/beast_FileLogger.h"
|
||||
#include "logging/beast_Logger.h"
|
||||
#include "maths/beast_Expression.h"
|
||||
#include "maths/beast_Interval.h"
|
||||
#include "maths/beast_MathsFunctions.h"
|
||||
#include "maths/beast_MurmurHash.h"
|
||||
#include "memory/beast_ByteOrder.h"
|
||||
#include "memory/beast_Memory.h"
|
||||
#include "memory/beast_OptionalScopedPointer.h"
|
||||
#include "memory/beast_SharedSingleton.h"
|
||||
#include "memory/beast_WeakReference.h"
|
||||
#include "memory/beast_RecycledObjectPool.h"
|
||||
#include "misc/beast_Main.h"
|
||||
#include "misc/beast_Uuid.h"
|
||||
#include "misc/beast_WindowsRegistry.h"
|
||||
#include "network/beast_IPAddress.h"
|
||||
#include "network/beast_MACAddress.h"
|
||||
#include "threads/beast_ReadWriteLock.h"
|
||||
#include "network/beast_NamedPipe.h"
|
||||
#include "network/beast_Socket.h"
|
||||
#include "network/beast_URL.h"
|
||||
#include "streams/beast_BufferedInputStream.h"
|
||||
#include "streams/beast_MemoryInputStream.h"
|
||||
#include "streams/beast_MemoryOutputStream.h"
|
||||
#include "streams/beast_SubregionStream.h"
|
||||
|
||||
#include "system/SystemStats.h"
|
||||
#include "text/beast_LocalisedStrings.h"
|
||||
#include "diagnostic/beast_SemanticVersion.h"
|
||||
#include "text/beast_StringPool.h"
|
||||
#include "text/beast_TextDiff.h"
|
||||
#include "threads/beast_ChildProcess.h"
|
||||
#include "threads/beast_DynamicLibrary.h"
|
||||
#include "threads/beast_HighResolutionTimer.h"
|
||||
#include "threads/beast_InterProcessLock.h"
|
||||
#include "threads/beast_Process.h"
|
||||
#include "threads/beast_ScopedReadLock.h"
|
||||
#include "threads/beast_ScopedWriteLock.h"
|
||||
#include "threads/beast_ThreadPool.h"
|
||||
#include "threads/beast_TimeSliceThread.h"
|
||||
#include "diagnostic/beast_UnitTest.h"
|
||||
#include "xml/beast_XmlDocument.h"
|
||||
#include "xml/beast_XmlElement.h"
|
||||
#include "diagnostic/beast_UnitTestUtilities.h"
|
||||
#include "zip/beast_GZIPCompressorOutputStream.h"
|
||||
#include "zip/beast_GZIPDecompressorInputStream.h"
|
||||
#include "zip/beast_ZipFile.h"
|
||||
|
||||
#include "diagnostic/MeasureFunctionCallTime.h"
|
||||
|
||||
#include "functional/beast_Function.h"
|
||||
|
||||
#include "thread/beast_DeadlineTimer.h"
|
||||
|
||||
#include "memory/beast_AllocatedBy.h"
|
||||
#include "memory/beast_PagedFreeStore.h"
|
||||
#include "memory/beast_GlobalPagedFreeStore.h"
|
||||
#include "memory/beast_FifoFreeStoreWithTLS.h"
|
||||
#include "memory/beast_FifoFreeStoreWithoutTLS.h"
|
||||
#include "memory/beast_FifoFreeStore.h"
|
||||
#include "memory/beast_GlobalFifoFreeStore.h"
|
||||
|
||||
#include "thread/beast_Semaphore.h"
|
||||
#include "thread/beast_SerialFor.h"
|
||||
#include "thread/beast_InterruptibleThread.h"
|
||||
#include "thread/beast_ThreadGroup.h"
|
||||
#include "thread/beast_CallQueue.h"
|
||||
#include "thread/beast_GlobalThreadGroup.h"
|
||||
#include "thread/beast_Listeners.h"
|
||||
#include "thread/beast_ManualCallQueue.h"
|
||||
#include "thread/beast_ParallelFor.h"
|
||||
#include "thread/beast_ThreadWithCallQueue.h"
|
||||
#include "thread/beast_Workers.h"
|
||||
|
||||
}
|
||||
|
||||
#ifdef _CRTDBG_MAP_ALLOC
|
||||
#pragma pop_macro("_aligned_msize")
|
||||
#pragma pop_macro("_aligned_offset_recalloc")
|
||||
#pragma pop_macro("_aligned_offset_realloc")
|
||||
#pragma pop_macro("_aligned_recalloc")
|
||||
#pragma pop_macro("_aligned_realloc")
|
||||
#pragma pop_macro("_aligned_offset_malloc")
|
||||
#pragma pop_macro("_aligned_malloc")
|
||||
#pragma pop_macro("_aligned_free")
|
||||
#pragma pop_macro("_recalloc")
|
||||
#pragma pop_macro("realloc")
|
||||
#pragma pop_macro("malloc")
|
||||
#pragma pop_macro("free")
|
||||
#pragma pop_macro("calloc")
|
||||
#endif
|
||||
|
||||
#if BEAST_MSVC
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
24
src/beast/modules/beast_core/beast_core.mm
Normal file
24
src/beast/modules/beast_core/beast_core.mm
Normal file
@@ -0,0 +1,24 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include "beast_core.cpp"
|
||||
175
src/beast/modules/beast_core/containers/DynamicArray.cpp
Normal file
175
src/beast/modules/beast_core/containers/DynamicArray.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
class DynamicArrayTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
struct T
|
||||
{
|
||||
T ()
|
||||
{
|
||||
}
|
||||
|
||||
explicit T (String what)
|
||||
: msg (what)
|
||||
{
|
||||
}
|
||||
|
||||
T& operator= (T const& other)
|
||||
{
|
||||
msg = other.msg;
|
||||
return *this;
|
||||
}
|
||||
|
||||
String msg;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
numberToAssign = 1000 * 1000,
|
||||
numberToReserve = 1000 * 1000,
|
||||
numberToMutate = 12139
|
||||
|
||||
};
|
||||
|
||||
void testAssign ()
|
||||
{
|
||||
String s;
|
||||
s << "assign (" << String::fromNumber <int> (numberToAssign) << ")";
|
||||
beginTestCase (s);
|
||||
|
||||
DynamicArray <T> v;
|
||||
v.assign (numberToAssign);
|
||||
|
||||
pass ();
|
||||
}
|
||||
|
||||
void testReserve ()
|
||||
{
|
||||
String s;
|
||||
s << "reserve (" << String::fromNumber <int> (numberToReserve) << ")";
|
||||
beginTestCase (s);
|
||||
|
||||
DynamicArray <T> v;
|
||||
v.reserve (numberToReserve);
|
||||
|
||||
v.assign (numberToReserve);
|
||||
|
||||
pass ();
|
||||
}
|
||||
|
||||
void testMutate ()
|
||||
{
|
||||
String s;
|
||||
DynamicArray <T> v;
|
||||
|
||||
s = "push_back (" + String::fromNumber <int> (numberToMutate) + ")";
|
||||
beginTestCase (s);
|
||||
for (std::size_t i = 0; i < numberToMutate; ++i)
|
||||
v.push_back (T (String::fromNumber (i)));
|
||||
pass ();
|
||||
|
||||
s = "read [] (" + String::fromNumber <int> (numberToMutate) + ")";
|
||||
beginTestCase (s);
|
||||
for (std::size_t i = 0; i < numberToMutate; ++i)
|
||||
expect (v [i].msg == String::fromNumber (i));
|
||||
|
||||
s = "write [] (" + String::fromNumber <int> (numberToMutate) + ")";
|
||||
beginTestCase (s);
|
||||
for (std::size_t i = 0; i < numberToMutate; ++i)
|
||||
v [i].msg = "+" + String::fromNumber (i);
|
||||
pass ();
|
||||
|
||||
s = "verify [] (" + String::fromNumber <int> (numberToMutate) + ")";
|
||||
beginTestCase (s);
|
||||
for (std::size_t i = 0; i < numberToMutate; ++i)
|
||||
expect (v [i].msg == String ("+") + String::fromNumber (i));
|
||||
}
|
||||
|
||||
void testIterate ()
|
||||
{
|
||||
typedef DynamicArray <T> V;
|
||||
|
||||
V v;
|
||||
for (std::size_t i = 0; i < numberToMutate; ++i)
|
||||
v.push_back (T (String::fromNumber (i)));
|
||||
|
||||
{
|
||||
int step = 1;
|
||||
beginTestCase ("iterator");
|
||||
V::iterator iter;
|
||||
for (iter = v.begin (); iter + step < v.end (); iter += step)
|
||||
{
|
||||
step ++;
|
||||
V::difference_type d = iter - v.begin ();
|
||||
expect (iter->msg == String::fromNumber (d));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int step = 1;
|
||||
beginTestCase ("const_iterator");
|
||||
V::const_iterator iter;
|
||||
for (iter = v.begin (); iter + step < v.end (); iter += step)
|
||||
{
|
||||
step ++;
|
||||
V::difference_type d = iter - v.begin ();
|
||||
expect (iter->msg == String::fromNumber (d));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int step = 1;
|
||||
beginTestCase ("reverse_iterator");
|
||||
V::reverse_iterator iter;
|
||||
for (iter = v.rbegin (); iter + step < v.rend (); iter += step)
|
||||
{
|
||||
step ++;
|
||||
iter - v.rend ();
|
||||
}
|
||||
pass ();
|
||||
}
|
||||
|
||||
{
|
||||
int step = 1;
|
||||
beginTestCase ("const_reverse_iterator");
|
||||
V::const_reverse_iterator iter;
|
||||
for (iter = v.crbegin (); iter + step < v.crend (); iter += step)
|
||||
{
|
||||
step ++;
|
||||
iter - v.crend ();
|
||||
}
|
||||
pass ();
|
||||
}
|
||||
}
|
||||
|
||||
void runTest ()
|
||||
{
|
||||
testAssign ();
|
||||
testReserve ();
|
||||
testMutate ();
|
||||
testIterate ();
|
||||
}
|
||||
|
||||
DynamicArrayTests () : UnitTest ("DynamicArray", "beast")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static DynamicArrayTests dynamicArrayTests;
|
||||
728
src/beast/modules/beast_core/containers/DynamicArray.h
Normal file
728
src/beast/modules/beast_core/containers/DynamicArray.h
Normal file
@@ -0,0 +1,728 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CORE_CONTAINERS_DYNAMICARRAY_H_INCLUDED
|
||||
#define BEAST_CORE_CONTAINERS_DYNAMICARRAY_H_INCLUDED
|
||||
|
||||
template <typename, typename>
|
||||
class DynamicArray;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename V>
|
||||
class DynamicArrayIterator
|
||||
: public std::iterator <std::random_access_iterator_tag,
|
||||
typename V::size_type>
|
||||
{
|
||||
public:
|
||||
typedef typename copyconst <V, typename V::value_type>::type
|
||||
|
||||
value_type;
|
||||
typedef value_type* pointer;
|
||||
typedef value_type& reference;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef typename V::size_type size_type;
|
||||
|
||||
DynamicArrayIterator (V* v = nullptr, size_type pos = 0) noexcept
|
||||
: m_v (v)
|
||||
, m_pos (pos)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
DynamicArrayIterator (DynamicArrayIterator <W> const& u) noexcept
|
||||
: m_v (u.m_v)
|
||||
, m_pos (u.m_pos)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
DynamicArrayIterator& operator= (DynamicArrayIterator <W> const& u) noexcept
|
||||
{
|
||||
m_v = u.m_v;
|
||||
m_pos = u.m_pos;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator== (DynamicArrayIterator <W> const& u) const noexcept
|
||||
{
|
||||
return (m_v == u.m_v) && (m_pos == u.m_pos);
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator!= (DynamicArrayIterator <W> const& u) const noexcept
|
||||
{
|
||||
return ! ((*this) == u);
|
||||
}
|
||||
|
||||
reference operator* () const noexcept
|
||||
{
|
||||
return dereference ();
|
||||
}
|
||||
|
||||
pointer operator-> () const noexcept
|
||||
{
|
||||
return &dereference ();
|
||||
}
|
||||
|
||||
DynamicArrayIterator& operator++ () noexcept
|
||||
{
|
||||
increment (1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
DynamicArrayIterator operator++ (int) noexcept
|
||||
{
|
||||
DynamicArrayIterator const result (*this);
|
||||
increment (1);
|
||||
return result;
|
||||
}
|
||||
|
||||
DynamicArrayIterator& operator-- () noexcept
|
||||
{
|
||||
decrement (1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
DynamicArrayIterator operator-- (int) noexcept
|
||||
{
|
||||
DynamicArrayIterator const result (*this);
|
||||
decrement (1);
|
||||
return result;
|
||||
}
|
||||
|
||||
DynamicArrayIterator& operator+= (difference_type n) noexcept
|
||||
{
|
||||
increment (n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
DynamicArrayIterator& operator-= (difference_type n) noexcept
|
||||
{
|
||||
decrement (n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
DynamicArrayIterator operator+ (difference_type n) noexcept
|
||||
{
|
||||
return DynamicArrayIterator (m_v, m_pos + n);
|
||||
}
|
||||
|
||||
DynamicArrayIterator operator- (difference_type n) noexcept
|
||||
{
|
||||
return DynamicArrayIterator (m_v, m_pos - n);
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
difference_type operator- (DynamicArrayIterator <W> const& rhs) const noexcept
|
||||
{
|
||||
return m_pos - rhs.m_pos;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator< (DynamicArrayIterator <W> const& rhs) const noexcept
|
||||
{
|
||||
return m_pos < rhs.m_pos;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator> (DynamicArrayIterator <W> const& rhs) const noexcept
|
||||
{
|
||||
return m_pos > rhs.m_pos;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator<= (DynamicArrayIterator <W> const& rhs) const noexcept
|
||||
{
|
||||
return m_pos <= rhs.m_pos;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator>= (DynamicArrayIterator <W> const& rhs) const noexcept
|
||||
{
|
||||
return m_pos >= rhs.m_pos;
|
||||
}
|
||||
|
||||
reference operator[] (difference_type n) noexcept
|
||||
{
|
||||
return (*m_v)[m_pos + n];
|
||||
}
|
||||
|
||||
private:
|
||||
reference dereference () const noexcept
|
||||
{
|
||||
return (*m_v) [m_pos];
|
||||
}
|
||||
|
||||
void increment (difference_type n) noexcept
|
||||
{
|
||||
m_pos += n;
|
||||
}
|
||||
|
||||
void decrement (difference_type n) noexcept
|
||||
{
|
||||
m_pos -= n;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename>
|
||||
friend class DynamicArrayIterator;
|
||||
|
||||
V* m_v;
|
||||
size_type m_pos;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename V>
|
||||
DynamicArrayIterator <V> operator+ (
|
||||
typename DynamicArrayIterator <V>::difference_type n,
|
||||
DynamicArrayIterator <V> iter) noexcept
|
||||
{
|
||||
return iter + n;
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
DynamicArrayIterator <V> operator- (
|
||||
typename DynamicArrayIterator <V>::difference_type n,
|
||||
DynamicArrayIterator <V> iter) noexcept
|
||||
{
|
||||
return iter - n;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename V>
|
||||
class DynamicArrayReverseIterator
|
||||
: public std::iterator <std::random_access_iterator_tag,
|
||||
typename V::size_type>
|
||||
{
|
||||
public:
|
||||
typedef typename copyconst <V, typename V::value_type>::type
|
||||
|
||||
value_type;
|
||||
typedef value_type* pointer;
|
||||
typedef value_type& reference;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef typename V::size_type size_type;
|
||||
|
||||
DynamicArrayReverseIterator (V* v = nullptr, difference_type pos = 0) noexcept
|
||||
: m_v (v)
|
||||
, m_pos (pos)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
DynamicArrayReverseIterator (DynamicArrayReverseIterator <W> const& u) noexcept
|
||||
: m_v (u.m_v)
|
||||
, m_pos (u.m_pos)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
DynamicArrayReverseIterator& operator= (DynamicArrayReverseIterator <W> const& u) noexcept
|
||||
{
|
||||
m_v = u.m_v;
|
||||
m_pos = u.m_pos;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator== (DynamicArrayReverseIterator <W> const& u) const noexcept
|
||||
{
|
||||
return (m_v == u.m_v) && (m_pos == u.m_pos);
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator!= (DynamicArrayReverseIterator <W> const& u) const noexcept
|
||||
{
|
||||
return ! ((*this) == u);
|
||||
}
|
||||
|
||||
reference operator* () const noexcept
|
||||
{
|
||||
return dereference ();
|
||||
}
|
||||
|
||||
pointer operator-> () const noexcept
|
||||
{
|
||||
return &dereference ();
|
||||
}
|
||||
|
||||
DynamicArrayReverseIterator& operator++ () noexcept
|
||||
{
|
||||
increment (1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
DynamicArrayReverseIterator operator++ (int) noexcept
|
||||
{
|
||||
DynamicArrayReverseIterator const result (*this);
|
||||
increment (1);
|
||||
return result;
|
||||
}
|
||||
|
||||
DynamicArrayReverseIterator& operator-- () noexcept
|
||||
{
|
||||
decrement (1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
DynamicArrayReverseIterator operator-- (int) noexcept
|
||||
{
|
||||
DynamicArrayReverseIterator const result (*this);
|
||||
decrement (1);
|
||||
return result;
|
||||
}
|
||||
|
||||
DynamicArrayReverseIterator& operator+= (difference_type n) noexcept
|
||||
{
|
||||
increment (n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
DynamicArrayReverseIterator& operator-= (difference_type n) noexcept
|
||||
{
|
||||
decrement (n);
|
||||
return *this;
|
||||
}
|
||||
|
||||
DynamicArrayReverseIterator operator+ (difference_type n) noexcept
|
||||
{
|
||||
return DynamicArrayReverseIterator (m_v, m_pos - n);
|
||||
}
|
||||
|
||||
DynamicArrayReverseIterator operator- (difference_type n) noexcept
|
||||
{
|
||||
return DynamicArrayReverseIterator (m_v, m_pos + n);
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
difference_type operator- (DynamicArrayReverseIterator <W> const& rhs) const noexcept
|
||||
{
|
||||
return rhs.m_pos - m_pos;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator< (DynamicArrayReverseIterator <W> const& rhs) const noexcept
|
||||
{
|
||||
return m_pos > rhs.m_pos;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator> (DynamicArrayReverseIterator <W> const& rhs) const noexcept
|
||||
{
|
||||
return m_pos < rhs.m_pos;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator<= (DynamicArrayReverseIterator <W> const& rhs) const noexcept
|
||||
{
|
||||
return m_pos >= rhs.m_pos;
|
||||
}
|
||||
|
||||
template <typename W>
|
||||
bool operator>= (DynamicArrayReverseIterator <W> const& rhs) const noexcept
|
||||
{
|
||||
return m_pos <= rhs.m_pos;
|
||||
}
|
||||
|
||||
reference operator[] (difference_type n) noexcept
|
||||
{
|
||||
return (*m_v)[(m_pos - 1) - n];
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename>
|
||||
friend class DynamicArrayReverseIterator;
|
||||
|
||||
reference dereference () const noexcept
|
||||
{
|
||||
return (*m_v) [m_pos - 1];
|
||||
}
|
||||
|
||||
void increment (difference_type n) noexcept
|
||||
{
|
||||
m_pos -= n;
|
||||
}
|
||||
|
||||
void decrement (difference_type n) noexcept
|
||||
{
|
||||
m_pos += n;
|
||||
}
|
||||
|
||||
V* m_v;
|
||||
difference_type m_pos;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename V>
|
||||
DynamicArrayReverseIterator <V> operator+ (
|
||||
typename DynamicArrayReverseIterator <V>::difference_type n,
|
||||
DynamicArrayReverseIterator <V> iter) noexcept
|
||||
{
|
||||
return iter + n;
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
DynamicArrayReverseIterator <V> operator- (
|
||||
typename DynamicArrayReverseIterator <V>::difference_type n,
|
||||
DynamicArrayReverseIterator <V> iter) noexcept
|
||||
{
|
||||
return iter - n;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename T,
|
||||
typename Allocator = std::allocator <char> >
|
||||
class DynamicArray
|
||||
{
|
||||
private:
|
||||
typedef PARAMETER_TYPE (T) TParam;
|
||||
|
||||
typedef std::vector <T*> handles_t;
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
defaultBlocksize = 1000,
|
||||
growthPercentage = 10
|
||||
};
|
||||
|
||||
typedef T value_type;
|
||||
typedef Allocator allocator_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef value_type* pointer;
|
||||
typedef value_type& reference;
|
||||
typedef value_type const* const_pointer;
|
||||
typedef value_type const& const_reference;
|
||||
|
||||
typedef detail::DynamicArrayIterator <DynamicArray <T> > iterator;
|
||||
|
||||
typedef detail::DynamicArrayIterator <DynamicArray <T> const> const_iterator;
|
||||
|
||||
typedef detail::DynamicArrayReverseIterator <DynamicArray <T> > reverse_iterator;
|
||||
|
||||
typedef detail::DynamicArrayReverseIterator <DynamicArray <T> const> const_reverse_iterator;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
explicit DynamicArray (size_type blocksize = defaultBlocksize) noexcept
|
||||
: m_blocksize (blocksize)
|
||||
, m_capacity (0)
|
||||
, m_size (0)
|
||||
{
|
||||
}
|
||||
|
||||
~DynamicArray()
|
||||
{
|
||||
clear ();
|
||||
shrink_to_fit ();
|
||||
}
|
||||
|
||||
/** Replace the array with 'count' copies of a default-constructed T.
|
||||
*/
|
||||
void assign (size_type count)
|
||||
{
|
||||
clear ();
|
||||
resize (count);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
reference at (size_type pos)
|
||||
{
|
||||
if (pos >= size ())
|
||||
Throw (std::out_of_range ("bad pos"), __FILE__, __LINE__);
|
||||
return get (pos);
|
||||
}
|
||||
|
||||
const_reference at (size_type pos) const
|
||||
{
|
||||
if (pos >= size ())
|
||||
Throw (std::out_of_range ("bad pos"), __FILE__, __LINE__);
|
||||
return get (pos);
|
||||
}
|
||||
|
||||
reference operator[] (size_type pos) noexcept
|
||||
{
|
||||
return get (pos);
|
||||
}
|
||||
|
||||
const_reference operator[] (size_type pos) const noexcept
|
||||
{
|
||||
return get (pos);
|
||||
}
|
||||
|
||||
reference front () noexcept
|
||||
{
|
||||
return get (0);
|
||||
}
|
||||
|
||||
const_reference front () const noexcept
|
||||
{
|
||||
return get (0);
|
||||
}
|
||||
|
||||
reference back () noexcept
|
||||
{
|
||||
return get (size () - 1);
|
||||
}
|
||||
|
||||
const_reference back () const noexcept
|
||||
{
|
||||
return get (size () - 1);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
iterator begin () noexcept
|
||||
{
|
||||
return iterator (this, 0);
|
||||
}
|
||||
|
||||
const_iterator begin () const noexcept
|
||||
{
|
||||
return const_iterator (this, 0);
|
||||
}
|
||||
|
||||
const_iterator cbegin () const noexcept
|
||||
{
|
||||
return const_iterator (this, 0);
|
||||
}
|
||||
|
||||
iterator end () noexcept
|
||||
{
|
||||
return iterator (this, size ());
|
||||
}
|
||||
|
||||
const_iterator end () const noexcept
|
||||
{
|
||||
return const_iterator (this, size ());
|
||||
}
|
||||
|
||||
const_iterator cend () const noexcept
|
||||
{
|
||||
return const_iterator (this, size ());
|
||||
}
|
||||
|
||||
reverse_iterator rbegin () noexcept
|
||||
{
|
||||
return reverse_iterator (this, size ());
|
||||
}
|
||||
|
||||
const_reverse_iterator rbegin () const noexcept
|
||||
{
|
||||
return const_reverse_iterator (this, size ());
|
||||
}
|
||||
|
||||
const_reverse_iterator crbegin () const noexcept
|
||||
{
|
||||
return const_reverse_iterator (this, size ());
|
||||
}
|
||||
|
||||
reverse_iterator rend () noexcept
|
||||
{
|
||||
return reverse_iterator (this, 0);
|
||||
}
|
||||
|
||||
const_reverse_iterator rend () const noexcept
|
||||
{
|
||||
return const_reverse_iterator (this, 0);
|
||||
}
|
||||
|
||||
const_reverse_iterator crend () const noexcept
|
||||
{
|
||||
return const_reverse_iterator (this, 0);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
bool empty () const noexcept
|
||||
{
|
||||
return m_size == 0;
|
||||
}
|
||||
|
||||
size_type size () const noexcept
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
size_type max_size () const noexcept
|
||||
{
|
||||
return std::numeric_limits <size_type>::max ();
|
||||
}
|
||||
|
||||
void reserve (size_type new_cap)
|
||||
{
|
||||
new_cap = m_blocksize * (
|
||||
(new_cap + m_blocksize - 1) / m_blocksize);
|
||||
if (new_cap > max_size ())
|
||||
Throw (std::length_error ("new_cap > max_size"), __FILE__, __LINE__);
|
||||
if (new_cap <= m_capacity)
|
||||
return;
|
||||
size_type const n (new_cap / m_blocksize);
|
||||
m_handles.reserve (n);
|
||||
for (size_type i = m_handles.size (); i < n; ++i)
|
||||
m_handles.push_back (static_cast <T*> (std::malloc (
|
||||
m_blocksize * sizeof (T))));
|
||||
m_capacity = new_cap;
|
||||
}
|
||||
|
||||
size_type capacity () const noexcept
|
||||
{
|
||||
return m_capacity;
|
||||
}
|
||||
|
||||
void shrink_to_fit ()
|
||||
{
|
||||
size_type const handles (
|
||||
(size () + m_blocksize - 1) / m_blocksize);
|
||||
m_capacity = handles * m_blocksize;
|
||||
for (size_type i = m_handles.size (); i-- > handles;)
|
||||
{
|
||||
std::free (m_handles [i]);
|
||||
m_handles.erase (m_handles.begin () + i);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void clear ()
|
||||
{
|
||||
resize (0);
|
||||
}
|
||||
|
||||
iterator push_back (TParam value)
|
||||
{
|
||||
::new (alloc ()) T (value);
|
||||
return iterator (this, size () - 1);
|
||||
}
|
||||
|
||||
iterator emplace_back ()
|
||||
{
|
||||
::new (alloc ()) T ();
|
||||
return iterator (this, size () - 1);
|
||||
}
|
||||
|
||||
template <class A1>
|
||||
iterator emplace_back (A1 a1)
|
||||
{
|
||||
::new (alloc ()) T (a1);
|
||||
return iterator (this, size () - 1);
|
||||
}
|
||||
|
||||
template <class A1, class A2>
|
||||
iterator emplace_back (A1 a1, A2 a2)
|
||||
{
|
||||
::new (alloc ()) T (a1, a2);
|
||||
return iterator (this, size () - 1);
|
||||
}
|
||||
|
||||
template <class A1, class A2, class A3>
|
||||
iterator emplace_back (A1 a1, A2 a2, A3 a3)
|
||||
{
|
||||
::new (alloc ()) T (a1, a2, a3);
|
||||
return iterator (this, size () - 1);
|
||||
}
|
||||
|
||||
template <class A1, class A2, class A3, class A4>
|
||||
iterator emplace_back (A1 a1, A2 a2, A3 a3, A4 a4)
|
||||
{
|
||||
::new (alloc ()) T (a1, a2, a3, a4);
|
||||
return iterator (this, size () - 1);
|
||||
}
|
||||
|
||||
template <class A1, class A2, class A3, class A4, class A5>
|
||||
iterator emplace_back (A1 a1, A2 a2, A3 a3, A4 a4, A5 a5)
|
||||
{
|
||||
::new (alloc ()) T (a1, a2, a3, a4, a5);
|
||||
return iterator (this, size () - 1);
|
||||
}
|
||||
|
||||
void pop_back ()
|
||||
{
|
||||
resize (size () - 1);
|
||||
}
|
||||
|
||||
void resize (size_type count)
|
||||
{
|
||||
while (count > size ())
|
||||
::new (alloc ()) T;
|
||||
|
||||
while (count < size ())
|
||||
get (--m_size).~T ();
|
||||
}
|
||||
|
||||
void resize (size_type count, TParam value)
|
||||
{
|
||||
while (count > size ())
|
||||
::new (alloc ()) T (value);
|
||||
|
||||
while (count < size ())
|
||||
get (--m_size).~T ();
|
||||
}
|
||||
|
||||
void swap (DynamicArray& other)
|
||||
{
|
||||
std::swap (m_blocksize, other.m_blocksize);
|
||||
std::swap (m_size, other.m_size);
|
||||
std::swap (m_capacity, other.m_capacity);
|
||||
std::swap (m_handles, other.m_handles);
|
||||
}
|
||||
|
||||
private:
|
||||
reference get (size_type pos) noexcept
|
||||
{
|
||||
size_type const index (pos / m_blocksize);
|
||||
size_type const offset (pos % m_blocksize);
|
||||
return m_handles [index] [offset];
|
||||
}
|
||||
|
||||
const_reference get (size_type pos) const noexcept
|
||||
{
|
||||
size_type const index (pos / m_blocksize);
|
||||
size_type const offset (pos % m_blocksize);
|
||||
return m_handles [index] [offset];
|
||||
}
|
||||
|
||||
T* alloc () noexcept
|
||||
{
|
||||
size_type const needed (size () + 1);
|
||||
if (capacity () < needed)
|
||||
reserve ((needed * (100 + growthPercentage) + 99) / 100);
|
||||
return &get (m_size++);
|
||||
}
|
||||
|
||||
private:
|
||||
Allocator m_allocator;
|
||||
size_type m_blocksize;
|
||||
size_type m_capacity;
|
||||
size_type m_size;
|
||||
handles_t m_handles;
|
||||
};
|
||||
|
||||
#endif
|
||||
327
src/beast/modules/beast_core/containers/DynamicList.cpp
Normal file
327
src/beast/modules/beast_core/containers/DynamicList.cpp
Normal file
@@ -0,0 +1,327 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
namespace ContainerTests
|
||||
{
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Counts the number of occurrences of each type of operation. */
|
||||
class Counts
|
||||
{
|
||||
public:
|
||||
typedef std::size_t count_type;
|
||||
|
||||
Counts ()
|
||||
: default_ctor (0)
|
||||
, copy_ctor (0)
|
||||
, copy_assign (0)
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
, move_ctor (0)
|
||||
, move_assign (0)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
Counts (Counts const& other)
|
||||
: default_ctor (other.default_ctor)
|
||||
, copy_ctor (other.copy_ctor)
|
||||
, copy_assign (other.copy_assign)
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
, move_ctor (other.move_ctor)
|
||||
, move_assign (other.move_assign)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
Counts& operator= (Counts const& other)
|
||||
{
|
||||
default_ctor = other.default_ctor;
|
||||
copy_ctor = other.copy_ctor;
|
||||
copy_assign = other.copy_assign;
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
move_ctor = other.move_ctor;
|
||||
move_assign = other.move_assign;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend inline Counts operator- (Counts const& lhs, Counts const& rhs)
|
||||
{
|
||||
Counts result;
|
||||
result.default_ctor = lhs.default_ctor - rhs.default_ctor;
|
||||
result.copy_ctor = lhs.copy_ctor - rhs.copy_ctor;
|
||||
result.copy_assign = lhs.copy_assign - rhs.copy_assign;
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
result.move_ctor = lhs.move_ctor - rhs.move_ctor;
|
||||
result.move_assign = lhs.move_assign - rhs.move_assign;
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
String toString () const
|
||||
{
|
||||
return String()
|
||||
+ "default_ctor(" + String::fromNumber (default_ctor) + ") "
|
||||
+ ", copy_ctor(" + String::fromNumber (copy_ctor) + ")"
|
||||
+ ", copy_assign(" + String::fromNumber (copy_assign) + ")"
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
+ ", move_ctor(" + String::fromNumber (move_ctor) + ")"
|
||||
+ ", move_assign(" + String::fromNumber (move_assign) + ")"
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
count_type default_ctor;
|
||||
count_type copy_ctor;
|
||||
count_type copy_assign;
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
count_type move_ctor;
|
||||
count_type move_assign;
|
||||
#endif
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Counts the number of element operations performed in a scope. */
|
||||
class ScopedCounts : public Uncopyable
|
||||
{
|
||||
public:
|
||||
ScopedCounts (Counts const& counts)
|
||||
: m_start (counts)
|
||||
, m_counts (counts)
|
||||
{
|
||||
}
|
||||
|
||||
Counts get () const
|
||||
{
|
||||
return m_counts - m_start;
|
||||
}
|
||||
|
||||
private:
|
||||
Counts const m_start;
|
||||
Counts const& m_counts;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/* Base for element configurations. */
|
||||
class ElementConfigBase : public Uncopyable
|
||||
{
|
||||
public:
|
||||
typedef std::size_t IdType;
|
||||
};
|
||||
|
||||
/** Provides the element-specific configuration members. */
|
||||
template <class Params>
|
||||
class ElementConfig : public ElementConfigBase
|
||||
{
|
||||
public:
|
||||
static Counts& getCounts ()
|
||||
{
|
||||
static Counts counts;
|
||||
return counts;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Base for elements used in container unit tests. */
|
||||
class ElementBase
|
||||
{
|
||||
public:
|
||||
};
|
||||
|
||||
/** An object placed into a container for unit testing. */
|
||||
template <class Config>
|
||||
class Element : public ElementBase
|
||||
{
|
||||
public:
|
||||
typedef typename Config::IdType IdType;
|
||||
|
||||
Element ()
|
||||
: m_id (0)
|
||||
, m_msg (String::empty)
|
||||
{
|
||||
++Config::getCounts ().default_ctor;
|
||||
}
|
||||
|
||||
explicit Element (IdType id)
|
||||
: m_id (id)
|
||||
, m_msg (String::fromNumber (id))
|
||||
{
|
||||
}
|
||||
|
||||
Element (Element const& other)
|
||||
: m_id (other.m_id)
|
||||
, m_msg (other.m_msg)
|
||||
{
|
||||
++Config::getCounts ().copy_ctor;
|
||||
}
|
||||
|
||||
Element& operator= (Element const& other)
|
||||
{
|
||||
m_id = other.m_id;
|
||||
m_msg = other.m_msg;
|
||||
++Config::getCounts ().copy_assign;
|
||||
}
|
||||
|
||||
#if BEAST_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||
Element (Element&& other)
|
||||
: m_id (other.m_id)
|
||||
, m_msg (other.m_msg)
|
||||
{
|
||||
other.m_msg = String::empty;
|
||||
++Config::getCounts ().move_ctor;
|
||||
}
|
||||
|
||||
Element& operator= (Element&& other)
|
||||
{
|
||||
m_id = other.m_id;
|
||||
m_msg = other.m_msg;
|
||||
other.m_msg = String::empty;
|
||||
++Config::getCounts ().move_assign;
|
||||
}
|
||||
#endif
|
||||
|
||||
IdType id () const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
String msg () const
|
||||
{
|
||||
return m_msg;
|
||||
}
|
||||
|
||||
private:
|
||||
IdType m_id;
|
||||
String m_msg;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Base for test state parameters. */
|
||||
class StateBase : public Uncopyable
|
||||
{
|
||||
public:
|
||||
typedef int64 SeedType;
|
||||
};
|
||||
|
||||
/** Provides configuration-specific test state parameters. */
|
||||
template <class Params>
|
||||
class State : public StateBase
|
||||
{
|
||||
public:
|
||||
static Random& random ()
|
||||
{
|
||||
static Random generator (Params::seedValue);
|
||||
return generator;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class ConfigBase
|
||||
{
|
||||
};
|
||||
|
||||
template <template <typename, class> class Container,
|
||||
class Params>
|
||||
class Config
|
||||
: public State <Params>
|
||||
, public ElementConfig <Params>
|
||||
{
|
||||
public:
|
||||
typedef Config ConfigType;
|
||||
typedef Params ParamsType;
|
||||
typedef State <Params> StateType;
|
||||
typedef ElementConfig <Params> ElementConfigType;
|
||||
typedef Element <ElementConfigType> ElementType;
|
||||
typedef Container <
|
||||
ElementType,
|
||||
std::allocator <char> > ContainerType;
|
||||
|
||||
typedef StateBase::SeedType SeedType;
|
||||
|
||||
// default seed
|
||||
static SeedType const seedValue = 69;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** A generic container test. */
|
||||
template <class Params>
|
||||
class Test : public Params
|
||||
{
|
||||
public:
|
||||
typedef typename Params::StateType StateType;
|
||||
typedef typename Params::ElementConfigType ElementConfigType;
|
||||
typedef typename Params::ContainerType ContainerType;
|
||||
|
||||
void doInsert ()
|
||||
{
|
||||
m_container.reserve (Params::elementCount);
|
||||
for (typename ContainerType::size_type i = 0;
|
||||
i < Params::elementCount; ++i)
|
||||
{
|
||||
m_container.push_back (typename Params::ElementType ());
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typename Params::ContainerType m_container;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class DynamicListTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
struct Params : Config <DynamicList, Params>
|
||||
{
|
||||
static SeedType const seedValue = 42;
|
||||
static ContainerType::size_type const elementCount = 100 * 1000;
|
||||
};
|
||||
|
||||
typedef Test <Params> TestType;
|
||||
|
||||
void runTest ()
|
||||
{
|
||||
TestType test;
|
||||
|
||||
beginTestCase ("insert");
|
||||
|
||||
{
|
||||
ScopedCounts counts (TestType::getCounts ());
|
||||
test.doInsert ();
|
||||
this->logMessage (counts.get ().toString ());
|
||||
}
|
||||
|
||||
pass ();
|
||||
}
|
||||
|
||||
DynamicListTests () : UnitTest ("DynamicList", "beast")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static DynamicListTests dynamicListTests;
|
||||
|
||||
}
|
||||
473
src/beast/modules/beast_core/containers/DynamicList.h
Normal file
473
src/beast/modules/beast_core/containers/DynamicList.h
Normal file
@@ -0,0 +1,473 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CORE_CONTAINERS_DYNAMICLIST_H_INCLUDED
|
||||
#define BEAST_CORE_CONTAINERS_DYNAMICLIST_H_INCLUDED
|
||||
|
||||
template <typename, typename>
|
||||
class DynamicList;
|
||||
|
||||
template <class Container, bool IsConst>
|
||||
class DynamicListIterator
|
||||
: public std::iterator <
|
||||
std::bidirectional_iterator_tag,
|
||||
typename Container::value_type,
|
||||
typename Container::difference_type,
|
||||
typename mpl::IfCond <IsConst,
|
||||
typename Container::const_pointer,
|
||||
typename Container::pointer>::type,
|
||||
typename mpl::IfCond <IsConst,
|
||||
typename Container::const_reference,
|
||||
typename Container::reference>::type>
|
||||
{
|
||||
private:
|
||||
typedef typename mpl::IfCond <IsConst,
|
||||
typename List <typename Container::Item>::const_iterator,
|
||||
typename List <typename Container::Item>::iterator>::type iterator_type;
|
||||
|
||||
typedef typename mpl::IfCond <IsConst,
|
||||
typename Container::const_pointer,
|
||||
typename Container::pointer>::type pointer;
|
||||
|
||||
typedef typename mpl::IfCond <IsConst,
|
||||
typename Container::const_reference,
|
||||
typename Container::reference>::type reference;
|
||||
|
||||
public:
|
||||
DynamicListIterator ()
|
||||
{
|
||||
}
|
||||
|
||||
DynamicListIterator (iterator_type iter)
|
||||
: m_iter (iter)
|
||||
{
|
||||
}
|
||||
|
||||
DynamicListIterator (DynamicListIterator const& other)
|
||||
: m_iter (other.m_iter)
|
||||
{
|
||||
}
|
||||
|
||||
template <bool OtherIsConst>
|
||||
DynamicListIterator (DynamicListIterator <Container, OtherIsConst> const& other)
|
||||
: m_iter (other.m_iter)
|
||||
{
|
||||
}
|
||||
|
||||
DynamicListIterator& operator= (DynamicListIterator const& other)
|
||||
{
|
||||
m_iter = other.m_iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <bool OtherIsConst>
|
||||
DynamicListIterator& operator= (DynamicListIterator <
|
||||
Container, OtherIsConst> const& other)
|
||||
{
|
||||
m_iter = other.m_iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <bool OtherIsConst>
|
||||
bool operator== (DynamicListIterator <Container, OtherIsConst> const& other) const
|
||||
{
|
||||
return m_iter == other.m_iter;
|
||||
}
|
||||
|
||||
template <bool OtherIsConst>
|
||||
bool operator!= (DynamicListIterator <Container, OtherIsConst> const& other) const
|
||||
{
|
||||
return ! ((*this) == other);
|
||||
}
|
||||
|
||||
reference operator* () const
|
||||
{
|
||||
return dereference ();
|
||||
}
|
||||
|
||||
pointer operator-> () const
|
||||
{
|
||||
return &dereference ();
|
||||
}
|
||||
|
||||
DynamicListIterator& operator++ ()
|
||||
{
|
||||
increment ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
DynamicListIterator operator++ (int)
|
||||
{
|
||||
DynamicListIterator const result (*this);
|
||||
increment ();
|
||||
return result;
|
||||
}
|
||||
|
||||
DynamicListIterator& operator-- ()
|
||||
{
|
||||
decrement ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
DynamicListIterator operator-- (int)
|
||||
{
|
||||
DynamicListIterator const result (*this);
|
||||
decrement ();
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename, typename>
|
||||
friend class DynamicList;
|
||||
|
||||
reference dereference () const
|
||||
{
|
||||
return *(m_iter->get ());
|
||||
}
|
||||
|
||||
void increment ()
|
||||
{
|
||||
++m_iter;
|
||||
}
|
||||
|
||||
void decrement ()
|
||||
{
|
||||
--m_iter;
|
||||
}
|
||||
|
||||
iterator_type m_iter;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** A list that uses a very small number of dynamic allocations.
|
||||
|
||||
Once an element is allocated, its address does not change. Elements
|
||||
can be erased, and they are placed onto a deleted list for re-use.
|
||||
Allocations occur in configurable batches.
|
||||
|
||||
Iterators to elements never become invalid, they can be safely
|
||||
stored elsewhere, as long as the underlying element is not erased.
|
||||
|
||||
T may support these concepts:
|
||||
DefaultConstructible
|
||||
MoveConstructible (C++11)
|
||||
|
||||
T must support these concepts:
|
||||
Destructible
|
||||
*/
|
||||
template <typename T,
|
||||
class Allocator = std::allocator <char> >
|
||||
class DynamicList
|
||||
{
|
||||
private:
|
||||
typedef PARAMETER_TYPE (T) TParam;
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
defaultBlocksize = 1000
|
||||
};
|
||||
|
||||
typedef T value_type;
|
||||
typedef Allocator allocator_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef T* pointer;
|
||||
typedef T& reference;
|
||||
typedef T const* const_pointer;
|
||||
typedef T const& const_reference;
|
||||
|
||||
typedef DynamicList <
|
||||
T,
|
||||
Allocator> container_type;
|
||||
|
||||
typedef DynamicListIterator <container_type, false> iterator;
|
||||
typedef DynamicListIterator <container_type, true> const_iterator;
|
||||
|
||||
public:
|
||||
explicit DynamicList (
|
||||
size_type blocksize = defaultBlocksize,
|
||||
Allocator const& allocator = Allocator ())
|
||||
: m_allocator (allocator)
|
||||
, m_blocksize (blocksize)
|
||||
, m_capacity (0)
|
||||
{
|
||||
}
|
||||
|
||||
~DynamicList ()
|
||||
{
|
||||
clear ();
|
||||
shrink_to_fit ();
|
||||
}
|
||||
|
||||
allocator_type get_allocator () const noexcept
|
||||
{
|
||||
return m_allocator;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
reference front () noexcept
|
||||
{
|
||||
return *m_items.front ().get ();
|
||||
}
|
||||
|
||||
const_reference front () const noexcept
|
||||
{
|
||||
return *m_items.front ().get ();
|
||||
}
|
||||
|
||||
reference back () noexcept
|
||||
{
|
||||
return *m_items.back ().get ();
|
||||
}
|
||||
|
||||
const_reference back () const noexcept
|
||||
{
|
||||
return *m_items.back ().get ();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
iterator begin () noexcept
|
||||
{
|
||||
return iterator (m_items.begin ());
|
||||
}
|
||||
|
||||
const_iterator begin () const noexcept
|
||||
{
|
||||
return const_iterator (m_items.begin ());
|
||||
}
|
||||
|
||||
const_iterator cbegin () const noexcept
|
||||
{
|
||||
return const_iterator (m_items.cbegin ());
|
||||
}
|
||||
|
||||
iterator end () noexcept
|
||||
{
|
||||
return iterator (m_items.end ());
|
||||
}
|
||||
|
||||
const_iterator end () const noexcept
|
||||
{
|
||||
return const_iterator (m_items.end ());
|
||||
}
|
||||
|
||||
const_iterator cend () const noexcept
|
||||
{
|
||||
return const_iterator (m_items.cend ());
|
||||
}
|
||||
|
||||
iterator iterator_to (T& value) noexcept
|
||||
{
|
||||
std::ptrdiff_t const offset (
|
||||
(std::ptrdiff_t)(((Item const*)0)->get ()));
|
||||
Item& item (*addBytesToPointer (((Item*)&value), -offset));
|
||||
return iterator (m_items.iterator_to (item));
|
||||
}
|
||||
|
||||
const_iterator const_iterator_to (T const& value) const noexcept
|
||||
{
|
||||
std::ptrdiff_t const offset (
|
||||
(std::ptrdiff_t)(((Item const*)0)->get ()));
|
||||
Item const& item (*addBytesToPointer (((Item const*)&value), -offset));
|
||||
return const_iterator (m_items.const_iterator_to (item));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
bool empty () const noexcept
|
||||
{
|
||||
return m_items.empty ();
|
||||
}
|
||||
|
||||
size_type size () const noexcept
|
||||
{
|
||||
return m_items.size ();
|
||||
}
|
||||
|
||||
size_type max_size () const noexcept
|
||||
{
|
||||
return std::numeric_limits <size_type>::max ();
|
||||
}
|
||||
|
||||
void reserve (size_type new_cap) noexcept
|
||||
{
|
||||
new_cap = m_blocksize * (
|
||||
(new_cap + m_blocksize - 1) / m_blocksize);
|
||||
if (new_cap > max_size ())
|
||||
Throw (std::length_error ("new_cap > max_size"), __FILE__, __LINE__);
|
||||
if (new_cap <= m_capacity)
|
||||
return;
|
||||
size_type const n (new_cap / m_blocksize);
|
||||
m_handles.reserve (n);
|
||||
for (size_type i = m_handles.size (); i < n; ++i)
|
||||
m_handles.push_back (static_cast <Item*> (std::malloc (
|
||||
m_blocksize * sizeof (Item))));
|
||||
m_capacity = new_cap;
|
||||
}
|
||||
|
||||
size_type capacity () const noexcept
|
||||
{
|
||||
return m_capacity;
|
||||
}
|
||||
|
||||
void shrink_to_fit ()
|
||||
{
|
||||
// Special case when all allocated
|
||||
// items are part of the free list.
|
||||
if (m_items.empty ())
|
||||
m_free.clear ();
|
||||
|
||||
size_type const used (m_items.size () + m_free.size ());
|
||||
size_type const handles ((used + m_blocksize - 1) / m_blocksize);
|
||||
m_capacity = handles * m_blocksize;
|
||||
for (size_type i = m_handles.size (); i-- > handles;)
|
||||
{
|
||||
std::free (m_handles [i]);
|
||||
m_handles.erase (m_handles.begin () + i);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void clear ()
|
||||
{
|
||||
// Might want to skip this if is_pod<T> is true
|
||||
for (typename List <Item>::iterator iter = m_items.begin ();
|
||||
iter != m_items.end ();)
|
||||
{
|
||||
Item& item (*iter++);
|
||||
item.get ()->~T ();
|
||||
m_free.push_back (item);
|
||||
}
|
||||
}
|
||||
|
||||
/** Allocate a new default-constructed element and return the iterator.
|
||||
If there are deleted elements in the free list, the new element
|
||||
may not be created at the end of the storage area.
|
||||
*/
|
||||
iterator emplace_back ()
|
||||
{
|
||||
return iterator_to (*::new (alloc ()->get ()) T ());
|
||||
}
|
||||
|
||||
template <class A1>
|
||||
iterator emplace_back (A1 a1)
|
||||
{
|
||||
return iterator_to (*::new (alloc ()->get ()) T (a1));
|
||||
}
|
||||
|
||||
template <class A1, class A2>
|
||||
iterator emplace_back (A1 a1, A2 a2)
|
||||
{
|
||||
return iterator_to (*::new (alloc ()->get ()) T (a1, a2));
|
||||
}
|
||||
|
||||
template <class A1, class A2, class A3>
|
||||
iterator emplace_back (A1 a1, A2 a2, A3 a3)
|
||||
{
|
||||
return iterator_to (*::new (alloc ()->get ()) T (a1, a2, a3));
|
||||
}
|
||||
|
||||
template <class A1, class A2, class A3, class A4>
|
||||
iterator emplace_back (A1 a1, A2 a2, A3 a3, A4 a4)
|
||||
{
|
||||
return iterator_to (*::new (alloc ()->get ()) T (a1, a2, a3, a4));
|
||||
}
|
||||
|
||||
template <class A1, class A2, class A3, class A4, class A5>
|
||||
iterator emplace_back (A1 a1, A2 a2, A3 a3, A4 a4, A5 a5)
|
||||
{
|
||||
return iterator_to (*::new (alloc ()->get ()) T (a1, a2, a3, a4, a5));
|
||||
}
|
||||
|
||||
/** Allocate a new copy-constructed element and return the index. */
|
||||
iterator push_back (TParam value) noexcept
|
||||
{
|
||||
return iterator_to (*::new (alloc ()->get ()) T (value));
|
||||
}
|
||||
|
||||
/** Erase the element at the specified position. */
|
||||
iterator erase (iterator pos)
|
||||
{
|
||||
Item& item (*pos.m_iter);
|
||||
item.get ()->~T ();
|
||||
pos = m_items.erase (m_items.iterator_to (item));
|
||||
m_free.push_front (item);
|
||||
return pos;
|
||||
}
|
||||
|
||||
private:
|
||||
template <class, bool>
|
||||
friend class DynamicListIterator;
|
||||
|
||||
struct Item : List <Item>::Node
|
||||
{
|
||||
typedef T value_type;
|
||||
|
||||
T* get () noexcept
|
||||
{
|
||||
return reinterpret_cast <T*> (&storage [0]);
|
||||
}
|
||||
|
||||
T const* get () const noexcept
|
||||
{
|
||||
return reinterpret_cast <T const*> (&storage [0]);
|
||||
}
|
||||
|
||||
private:
|
||||
// Lets hope this is padded correctly
|
||||
uint8 storage [sizeof (T)];
|
||||
};
|
||||
|
||||
Item* alloc () noexcept
|
||||
{
|
||||
Item* item;
|
||||
if (m_free.empty ())
|
||||
{
|
||||
if (m_capacity <= m_items.size ())
|
||||
reserve (m_items.size () + 1);
|
||||
|
||||
size_type const index (m_items.size () / m_blocksize);
|
||||
size_type const offset (m_items.size () - index * m_blocksize);
|
||||
item = m_handles [index] + offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
item = &m_free.pop_front ();
|
||||
}
|
||||
|
||||
m_items.push_back (*item);
|
||||
return item;
|
||||
}
|
||||
|
||||
typedef std::vector <Item*> blocks_t;
|
||||
|
||||
Allocator m_allocator;
|
||||
size_type m_blocksize;
|
||||
size_type m_capacity;
|
||||
std::vector <Item*> m_handles;
|
||||
List <Item> m_items;
|
||||
List <Item> m_free;
|
||||
};
|
||||
|
||||
#endif
|
||||
154
src/beast/modules/beast_core/containers/HashMap.cpp
Normal file
154
src/beast/modules/beast_core/containers/HashMap.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
class HashMapTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
numberOfItems = 100 * 1000
|
||||
};
|
||||
|
||||
template <int keyBytes>
|
||||
class TestTraits
|
||||
{
|
||||
public:
|
||||
struct Value
|
||||
{
|
||||
int unused;
|
||||
};
|
||||
|
||||
struct Key
|
||||
{
|
||||
class Equal
|
||||
{
|
||||
public:
|
||||
bool operator() (Key const& lhs, Key const& rhs) const noexcept
|
||||
{
|
||||
return memcmp (lhs.data, rhs.data, keyBytes) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
// stateful hardened hash
|
||||
class Hash
|
||||
{
|
||||
public:
|
||||
explicit Hash (HashValue seedToUse = Random::getSystemRandom ().nextInt ())
|
||||
: m_seed (seedToUse)
|
||||
{
|
||||
}
|
||||
|
||||
HashValue generateHash (Key const& key) const noexcept
|
||||
{
|
||||
HashValue hash;
|
||||
Murmur::Hash (key.data, keyBytes, m_seed, &hash);
|
||||
return hash;
|
||||
}
|
||||
|
||||
private:
|
||||
HashValue m_seed;
|
||||
};
|
||||
|
||||
/*
|
||||
Key ()
|
||||
: std::memset (data, 0, keyBytes)
|
||||
{
|
||||
}
|
||||
*/
|
||||
|
||||
uint8 data [keyBytes];
|
||||
};
|
||||
|
||||
typedef Key key_type;
|
||||
typedef Value value_type;
|
||||
typedef typename Key::Hash hasher;
|
||||
typedef typename Key::Equal key_equal;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
TestTraits (size_type const numberOfKeys, Random& random)
|
||||
{
|
||||
// need to static_bassert keyBytes can represent numberOfKeys. Log base 256 or something?
|
||||
|
||||
m_keys.reserve (numberOfKeys);
|
||||
m_shuffled_keys.reserve (numberOfKeys);
|
||||
for (size_type i = 0; i < numberOfKeys; ++i)
|
||||
{
|
||||
// VFALCO NOTE std::vector is garbage..want to emplace_back() here
|
||||
Key key;
|
||||
memset (key.data, 0, sizeof (key.data));
|
||||
memcpy (& key.data [0], &i, std::min (sizeof (key.data), sizeof (i)));
|
||||
m_keys.push_back (key);
|
||||
m_shuffled_keys.push_back (&m_keys [i]);
|
||||
}
|
||||
|
||||
UnitTestUtilities::repeatableShuffle (numberOfKeys, m_shuffled_keys, random);
|
||||
}
|
||||
|
||||
Key const& getKey (size_type index) const noexcept
|
||||
{
|
||||
return *m_shuffled_keys [index];
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector <Key> m_keys;
|
||||
std::vector <Key*> m_shuffled_keys;
|
||||
};
|
||||
|
||||
template <int keyBytes>
|
||||
void testInsert (std::size_t numberOfKeys, Random& random)
|
||||
{
|
||||
beginTestCase (String
|
||||
("insertion, numberOfKeys = ") + String::fromNumber (numberOfKeys) +
|
||||
", keyBytes = " + String::fromNumber (keyBytes));
|
||||
|
||||
typedef TestTraits <keyBytes> Traits;
|
||||
Traits traits (numberOfKeys, random);
|
||||
|
||||
typedef HashMap <
|
||||
typename Traits::key_type,
|
||||
typename Traits::value_type,
|
||||
typename Traits::hasher,
|
||||
typename Traits::key_equal> Map;
|
||||
Map map;
|
||||
|
||||
for (std::size_t i = 0; i < numberOfKeys; ++i)
|
||||
map.insert (traits.getKey (i));
|
||||
|
||||
String s (
|
||||
"load_factor = " + String::fromNumber (map.load_factor (), 2) +
|
||||
", bucket_count = " + String::fromNumber (map.bucket_count ()));
|
||||
this->logMessage (s);
|
||||
|
||||
expect (map.size () == numberOfKeys);
|
||||
}
|
||||
|
||||
void runTest ()
|
||||
{
|
||||
int64 const seedValue = 072472;
|
||||
Random random (seedValue);
|
||||
testInsert <4> (numberOfItems, random);
|
||||
testInsert <20> (numberOfItems, random);
|
||||
}
|
||||
|
||||
HashMapTests () : UnitTest ("HashMap", "beast")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static HashMapTests hashMapTests;
|
||||
856
src/beast/modules/beast_core/containers/HashMap.h
Normal file
856
src/beast/modules/beast_core/containers/HashMap.h
Normal file
@@ -0,0 +1,856 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.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_HASHMAP_H_INCLUDED
|
||||
#define BEAST_HASHMAP_H_INCLUDED
|
||||
|
||||
/** The integral type for holding a non cryptographic hash.
|
||||
HashValue is used for fast comparisons, bloom filters, and hash maps.
|
||||
*/
|
||||
typedef uint32 HashValue;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Simple hash functions for use with HashMap.
|
||||
|
||||
@see HashMap
|
||||
*/
|
||||
// VFALCO TODO Rewrite the hash functions to return a uint32, and not
|
||||
// take the upperLimit parameter. Just do the mod in the
|
||||
// calling function for simplicity.
|
||||
class DefaultHashFunctions
|
||||
{
|
||||
public:
|
||||
/** Generates a simple hash from an integer. */
|
||||
HashValue generateHash (const int key) const noexcept
|
||||
{
|
||||
return HashValue (std::abs (key));
|
||||
}
|
||||
|
||||
/** Generates a simple hash from an int64. */
|
||||
HashValue generateHash (const int64 key) const noexcept
|
||||
{
|
||||
return HashValue (key);
|
||||
}
|
||||
|
||||
/** Generates a simple hash from a string. */
|
||||
HashValue generateHash (const String& key) const noexcept
|
||||
{
|
||||
return HashValue (key.hashCode ());
|
||||
}
|
||||
|
||||
/** Generates a simple hash from a variant. */
|
||||
HashValue generateHash (const var& key) const noexcept
|
||||
{
|
||||
return generateHash (key.toString ());
|
||||
}
|
||||
};
|
||||
|
||||
#if 0
|
||||
/** Hardened hash functions for use with HashMap.
|
||||
|
||||
The seed is used to make the hash unpredictable. This prevents
|
||||
attackers from exploiting crafted inputs to produce degenerate
|
||||
containers.
|
||||
*/
|
||||
class HardenedHashFunctions
|
||||
{
|
||||
public:
|
||||
/** Construct a hash function.
|
||||
|
||||
If a seed is specified it will be used, else a random seed
|
||||
will be generated from the system.
|
||||
|
||||
@param seedToUse An optional seed to use.
|
||||
*/
|
||||
explicit HardenedHashFunctions (int seedToUse = Random::getSystemRandom ().nextInt ())
|
||||
: m_seed (seedToUse)
|
||||
{
|
||||
}
|
||||
|
||||
// VFALCO TODO Need hardened versions of these functions which use the seed!
|
||||
|
||||
private:
|
||||
int m_seed;
|
||||
};
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
struct BucketTag { };
|
||||
|
||||
template <typename M, typename I>
|
||||
class HashMapLocalIterator
|
||||
: public std::iterator <std::forward_iterator_tag, typename M::size_type>
|
||||
{
|
||||
public:
|
||||
typedef typename M::Pair value_type;
|
||||
typedef value_type* pointer;
|
||||
typedef value_type& reference;
|
||||
typedef typename M::size_type size_type;
|
||||
|
||||
HashMapLocalIterator (M* map = nullptr, I iter = I ())
|
||||
: m_map (map)
|
||||
, m_iter (iter)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename N, typename J>
|
||||
HashMapLocalIterator (HashMapLocalIterator <N, J> const& other)
|
||||
: m_map (other.m_map)
|
||||
, m_iter (other.m_iter)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename N, typename J>
|
||||
HashMapLocalIterator& operator= (HashMapLocalIterator <N, J> const& other)
|
||||
{
|
||||
m_map = other.m_map;
|
||||
m_iter = other.m_iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename N, typename J>
|
||||
bool operator== (HashMapLocalIterator <N, J> const& other)
|
||||
{
|
||||
return m_map == other.m_map && m_iter == other.m_iter;
|
||||
}
|
||||
|
||||
template <typename N, typename J>
|
||||
bool operator!= (HashMapLocalIterator <N, J> const& other)
|
||||
{
|
||||
return ! ((*this)==other);
|
||||
}
|
||||
|
||||
reference operator* () const noexcept
|
||||
{
|
||||
return dereference ();
|
||||
}
|
||||
|
||||
pointer operator-> () const noexcept
|
||||
{
|
||||
return &dereference ();
|
||||
}
|
||||
|
||||
HashMapLocalIterator& operator++ () noexcept
|
||||
{
|
||||
increment ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
HashMapLocalIterator operator++ (int) noexcept
|
||||
{
|
||||
HashMapLocalIterator const result (*this);
|
||||
increment ();
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
reference dereference () const noexcept
|
||||
{
|
||||
return m_iter->pair ();
|
||||
}
|
||||
|
||||
void increment () noexcept
|
||||
{
|
||||
++m_iter;
|
||||
}
|
||||
|
||||
M* m_map;
|
||||
I m_iter;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
|
||||
template <typename M>
|
||||
class HashMapIterator
|
||||
: public std::iterator <std::forward_iterator_tag, typename M::size_type>
|
||||
{
|
||||
private:
|
||||
typedef typename M::Item Item;
|
||||
typedef typename M::Bucket Bucket;
|
||||
typedef detail::ListIterator <typename detail::copyconst <M,
|
||||
typename List <Bucket>::Node>::type> bucket_iterator;
|
||||
typedef detail::ListIterator <typename detail::copyconst <M,
|
||||
typename List <Item, detail::BucketTag>::Node>::type> item_iterator;
|
||||
|
||||
public:
|
||||
typedef typename M::Pair value_type;
|
||||
typedef value_type* pointer;
|
||||
typedef value_type& reference;
|
||||
typedef typename M::size_type size_type;
|
||||
|
||||
HashMapIterator ()
|
||||
: m_map (nullptr)
|
||||
, m_bucket (bucket_iterator ())
|
||||
, m_local (item_iterator ())
|
||||
{
|
||||
}
|
||||
|
||||
// represents end()
|
||||
explicit HashMapIterator (M* map)
|
||||
: m_map (map)
|
||||
, m_bucket (bucket_iterator ())
|
||||
, m_local (item_iterator ())
|
||||
{
|
||||
}
|
||||
|
||||
HashMapIterator (M* map, bucket_iterator const& bucket, item_iterator const& local)
|
||||
: m_map (map)
|
||||
, m_bucket (bucket)
|
||||
, m_local (local)
|
||||
{
|
||||
}
|
||||
|
||||
#if 0
|
||||
HashMapIterator (HashMapIterator const& other) noexcept
|
||||
: m_map (other.m_map)
|
||||
, m_bucket (other.m_bucket)
|
||||
, m_local (other.m_local)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename N>
|
||||
HashMapIterator (HashMapIterator <N> const& other) noexcept
|
||||
: m_map (other.m_map)
|
||||
, m_bucket (other.m_bucket)
|
||||
, m_local (other.m_local)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
template <typename N>
|
||||
HashMapIterator& operator= (HashMapIterator <N> const& other) noexcept
|
||||
{
|
||||
m_map = other.m_map;
|
||||
m_bucket = other.m_bucket;
|
||||
m_local = other.m_local;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename N>
|
||||
bool operator== (HashMapIterator <N> const& other) noexcept
|
||||
{
|
||||
return m_map == other.m_map &&
|
||||
m_bucket == other.m_bucket &&
|
||||
m_local == other.m_local;
|
||||
}
|
||||
|
||||
template <typename N>
|
||||
bool operator!= (HashMapIterator <N> const& other) noexcept
|
||||
{
|
||||
return ! ((*this) == other);
|
||||
}
|
||||
|
||||
reference operator* () const noexcept
|
||||
{
|
||||
return dereference ();
|
||||
}
|
||||
|
||||
pointer operator-> () const noexcept
|
||||
{
|
||||
return &dereference ();
|
||||
}
|
||||
|
||||
HashMapIterator& operator++ () noexcept
|
||||
{
|
||||
increment ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
HashMapIterator operator++ (int) noexcept
|
||||
{
|
||||
HashMapIterator const result (*this);
|
||||
increment ();
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename, typename, typename, typename, typename>
|
||||
friend class HashMap;
|
||||
|
||||
reference dereference () const noexcept
|
||||
{
|
||||
return m_local->pair ();
|
||||
}
|
||||
|
||||
void increment () noexcept
|
||||
{
|
||||
++m_local;
|
||||
if (m_local == m_bucket->items.end ())
|
||||
{
|
||||
++m_bucket;
|
||||
if (m_bucket != m_map->m_bucketlist.end ())
|
||||
m_local = m_bucket->items.begin ();
|
||||
}
|
||||
}
|
||||
|
||||
M* m_map;
|
||||
bucket_iterator m_bucket;
|
||||
item_iterator m_local;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Associative container mapping Key to T pairs.
|
||||
*/
|
||||
template <typename Key,
|
||||
typename T,
|
||||
typename Hash = DefaultHashFunctions,
|
||||
typename KeyEqual = std::equal_to <Key>,
|
||||
typename Allocator = std::allocator <char> >
|
||||
class HashMap
|
||||
{
|
||||
private:
|
||||
typedef PARAMETER_TYPE (Key) KeyParam;
|
||||
typedef PARAMETER_TYPE (T) TParam;
|
||||
|
||||
public:
|
||||
struct Pair
|
||||
{
|
||||
explicit Pair (Key key)
|
||||
: m_key (key)
|
||||
{
|
||||
}
|
||||
|
||||
Pair (Key key, T t)
|
||||
: m_key (key)
|
||||
, m_t (t)
|
||||
{
|
||||
}
|
||||
|
||||
Key const& key () const noexcept
|
||||
{
|
||||
return m_key;
|
||||
}
|
||||
|
||||
T& value () noexcept
|
||||
{
|
||||
return m_t;
|
||||
}
|
||||
|
||||
T const& value () const noexcept
|
||||
{
|
||||
return m_t;
|
||||
}
|
||||
|
||||
private:
|
||||
Key m_key;
|
||||
T m_t;
|
||||
};
|
||||
|
||||
private:
|
||||
template <typename M, typename I>
|
||||
friend class detail::HashMapLocalIterator;
|
||||
|
||||
class Item;
|
||||
|
||||
// Each non-empty bucket is in the linked list.
|
||||
struct Bucket : List <Bucket>::Node
|
||||
{
|
||||
Bucket ()
|
||||
{
|
||||
}
|
||||
|
||||
inline bool empty () const noexcept
|
||||
{
|
||||
return items.empty ();
|
||||
}
|
||||
|
||||
List <Item, detail::BucketTag> items;
|
||||
|
||||
private:
|
||||
Bucket& operator= (Bucket const&);
|
||||
Bucket (Bucket const&);
|
||||
};
|
||||
|
||||
// Every item in the map is in one linked list
|
||||
struct Item
|
||||
: List <Item>::Node
|
||||
, List <Item, detail::BucketTag>::Node
|
||||
{
|
||||
Item (Pair const& pair_)
|
||||
: m_pair (pair_)
|
||||
{
|
||||
}
|
||||
|
||||
Pair& pair () noexcept
|
||||
{
|
||||
return m_pair;
|
||||
}
|
||||
|
||||
Pair const& pair () const noexcept
|
||||
{
|
||||
return m_pair;
|
||||
}
|
||||
|
||||
private:
|
||||
Pair m_pair;
|
||||
};
|
||||
|
||||
public:
|
||||
typedef Key key_type;
|
||||
typedef T mapped_type;
|
||||
typedef Pair value_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef Hash hasher;
|
||||
typedef KeyEqual key_equal;
|
||||
typedef Allocator allocator_type;
|
||||
typedef value_type* pointer;
|
||||
typedef value_type& reference;
|
||||
typedef value_type const* const_pointer;
|
||||
typedef value_type const& const_reference;
|
||||
|
||||
typedef HashMap <Key, T, Hash, KeyEqual, Allocator> container_type;
|
||||
|
||||
typedef detail::HashMapIterator <container_type> iterator;
|
||||
typedef detail::HashMapIterator <container_type const> const_iterator;
|
||||
|
||||
typedef detail::HashMapLocalIterator <container_type,
|
||||
typename List <Item, detail::BucketTag>::iterator> local_iterator;
|
||||
|
||||
typedef detail::HashMapLocalIterator <container_type const,
|
||||
typename List <Item, detail::BucketTag>::const_iterator> const_local_iterator;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
enum
|
||||
{
|
||||
initialBucketCount = 101,
|
||||
percentageIncrease = 25
|
||||
};
|
||||
|
||||
static float getDefaultLoadFactor () noexcept
|
||||
{
|
||||
return 1.2f;
|
||||
}
|
||||
|
||||
explicit HashMap (
|
||||
size_type bucket_count = initialBucketCount,
|
||||
KeyEqual const& equal = KeyEqual (),
|
||||
Hash const& hash = Hash (),
|
||||
Allocator const& allocator = Allocator ())
|
||||
: m_hash (hash)
|
||||
, m_equal (equal)
|
||||
, m_allocator (allocator)
|
||||
, m_max_load_factor (getDefaultLoadFactor ())
|
||||
{
|
||||
rehash (bucket_count);
|
||||
}
|
||||
|
||||
HashMap (
|
||||
size_type bucket_count,
|
||||
Allocator const& allocator = Allocator ())
|
||||
: m_allocator (allocator)
|
||||
, m_max_load_factor (getDefaultLoadFactor ())
|
||||
{
|
||||
rehash (bucket_count);
|
||||
}
|
||||
|
||||
HashMap (
|
||||
size_type bucket_count,
|
||||
Hash const& hash = Hash (),
|
||||
Allocator const& allocator = Allocator ())
|
||||
: m_hash (hash)
|
||||
, m_allocator (allocator)
|
||||
, m_max_load_factor (getDefaultLoadFactor ())
|
||||
{
|
||||
rehash (bucket_count);
|
||||
}
|
||||
|
||||
explicit HashMap (Allocator const& allocator)
|
||||
: m_allocator (allocator)
|
||||
, m_max_load_factor (getDefaultLoadFactor ())
|
||||
{
|
||||
rehash (initialBucketCount);
|
||||
}
|
||||
|
||||
~HashMap()
|
||||
{
|
||||
clear ();
|
||||
}
|
||||
|
||||
HashMap& operator= (HashMap const& other)
|
||||
{
|
||||
clear ();
|
||||
for (iterator iter = other.begin (); iter != other.end (); ++iter)
|
||||
(*this)[iter->key ()] = iter->value ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
allocator_type get_allocator () const noexcept
|
||||
{
|
||||
return m_allocator;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
iterator begin () noexcept
|
||||
{
|
||||
if (m_bucketlist.size () > 0)
|
||||
return iterator (this, m_bucketlist.begin (),
|
||||
m_bucketlist.front ().items.begin ());
|
||||
return end ();
|
||||
}
|
||||
|
||||
const_iterator begin () const noexcept
|
||||
{
|
||||
if (m_bucketlist.size () > 0)
|
||||
return const_iterator (this, m_bucketlist.begin (),
|
||||
m_bucketlist.front ().items.begin ());
|
||||
return end ();
|
||||
}
|
||||
|
||||
const_iterator cbegin () const noexcept
|
||||
{
|
||||
if (m_bucketlist.size () > 0)
|
||||
return const_iterator (this, m_bucketlist.begin (),
|
||||
m_bucketlist.front ().items.begin ());
|
||||
return end ();
|
||||
}
|
||||
|
||||
iterator end () noexcept
|
||||
{
|
||||
return iterator (static_cast <container_type*> (this));
|
||||
}
|
||||
|
||||
const_iterator end () const noexcept
|
||||
{
|
||||
return const_iterator (this);
|
||||
}
|
||||
|
||||
const_iterator cend () const noexcept
|
||||
{
|
||||
return const_iterator (this);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
bool empty () const noexcept
|
||||
{
|
||||
return size () == 0;
|
||||
}
|
||||
|
||||
size_type size () const noexcept
|
||||
{
|
||||
return m_itemlist.size ();
|
||||
}
|
||||
|
||||
size_type max_size () const noexcept
|
||||
{
|
||||
return std::numeric_limits <size_type>::max ();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (typename DynamicList <Item>::iterator iter = m_items.begin ();
|
||||
iter != m_items.end ();)
|
||||
{
|
||||
typename DynamicList <Item>::iterator const cur (iter++);
|
||||
m_items.erase (cur);
|
||||
}
|
||||
|
||||
m_itemlist.clear ();
|
||||
m_bucketlist.clear ();
|
||||
size_type const count (m_buckets.size ());
|
||||
m_buckets.assign (count);
|
||||
}
|
||||
|
||||
struct Result
|
||||
{
|
||||
Result (iterator iter_ = iterator (), bool inserted_ = false)
|
||||
: iter (iter_)
|
||||
, inserted (inserted_)
|
||||
{
|
||||
}
|
||||
|
||||
iterator iter;
|
||||
bool inserted;
|
||||
};
|
||||
|
||||
Result insert (Pair const& p)
|
||||
{
|
||||
size_type const n (bucket (p.key ()));
|
||||
iterator iter (find (p.key (), n));
|
||||
if (iter != end ())
|
||||
return Result (iter, false);
|
||||
check_load ();
|
||||
return Result (store (*m_items.emplace_back (p), n), true);
|
||||
}
|
||||
|
||||
Result insert (KeyParam key)
|
||||
{
|
||||
return insert (Pair (key));
|
||||
}
|
||||
|
||||
iterator erase (const_iterator pos)
|
||||
{
|
||||
iterator iter = pos;
|
||||
++iter;
|
||||
Bucket& b (*pos.m_iter);
|
||||
erase (b, pos->m_local);
|
||||
return iter;
|
||||
}
|
||||
|
||||
size_type erase (KeyParam key)
|
||||
{
|
||||
size_type found (0);
|
||||
Bucket& b (m_buckets [bucket (key)]);
|
||||
for (typename List <Item, detail::BucketTag>::iterator iter (b.items.begin ());
|
||||
iter != b.items.end ();)
|
||||
{
|
||||
typename List <Item, detail::BucketTag>::iterator cur (iter++);
|
||||
if (m_equal (cur->pair ().key (), key))
|
||||
{
|
||||
erase (b, cur);
|
||||
++found;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
T& at (KeyParam key)
|
||||
{
|
||||
iterator const iter (find (key));
|
||||
if (iter == end ())
|
||||
Throw (std::out_of_range ("key not found"), __FILE__, __LINE__);
|
||||
return iter->value ();
|
||||
}
|
||||
|
||||
T const& at (KeyParam key) const
|
||||
{
|
||||
const_iterator const iter (find (key));
|
||||
if (iter == end ())
|
||||
Throw (std::out_of_range ("key not found"), __FILE__, __LINE__);
|
||||
return iter->value ();
|
||||
}
|
||||
|
||||
T& operator[] (KeyParam key) noexcept
|
||||
{
|
||||
return insert (key).iter->value ();
|
||||
}
|
||||
|
||||
size_type count (KeyParam key) const noexcept
|
||||
{
|
||||
size_type n = 0;
|
||||
Bucket const& b (m_buckets [bucket (key)]);
|
||||
for (typename List <Item, detail::BucketTag>::iterator iter = b.items.begin ();
|
||||
iter != b.items.end (); ++iter)
|
||||
if (m_equal (iter->key (), key))
|
||||
++n;
|
||||
return n;
|
||||
}
|
||||
|
||||
iterator find (KeyParam key) noexcept
|
||||
{
|
||||
return find (key, bucket (key));
|
||||
}
|
||||
|
||||
const_iterator find (KeyParam key) const noexcept
|
||||
{
|
||||
return find (key, bucket (key));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
local_iterator begin (size_type n) noexcept
|
||||
{
|
||||
return local_iterator (this, m_buckets [n].items.begin ());
|
||||
}
|
||||
|
||||
const_local_iterator begin (size_type n) const noexcept
|
||||
{
|
||||
return const_local_iterator (this, m_buckets [n].items.begin ());
|
||||
}
|
||||
|
||||
const_local_iterator cbegin (size_type n) const noexcept
|
||||
{
|
||||
return const_local_iterator (this, m_buckets [n].items.cbegin ());
|
||||
}
|
||||
|
||||
local_iterator end (size_type n) noexcept
|
||||
{
|
||||
return local_iterator (this, m_buckets [n].items.end ());
|
||||
}
|
||||
|
||||
const_local_iterator end (size_type n) const noexcept
|
||||
{
|
||||
return const_local_iterator (this, m_buckets [n].items.end ());
|
||||
}
|
||||
|
||||
const_local_iterator cend (size_type n) const noexcept
|
||||
{
|
||||
return const_local_iterator (this, m_buckets [n].items.cend ());
|
||||
}
|
||||
|
||||
size_type bucket_count () const noexcept
|
||||
{
|
||||
return m_buckets.size ();
|
||||
}
|
||||
|
||||
size_type max_bucket_count () const noexcept
|
||||
{
|
||||
return std::numeric_limits <size_type>::max ();
|
||||
}
|
||||
|
||||
size_type bucket_size (size_type n) const noexcept
|
||||
{
|
||||
return m_buckets [n].items.size ();
|
||||
}
|
||||
|
||||
size_type bucket (KeyParam key) const noexcept
|
||||
{
|
||||
HashValue const hash (m_hash.generateHash (key));
|
||||
return hash % bucket_count ();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
float load_factor () const noexcept
|
||||
{
|
||||
return float (m_items.size ()) / float (m_buckets.size ());
|
||||
}
|
||||
|
||||
float max_load_factor () const noexcept
|
||||
{
|
||||
return m_max_load_factor;
|
||||
}
|
||||
|
||||
void max_load_factor (float ml) noexcept
|
||||
{
|
||||
m_max_load_factor = ml;
|
||||
check_load ();
|
||||
}
|
||||
|
||||
void rehash (size_type const count)
|
||||
{
|
||||
m_bucketlist.clear ();
|
||||
m_buckets.assign (count);
|
||||
for (typename List <Item>::iterator iter = m_itemlist.begin ();
|
||||
iter != m_itemlist.end (); ++iter)
|
||||
{
|
||||
Item& item (*iter);
|
||||
size_type const n (bucket (item.pair ().key ()));
|
||||
Bucket& b (m_buckets [n]);
|
||||
if (b.empty ())
|
||||
m_bucketlist.push_front (b);
|
||||
b.items.push_front (item);
|
||||
}
|
||||
}
|
||||
|
||||
void reserve (size_type count)
|
||||
{
|
||||
m_items.reserve (count);
|
||||
rehash (std::ceil (count / max_load_factor ()));
|
||||
}
|
||||
|
||||
private:
|
||||
// rehashes if adding one more item would put us over
|
||||
void check_load () noexcept
|
||||
{
|
||||
if ( (float (m_items.size () + 1) /
|
||||
float (m_buckets.size ())) >=
|
||||
max_load_factor ())
|
||||
{
|
||||
grow_buckets ();
|
||||
}
|
||||
}
|
||||
|
||||
void grow_buckets ()
|
||||
{
|
||||
double const scale = 1. + (double (percentageIncrease) / 100.);
|
||||
size_type const count (size_type (std::ceil (
|
||||
(double (size ()) / double (max_load_factor ())) * scale)));
|
||||
rehash (count);
|
||||
}
|
||||
|
||||
iterator find (KeyParam key, size_type n) noexcept
|
||||
{
|
||||
Bucket& b (m_buckets [n]);
|
||||
for (typename List <Item, detail::BucketTag>::iterator iter =
|
||||
b.items.begin (); iter != b.items.end (); ++iter)
|
||||
if (m_equal (iter->pair ().key (), key))
|
||||
return iterator (this, m_bucketlist.iterator_to (b), iter);
|
||||
return end ();
|
||||
}
|
||||
|
||||
const_iterator find (KeyParam key, size_type n) const noexcept
|
||||
{
|
||||
Bucket const& b (m_buckets [n]);
|
||||
for (typename List <Item, detail::BucketTag>::const_iterator iter =
|
||||
b.items.begin (); iter != b.items.end (); ++iter)
|
||||
if (m_equal (iter->pair ().key (), key))
|
||||
return const_iterator (this,
|
||||
m_bucketlist.const_iterator_to (b), iter);
|
||||
return end ();
|
||||
}
|
||||
|
||||
iterator store (Item& item, size_type n)
|
||||
{
|
||||
check_load ();
|
||||
Bucket& b (m_buckets [n]);
|
||||
if (b.empty ())
|
||||
m_bucketlist.push_front (b);
|
||||
b.items.push_front (item);
|
||||
m_itemlist.push_front (item);
|
||||
return iterator (this,
|
||||
m_bucketlist.iterator_to (b),
|
||||
b.items.begin ());
|
||||
}
|
||||
|
||||
void erase (Bucket& b, typename List <Item, detail::BucketTag>::iterator pos)
|
||||
{
|
||||
Item& item (*pos);
|
||||
b.items.erase (b.items.iterator_to (item));
|
||||
if (b.empty ())
|
||||
m_bucketlist.erase (m_bucketlist.iterator_to (b));
|
||||
m_itemlist.erase (m_itemlist.iterator_to (item));
|
||||
m_items.erase (m_items.iterator_to (item));
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename M>
|
||||
friend class detail::HashMapIterator;
|
||||
|
||||
Hash m_hash;
|
||||
KeyEqual m_equal;
|
||||
Allocator m_allocator;
|
||||
DynamicList <Item> m_items;
|
||||
DynamicArray <Bucket> m_buckets;
|
||||
List <Item> m_itemlist;
|
||||
List <Bucket> m_bucketlist;
|
||||
float m_max_load_factor;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
720
src/beast/modules/beast_core/containers/List.h
Normal file
720
src/beast/modules/beast_core/containers/List.h
Normal file
@@ -0,0 +1,720 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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_CORE_CONTAINERS_LIST_H_INCLUDED
|
||||
#define BEAST_CORE_CONTAINERS_LIST_H_INCLUDED
|
||||
|
||||
/** Intrusive Containers
|
||||
|
||||
# Introduction
|
||||
|
||||
Intrusive containers are special containers that offer better performance
|
||||
and exception safety guarantees than non-intrusive containers (like the
|
||||
STL containers). They are useful building blocks for high performance
|
||||
concurrent systems or other purposes where allocations are restricted
|
||||
(such as the AudioIODeviceCallback object), because intrusive list
|
||||
operations do not allocate or free memory.
|
||||
|
||||
While intrusive containers were and are widely used in C, they became more
|
||||
and more forgotten in C++ due to the presence of the standard containers
|
||||
which don't support intrusive techniques. VFLib not only reintroduces this
|
||||
technique to C++ for lists, it also encapsulates the implementation in a
|
||||
mostly compliant STL interface. Hence anyone familiar with standard
|
||||
containers can easily use them.
|
||||
|
||||
# Interface
|
||||
|
||||
The interface for intrusive elements in this library is unified for all
|
||||
containers. Unlike STL containers, objects placed into intrusive containers
|
||||
are not copied. Instead, a pointer to the object is stored. All
|
||||
responsibility for object lifetime is the responsibility of the caller;
|
||||
the intrusive container just keeps track of what is in it.
|
||||
|
||||
Summary of intrusive container differences:
|
||||
|
||||
- Holds pointers to existing objects instead of copies.
|
||||
|
||||
- Does not allocate or free any objects.
|
||||
|
||||
- Requires a element's class declaration to be modified.
|
||||
|
||||
- Methods never throw exceptions when called with valid arguments.
|
||||
|
||||
# Usage
|
||||
|
||||
Like STL containers, intrusive containers are all template based, where the
|
||||
template argument specifies the type of object that the container will hold.
|
||||
These declarations specify a doubly linked list where each element points
|
||||
to a user defined class:
|
||||
|
||||
@code
|
||||
|
||||
struct Object; // Forward declaration
|
||||
|
||||
List <Object> list; // Doubly-linked list of Object
|
||||
|
||||
@endcode
|
||||
|
||||
Because intrusive containers allocate no memory, allowing objects to be
|
||||
placed inside requires a modification to their class declaration. Each
|
||||
intrusive container declares a nested class `Node` which elements must be
|
||||
derived from, using the Curiously Recurring Template Pattern (CRTP). We
|
||||
will continue to fully declare the Object type from the previous example
|
||||
to support emplacement into an intrusive container:
|
||||
|
||||
@code
|
||||
|
||||
struct Object : public List <Object>::Node // Required for List
|
||||
{
|
||||
void performAction ();
|
||||
};
|
||||
|
||||
@endcode
|
||||
|
||||
Usage of a typedef eliminates redundant specification of the template
|
||||
arguments but requires a forward declaration. The following code is
|
||||
equivalent.
|
||||
|
||||
@code
|
||||
|
||||
struct Object; // Forward declaration
|
||||
|
||||
// Specify template parameters just once
|
||||
typedef List <Object> ListType;
|
||||
|
||||
struct Object : public ListType::Node
|
||||
{
|
||||
void performAction ();
|
||||
};
|
||||
|
||||
ListType::Node list;
|
||||
|
||||
@endcode
|
||||
|
||||
With these declarations we may proceed to create our objects, add them to
|
||||
the list, and perform operations:
|
||||
|
||||
@code
|
||||
|
||||
// Create a few objects and put them in the list
|
||||
for (i = 0; i < 5; ++i)
|
||||
list.push_back (*new Object);
|
||||
|
||||
// Call a method on each list
|
||||
for (ListType::iterator iter = list.begin(); iter != list.end (); ++iter)
|
||||
iter->performAction ();
|
||||
|
||||
@endcode
|
||||
|
||||
Unlike regular STL containers, an object derived from an intrusive container
|
||||
node cannot exist in more than one instance of that list at a time. This is
|
||||
because the bookkeeping information for maintaining the list is kept in
|
||||
the object rather than the list.
|
||||
|
||||
To support objects existing in multiple containers, templates variations
|
||||
are instantiated by distinguishing them with an empty structure, called a
|
||||
tag. The object is derived from multiple instances of Node, where each
|
||||
instance specifies a unique tag. The tag is passed as the second template
|
||||
argument. When the second argument is unspecified, the default tag is used.
|
||||
|
||||
This declaration example shows the usage of tags to allow an object to exist
|
||||
simultaneously in two separate lists:
|
||||
|
||||
@code
|
||||
|
||||
struct GlobalListTag { }; // list of all objects
|
||||
struct ActiveListTag { }; // subset of all objects that are active
|
||||
|
||||
class Object : public List <Object, GlobalListTag>
|
||||
, public List <Object, ActiveListTag>
|
||||
{
|
||||
public:
|
||||
Object () : m_isActive (false)
|
||||
{
|
||||
// Add ourselves to the global list
|
||||
s_globalList.push_front (*this);
|
||||
}
|
||||
|
||||
~Object ()
|
||||
{
|
||||
deactivate ();
|
||||
}
|
||||
|
||||
void becomeActive ()
|
||||
{
|
||||
// Add ourselves to the active list
|
||||
if (!m_isActive)
|
||||
{
|
||||
s_activeList.push_front (*this);
|
||||
m_isActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
void deactivate ()
|
||||
{
|
||||
if (m_isActive)
|
||||
{
|
||||
// Doesn't delete the object
|
||||
s_activeList.erase (s_activeList.iterator_to (this));
|
||||
|
||||
m_isActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_isActive;
|
||||
|
||||
static List <Object, GlobalListTag> s_globalList;
|
||||
static List <Object, ActiveListTag> s_activeList;
|
||||
}
|
||||
|
||||
@endcode
|
||||
|
||||
@defgroup intrusive intrusive
|
||||
@ingroup beast_core
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename, typename>
|
||||
class List;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// This is the intrusive portion of the doubly linked list.
|
||||
// One derivation per list that the object may appear on
|
||||
// concurrently is required.
|
||||
//
|
||||
template <typename T, typename Tag>
|
||||
class ListNode : public Uncopyable
|
||||
{
|
||||
private:
|
||||
typedef T value_type;
|
||||
|
||||
template <typename, typename>
|
||||
friend class List;
|
||||
|
||||
template <typename>
|
||||
friend class ListIterator;
|
||||
|
||||
ListNode* m_next;
|
||||
ListNode* m_prev;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <typename N>
|
||||
class ListIterator : public std::iterator <
|
||||
std::bidirectional_iterator_tag, std::size_t>
|
||||
{
|
||||
public:
|
||||
typedef typename copyconst <N, typename N::value_type>::type
|
||||
|
||||
value_type;
|
||||
typedef value_type* pointer;
|
||||
typedef value_type& reference;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
ListIterator (N* node = nullptr) noexcept
|
||||
: m_node (node)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
ListIterator (ListIterator <M> const& other) noexcept
|
||||
: m_node (other.m_node)
|
||||
{
|
||||
}
|
||||
|
||||
#if 0
|
||||
template <typename M>
|
||||
ListIterator& operator= (ListIterator <M> const& other) noexcept
|
||||
{
|
||||
m_node = other.m_node;
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
template <typename M>
|
||||
bool operator== (ListIterator <M> const& other) const noexcept
|
||||
{
|
||||
return m_node == other.m_node;
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
bool operator!= (ListIterator <M> const& other) const noexcept
|
||||
{
|
||||
return ! ((*this) == other);
|
||||
}
|
||||
|
||||
reference operator* () const noexcept
|
||||
{
|
||||
return dereference ();
|
||||
}
|
||||
|
||||
pointer operator-> () const noexcept
|
||||
{
|
||||
return &dereference ();
|
||||
}
|
||||
|
||||
ListIterator& operator++ () noexcept
|
||||
{
|
||||
increment ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ListIterator operator++ (int) noexcept
|
||||
{
|
||||
ListIterator result (*this);
|
||||
increment ();
|
||||
return result;
|
||||
}
|
||||
|
||||
ListIterator& operator-- () noexcept
|
||||
{
|
||||
decrement ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ListIterator operator-- (int) noexcept
|
||||
{
|
||||
ListIterator result (*this);
|
||||
decrement ();
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
reference dereference () const noexcept
|
||||
{
|
||||
return static_cast <reference> (*m_node);
|
||||
}
|
||||
|
||||
void increment () noexcept
|
||||
{
|
||||
bassert (m_node->m_next);
|
||||
m_node = m_node->m_next;
|
||||
}
|
||||
|
||||
void decrement () noexcept
|
||||
{
|
||||
bassert (m_node->m_prev &&
|
||||
m_node->m_prev->m_prev != nullptr);
|
||||
m_node = m_node->m_prev;
|
||||
}
|
||||
|
||||
N* m_node;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Intrusive doubly linked list.
|
||||
|
||||
This intrusive List is a container similar in operation to std::list in the
|
||||
Standard Template Library (STL). Like all @ref intrusive containers, List
|
||||
requires you to first derive your class from List<>::Node:
|
||||
|
||||
@code
|
||||
|
||||
struct Object : List <Object>::Node
|
||||
{
|
||||
explicit Object (int value) : m_value (value)
|
||||
{
|
||||
}
|
||||
|
||||
int m_value;
|
||||
};
|
||||
|
||||
@endcode
|
||||
|
||||
Now we define the list, and add a couple of items.
|
||||
|
||||
@code
|
||||
|
||||
List <Object> list;
|
||||
|
||||
list.push_back (* (new Object (1)));
|
||||
list.push_back (* (new Object (2)));
|
||||
|
||||
@endcode
|
||||
|
||||
For compatibility with the standard containers, push_back() expects a
|
||||
reference to the object. Unlike the standard container, however, push_back()
|
||||
places the actual object in the list and not a copy-constructed duplicate.
|
||||
|
||||
Iterating over the list follows the same idiom as the STL:
|
||||
|
||||
@code
|
||||
|
||||
for (List <Object>::iterator iter = list.begin(); iter != list.end; ++iter)
|
||||
std::cout << iter->m_value;
|
||||
|
||||
@endcode
|
||||
|
||||
You can even use BOOST_FOREACH, or range based for loops:
|
||||
|
||||
@code
|
||||
|
||||
BOOST_FOREACH (Object& object, list) // boost only
|
||||
std::cout << object.m_value;
|
||||
|
||||
for (Object& object : list) // C++11 only
|
||||
std::cout << object.m_value;
|
||||
|
||||
@endcode
|
||||
|
||||
Because List is mostly STL compliant, it can be passed into STL algorithms:
|
||||
e.g. `std::for_each()` or `std::find_first_of()`.
|
||||
|
||||
In general, objects placed into a List should be dynamically allocated
|
||||
although this cannot be enforced at compile time. Since the caller provides
|
||||
the storage for the object, the caller is also responsible for deleting the
|
||||
object. An object still exists after being removed from a List, until the
|
||||
caller deletes it. This means an element can be moved from one List to
|
||||
another with practically no overhead.
|
||||
|
||||
Unlike the standard containers, an object may only exist in one list at a
|
||||
time, unless special preparations are made. The Tag template parameter is
|
||||
used to distinguish between different list types for the same object,
|
||||
allowing the object to exist in more than one list simultaneously.
|
||||
|
||||
For example, consider an actor system where a global list of actors is
|
||||
maintained, so that they can each be periodically receive processing
|
||||
time. We wish to also maintain a list of the subset of actors that require
|
||||
a domain-dependent update. To achieve this, we declare two tags, the
|
||||
associated list types, and the list element thusly:
|
||||
|
||||
@code
|
||||
|
||||
struct Actor; // Forward declaration required
|
||||
|
||||
struct ProcessTag { };
|
||||
struct UpdateTag { };
|
||||
|
||||
typedef List <Actor, ProcessTag> ProcessList;
|
||||
typedef List <Actor, UpdateTag> UpdateList;
|
||||
|
||||
// Derive from both node types so we can be in each list at once.
|
||||
//
|
||||
struct Actor : ProcessList::Node, UpdateList::Node
|
||||
{
|
||||
bool process (); // returns true if we need an update
|
||||
void update ();
|
||||
};
|
||||
|
||||
@endcode
|
||||
|
||||
@tparam T The base type of element which the list will store
|
||||
pointers to.
|
||||
|
||||
@tparam Tag An optional unique type name used to distinguish lists and nodes,
|
||||
when the object can exist in multiple lists simultaneously.
|
||||
|
||||
@ingroup beast_core intrusive
|
||||
*/
|
||||
template <typename T, typename Tag = void>
|
||||
class List : public Uncopyable
|
||||
{
|
||||
public:
|
||||
typedef typename detail::ListNode <T, Tag> Node;
|
||||
|
||||
typedef T value_type;
|
||||
typedef value_type* pointer;
|
||||
typedef value_type& reference;
|
||||
typedef value_type const* const_pointer;
|
||||
typedef value_type const& const_reference;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
typedef detail::ListIterator <Node> iterator;
|
||||
typedef detail::ListIterator <Node const> const_iterator;
|
||||
|
||||
/** Create an empty list. */
|
||||
List ()
|
||||
{
|
||||
m_head.m_prev = nullptr; // identifies the head
|
||||
m_tail.m_next = nullptr; // identifies the tail
|
||||
clear ();
|
||||
}
|
||||
|
||||
/** Determine if the list is empty.
|
||||
@return `true` if the list is empty.
|
||||
*/
|
||||
bool empty () const noexcept
|
||||
{
|
||||
return size () == 0;
|
||||
}
|
||||
|
||||
/** Returns the number of elements in the list. */
|
||||
size_type size () const noexcept
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
/** Obtain a reference to the first element.
|
||||
@invariant The list may not be empty.
|
||||
@return A reference to the first element.
|
||||
*/
|
||||
reference front () noexcept
|
||||
{
|
||||
return element_from (m_head.m_next);
|
||||
}
|
||||
|
||||
/** Obtain a const reference to the first element.
|
||||
@invariant The list may not be empty.
|
||||
@return A const reference to the first element.
|
||||
*/
|
||||
const_reference front () const noexcept
|
||||
{
|
||||
return element_from (m_head.m_next);
|
||||
}
|
||||
|
||||
/** Obtain a reference to the last element.
|
||||
@invariant The list may not be empty.
|
||||
@return A reference to the last element.
|
||||
*/
|
||||
reference back () noexcept
|
||||
{
|
||||
return element_from (m_tail.m_prev);
|
||||
}
|
||||
|
||||
/** Obtain a const reference to the last element.
|
||||
@invariant The list may not be empty.
|
||||
@return A const reference to the last element.
|
||||
*/
|
||||
const_reference back () const noexcept
|
||||
{
|
||||
return element_from (m_tail.m_prev);
|
||||
}
|
||||
|
||||
/** Obtain an iterator to the beginning of the list.
|
||||
@return An iterator pointing to the beginning of the list.
|
||||
*/
|
||||
iterator begin () noexcept
|
||||
{
|
||||
return iterator (m_head.m_next);
|
||||
}
|
||||
|
||||
/** Obtain a const iterator to the beginning of the list.
|
||||
@return A const iterator pointing to the beginning of the list.
|
||||
*/
|
||||
const_iterator begin () const noexcept
|
||||
{
|
||||
return const_iterator (m_head.m_next);
|
||||
}
|
||||
|
||||
/** Obtain a const iterator to the beginning of the list.
|
||||
@return A const iterator pointing to the beginning of the list.
|
||||
*/
|
||||
const_iterator cbegin () const noexcept
|
||||
{
|
||||
return const_iterator (m_head.m_next);
|
||||
}
|
||||
|
||||
/** Obtain a iterator to the end of the list.
|
||||
@return An iterator pointing to the end of the list.
|
||||
*/
|
||||
iterator end () noexcept
|
||||
{
|
||||
return iterator (&m_tail);
|
||||
}
|
||||
|
||||
/** Obtain a const iterator to the end of the list.
|
||||
@return A constiterator pointing to the end of the list.
|
||||
*/
|
||||
const_iterator end () const noexcept
|
||||
{
|
||||
return const_iterator (&m_tail);
|
||||
}
|
||||
|
||||
/** Obtain a const iterator to the end of the list
|
||||
@return A constiterator pointing to the end of the list.
|
||||
*/
|
||||
const_iterator cend () const noexcept
|
||||
{
|
||||
return const_iterator (&m_tail);
|
||||
}
|
||||
|
||||
/** Clear the list.
|
||||
@note This does not free the elements.
|
||||
*/
|
||||
void clear () noexcept
|
||||
{
|
||||
m_head.m_next = &m_tail;
|
||||
m_tail.m_prev = &m_head;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
/** Insert an element.
|
||||
@invariant The element must not already be in the list.
|
||||
@param pos The location to insert after.
|
||||
@param element The element to insert.
|
||||
@return An iterator pointing to the newly inserted element.
|
||||
*/
|
||||
iterator insert (iterator pos, T& element) noexcept
|
||||
{
|
||||
Node* node = static_cast <Node*> (&element);
|
||||
node->m_next = &*pos;
|
||||
node->m_prev = node->m_next->m_prev;
|
||||
node->m_next->m_prev = node;
|
||||
node->m_prev->m_next = node;
|
||||
++m_size;
|
||||
return iterator (node);
|
||||
}
|
||||
|
||||
/** Insert another list into this one.
|
||||
The other list is cleared.
|
||||
@param pos The location to insert after.
|
||||
@param other The list to insert.
|
||||
*/
|
||||
|
||||
void insert (iterator pos, List& other) noexcept
|
||||
{
|
||||
if (!other.empty ())
|
||||
{
|
||||
Node* before = &*pos;
|
||||
other.m_head.m_next->m_prev = before->m_prev;
|
||||
before->m_prev->m_next = other.m_head.m_next;
|
||||
other.m_tail.m_prev->m_next = before;
|
||||
before->m_prev = other.m_tail.m_prev;
|
||||
m_size += other.m_size;
|
||||
other.clear ();
|
||||
}
|
||||
}
|
||||
|
||||
/** Remove an element.
|
||||
@invariant The element must exist in the list.
|
||||
@param pos An iterator pointing to the element to remove.
|
||||
@return An iterator pointing to the next element after the one removed.
|
||||
*/
|
||||
iterator erase (iterator pos) noexcept
|
||||
{
|
||||
Node* node = &*pos;
|
||||
++pos;
|
||||
node->m_next->m_prev = node->m_prev;
|
||||
node->m_prev->m_next = node->m_next;
|
||||
--m_size;
|
||||
return pos;
|
||||
}
|
||||
|
||||
/** Insert an element at the beginning of the list.
|
||||
@invariant The element must not exist in the list.
|
||||
@param element The element to insert.
|
||||
*/
|
||||
iterator push_front (T& element) noexcept
|
||||
{
|
||||
return insert (begin (), element);
|
||||
}
|
||||
|
||||
/** Remove the element at the beginning of the list.
|
||||
@invariant The list must not be empty.
|
||||
@return A reference to the popped element.
|
||||
*/
|
||||
T& pop_front () noexcept
|
||||
{
|
||||
T& element (front ());
|
||||
erase (begin ());
|
||||
return element;
|
||||
}
|
||||
|
||||
/** Append an element at the end of the list.
|
||||
@invariant The element must not exist in the list.
|
||||
@param element The element to append.
|
||||
*/
|
||||
iterator push_back (T& element) noexcept
|
||||
{
|
||||
return insert (end (), element);
|
||||
}
|
||||
|
||||
/** Remove the element at the end of the list.
|
||||
@invariant The list must not be empty.
|
||||
@return A reference to the popped element.
|
||||
*/
|
||||
T& pop_back () noexcept
|
||||
{
|
||||
T& element (back ());
|
||||
erase (--end ());
|
||||
return element;
|
||||
}
|
||||
|
||||
/** Swap contents with another list. */
|
||||
void swap (List& other) noexcept
|
||||
{
|
||||
List temp;
|
||||
temp.append (other);
|
||||
other.append (*this);
|
||||
append (temp);
|
||||
}
|
||||
|
||||
/** Insert another list at the beginning of this list.
|
||||
The other list is cleared.
|
||||
@param list The other list to insert.
|
||||
*/
|
||||
iterator prepend (List& list) noexcept
|
||||
{
|
||||
return insert (begin (), list);
|
||||
}
|
||||
|
||||
/** Append another list at the end of this list.
|
||||
The other list is cleared.
|
||||
@param list the other list to append.
|
||||
*/
|
||||
iterator append (List& list) noexcept
|
||||
{
|
||||
return insert (end (), list);
|
||||
}
|
||||
|
||||
/** Obtain an iterator from an element.
|
||||
@invariant The element must exist in the list.
|
||||
@param element The element to obtain an iterator for.
|
||||
@return An iterator to the element.
|
||||
*/
|
||||
iterator iterator_to (T& element) const noexcept
|
||||
{
|
||||
return iterator (static_cast <Node*> (&element));
|
||||
}
|
||||
|
||||
/** Obtain a const iterator from an element.
|
||||
@invariant The element must exist in the list.
|
||||
@param element The element to obtain an iterator for.
|
||||
@return A const iterator to the element.
|
||||
*/
|
||||
const_iterator const_iterator_to (T const& element) const noexcept
|
||||
{
|
||||
return const_iterator (static_cast <Node const*> (&element));
|
||||
}
|
||||
|
||||
private:
|
||||
reference element_from (Node* node) noexcept
|
||||
{
|
||||
return *(static_cast <pointer> (node));
|
||||
}
|
||||
|
||||
const_reference element_from (Node const* node) const noexcept
|
||||
{
|
||||
return *(static_cast <const_pointer> (node));
|
||||
}
|
||||
|
||||
private:
|
||||
size_type m_size;
|
||||
Node m_head;
|
||||
Node m_tail;
|
||||
};
|
||||
|
||||
#endif
|
||||
228
src/beast/modules/beast_core/containers/beast_AbstractFifo.cpp
Normal file
228
src/beast/modules/beast_core/containers/beast_AbstractFifo.cpp
Normal file
@@ -0,0 +1,228 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
AbstractFifo::AbstractFifo (const int capacity) noexcept
|
||||
: bufferSize (capacity)
|
||||
{
|
||||
bassert (bufferSize > 0);
|
||||
}
|
||||
|
||||
AbstractFifo::~AbstractFifo() {}
|
||||
|
||||
int AbstractFifo::getTotalSize() const noexcept { return bufferSize; }
|
||||
int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady(); }
|
||||
|
||||
int AbstractFifo::getNumReady() const noexcept
|
||||
{
|
||||
const int vs = validStart.get();
|
||||
const int ve = validEnd.get();
|
||||
return ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
|
||||
}
|
||||
|
||||
void AbstractFifo::reset() noexcept
|
||||
{
|
||||
validEnd = 0;
|
||||
validStart = 0;
|
||||
}
|
||||
|
||||
void AbstractFifo::setTotalSize (int newSize) noexcept
|
||||
{
|
||||
bassert (newSize > 0);
|
||||
reset();
|
||||
bufferSize = newSize;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept
|
||||
{
|
||||
const int vs = validStart.get();
|
||||
const int ve = validEnd.value;
|
||||
|
||||
const int freeSpace = ve >= vs ? (bufferSize - (ve - vs)) : (vs - ve);
|
||||
numToWrite = bmin (numToWrite, freeSpace - 1);
|
||||
|
||||
if (numToWrite <= 0)
|
||||
{
|
||||
startIndex1 = 0;
|
||||
startIndex2 = 0;
|
||||
blockSize1 = 0;
|
||||
blockSize2 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
startIndex1 = ve;
|
||||
startIndex2 = 0;
|
||||
blockSize1 = bmin (bufferSize - ve, numToWrite);
|
||||
numToWrite -= blockSize1;
|
||||
blockSize2 = numToWrite <= 0 ? 0 : bmin (numToWrite, vs);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractFifo::finishedWrite (int numWritten) noexcept
|
||||
{
|
||||
bassert (numWritten >= 0 && numWritten < bufferSize);
|
||||
int newEnd = validEnd.value + numWritten;
|
||||
if (newEnd >= bufferSize)
|
||||
newEnd -= bufferSize;
|
||||
|
||||
validEnd = newEnd;
|
||||
}
|
||||
|
||||
void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept
|
||||
{
|
||||
const int vs = validStart.value;
|
||||
const int ve = validEnd.get();
|
||||
|
||||
const int numReady = ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
|
||||
numWanted = bmin (numWanted, numReady);
|
||||
|
||||
if (numWanted <= 0)
|
||||
{
|
||||
startIndex1 = 0;
|
||||
startIndex2 = 0;
|
||||
blockSize1 = 0;
|
||||
blockSize2 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
startIndex1 = vs;
|
||||
startIndex2 = 0;
|
||||
blockSize1 = bmin (bufferSize - vs, numWanted);
|
||||
numWanted -= blockSize1;
|
||||
blockSize2 = numWanted <= 0 ? 0 : bmin (numWanted, ve);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractFifo::finishedRead (int numRead) noexcept
|
||||
{
|
||||
bassert (numRead >= 0 && numRead <= bufferSize);
|
||||
|
||||
int newStart = validStart.value + numRead;
|
||||
if (newStart >= bufferSize)
|
||||
newStart -= bufferSize;
|
||||
|
||||
validStart = newStart;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
||||
class AbstractFifoTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
AbstractFifoTests() : UnitTest ("Abstract Fifo", "beast")
|
||||
{
|
||||
}
|
||||
|
||||
class WriteThread : public Thread
|
||||
{
|
||||
public:
|
||||
WriteThread (AbstractFifo& fifo_, int* buffer_)
|
||||
: Thread ("fifo writer"), fifo (fifo_), buffer (buffer_)
|
||||
{
|
||||
startThread();
|
||||
}
|
||||
|
||||
~WriteThread()
|
||||
{
|
||||
stopThread (5000);
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
int n = 0;
|
||||
Random r;
|
||||
|
||||
while (! threadShouldExit())
|
||||
{
|
||||
int num = r.nextInt (2000) + 1;
|
||||
|
||||
int start1, size1, start2, size2;
|
||||
fifo.prepareToWrite (num, start1, size1, start2, size2);
|
||||
|
||||
bassert (size1 >= 0 && size2 >= 0);
|
||||
bassert (size1 == 0 || (start1 >= 0 && start1 < fifo.getTotalSize()));
|
||||
bassert (size2 == 0 || (start2 >= 0 && start2 < fifo.getTotalSize()));
|
||||
|
||||
for (int i = 0; i < size1; ++i)
|
||||
buffer [start1 + i] = n++;
|
||||
|
||||
for (int i = 0; i < size2; ++i)
|
||||
buffer [start2 + i] = n++;
|
||||
|
||||
fifo.finishedWrite (size1 + size2);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
AbstractFifo& fifo;
|
||||
int* buffer;
|
||||
};
|
||||
|
||||
void runTest()
|
||||
{
|
||||
beginTestCase ("AbstractFifo");
|
||||
|
||||
int buffer [5000];
|
||||
AbstractFifo fifo (numElementsInArray (buffer));
|
||||
|
||||
WriteThread writer (fifo, buffer);
|
||||
|
||||
int n = 0;
|
||||
Random r;
|
||||
|
||||
bool failed = false;
|
||||
|
||||
for (int count = 100000; --count >= 0;)
|
||||
{
|
||||
int num = r.nextInt (6000) + 1;
|
||||
|
||||
int start1, size1, start2, size2;
|
||||
fifo.prepareToRead (num, start1, size1, start2, size2);
|
||||
|
||||
if (! (size1 >= 0 && size2 >= 0)
|
||||
&& (size1 == 0 || (start1 >= 0 && start1 < fifo.getTotalSize()))
|
||||
&& (size2 == 0 || (start2 >= 0 && start2 < fifo.getTotalSize())))
|
||||
{
|
||||
expect (false, "prepareToRead returned negative values");
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < size1; ++i)
|
||||
failed = (buffer [start1 + i] != n++) || failed;
|
||||
|
||||
for (int i = 0; i < size2; ++i)
|
||||
failed = (buffer [start2 + i] != n++) || failed;
|
||||
|
||||
if (failed)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
fifo.finishedRead (size1 + size2);
|
||||
}
|
||||
|
||||
expect (! failed, "read values were incorrect");
|
||||
}
|
||||
};
|
||||
|
||||
static AbstractFifoTests abstractFifoTests;
|
||||
212
src/beast/modules/beast_core/containers/beast_AbstractFifo.h
Normal file
212
src/beast/modules/beast_core/containers/beast_AbstractFifo.h
Normal file
@@ -0,0 +1,212 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
Portions of this file are from JUCE.
|
||||
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||
Please visit http://www.juce.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_ABSTRACTFIFO_H_INCLUDED
|
||||
#define BEAST_ABSTRACTFIFO_H_INCLUDED
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Encapsulates the logic required to implement a lock-free FIFO.
|
||||
|
||||
This class handles the logic needed when building a single-reader,
|
||||
single-writer FIFO.
|
||||
|
||||
It doesn't actually hold any data itself, but your FIFO class can use one of
|
||||
these to manage its position and status when reading or writing to it.
|
||||
|
||||
To use it, you can call prepareToWrite() to determine the position within
|
||||
your own buffer that an incoming block of data should be stored, and
|
||||
prepareToRead() to find out when the next outgoing block should be read from.
|
||||
|
||||
e.g.
|
||||
@code
|
||||
class MyFifo
|
||||
{
|
||||
public:
|
||||
MyFifo() : abstractFifo (1024)
|
||||
{
|
||||
}
|
||||
|
||||
void addToFifo (const int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
abstractFifo.prepareToWrite (numItems, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (myBuffer + start1, someData, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (myBuffer + start2, someData + size1, size2);
|
||||
|
||||
abstractFifo.finishedWrite (size1 + size2);
|
||||
}
|
||||
|
||||
void readFromFifo (int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
abstractFifo.prepareToRead (numSamples, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (someData, myBuffer + start1, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (someData + size1, myBuffer + start2, size2);
|
||||
|
||||
abstractFifo.finishedRead (size1 + size2);
|
||||
}
|
||||
|
||||
private:
|
||||
AbstractFifo abstractFifo;
|
||||
int myBuffer [1024];
|
||||
};
|
||||
@endcode
|
||||
*/
|
||||
class BEAST_API AbstractFifo : LeakChecked <AbstractFifo>, public Uncopyable
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates a FIFO to manage a buffer with the specified capacity. */
|
||||
AbstractFifo (int capacity) noexcept;
|
||||
|
||||
/** Destructor */
|
||||
~AbstractFifo();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the total size of the buffer being managed. */
|
||||
int getTotalSize() const noexcept;
|
||||
|
||||
/** Returns the number of items that can currently be added to the buffer without it overflowing. */
|
||||
int getFreeSpace() const noexcept;
|
||||
|
||||
/** Returns the number of items that can currently be read from the buffer. */
|
||||
int getNumReady() const noexcept;
|
||||
|
||||
/** Clears the buffer positions, so that it appears empty. */
|
||||
void reset() noexcept;
|
||||
|
||||
/** Changes the buffer's total size.
|
||||
Note that this isn't thread-safe, so don't call it if there's any danger that it
|
||||
might overlap with a call to any other method in this class!
|
||||
*/
|
||||
void setTotalSize (int newSize) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the location within the buffer at which an incoming block of data should be written.
|
||||
|
||||
Because the section of data that you want to add to the buffer may overlap the end
|
||||
and wrap around to the start, two blocks within your buffer are returned, and you
|
||||
should copy your data into the first one, with any remaining data spilling over into
|
||||
the second.
|
||||
|
||||
If the number of items you ask for is too large to fit within the buffer's free space, then
|
||||
blockSize1 + blockSize2 may add up to a lower value than numToWrite. If this happens, you
|
||||
may decide to keep waiting and re-trying the method until there's enough space available.
|
||||
|
||||
After calling this method, if you choose to write your data into the blocks returned, you
|
||||
must call finishedWrite() to tell the FIFO how much data you actually added.
|
||||
|
||||
e.g.
|
||||
@code
|
||||
void addToFifo (const int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
prepareToWrite (numItems, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (myBuffer + start1, someData, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (myBuffer + start2, someData + size1, size2);
|
||||
|
||||
finishedWrite (size1 + size2);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@param numToWrite indicates how many items you'd like to add to the buffer
|
||||
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
|
||||
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
|
||||
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
|
||||
the first block should be written
|
||||
@param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
|
||||
@see finishedWrite
|
||||
*/
|
||||
void prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
|
||||
|
||||
/** Called after writing from the FIFO, to indicate that this many items have been added.
|
||||
@see prepareToWrite
|
||||
*/
|
||||
void finishedWrite (int numWritten) noexcept;
|
||||
|
||||
/** Returns the location within the buffer from which the next block of data should be read.
|
||||
|
||||
Because the section of data that you want to read from the buffer may overlap the end
|
||||
and wrap around to the start, two blocks within your buffer are returned, and you
|
||||
should read from both of them.
|
||||
|
||||
If the number of items you ask for is greater than the amount of data available, then
|
||||
blockSize1 + blockSize2 may add up to a lower value than numWanted. If this happens, you
|
||||
may decide to keep waiting and re-trying the method until there's enough data available.
|
||||
|
||||
After calling this method, if you choose to read the data, you must call finishedRead() to
|
||||
tell the FIFO how much data you have consumed.
|
||||
|
||||
e.g.
|
||||
@code
|
||||
void readFromFifo (int* someData, int numItems)
|
||||
{
|
||||
int start1, size1, start2, size2;
|
||||
prepareToRead (numSamples, start1, size1, start2, size2);
|
||||
|
||||
if (size1 > 0)
|
||||
copySomeData (someData, myBuffer + start1, size1);
|
||||
|
||||
if (size2 > 0)
|
||||
copySomeData (someData + size1, myBuffer + start2, size2);
|
||||
|
||||
finishedRead (size1 + size2);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@param numWanted indicates how many items you'd like to add to the buffer
|
||||
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
|
||||
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
|
||||
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
|
||||
the first block should be written
|
||||
@param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
|
||||
@see finishedRead
|
||||
*/
|
||||
void prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
|
||||
|
||||
/** Called after reading from the FIFO, to indicate that this many items have now been consumed.
|
||||
@see prepareToRead
|
||||
*/
|
||||
void finishedRead (int numRead) noexcept;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
int bufferSize;
|
||||
Atomic <int> validStart, validEnd;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
1055
src/beast/modules/beast_core/containers/beast_Array.h
Normal file
1055
src/beast/modules/beast_core/containers/beast_Array.h
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user