diff --git a/Readme.md b/Readme.md index 5585673..b99c42d 100644 --- a/Readme.md +++ b/Readme.md @@ -1,7 +1,7 @@ Boost libraries - trimmed down for yuzu ======================================== -This is a subset of Boost v1.68.0 generated using the bcp tool. To get a list of boost modules guaranteed to exist, check the build script. +This is a subset of Boost v1.71.0 generated using the bcp tool. To get a list of boost modules guaranteed to exist, check the build script. Updating this repo (on Windows) =============================== @@ -20,4 +20,5 @@ To update the Boost version (or to add a new library) follow these steps: - `cd` to this repo's directory (`...\externals\boost\`) - Remove the existing boost from the repo: `rm -r boost` (This is only necessary if doing a Boost version upgrade, in case they removed any files in the new version.) - Run `.\build.cmd $boost_dir` to build a new trimmed down distro. + - Remove `libs\` and `Jamroot` if you didn't introduce any new boost dependencies that aren't header only - Add/remove all files in git and commit. diff --git a/boost/algorithm/string/case_conv.hpp b/boost/algorithm/string/case_conv.hpp new file mode 100644 index 0000000..683340b --- /dev/null +++ b/boost/algorithm/string/case_conv.hpp @@ -0,0 +1,176 @@ +// Boost string_algo library case_conv.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_CASE_CONV_HPP +#define BOOST_STRING_CASE_CONV_HPP + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/*! \file + Defines sequence case-conversion algorithms. + Algorithms convert each element in the input sequence to the + desired case using provided locales. +*/ + +namespace boost { + namespace algorithm { + +// to_lower -----------------------------------------------// + + //! Convert to lower case + /*! + Each element of the input sequence is converted to lower + case. The result is a copy of the input converted to lower case. + It is returned as a sequence or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input range + \param Loc A locale used for conversion + \return + An output iterator pointing just after the last inserted character or + a copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + + */ + template + inline OutputIteratorT + to_lower_copy( + OutputIteratorT Output, + const RangeT& Input, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::detail::transform_range_copy( + Output, + ::boost::as_literal(Input), + ::boost::algorithm::detail::to_lowerF< + typename range_value::type >(Loc)); + } + + //! Convert to lower case + /*! + \overload + */ + template + inline SequenceT to_lower_copy( + const SequenceT& Input, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::detail::transform_range_copy( + Input, + ::boost::algorithm::detail::to_lowerF< + typename range_value::type >(Loc)); + } + + //! Convert to lower case + /*! + Each element of the input sequence is converted to lower + case. The input sequence is modified in-place. + + \param Input A range + \param Loc a locale used for conversion + */ + template + inline void to_lower( + WritableRangeT& Input, + const std::locale& Loc=std::locale()) + { + ::boost::algorithm::detail::transform_range( + ::boost::as_literal(Input), + ::boost::algorithm::detail::to_lowerF< + typename range_value::type >(Loc)); + } + +// to_upper -----------------------------------------------// + + //! Convert to upper case + /*! + Each element of the input sequence is converted to upper + case. The result is a copy of the input converted to upper case. + It is returned as a sequence or copied to the output iterator + + \param Output An output iterator to which the result will be copied + \param Input An input range + \param Loc A locale used for conversion + \return + An output iterator pointing just after the last inserted character or + a copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template + inline OutputIteratorT + to_upper_copy( + OutputIteratorT Output, + const RangeT& Input, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::detail::transform_range_copy( + Output, + ::boost::as_literal(Input), + ::boost::algorithm::detail::to_upperF< + typename range_value::type >(Loc)); + } + + //! Convert to upper case + /*! + \overload + */ + template + inline SequenceT to_upper_copy( + const SequenceT& Input, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::detail::transform_range_copy( + Input, + ::boost::algorithm::detail::to_upperF< + typename range_value::type >(Loc)); + } + + //! Convert to upper case + /*! + Each element of the input sequence is converted to upper + case. The input sequence is modified in-place. + + \param Input An input range + \param Loc a locale used for conversion + */ + template + inline void to_upper( + WritableRangeT& Input, + const std::locale& Loc=std::locale()) + { + ::boost::algorithm::detail::transform_range( + ::boost::as_literal(Input), + ::boost::algorithm::detail::to_upperF< + typename range_value::type >(Loc)); + } + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::to_lower; + using algorithm::to_lower_copy; + using algorithm::to_upper; + using algorithm::to_upper_copy; + +} // namespace boost + +#endif // BOOST_STRING_CASE_CONV_HPP diff --git a/boost/algorithm/string/compare.hpp b/boost/algorithm/string/compare.hpp new file mode 100644 index 0000000..734303a --- /dev/null +++ b/boost/algorithm/string/compare.hpp @@ -0,0 +1,199 @@ +// Boost string_algo library compare.hpp header file -------------------------// + +// Copyright Pavol Droba 2002-2006. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_COMPARE_HPP +#define BOOST_STRING_COMPARE_HPP + +#include +#include + +/*! \file + Defines element comparison predicates. Many algorithms in this library can + take an additional argument with a predicate used to compare elements. + This makes it possible, for instance, to have case insensitive versions + of the algorithms. +*/ + +namespace boost { + namespace algorithm { + + // is_equal functor -----------------------------------------------// + + //! is_equal functor + /*! + Standard STL equal_to only handle comparison between arguments + of the same type. This is a less restrictive version which wraps operator ==. + */ + struct is_equal + { + //! Function operator + /*! + Compare two operands for equality + */ + template< typename T1, typename T2 > + bool operator()( const T1& Arg1, const T2& Arg2 ) const + { + return Arg1==Arg2; + } + }; + + //! case insensitive version of is_equal + /*! + Case insensitive comparison predicate. Comparison is done using + specified locales. + */ + struct is_iequal + { + //! Constructor + /*! + \param Loc locales used for comparison + */ + is_iequal( const std::locale& Loc=std::locale() ) : + m_Loc( Loc ) {} + + //! Function operator + /*! + Compare two operands. Case is ignored. + */ + template< typename T1, typename T2 > + bool operator()( const T1& Arg1, const T2& Arg2 ) const + { + #if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL) + return std::toupper(Arg1)==std::toupper(Arg2); + #else + return std::toupper(Arg1,m_Loc)==std::toupper(Arg2,m_Loc); + #endif + } + + private: + std::locale m_Loc; + }; + + // is_less functor -----------------------------------------------// + + //! is_less functor + /*! + Convenient version of standard std::less. Operation is templated, therefore it is + not required to specify the exact types upon the construction + */ + struct is_less + { + //! Functor operation + /*! + Compare two operands using > operator + */ + template< typename T1, typename T2 > + bool operator()( const T1& Arg1, const T2& Arg2 ) const + { + return Arg1 + bool operator()( const T1& Arg1, const T2& Arg2 ) const + { + #if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL) + return std::toupper(Arg1)(Arg1,m_Loc)(Arg2,m_Loc); + #endif + } + + private: + std::locale m_Loc; + }; + + // is_not_greater functor -----------------------------------------------// + + //! is_not_greater functor + /*! + Convenient version of standard std::not_greater_to. Operation is templated, therefore it is + not required to specify the exact types upon the construction + */ + struct is_not_greater + { + //! Functor operation + /*! + Compare two operands using > operator + */ + template< typename T1, typename T2 > + bool operator()( const T1& Arg1, const T2& Arg2 ) const + { + return Arg1<=Arg2; + } + }; + + + //! case insensitive version of is_not_greater + /*! + Case insensitive comparison predicate. Comparison is done using + specified locales. + */ + struct is_not_igreater + { + //! Constructor + /*! + \param Loc locales used for comparison + */ + is_not_igreater( const std::locale& Loc=std::locale() ) : + m_Loc( Loc ) {} + + //! Function operator + /*! + Compare two operands. Case is ignored. + */ + template< typename T1, typename T2 > + bool operator()( const T1& Arg1, const T2& Arg2 ) const + { + #if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL) + return std::toupper(Arg1)<=std::toupper(Arg2); + #else + return std::toupper(Arg1,m_Loc)<=std::toupper(Arg2,m_Loc); + #endif + } + + private: + std::locale m_Loc; + }; + + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::is_equal; + using algorithm::is_iequal; + using algorithm::is_less; + using algorithm::is_iless; + using algorithm::is_not_greater; + using algorithm::is_not_igreater; + +} // namespace boost + + +#endif // BOOST_STRING_COMPARE_HPP diff --git a/boost/algorithm/string/concept.hpp b/boost/algorithm/string/concept.hpp new file mode 100644 index 0000000..17e8349 --- /dev/null +++ b/boost/algorithm/string/concept.hpp @@ -0,0 +1,83 @@ +// Boost string_algo library concept.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_CONCEPT_HPP +#define BOOST_STRING_CONCEPT_HPP + +#include +#include +#include +#include + +/*! \file + Defines concepts used in string_algo library +*/ + +namespace boost { + namespace algorithm { + + //! Finder concept + /*! + Defines the Finder concept. Finder is a functor which selects + an arbitrary part of a string. Search is performed on + the range specified by starting and ending iterators. + + Result of the find operation must be convertible to iterator_range. + */ + template + struct FinderConcept + { + private: + typedef iterator_range range; + public: + void constraints() + { + // Operation + r=(*pF)(i,i); + } + private: + range r; + IteratorT i; + FinderT* pF; + }; // Finder_concept + + + //! Formatter concept + /*! + Defines the Formatter concept. Formatter is a functor, which + takes a result from a finder operation and transforms it + in a specific way. + + Result must be a container supported by container_traits, + or a reference to it. + */ + template + struct FormatterConcept + { + public: + void constraints() + { + // Operation + ::boost::begin((*pFo)( (*pF)(i,i) )); + ::boost::end((*pFo)( (*pF)(i,i) )); + } + private: + IteratorT i; + FinderT* pF; + FormatterT *pFo; + }; // FormatterConcept; + + } // namespace algorithm +} // namespace boost + + + + +#endif // BOOST_STRING_CONCEPT_HPP diff --git a/boost/algorithm/string/config.hpp b/boost/algorithm/string/config.hpp new file mode 100644 index 0000000..559750a --- /dev/null +++ b/boost/algorithm/string/config.hpp @@ -0,0 +1,28 @@ +// Boost string_algo library config.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_CONFIG_HPP +#define BOOST_STRING_CONFIG_HPP + +#include +#include + +#ifdef BOOST_STRING_DEDUCED_TYPENAME +# error "macro already defined!" +#endif + +#define BOOST_STRING_TYPENAME BOOST_DEDUCED_TYPENAME + +// Metrowerks workaround +#if BOOST_WORKAROUND(__MWERKS__, <= 0x3003) // 8.x +#pragma parse_func_templ off +#endif + +#endif // BOOST_STRING_CONFIG_HPP diff --git a/boost/algorithm/string/constants.hpp b/boost/algorithm/string/constants.hpp new file mode 100644 index 0000000..6ed70ef --- /dev/null +++ b/boost/algorithm/string/constants.hpp @@ -0,0 +1,36 @@ +// Boost string_algo library constants.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_CONSTANTS_HPP +#define BOOST_STRING_CONSTANTS_HPP + +namespace boost { + namespace algorithm { + + //! Token compression mode + /*! + Specifies token compression mode for the token_finder. + */ + enum token_compress_mode_type + { + token_compress_on, //!< Compress adjacent tokens + token_compress_off //!< Do not compress adjacent tokens + }; + + } // namespace algorithm + + // pull the names to the boost namespace + using algorithm::token_compress_on; + using algorithm::token_compress_off; + +} // namespace boost + +#endif // BOOST_STRING_CONSTANTS_HPP + diff --git a/boost/algorithm/string/detail/case_conv.hpp b/boost/algorithm/string/detail/case_conv.hpp new file mode 100644 index 0000000..233912c --- /dev/null +++ b/boost/algorithm/string/detail/case_conv.hpp @@ -0,0 +1,127 @@ +// Boost string_algo library string_funct.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_CASE_CONV_DETAIL_HPP +#define BOOST_STRING_CASE_CONV_DETAIL_HPP + +#include +#include +#include + +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// case conversion functors -----------------------------------------------// + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(push) +#pragma warning(disable:4512) //assignment operator could not be generated +#endif + + // a tolower functor + template + struct to_lowerF + { + typedef CharT argument_type; + typedef CharT result_type; + // Constructor + to_lowerF( const std::locale& Loc ) : m_Loc( &Loc ) {} + + // Operation + CharT operator ()( CharT Ch ) const + { + #if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL) + return std::tolower( static_cast::type> ( Ch )); + #else + return std::tolower( Ch, *m_Loc ); + #endif + } + private: + const std::locale* m_Loc; + }; + + // a toupper functor + template + struct to_upperF + { + typedef CharT argument_type; + typedef CharT result_type; + // Constructor + to_upperF( const std::locale& Loc ) : m_Loc( &Loc ) {} + + // Operation + CharT operator ()( CharT Ch ) const + { + #if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL) + return std::toupper( static_cast::type> ( Ch )); + #else + return std::toupper( Ch, *m_Loc ); + #endif + } + private: + const std::locale* m_Loc; + }; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +// algorithm implementation ------------------------------------------------------------------------- + + // Transform a range + template + OutputIteratorT transform_range_copy( + OutputIteratorT Output, + const RangeT& Input, + FunctorT Functor) + { + return std::transform( + ::boost::begin(Input), + ::boost::end(Input), + Output, + Functor); + } + + // Transform a range (in-place) + template + void transform_range( + const RangeT& Input, + FunctorT Functor) + { + std::transform( + ::boost::begin(Input), + ::boost::end(Input), + ::boost::begin(Input), + Functor); + } + + template + inline SequenceT transform_range_copy( + const RangeT& Input, + FunctorT Functor) + { + return SequenceT( + ::boost::make_transform_iterator( + ::boost::begin(Input), + Functor), + ::boost::make_transform_iterator( + ::boost::end(Input), + Functor)); + } + + } // namespace detail + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_CASE_CONV_DETAIL_HPP diff --git a/boost/algorithm/string/detail/find_format.hpp b/boost/algorithm/string/detail/find_format.hpp new file mode 100644 index 0000000..b398750 --- /dev/null +++ b/boost/algorithm/string/detail/find_format.hpp @@ -0,0 +1,204 @@ +// Boost string_algo library find_format.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FIND_FORMAT_DETAIL_HPP +#define BOOST_STRING_FIND_FORMAT_DETAIL_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// find_format_copy (iterator variant) implementation -------------------------------// + + template< + typename OutputIteratorT, + typename InputT, + typename FormatterT, + typename FindResultT, + typename FormatResultT > + inline OutputIteratorT find_format_copy_impl2( + OutputIteratorT Output, + const InputT& Input, + FormatterT Formatter, + const FindResultT& FindResult, + const FormatResultT& FormatResult ) + { + typedef find_format_store< + BOOST_STRING_TYPENAME + range_const_iterator::type, + FormatterT, + FormatResultT > store_type; + + // Create store for the find result + store_type M( FindResult, FormatResult, Formatter ); + + if ( !M ) + { + // Match not found - return original sequence + Output = std::copy( ::boost::begin(Input), ::boost::end(Input), Output ); + return Output; + } + + // Copy the beginning of the sequence + Output = std::copy( ::boost::begin(Input), ::boost::begin(M), Output ); + // Format find result + // Copy formatted result + Output = std::copy( ::boost::begin(M.format_result()), ::boost::end(M.format_result()), Output ); + // Copy the rest of the sequence + Output = std::copy( M.end(), ::boost::end(Input), Output ); + + return Output; + } + + template< + typename OutputIteratorT, + typename InputT, + typename FormatterT, + typename FindResultT > + inline OutputIteratorT find_format_copy_impl( + OutputIteratorT Output, + const InputT& Input, + FormatterT Formatter, + const FindResultT& FindResult ) + { + if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) { + return ::boost::algorithm::detail::find_format_copy_impl2( + Output, + Input, + Formatter, + FindResult, + Formatter(FindResult) ); + } else { + return std::copy( ::boost::begin(Input), ::boost::end(Input), Output ); + } + } + + +// find_format_copy implementation --------------------------------------------------// + + template< + typename InputT, + typename FormatterT, + typename FindResultT, + typename FormatResultT > + inline InputT find_format_copy_impl2( + const InputT& Input, + FormatterT Formatter, + const FindResultT& FindResult, + const FormatResultT& FormatResult) + { + typedef find_format_store< + BOOST_STRING_TYPENAME + range_const_iterator::type, + FormatterT, + FormatResultT > store_type; + + // Create store for the find result + store_type M( FindResult, FormatResult, Formatter ); + + if ( !M ) + { + // Match not found - return original sequence + return InputT( Input ); + } + + InputT Output; + // Copy the beginning of the sequence + boost::algorithm::detail::insert( Output, ::boost::end(Output), ::boost::begin(Input), M.begin() ); + // Copy formatted result + boost::algorithm::detail::insert( Output, ::boost::end(Output), M.format_result() ); + // Copy the rest of the sequence + boost::algorithm::detail::insert( Output, ::boost::end(Output), M.end(), ::boost::end(Input) ); + + return Output; + } + + template< + typename InputT, + typename FormatterT, + typename FindResultT > + inline InputT find_format_copy_impl( + const InputT& Input, + FormatterT Formatter, + const FindResultT& FindResult) + { + if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) { + return ::boost::algorithm::detail::find_format_copy_impl2( + Input, + Formatter, + FindResult, + Formatter(FindResult) ); + } else { + return Input; + } + } + + // replace implementation ----------------------------------------------------// + + template< + typename InputT, + typename FormatterT, + typename FindResultT, + typename FormatResultT > + inline void find_format_impl2( + InputT& Input, + FormatterT Formatter, + const FindResultT& FindResult, + const FormatResultT& FormatResult) + { + typedef find_format_store< + BOOST_STRING_TYPENAME + range_iterator::type, + FormatterT, + FormatResultT > store_type; + + // Create store for the find result + store_type M( FindResult, FormatResult, Formatter ); + + if ( !M ) + { + // Search not found - return original sequence + return; + } + + // Replace match + ::boost::algorithm::detail::replace( Input, M.begin(), M.end(), M.format_result() ); + } + + template< + typename InputT, + typename FormatterT, + typename FindResultT > + inline void find_format_impl( + InputT& Input, + FormatterT Formatter, + const FindResultT& FindResult) + { + if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) { + ::boost::algorithm::detail::find_format_impl2( + Input, + Formatter, + FindResult, + Formatter(FindResult) ); + } + } + + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_FIND_FORMAT_DETAIL_HPP diff --git a/boost/algorithm/string/detail/find_format_all.hpp b/boost/algorithm/string/detail/find_format_all.hpp new file mode 100644 index 0000000..52930c8 --- /dev/null +++ b/boost/algorithm/string/detail/find_format_all.hpp @@ -0,0 +1,273 @@ +// Boost string_algo library find_format_all.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FIND_FORMAT_ALL_DETAIL_HPP +#define BOOST_STRING_FIND_FORMAT_ALL_DETAIL_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// find_format_all_copy (iterator variant) implementation ---------------------------// + + template< + typename OutputIteratorT, + typename InputT, + typename FinderT, + typename FormatterT, + typename FindResultT, + typename FormatResultT > + inline OutputIteratorT find_format_all_copy_impl2( + OutputIteratorT Output, + const InputT& Input, + FinderT Finder, + FormatterT Formatter, + const FindResultT& FindResult, + const FormatResultT& FormatResult ) + { + typedef BOOST_STRING_TYPENAME + range_const_iterator::type input_iterator_type; + + typedef find_format_store< + input_iterator_type, + FormatterT, + FormatResultT > store_type; + + // Create store for the find result + store_type M( FindResult, FormatResult, Formatter ); + + // Initialize last match + input_iterator_type LastMatch=::boost::begin(Input); + + // Iterate through all matches + while( M ) + { + // Copy the beginning of the sequence + Output = std::copy( LastMatch, M.begin(), Output ); + // Copy formatted result + Output = std::copy( ::boost::begin(M.format_result()), ::boost::end(M.format_result()), Output ); + + // Proceed to the next match + LastMatch=M.end(); + M=Finder( LastMatch, ::boost::end(Input) ); + } + + // Copy the rest of the sequence + Output = std::copy( LastMatch, ::boost::end(Input), Output ); + + return Output; + } + + template< + typename OutputIteratorT, + typename InputT, + typename FinderT, + typename FormatterT, + typename FindResultT > + inline OutputIteratorT find_format_all_copy_impl( + OutputIteratorT Output, + const InputT& Input, + FinderT Finder, + FormatterT Formatter, + const FindResultT& FindResult ) + { + if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) { + return ::boost::algorithm::detail::find_format_all_copy_impl2( + Output, + Input, + Finder, + Formatter, + FindResult, + Formatter(FindResult) ); + } else { + return std::copy( ::boost::begin(Input), ::boost::end(Input), Output ); + } + } + + // find_format_all_copy implementation ----------------------------------------------// + + template< + typename InputT, + typename FinderT, + typename FormatterT, + typename FindResultT, + typename FormatResultT > + inline InputT find_format_all_copy_impl2( + const InputT& Input, + FinderT Finder, + FormatterT Formatter, + const FindResultT& FindResult, + const FormatResultT& FormatResult) + { + typedef BOOST_STRING_TYPENAME + range_const_iterator::type input_iterator_type; + + typedef find_format_store< + input_iterator_type, + FormatterT, + FormatResultT > store_type; + + // Create store for the find result + store_type M( FindResult, FormatResult, Formatter ); + + // Initialize last match + input_iterator_type LastMatch=::boost::begin(Input); + + // Output temporary + InputT Output; + + // Iterate through all matches + while( M ) + { + // Copy the beginning of the sequence + boost::algorithm::detail::insert( Output, ::boost::end(Output), LastMatch, M.begin() ); + // Copy formatted result + boost::algorithm::detail::insert( Output, ::boost::end(Output), M.format_result() ); + + // Proceed to the next match + LastMatch=M.end(); + M=Finder( LastMatch, ::boost::end(Input) ); + } + + // Copy the rest of the sequence + ::boost::algorithm::detail::insert( Output, ::boost::end(Output), LastMatch, ::boost::end(Input) ); + + return Output; + } + + template< + typename InputT, + typename FinderT, + typename FormatterT, + typename FindResultT > + inline InputT find_format_all_copy_impl( + const InputT& Input, + FinderT Finder, + FormatterT Formatter, + const FindResultT& FindResult) + { + if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) { + return ::boost::algorithm::detail::find_format_all_copy_impl2( + Input, + Finder, + Formatter, + FindResult, + Formatter(FindResult) ); + } else { + return Input; + } + } + + // find_format_all implementation ------------------------------------------------// + + template< + typename InputT, + typename FinderT, + typename FormatterT, + typename FindResultT, + typename FormatResultT > + inline void find_format_all_impl2( + InputT& Input, + FinderT Finder, + FormatterT Formatter, + FindResultT FindResult, + FormatResultT FormatResult) + { + typedef BOOST_STRING_TYPENAME + range_iterator::type input_iterator_type; + typedef find_format_store< + input_iterator_type, + FormatterT, + FormatResultT > store_type; + + // Create store for the find result + store_type M( FindResult, FormatResult, Formatter ); + + // Instantiate replacement storage + std::deque< + BOOST_STRING_TYPENAME range_value::type> Storage; + + // Initialize replacement iterators + input_iterator_type InsertIt=::boost::begin(Input); + input_iterator_type SearchIt=::boost::begin(Input); + + while( M ) + { + // process the segment + InsertIt=process_segment( + Storage, + Input, + InsertIt, + SearchIt, + M.begin() ); + + // Adjust search iterator + SearchIt=M.end(); + + // Copy formatted replace to the storage + ::boost::algorithm::detail::copy_to_storage( Storage, M.format_result() ); + + // Find range for a next match + M=Finder( SearchIt, ::boost::end(Input) ); + } + + // process the last segment + InsertIt=::boost::algorithm::detail::process_segment( + Storage, + Input, + InsertIt, + SearchIt, + ::boost::end(Input) ); + + if ( Storage.empty() ) + { + // Truncate input + ::boost::algorithm::detail::erase( Input, InsertIt, ::boost::end(Input) ); + } + else + { + // Copy remaining data to the end of input + ::boost::algorithm::detail::insert( Input, ::boost::end(Input), Storage.begin(), Storage.end() ); + } + } + + template< + typename InputT, + typename FinderT, + typename FormatterT, + typename FindResultT > + inline void find_format_all_impl( + InputT& Input, + FinderT Finder, + FormatterT Formatter, + FindResultT FindResult) + { + if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) { + ::boost::algorithm::detail::find_format_all_impl2( + Input, + Finder, + Formatter, + FindResult, + Formatter(FindResult) ); + } + } + + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_FIND_FORMAT_ALL_DETAIL_HPP diff --git a/boost/algorithm/string/detail/find_format_store.hpp b/boost/algorithm/string/detail/find_format_store.hpp new file mode 100644 index 0000000..b9f4a88 --- /dev/null +++ b/boost/algorithm/string/detail/find_format_store.hpp @@ -0,0 +1,89 @@ +// Boost string_algo library find_format_store.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FIND_FORMAT_STORE_DETAIL_HPP +#define BOOST_STRING_FIND_FORMAT_STORE_DETAIL_HPP + +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// temporary format and find result storage --------------------------------// + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(push) +#pragma warning(disable:4512) //assignment operator could not be generated +#endif + template< + typename ForwardIteratorT, + typename FormatterT, + typename FormatResultT > + class find_format_store : + public iterator_range + { + public: + // typedefs + typedef iterator_range base_type; + typedef FormatterT formatter_type; + typedef FormatResultT format_result_type; + + public: + // Construction + find_format_store( + const base_type& FindResult, + const format_result_type& FormatResult, + const formatter_type& Formatter ) : + base_type(FindResult), + m_FormatResult(FormatResult), + m_Formatter(Formatter) {} + + // Assignment + template< typename FindResultT > + find_format_store& operator=( FindResultT FindResult ) + { + iterator_range::operator=(FindResult); + if( !this->empty() ) { + m_FormatResult=m_Formatter(FindResult); + } + + return *this; + } + + // Retrieve format result + const format_result_type& format_result() + { + return m_FormatResult; + } + + private: + format_result_type m_FormatResult; + const formatter_type& m_Formatter; + }; + + template + bool check_find_result(InputT&, FindResultT& FindResult) + { + typedef BOOST_STRING_TYPENAME + range_const_iterator::type input_iterator_type; + iterator_range ResultRange(FindResult); + return !ResultRange.empty(); + } + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_FIND_FORMAT_STORE_DETAIL_HPP diff --git a/boost/algorithm/string/detail/finder.hpp b/boost/algorithm/string/detail/finder.hpp new file mode 100644 index 0000000..a2a9582 --- /dev/null +++ b/boost/algorithm/string/detail/finder.hpp @@ -0,0 +1,639 @@ +// Boost string_algo library finder.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2006. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FINDER_DETAIL_HPP +#define BOOST_STRING_FINDER_DETAIL_HPP + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + + +// find first functor -----------------------------------------------// + + // find a subsequence in the sequence ( functor ) + /* + Returns a pair marking the subsequence in the sequence. + If the find fails, functor returns + */ + template + struct first_finderF + { + typedef SearchIteratorT search_iterator_type; + + // Construction + template< typename SearchT > + first_finderF( const SearchT& Search, PredicateT Comp ) : + m_Search(::boost::begin(Search), ::boost::end(Search)), m_Comp(Comp) {} + first_finderF( + search_iterator_type SearchBegin, + search_iterator_type SearchEnd, + PredicateT Comp ) : + m_Search(SearchBegin, SearchEnd), m_Comp(Comp) {} + + // Operation + template< typename ForwardIteratorT > + iterator_range + operator()( + ForwardIteratorT Begin, + ForwardIteratorT End ) const + { + typedef iterator_range result_type; + typedef ForwardIteratorT input_iterator_type; + + // Outer loop + for(input_iterator_type OuterIt=Begin; + OuterIt!=End; + ++OuterIt) + { + // Sanity check + if( boost::empty(m_Search) ) + return result_type( End, End ); + + input_iterator_type InnerIt=OuterIt; + search_iterator_type SubstrIt=m_Search.begin(); + for(; + InnerIt!=End && SubstrIt!=m_Search.end(); + ++InnerIt,++SubstrIt) + { + if( !( m_Comp(*InnerIt,*SubstrIt) ) ) + break; + } + + // Substring matching succeeded + if ( SubstrIt==m_Search.end() ) + return result_type( OuterIt, InnerIt ); + } + + return result_type( End, End ); + } + + private: + iterator_range m_Search; + PredicateT m_Comp; + }; + +// find last functor -----------------------------------------------// + + // find the last match a subsequence in the sequence ( functor ) + /* + Returns a pair marking the subsequence in the sequence. + If the find fails, returns + */ + template + struct last_finderF + { + typedef SearchIteratorT search_iterator_type; + typedef first_finderF< + search_iterator_type, + PredicateT> first_finder_type; + + // Construction + template< typename SearchT > + last_finderF( const SearchT& Search, PredicateT Comp ) : + m_Search(::boost::begin(Search), ::boost::end(Search)), m_Comp(Comp) {} + last_finderF( + search_iterator_type SearchBegin, + search_iterator_type SearchEnd, + PredicateT Comp ) : + m_Search(SearchBegin, SearchEnd), m_Comp(Comp) {} + + // Operation + template< typename ForwardIteratorT > + iterator_range + operator()( + ForwardIteratorT Begin, + ForwardIteratorT End ) const + { + typedef iterator_range result_type; + + if( boost::empty(m_Search) ) + return result_type( End, End ); + + typedef BOOST_STRING_TYPENAME boost::detail:: + iterator_traits::iterator_category category; + + return findit( Begin, End, category() ); + } + + private: + // forward iterator + template< typename ForwardIteratorT > + iterator_range + findit( + ForwardIteratorT Begin, + ForwardIteratorT End, + std::forward_iterator_tag ) const + { + typedef iterator_range result_type; + + first_finder_type first_finder( + m_Search.begin(), m_Search.end(), m_Comp ); + + result_type M=first_finder( Begin, End ); + result_type Last=M; + + while( M ) + { + Last=M; + M=first_finder( ::boost::end(M), End ); + } + + return Last; + } + + // bidirectional iterator + template< typename ForwardIteratorT > + iterator_range + findit( + ForwardIteratorT Begin, + ForwardIteratorT End, + std::bidirectional_iterator_tag ) const + { + typedef iterator_range result_type; + typedef ForwardIteratorT input_iterator_type; + + // Outer loop + for(input_iterator_type OuterIt=End; + OuterIt!=Begin; ) + { + input_iterator_type OuterIt2=--OuterIt; + + input_iterator_type InnerIt=OuterIt2; + search_iterator_type SubstrIt=m_Search.begin(); + for(; + InnerIt!=End && SubstrIt!=m_Search.end(); + ++InnerIt,++SubstrIt) + { + if( !( m_Comp(*InnerIt,*SubstrIt) ) ) + break; + } + + // Substring matching succeeded + if( SubstrIt==m_Search.end() ) + return result_type( OuterIt2, InnerIt ); + } + + return result_type( End, End ); + } + + private: + iterator_range m_Search; + PredicateT m_Comp; + }; + +// find n-th functor -----------------------------------------------// + + // find the n-th match of a subsequence in the sequence ( functor ) + /* + Returns a pair marking the subsequence in the sequence. + If the find fails, returns + */ + template + struct nth_finderF + { + typedef SearchIteratorT search_iterator_type; + typedef first_finderF< + search_iterator_type, + PredicateT> first_finder_type; + typedef last_finderF< + search_iterator_type, + PredicateT> last_finder_type; + + // Construction + template< typename SearchT > + nth_finderF( + const SearchT& Search, + int Nth, + PredicateT Comp) : + m_Search(::boost::begin(Search), ::boost::end(Search)), + m_Nth(Nth), + m_Comp(Comp) {} + nth_finderF( + search_iterator_type SearchBegin, + search_iterator_type SearchEnd, + int Nth, + PredicateT Comp) : + m_Search(SearchBegin, SearchEnd), + m_Nth(Nth), + m_Comp(Comp) {} + + // Operation + template< typename ForwardIteratorT > + iterator_range + operator()( + ForwardIteratorT Begin, + ForwardIteratorT End ) const + { + if(m_Nth>=0) + { + return find_forward(Begin, End, m_Nth); + } + else + { + return find_backward(Begin, End, -m_Nth); + } + + } + + private: + // Implementation helpers + template< typename ForwardIteratorT > + iterator_range + find_forward( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N) const + { + typedef iterator_range result_type; + + // Sanity check + if( boost::empty(m_Search) ) + return result_type( End, End ); + + // Instantiate find functor + first_finder_type first_finder( + m_Search.begin(), m_Search.end(), m_Comp ); + + result_type M( Begin, Begin ); + + for( unsigned int n=0; n<=N; ++n ) + { + // find next match + M=first_finder( ::boost::end(M), End ); + + if ( !M ) + { + // Subsequence not found, return + return M; + } + } + + return M; + } + + template< typename ForwardIteratorT > + iterator_range + find_backward( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N) const + { + typedef iterator_range result_type; + + // Sanity check + if( boost::empty(m_Search) ) + return result_type( End, End ); + + // Instantiate find functor + last_finder_type last_finder( + m_Search.begin(), m_Search.end(), m_Comp ); + + result_type M( End, End ); + + for( unsigned int n=1; n<=N; ++n ) + { + // find next match + M=last_finder( Begin, ::boost::begin(M) ); + + if ( !M ) + { + // Subsequence not found, return + return M; + } + } + + return M; + } + + + private: + iterator_range m_Search; + int m_Nth; + PredicateT m_Comp; + }; + +// find head/tail implementation helpers ---------------------------// + + template + iterator_range + find_head_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N, + std::forward_iterator_tag ) + { + typedef ForwardIteratorT input_iterator_type; + typedef iterator_range result_type; + + input_iterator_type It=Begin; + for( + unsigned int Index=0; + Index + iterator_range + find_head_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N, + std::random_access_iterator_tag ) + { + typedef iterator_range result_type; + + if ( (End<=Begin) || ( static_cast(End-Begin) < N ) ) + return result_type( Begin, End ); + + return result_type(Begin,Begin+N); + } + + // Find head implementation + template + iterator_range + find_head_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N ) + { + typedef BOOST_STRING_TYPENAME boost::detail:: + iterator_traits::iterator_category category; + + return ::boost::algorithm::detail::find_head_impl( Begin, End, N, category() ); + } + + template< typename ForwardIteratorT > + iterator_range + find_tail_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N, + std::forward_iterator_tag ) + { + typedef ForwardIteratorT input_iterator_type; + typedef iterator_range result_type; + + unsigned int Index=0; + input_iterator_type It=Begin; + input_iterator_type It2=Begin; + + // Advance It2 by N increments + for( Index=0; Index + iterator_range + find_tail_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N, + std::bidirectional_iterator_tag ) + { + typedef ForwardIteratorT input_iterator_type; + typedef iterator_range result_type; + + input_iterator_type It=End; + for( + unsigned int Index=0; + Index + iterator_range + find_tail_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N, + std::random_access_iterator_tag ) + { + typedef iterator_range result_type; + + if ( (End<=Begin) || ( static_cast(End-Begin) < N ) ) + return result_type( Begin, End ); + + return result_type( End-N, End ); + } + + // Operation + template< typename ForwardIteratorT > + iterator_range + find_tail_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N ) + { + typedef BOOST_STRING_TYPENAME boost::detail:: + iterator_traits::iterator_category category; + + return ::boost::algorithm::detail::find_tail_impl( Begin, End, N, category() ); + } + + + +// find head functor -----------------------------------------------// + + + // find a head in the sequence ( functor ) + /* + This functor find a head of the specified range. For + a specified N, the head is a subsequence of N starting + elements of the range. + */ + struct head_finderF + { + // Construction + head_finderF( int N ) : m_N(N) {} + + // Operation + template< typename ForwardIteratorT > + iterator_range + operator()( + ForwardIteratorT Begin, + ForwardIteratorT End ) const + { + if(m_N>=0) + { + return ::boost::algorithm::detail::find_head_impl( Begin, End, m_N ); + } + else + { + iterator_range Res= + ::boost::algorithm::detail::find_tail_impl( Begin, End, -m_N ); + + return ::boost::make_iterator_range(Begin, Res.begin()); + } + } + + private: + int m_N; + }; + +// find tail functor -----------------------------------------------// + + + // find a tail in the sequence ( functor ) + /* + This functor find a tail of the specified range. For + a specified N, the head is a subsequence of N starting + elements of the range. + */ + struct tail_finderF + { + // Construction + tail_finderF( int N ) : m_N(N) {} + + // Operation + template< typename ForwardIteratorT > + iterator_range + operator()( + ForwardIteratorT Begin, + ForwardIteratorT End ) const + { + if(m_N>=0) + { + return ::boost::algorithm::detail::find_tail_impl( Begin, End, m_N ); + } + else + { + iterator_range Res= + ::boost::algorithm::detail::find_head_impl( Begin, End, -m_N ); + + return ::boost::make_iterator_range(Res.end(), End); + } + } + + private: + int m_N; + }; + +// find token functor -----------------------------------------------// + + // find a token in a sequence ( functor ) + /* + This find functor finds a token specified be a predicate + in a sequence. It is equivalent of std::find algorithm, + with an exception that it return range instead of a single + iterator. + + If bCompress is set to true, adjacent matching tokens are + concatenated into one match. + */ + template< typename PredicateT > + struct token_finderF + { + // Construction + token_finderF( + PredicateT Pred, + token_compress_mode_type eCompress=token_compress_off ) : + m_Pred(Pred), m_eCompress(eCompress) {} + + // Operation + template< typename ForwardIteratorT > + iterator_range + operator()( + ForwardIteratorT Begin, + ForwardIteratorT End ) const + { + typedef iterator_range result_type; + + ForwardIteratorT It=std::find_if( Begin, End, m_Pred ); + + if( It==End ) + { + return result_type( End, End ); + } + else + { + ForwardIteratorT It2=It; + + if( m_eCompress==token_compress_on ) + { + // Find first non-matching character + while( It2!=End && m_Pred(*It2) ) ++It2; + } + else + { + // Advance by one position + ++It2; + } + + return result_type( It, It2 ); + } + } + + private: + PredicateT m_Pred; + token_compress_mode_type m_eCompress; + }; + +// find range functor -----------------------------------------------// + + // find a range in the sequence ( functor ) + /* + This functor actually does not perform any find operation. + It always returns given iterator range as a result. + */ + template + struct range_finderF + { + typedef ForwardIterator1T input_iterator_type; + typedef iterator_range result_type; + + // Construction + range_finderF( + input_iterator_type Begin, + input_iterator_type End ) : m_Range(Begin, End) {} + + range_finderF(const iterator_range& Range) : + m_Range(Range) {} + + // Operation + template< typename ForwardIterator2T > + iterator_range + operator()( + ForwardIterator2T, + ForwardIterator2T ) const + { +#if BOOST_WORKAROUND( __MWERKS__, <= 0x3003 ) + return iterator_range(this->m_Range); +#else + return m_Range; +#endif + } + + private: + iterator_range m_Range; + }; + + + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_FINDER_DETAIL_HPP diff --git a/boost/algorithm/string/detail/formatter.hpp b/boost/algorithm/string/detail/formatter.hpp new file mode 100644 index 0000000..c071822 --- /dev/null +++ b/boost/algorithm/string/detail/formatter.hpp @@ -0,0 +1,119 @@ +// Boost string_algo library formatter.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FORMATTER_DETAIL_HPP +#define BOOST_STRING_FORMATTER_DETAIL_HPP + + +#include +#include +#include +#include + +#include + +// generic replace functors -----------------------------------------------// + +namespace boost { + namespace algorithm { + namespace detail { + +// const format functor ----------------------------------------------------// + + // constant format functor + template + struct const_formatF + { + private: + typedef BOOST_STRING_TYPENAME + range_const_iterator::type format_iterator; + typedef iterator_range result_type; + + public: + // Construction + const_formatF(const RangeT& Format) : + m_Format(::boost::begin(Format), ::boost::end(Format)) {} + + // Operation +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + template + result_type& operator()(const Range2T&) + { + return m_Format; + } +#endif + + template + const result_type& operator()(const Range2T&) const + { + return m_Format; + } + + private: + result_type m_Format; + }; + +// identity format functor ----------------------------------------------------// + + // identity format functor + template + struct identity_formatF + { + // Operation + template< typename Range2T > + const RangeT& operator()(const Range2T& Replace) const + { + return RangeT(::boost::begin(Replace), ::boost::end(Replace)); + } + }; + +// empty format functor ( used by erase ) ------------------------------------// + + // empty format functor + template< typename CharT > + struct empty_formatF + { + template< typename ReplaceT > + empty_container operator()(const ReplaceT&) const + { + return empty_container(); + } + }; + +// dissect format functor ----------------------------------------------------// + + // dissect format functor + template + struct dissect_formatF + { + public: + // Construction + dissect_formatF(FinderT Finder) : + m_Finder(Finder) {} + + // Operation + template + inline iterator_range< + BOOST_STRING_TYPENAME range_const_iterator::type> + operator()(const RangeT& Replace) const + { + return m_Finder(::boost::begin(Replace), ::boost::end(Replace)); + } + + private: + FinderT m_Finder; + }; + + + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_FORMATTER_DETAIL_HPP diff --git a/boost/algorithm/string/detail/replace_storage.hpp b/boost/algorithm/string/detail/replace_storage.hpp new file mode 100644 index 0000000..db35e4c --- /dev/null +++ b/boost/algorithm/string/detail/replace_storage.hpp @@ -0,0 +1,159 @@ +// Boost string_algo library replace_storage.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_REPLACE_STORAGE_DETAIL_HPP +#define BOOST_STRING_REPLACE_STORAGE_DETAIL_HPP + +#include +#include +#include +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// storage handling routines -----------------------------------------------// + + template< typename StorageT, typename OutputIteratorT > + inline OutputIteratorT move_from_storage( + StorageT& Storage, + OutputIteratorT DestBegin, + OutputIteratorT DestEnd ) + { + OutputIteratorT OutputIt=DestBegin; + + while( !Storage.empty() && OutputIt!=DestEnd ) + { + *OutputIt=Storage.front(); + Storage.pop_front(); + ++OutputIt; + } + + return OutputIt; + } + + template< typename StorageT, typename WhatT > + inline void copy_to_storage( + StorageT& Storage, + const WhatT& What ) + { + Storage.insert( Storage.end(), ::boost::begin(What), ::boost::end(What) ); + } + + +// process segment routine -----------------------------------------------// + + template< bool HasStableIterators > + struct process_segment_helper + { + // Optimized version of process_segment for generic sequence + template< + typename StorageT, + typename InputT, + typename ForwardIteratorT > + ForwardIteratorT operator()( + StorageT& Storage, + InputT& /*Input*/, + ForwardIteratorT InsertIt, + ForwardIteratorT SegmentBegin, + ForwardIteratorT SegmentEnd ) + { + // Copy data from the storage until the beginning of the segment + ForwardIteratorT It=::boost::algorithm::detail::move_from_storage( Storage, InsertIt, SegmentBegin ); + + // 3 cases are possible : + // a) Storage is empty, It==SegmentBegin + // b) Storage is empty, It!=SegmentBegin + // c) Storage is not empty + + if( Storage.empty() ) + { + if( It==SegmentBegin ) + { + // Case a) everything is grand, just return end of segment + return SegmentEnd; + } + else + { + // Case b) move the segment backwards + return std::copy( SegmentBegin, SegmentEnd, It ); + } + } + else + { + // Case c) -> shift the segment to the left and keep the overlap in the storage + while( It!=SegmentEnd ) + { + // Store value into storage + Storage.push_back( *It ); + // Get the top from the storage and put it here + *It=Storage.front(); + Storage.pop_front(); + + // Advance + ++It; + } + + return It; + } + } + }; + + template<> + struct process_segment_helper< true > + { + // Optimized version of process_segment for list-like sequence + template< + typename StorageT, + typename InputT, + typename ForwardIteratorT > + ForwardIteratorT operator()( + StorageT& Storage, + InputT& Input, + ForwardIteratorT InsertIt, + ForwardIteratorT SegmentBegin, + ForwardIteratorT SegmentEnd ) + + { + // Call replace to do the job + ::boost::algorithm::detail::replace( Input, InsertIt, SegmentBegin, Storage ); + // Empty the storage + Storage.clear(); + // Iterators were not changed, simply return the end of segment + return SegmentEnd; + } + }; + + // Process one segment in the replace_all algorithm + template< + typename StorageT, + typename InputT, + typename ForwardIteratorT > + inline ForwardIteratorT process_segment( + StorageT& Storage, + InputT& Input, + ForwardIteratorT InsertIt, + ForwardIteratorT SegmentBegin, + ForwardIteratorT SegmentEnd ) + { + return + process_segment_helper< + has_stable_iterators::value>()( + Storage, Input, InsertIt, SegmentBegin, SegmentEnd ); + } + + + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_REPLACE_STORAGE_DETAIL_HPP diff --git a/boost/algorithm/string/detail/sequence.hpp b/boost/algorithm/string/detail/sequence.hpp new file mode 100644 index 0000000..dc47409 --- /dev/null +++ b/boost/algorithm/string/detail/sequence.hpp @@ -0,0 +1,200 @@ +// Boost string_algo library sequence.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_DETAIL_SEQUENCE_HPP +#define BOOST_STRING_DETAIL_SEQUENCE_HPP + +#include +#include +#include +#include +#include + +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// insert helpers -------------------------------------------------// + + template< typename InputT, typename ForwardIteratorT > + inline void insert( + InputT& Input, + BOOST_STRING_TYPENAME InputT::iterator At, + ForwardIteratorT Begin, + ForwardIteratorT End ) + { + Input.insert( At, Begin, End ); + } + + template< typename InputT, typename InsertT > + inline void insert( + InputT& Input, + BOOST_STRING_TYPENAME InputT::iterator At, + const InsertT& Insert ) + { + ::boost::algorithm::detail::insert( Input, At, ::boost::begin(Insert), ::boost::end(Insert) ); + } + +// erase helper ---------------------------------------------------// + + // Erase a range in the sequence + /* + Returns the iterator pointing just after the erase subrange + */ + template< typename InputT > + inline typename InputT::iterator erase( + InputT& Input, + BOOST_STRING_TYPENAME InputT::iterator From, + BOOST_STRING_TYPENAME InputT::iterator To ) + { + return Input.erase( From, To ); + } + +// replace helper implementation ----------------------------------// + + // Optimized version of replace for generic sequence containers + // Assumption: insert and erase are expensive + template< bool HasConstTimeOperations > + struct replace_const_time_helper + { + template< typename InputT, typename ForwardIteratorT > + void operator()( + InputT& Input, + BOOST_STRING_TYPENAME InputT::iterator From, + BOOST_STRING_TYPENAME InputT::iterator To, + ForwardIteratorT Begin, + ForwardIteratorT End ) + { + // Copy data to the container ( as much as possible ) + ForwardIteratorT InsertIt=Begin; + BOOST_STRING_TYPENAME InputT::iterator InputIt=From; + for(; InsertIt!=End && InputIt!=To; InsertIt++, InputIt++ ) + { + *InputIt=*InsertIt; + } + + if ( InsertIt!=End ) + { + // Replace sequence is longer, insert it + Input.insert( InputIt, InsertIt, End ); + } + else + { + if ( InputIt!=To ) + { + // Replace sequence is shorter, erase the rest + Input.erase( InputIt, To ); + } + } + } + }; + + template<> + struct replace_const_time_helper< true > + { + // Const-time erase and insert methods -> use them + template< typename InputT, typename ForwardIteratorT > + void operator()( + InputT& Input, + BOOST_STRING_TYPENAME InputT::iterator From, + BOOST_STRING_TYPENAME InputT::iterator To, + ForwardIteratorT Begin, + ForwardIteratorT End ) + { + BOOST_STRING_TYPENAME InputT::iterator At=Input.erase( From, To ); + if ( Begin!=End ) + { + if(!Input.empty()) + { + Input.insert( At, Begin, End ); + } + else + { + Input.insert( Input.begin(), Begin, End ); + } + } + } + }; + + // No native replace method + template< bool HasNative > + struct replace_native_helper + { + template< typename InputT, typename ForwardIteratorT > + void operator()( + InputT& Input, + BOOST_STRING_TYPENAME InputT::iterator From, + BOOST_STRING_TYPENAME InputT::iterator To, + ForwardIteratorT Begin, + ForwardIteratorT End ) + { + replace_const_time_helper< + boost::mpl::and_< + has_const_time_insert, + has_const_time_erase >::value >()( + Input, From, To, Begin, End ); + } + }; + + // Container has native replace method + template<> + struct replace_native_helper< true > + { + template< typename InputT, typename ForwardIteratorT > + void operator()( + InputT& Input, + BOOST_STRING_TYPENAME InputT::iterator From, + BOOST_STRING_TYPENAME InputT::iterator To, + ForwardIteratorT Begin, + ForwardIteratorT End ) + { + Input.replace( From, To, Begin, End ); + } + }; + +// replace helper -------------------------------------------------// + + template< typename InputT, typename ForwardIteratorT > + inline void replace( + InputT& Input, + BOOST_STRING_TYPENAME InputT::iterator From, + BOOST_STRING_TYPENAME InputT::iterator To, + ForwardIteratorT Begin, + ForwardIteratorT End ) + { + replace_native_helper< has_native_replace::value >()( + Input, From, To, Begin, End ); + } + + template< typename InputT, typename InsertT > + inline void replace( + InputT& Input, + BOOST_STRING_TYPENAME InputT::iterator From, + BOOST_STRING_TYPENAME InputT::iterator To, + const InsertT& Insert ) + { + if(From!=To) + { + ::boost::algorithm::detail::replace( Input, From, To, ::boost::begin(Insert), ::boost::end(Insert) ); + } + else + { + ::boost::algorithm::detail::insert( Input, From, ::boost::begin(Insert), ::boost::end(Insert) ); + } + } + + } // namespace detail + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_DETAIL_SEQUENCE_HPP diff --git a/boost/algorithm/string/detail/util.hpp b/boost/algorithm/string/detail/util.hpp new file mode 100644 index 0000000..7844b67 --- /dev/null +++ b/boost/algorithm/string/detail/util.hpp @@ -0,0 +1,107 @@ +// Boost string_algo library util.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_UTIL_DETAIL_HPP +#define BOOST_STRING_UTIL_DETAIL_HPP + +#include +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// empty container -----------------------------------------------// + + // empty_container + /* + This class represents always empty container, + containing elements of type CharT. + + It is supposed to be used in a const version only + */ + template< typename CharT > + struct empty_container + { + typedef empty_container type; + typedef CharT value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef const value_type& reference; + typedef const value_type& const_reference; + typedef const value_type* iterator; + typedef const value_type* const_iterator; + + + // Operations + const_iterator begin() const + { + return reinterpret_cast(0); + } + + const_iterator end() const + { + return reinterpret_cast(0); + } + + bool empty() const + { + return false; + } + + size_type size() const + { + return 0; + } + }; + +// bounded copy algorithm -----------------------------------------------// + + // Bounded version of the std::copy algorithm + template + inline OutputIteratorT bounded_copy( + InputIteratorT First, + InputIteratorT Last, + OutputIteratorT DestFirst, + OutputIteratorT DestLast ) + { + InputIteratorT InputIt=First; + OutputIteratorT OutputIt=DestFirst; + for(; InputIt!=Last && OutputIt!=DestLast; InputIt++, OutputIt++ ) + { + *OutputIt=*InputIt; + } + + return OutputIt; + } + +// iterator range utilities -----------------------------------------// + + // copy range functor + template< + typename SeqT, + typename IteratorT=BOOST_STRING_TYPENAME SeqT::const_iterator > + struct copy_iterator_rangeF + { + typedef iterator_range argument_type; + typedef SeqT result_type; + SeqT operator()( const iterator_range& Range ) const + { + return copy_range(Range); + } + }; + + } // namespace detail + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_UTIL_DETAIL_HPP diff --git a/boost/algorithm/string/erase.hpp b/boost/algorithm/string/erase.hpp new file mode 100644 index 0000000..6883790 --- /dev/null +++ b/boost/algorithm/string/erase.hpp @@ -0,0 +1,844 @@ +// Boost string_algo library erase.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2006. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_ERASE_HPP +#define BOOST_STRING_ERASE_HPP + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/*! \file + Defines various erase algorithms. Each algorithm removes + part(s) of the input according to a searching criteria. +*/ + +namespace boost { + namespace algorithm { + +// erase_range -------------------------------------------------------// + + //! Erase range algorithm + /*! + Remove the given range from the input. The result is a modified copy of + the input. It is returned as a sequence or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input sequence + \param SearchRange A range in the input to be removed + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template + inline OutputIteratorT erase_range_copy( + OutputIteratorT Output, + const RangeT& Input, + const iterator_range< + BOOST_STRING_TYPENAME + range_const_iterator::type>& SearchRange ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::range_finder(SearchRange), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase range algorithm + /*! + \overload + */ + template + inline SequenceT erase_range_copy( + const SequenceT& Input, + const iterator_range< + BOOST_STRING_TYPENAME + range_const_iterator::type>& SearchRange ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::range_finder(SearchRange), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase range algorithm + /*! + Remove the given range from the input. + The input sequence is modified in-place. + + \param Input An input sequence + \param SearchRange A range in the input to be removed + */ + template + inline void erase_range( + SequenceT& Input, + const iterator_range< + BOOST_STRING_TYPENAME + range_iterator::type>& SearchRange ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::range_finder(SearchRange), + ::boost::algorithm::empty_formatter(Input) ); + } + +// erase_first --------------------------------------------------------// + + //! Erase first algorithm + /*! + Remove the first occurrence of the substring from the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT erase_first_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase first algorithm + /*! + \overload + */ + template + inline SequenceT erase_first_copy( + const SequenceT& Input, + const RangeT& Search ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase first algorithm + /*! + Remove the first occurrence of the substring from the input. + The input sequence is modified in-place. + + \param Input An input string + \param Search A substring to be searched for. + */ + template + inline void erase_first( + SequenceT& Input, + const RangeT& Search ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::empty_formatter(Input) ); + } + +// erase_first ( case insensitive ) ------------------------------------// + + //! Erase first algorithm ( case insensitive ) + /*! + Remove the first occurrence of the substring from the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + Searching is case insensitive. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Loc A locale used for case insensitive comparison + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT ierase_first_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase first algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ierase_first_copy( + const SequenceT& Input, + const RangeT& Search, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase first algorithm ( case insensitive ) + /*! + Remove the first occurrence of the substring from the input. + The input sequence is modified in-place. Searching is case insensitive. + + \param Input An input string + \param Search A substring to be searched for + \param Loc A locale used for case insensitive comparison + */ + template + inline void ierase_first( + SequenceT& Input, + const RangeT& Search, + const std::locale& Loc=std::locale() ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + +// erase_last --------------------------------------------------------// + + //! Erase last algorithm + /*! + Remove the last occurrence of the substring from the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for. + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT erase_last_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::last_finder(Search), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase last algorithm + /*! + \overload + */ + template + inline SequenceT erase_last_copy( + const SequenceT& Input, + const RangeT& Search ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::last_finder(Search), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase last algorithm + /*! + Remove the last occurrence of the substring from the input. + The input sequence is modified in-place. + + \param Input An input string + \param Search A substring to be searched for + */ + template + inline void erase_last( + SequenceT& Input, + const RangeT& Search ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::last_finder(Search), + ::boost::algorithm::empty_formatter(Input) ); + } + +// erase_last ( case insensitive ) ------------------------------------// + + //! Erase last algorithm ( case insensitive ) + /*! + Remove the last occurrence of the substring from the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + Searching is case insensitive. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Loc A locale used for case insensitive comparison + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT ierase_last_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::last_finder(Search, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase last algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ierase_last_copy( + const SequenceT& Input, + const RangeT& Search, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::last_finder(Search, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase last algorithm ( case insensitive ) + /*! + Remove the last occurrence of the substring from the input. + The input sequence is modified in-place. Searching is case insensitive. + + \param Input An input string + \param Search A substring to be searched for + \param Loc A locale used for case insensitive comparison + */ + template + inline void ierase_last( + SequenceT& Input, + const RangeT& Search, + const std::locale& Loc=std::locale() ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::last_finder(Search, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + +// erase_nth --------------------------------------------------------------------// + + //! Erase nth algorithm + /*! + Remove the Nth occurrence of the substring in the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Nth An index of the match to be replaced. The index is 0-based. + For negative N, matches are counted from the end of string. + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT erase_nth_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + int Nth ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::nth_finder(Search, Nth), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase nth algorithm + /*! + \overload + */ + template + inline SequenceT erase_nth_copy( + const SequenceT& Input, + const RangeT& Search, + int Nth ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::nth_finder(Search, Nth), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase nth algorithm + /*! + Remove the Nth occurrence of the substring in the input. + The input sequence is modified in-place. + + \param Input An input string + \param Search A substring to be searched for. + \param Nth An index of the match to be replaced. The index is 0-based. + For negative N, matches are counted from the end of string. + */ + template + inline void erase_nth( + SequenceT& Input, + const RangeT& Search, + int Nth ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::nth_finder(Search, Nth), + ::boost::algorithm::empty_formatter(Input) ); + } + +// erase_nth ( case insensitive ) ---------------------------------------------// + + //! Erase nth algorithm ( case insensitive ) + /*! + Remove the Nth occurrence of the substring in the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + Searching is case insensitive. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for. + \param Nth An index of the match to be replaced. The index is 0-based. + For negative N, matches are counted from the end of string. + \param Loc A locale used for case insensitive comparison + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT ierase_nth_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + int Nth, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase nth algorithm + /*! + \overload + */ + template + inline SequenceT ierase_nth_copy( + const SequenceT& Input, + const RangeT& Search, + int Nth, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)), + empty_formatter(Input) ); + } + + //! Erase nth algorithm + /*! + Remove the Nth occurrence of the substring in the input. + The input sequence is modified in-place. Searching is case insensitive. + + \param Input An input string + \param Search A substring to be searched for. + \param Nth An index of the match to be replaced. The index is 0-based. + For negative N, matches are counted from the end of string. + \param Loc A locale used for case insensitive comparison + */ + template + inline void ierase_nth( + SequenceT& Input, + const RangeT& Search, + int Nth, + const std::locale& Loc=std::locale() ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + + +// erase_all --------------------------------------------------------// + + //! Erase all algorithm + /*! + Remove all the occurrences of the string from the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + + \param Output An output iterator to which the result will be copied + \param Input An input sequence + \param Search A substring to be searched for. + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT erase_all_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search ) + { + return ::boost::algorithm::find_format_all_copy( + Output, + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase all algorithm + /*! + \overload + */ + template + inline SequenceT erase_all_copy( + const SequenceT& Input, + const RangeT& Search ) + { + return ::boost::algorithm::find_format_all_copy( + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase all algorithm + /*! + Remove all the occurrences of the string from the input. + The input sequence is modified in-place. + + \param Input An input string + \param Search A substring to be searched for. + */ + template + inline void erase_all( + SequenceT& Input, + const RangeT& Search ) + { + ::boost::algorithm::find_format_all( + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::empty_formatter(Input) ); + } + +// erase_all ( case insensitive ) ------------------------------------// + + //! Erase all algorithm ( case insensitive ) + /*! + Remove all the occurrences of the string from the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + Searching is case insensitive. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Loc A locale used for case insensitive comparison + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT ierase_all_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_all_copy( + Output, + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase all algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ierase_all_copy( + const SequenceT& Input, + const RangeT& Search, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_all_copy( + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase all algorithm ( case insensitive ) + /*! + Remove all the occurrences of the string from the input. + The input sequence is modified in-place. Searching is case insensitive. + + \param Input An input string + \param Search A substring to be searched for. + \param Loc A locale used for case insensitive comparison + */ + template + inline void ierase_all( + SequenceT& Input, + const RangeT& Search, + const std::locale& Loc=std::locale() ) + { + ::boost::algorithm::find_format_all( + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + +// erase_head --------------------------------------------------------------------// + + //! Erase head algorithm + /*! + Remove the head from the input. The head is a prefix of a sequence of given size. + If the sequence is shorter then required, the whole string is + considered to be the head. The result is a modified copy of the input. + It is returned as a sequence or copied to the output iterator. + + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param N Length of the head. + For N>=0, at most N characters are extracted. + For N<0, size(Input)-|N| characters are extracted. + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename RangeT> + inline OutputIteratorT erase_head_copy( + OutputIteratorT Output, + const RangeT& Input, + int N ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::head_finder(N), + ::boost::algorithm::empty_formatter( Input ) ); + } + + //! Erase head algorithm + /*! + \overload + */ + template + inline SequenceT erase_head_copy( + const SequenceT& Input, + int N ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::head_finder(N), + ::boost::algorithm::empty_formatter( Input ) ); + } + + //! Erase head algorithm + /*! + Remove the head from the input. The head is a prefix of a sequence of given size. + If the sequence is shorter then required, the whole string is + considered to be the head. The input sequence is modified in-place. + + \param Input An input string + \param N Length of the head + For N>=0, at most N characters are extracted. + For N<0, size(Input)-|N| characters are extracted. + */ + template + inline void erase_head( + SequenceT& Input, + int N ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::head_finder(N), + ::boost::algorithm::empty_formatter( Input ) ); + } + +// erase_tail --------------------------------------------------------------------// + + //! Erase tail algorithm + /*! + Remove the tail from the input. The tail is a suffix of a sequence of given size. + If the sequence is shorter then required, the whole string is + considered to be the tail. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param N Length of the tail. + For N>=0, at most N characters are extracted. + For N<0, size(Input)-|N| characters are extracted. + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename RangeT> + inline OutputIteratorT erase_tail_copy( + OutputIteratorT Output, + const RangeT& Input, + int N ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::tail_finder(N), + ::boost::algorithm::empty_formatter( Input ) ); + } + + //! Erase tail algorithm + /*! + \overload + */ + template + inline SequenceT erase_tail_copy( + const SequenceT& Input, + int N ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::tail_finder(N), + ::boost::algorithm::empty_formatter( Input ) ); + } + + //! Erase tail algorithm + /*! + Remove the tail from the input. The tail is a suffix of a sequence of given size. + If the sequence is shorter then required, the whole string is + considered to be the tail. The input sequence is modified in-place. + + \param Input An input string + \param N Length of the tail + For N>=0, at most N characters are extracted. + For N<0, size(Input)-|N| characters are extracted. + */ + template + inline void erase_tail( + SequenceT& Input, + int N ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::tail_finder(N), + ::boost::algorithm::empty_formatter( Input ) ); + } + + } // namespace algorithm + + // pull names into the boost namespace + using algorithm::erase_range_copy; + using algorithm::erase_range; + using algorithm::erase_first_copy; + using algorithm::erase_first; + using algorithm::ierase_first_copy; + using algorithm::ierase_first; + using algorithm::erase_last_copy; + using algorithm::erase_last; + using algorithm::ierase_last_copy; + using algorithm::ierase_last; + using algorithm::erase_nth_copy; + using algorithm::erase_nth; + using algorithm::ierase_nth_copy; + using algorithm::ierase_nth; + using algorithm::erase_all_copy; + using algorithm::erase_all; + using algorithm::ierase_all_copy; + using algorithm::ierase_all; + using algorithm::erase_head_copy; + using algorithm::erase_head; + using algorithm::erase_tail_copy; + using algorithm::erase_tail; + +} // namespace boost + + +#endif // BOOST_ERASE_HPP diff --git a/boost/algorithm/string/find_format.hpp b/boost/algorithm/string/find_format.hpp new file mode 100644 index 0000000..0e84a4e --- /dev/null +++ b/boost/algorithm/string/find_format.hpp @@ -0,0 +1,287 @@ +// Boost string_algo library find_format.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FIND_FORMAT_HPP +#define BOOST_STRING_FIND_FORMAT_HPP + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/*! \file + Defines generic replace algorithms. Each algorithm replaces + part(s) of the input. The part to be replaced is looked up using a Finder object. + Result of finding is then used by a Formatter object to generate the replacement. +*/ + +namespace boost { + namespace algorithm { + +// generic replace -----------------------------------------------------------------// + + //! Generic replace algorithm + /*! + Use the Finder to search for a substring. Use the Formatter to format + this substring and replace it in the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input sequence + \param Finder A Finder object used to search for a match to be replaced + \param Formatter A Formatter object used to format a match + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename RangeT, + typename FinderT, + typename FormatterT> + inline OutputIteratorT find_format_copy( + OutputIteratorT Output, + const RangeT& Input, + FinderT Finder, + FormatterT Formatter ) + { + // Concept check + BOOST_CONCEPT_ASSERT(( + FinderConcept< + FinderT, + BOOST_STRING_TYPENAME range_const_iterator::type> + )); + BOOST_CONCEPT_ASSERT(( + FormatterConcept< + FormatterT, + FinderT,BOOST_STRING_TYPENAME range_const_iterator::type> + )); + + iterator_range::type> lit_input(::boost::as_literal(Input)); + + return detail::find_format_copy_impl( + Output, + lit_input, + Formatter, + Finder( ::boost::begin(lit_input), ::boost::end(lit_input) ) ); + } + + //! Generic replace algorithm + /*! + \overload + */ + template< + typename SequenceT, + typename FinderT, + typename FormatterT> + inline SequenceT find_format_copy( + const SequenceT& Input, + FinderT Finder, + FormatterT Formatter ) + { + // Concept check + BOOST_CONCEPT_ASSERT(( + FinderConcept< + FinderT, + BOOST_STRING_TYPENAME range_const_iterator::type> + )); + BOOST_CONCEPT_ASSERT(( + FormatterConcept< + FormatterT, + FinderT,BOOST_STRING_TYPENAME range_const_iterator::type> + )); + + return detail::find_format_copy_impl( + Input, + Formatter, + Finder(::boost::begin(Input), ::boost::end(Input))); + } + + //! Generic replace algorithm + /*! + Use the Finder to search for a substring. Use the Formatter to format + this substring and replace it in the input. The input is modified in-place. + + \param Input An input sequence + \param Finder A Finder object used to search for a match to be replaced + \param Formatter A Formatter object used to format a match + */ + template< + typename SequenceT, + typename FinderT, + typename FormatterT> + inline void find_format( + SequenceT& Input, + FinderT Finder, + FormatterT Formatter) + { + // Concept check + BOOST_CONCEPT_ASSERT(( + FinderConcept< + FinderT, + BOOST_STRING_TYPENAME range_const_iterator::type> + )); + BOOST_CONCEPT_ASSERT(( + FormatterConcept< + FormatterT, + FinderT,BOOST_STRING_TYPENAME range_const_iterator::type> + )); + + detail::find_format_impl( + Input, + Formatter, + Finder(::boost::begin(Input), ::boost::end(Input))); + } + + +// find_format_all generic ----------------------------------------------------------------// + + //! Generic replace all algorithm + /*! + Use the Finder to search for a substring. Use the Formatter to format + this substring and replace it in the input. Repeat this for all matching + substrings. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input sequence + \param Finder A Finder object used to search for a match to be replaced + \param Formatter A Formatter object used to format a match + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename RangeT, + typename FinderT, + typename FormatterT> + inline OutputIteratorT find_format_all_copy( + OutputIteratorT Output, + const RangeT& Input, + FinderT Finder, + FormatterT Formatter) + { + // Concept check + BOOST_CONCEPT_ASSERT(( + FinderConcept< + FinderT, + BOOST_STRING_TYPENAME range_const_iterator::type> + )); + BOOST_CONCEPT_ASSERT(( + FormatterConcept< + FormatterT, + FinderT,BOOST_STRING_TYPENAME range_const_iterator::type> + )); + + iterator_range::type> lit_input(::boost::as_literal(Input)); + + return detail::find_format_all_copy_impl( + Output, + lit_input, + Finder, + Formatter, + Finder(::boost::begin(lit_input), ::boost::end(lit_input))); + } + + //! Generic replace all algorithm + /*! + \overload + */ + template< + typename SequenceT, + typename FinderT, + typename FormatterT > + inline SequenceT find_format_all_copy( + const SequenceT& Input, + FinderT Finder, + FormatterT Formatter ) + { + // Concept check + BOOST_CONCEPT_ASSERT(( + FinderConcept< + FinderT, + BOOST_STRING_TYPENAME range_const_iterator::type> + )); + BOOST_CONCEPT_ASSERT(( + FormatterConcept< + FormatterT, + FinderT,BOOST_STRING_TYPENAME range_const_iterator::type> + )); + + return detail::find_format_all_copy_impl( + Input, + Finder, + Formatter, + Finder( ::boost::begin(Input), ::boost::end(Input) ) ); + } + + //! Generic replace all algorithm + /*! + Use the Finder to search for a substring. Use the Formatter to format + this substring and replace it in the input. Repeat this for all matching + substrings.The input is modified in-place. + + \param Input An input sequence + \param Finder A Finder object used to search for a match to be replaced + \param Formatter A Formatter object used to format a match + */ + template< + typename SequenceT, + typename FinderT, + typename FormatterT > + inline void find_format_all( + SequenceT& Input, + FinderT Finder, + FormatterT Formatter ) + { + // Concept check + BOOST_CONCEPT_ASSERT(( + FinderConcept< + FinderT, + BOOST_STRING_TYPENAME range_const_iterator::type> + )); + BOOST_CONCEPT_ASSERT(( + FormatterConcept< + FormatterT, + FinderT,BOOST_STRING_TYPENAME range_const_iterator::type> + )); + + detail::find_format_all_impl( + Input, + Finder, + Formatter, + Finder(::boost::begin(Input), ::boost::end(Input))); + + } + + } // namespace algorithm + + // pull the names to the boost namespace + using algorithm::find_format_copy; + using algorithm::find_format; + using algorithm::find_format_all_copy; + using algorithm::find_format_all; + +} // namespace boost + + +#endif // BOOST_STRING_FIND_FORMAT_HPP diff --git a/boost/algorithm/string/finder.hpp b/boost/algorithm/string/finder.hpp new file mode 100644 index 0000000..61f6e41 --- /dev/null +++ b/boost/algorithm/string/finder.hpp @@ -0,0 +1,266 @@ +// Boost string_algo library finder.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2006. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FINDER_HPP +#define BOOST_STRING_FINDER_HPP + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/*! \file + Defines Finder generators. Finder object is a functor which is able to + find a substring matching a specific criteria in the input. + Finders are used as a pluggable components for replace, find + and split facilities. This header contains generator functions + for finders provided in this library. +*/ + +namespace boost { + namespace algorithm { + +// Finder generators ------------------------------------------// + + //! "First" finder + /*! + Construct the \c first_finder. The finder searches for the first + occurrence of the string in a given input. + The result is given as an \c iterator_range delimiting the match. + + \param Search A substring to be searched for. + \return An instance of the \c first_finder object + */ + template + inline detail::first_finderF< + BOOST_STRING_TYPENAME range_const_iterator::type, + is_equal> + first_finder( const RangeT& Search ) + { + return + detail::first_finderF< + BOOST_STRING_TYPENAME + range_const_iterator::type, + is_equal>( ::boost::as_literal(Search), is_equal() ) ; + } + + //! "First" finder + /*! + \overload + */ + template + inline detail::first_finderF< + BOOST_STRING_TYPENAME range_const_iterator::type, + PredicateT> + first_finder( + const RangeT& Search, PredicateT Comp ) + { + return + detail::first_finderF< + BOOST_STRING_TYPENAME + range_const_iterator::type, + PredicateT>( ::boost::as_literal(Search), Comp ); + } + + //! "Last" finder + /*! + Construct the \c last_finder. The finder searches for the last + occurrence of the string in a given input. + The result is given as an \c iterator_range delimiting the match. + + \param Search A substring to be searched for. + \return An instance of the \c last_finder object + */ + template + inline detail::last_finderF< + BOOST_STRING_TYPENAME range_const_iterator::type, + is_equal> + last_finder( const RangeT& Search ) + { + return + detail::last_finderF< + BOOST_STRING_TYPENAME + range_const_iterator::type, + is_equal>( ::boost::as_literal(Search), is_equal() ); + } + //! "Last" finder + /*! + \overload + */ + template + inline detail::last_finderF< + BOOST_STRING_TYPENAME range_const_iterator::type, + PredicateT> + last_finder( const RangeT& Search, PredicateT Comp ) + { + return + detail::last_finderF< + BOOST_STRING_TYPENAME + range_const_iterator::type, + PredicateT>( ::boost::as_literal(Search), Comp ) ; + } + + //! "Nth" finder + /*! + Construct the \c nth_finder. The finder searches for the n-th (zero-indexed) + occurrence of the string in a given input. + The result is given as an \c iterator_range delimiting the match. + + \param Search A substring to be searched for. + \param Nth An index of the match to be find + \return An instance of the \c nth_finder object + */ + template + inline detail::nth_finderF< + BOOST_STRING_TYPENAME range_const_iterator::type, + is_equal> + nth_finder( + const RangeT& Search, + int Nth) + { + return + detail::nth_finderF< + BOOST_STRING_TYPENAME + range_const_iterator::type, + is_equal>( ::boost::as_literal(Search), Nth, is_equal() ) ; + } + //! "Nth" finder + /*! + \overload + */ + template + inline detail::nth_finderF< + BOOST_STRING_TYPENAME range_const_iterator::type, + PredicateT> + nth_finder( + const RangeT& Search, + int Nth, + PredicateT Comp ) + { + return + detail::nth_finderF< + BOOST_STRING_TYPENAME + range_const_iterator::type, + PredicateT>( ::boost::as_literal(Search), Nth, Comp ); + } + + //! "Head" finder + /*! + Construct the \c head_finder. The finder returns a head of a given + input. The head is a prefix of a string up to n elements in + size. If an input has less then n elements, whole input is + considered a head. + The result is given as an \c iterator_range delimiting the match. + + \param N The size of the head + \return An instance of the \c head_finder object + */ + inline detail::head_finderF + head_finder( int N ) + { + return detail::head_finderF(N); + } + + //! "Tail" finder + /*! + Construct the \c tail_finder. The finder returns a tail of a given + input. The tail is a suffix of a string up to n elements in + size. If an input has less then n elements, whole input is + considered a head. + The result is given as an \c iterator_range delimiting the match. + + \param N The size of the head + \return An instance of the \c tail_finder object + */ + inline detail::tail_finderF + tail_finder( int N ) + { + return detail::tail_finderF(N); + } + + //! "Token" finder + /*! + Construct the \c token_finder. The finder searches for a token + specified by a predicate. It is similar to std::find_if + algorithm, with an exception that it return a range of + instead of a single iterator. + + If "compress token mode" is enabled, adjacent matching tokens are + concatenated into one match. Thus the finder can be used to + search for continuous segments of characters satisfying the + given predicate. + + The result is given as an \c iterator_range delimiting the match. + + \param Pred An element selection predicate + \param eCompress Compress flag + \return An instance of the \c token_finder object + */ + template< typename PredicateT > + inline detail::token_finderF + token_finder( + PredicateT Pred, + token_compress_mode_type eCompress=token_compress_off ) + { + return detail::token_finderF( Pred, eCompress ); + } + + //! "Range" finder + /*! + Construct the \c range_finder. The finder does not perform + any operation. It simply returns the given range for + any input. + + \param Begin Beginning of the range + \param End End of the range + \return An instance of the \c range_finger object + */ + template< typename ForwardIteratorT > + inline detail::range_finderF + range_finder( + ForwardIteratorT Begin, + ForwardIteratorT End ) + { + return detail::range_finderF( Begin, End ); + } + + //! "Range" finder + /*! + \overload + */ + template< typename ForwardIteratorT > + inline detail::range_finderF + range_finder( iterator_range Range ) + { + return detail::range_finderF( Range ); + } + + } // namespace algorithm + + // pull the names to the boost namespace + using algorithm::first_finder; + using algorithm::last_finder; + using algorithm::nth_finder; + using algorithm::head_finder; + using algorithm::tail_finder; + using algorithm::token_finder; + using algorithm::range_finder; + +} // namespace boost + + +#endif // BOOST_STRING_FINDER_HPP diff --git a/boost/algorithm/string/formatter.hpp b/boost/algorithm/string/formatter.hpp new file mode 100644 index 0000000..de8681b --- /dev/null +++ b/boost/algorithm/string/formatter.hpp @@ -0,0 +1,120 @@ +// Boost string_algo library formatter.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FORMATTER_HPP +#define BOOST_STRING_FORMATTER_HPP + +#include +#include +#include +#include + +#include + +/*! \file + Defines Formatter generators. Formatter is a functor which formats + a string according to given parameters. A Formatter works + in conjunction with a Finder. A Finder can provide additional information + for a specific Formatter. An example of such a cooperation is regex_finder + and regex_formatter. + + Formatters are used as pluggable components for replace facilities. + This header contains generator functions for the Formatters provided in this library. +*/ + +namespace boost { + namespace algorithm { + +// generic formatters ---------------------------------------------------------------// + + //! Constant formatter + /*! + Constructs a \c const_formatter. Const formatter always returns + the same value, regardless of the parameter. + + \param Format A predefined value used as a result for formatting + \return An instance of the \c const_formatter object. + */ + template + inline detail::const_formatF< + iterator_range< + BOOST_STRING_TYPENAME range_const_iterator::type> > + const_formatter(const RangeT& Format) + { + return detail::const_formatF< + iterator_range< + BOOST_STRING_TYPENAME range_const_iterator::type> >(::boost::as_literal(Format)); + } + + //! Identity formatter + /*! + Constructs an \c identity_formatter. Identity formatter always returns + the parameter. + + \return An instance of the \c identity_formatter object. + */ + template + inline detail::identity_formatF< + iterator_range< + BOOST_STRING_TYPENAME range_const_iterator::type> > + identity_formatter() + { + return detail::identity_formatF< + iterator_range< + BOOST_STRING_TYPENAME range_const_iterator::type> >(); + } + + //! Empty formatter + /*! + Constructs an \c empty_formatter. Empty formatter always returns an empty + sequence. + + \param Input container used to select a correct value_type for the + resulting empty_container<>. + \return An instance of the \c empty_formatter object. + */ + template + inline detail::empty_formatF< + BOOST_STRING_TYPENAME range_value::type> + empty_formatter(const RangeT&) + { + return detail::empty_formatF< + BOOST_STRING_TYPENAME range_value::type>(); + } + + //! Empty formatter + /*! + Constructs a \c dissect_formatter. Dissect formatter uses a specified finder + to extract a portion of the formatted sequence. The first finder's match is returned + as a result + + \param Finder a finder used to select a portion of the formatted sequence + \return An instance of the \c dissect_formatter object. + */ + template + inline detail::dissect_formatF< FinderT > + dissect_formatter(const FinderT& Finder) + { + return detail::dissect_formatF(Finder); + } + + + } // namespace algorithm + + // pull the names to the boost namespace + using algorithm::const_formatter; + using algorithm::identity_formatter; + using algorithm::empty_formatter; + using algorithm::dissect_formatter; + +} // namespace boost + + +#endif // BOOST_FORMATTER_HPP diff --git a/boost/algorithm/string/replace.hpp b/boost/algorithm/string/replace.hpp new file mode 100644 index 0000000..2adb031 --- /dev/null +++ b/boost/algorithm/string/replace.hpp @@ -0,0 +1,926 @@ +// Boost string_algo library replace.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2006. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_REPLACE_HPP +#define BOOST_STRING_REPLACE_HPP + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/*! \file + Defines various replace algorithms. Each algorithm replaces + part(s) of the input according to set of searching and replace criteria. +*/ + +namespace boost { + namespace algorithm { + +// replace_range --------------------------------------------------------------------// + + //! Replace range algorithm + /*! + Replace the given range in the input string. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param SearchRange A range in the input to be substituted + \param Format A substitute string + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT replace_range_copy( + OutputIteratorT Output, + const Range1T& Input, + const iterator_range< + BOOST_STRING_TYPENAME + range_const_iterator::type>& SearchRange, + const Range2T& Format) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::range_finder(SearchRange), + ::boost::algorithm::const_formatter(Format)); + } + + //! Replace range algorithm + /*! + \overload + */ + template + inline SequenceT replace_range_copy( + const SequenceT& Input, + const iterator_range< + BOOST_STRING_TYPENAME + range_const_iterator::type>& SearchRange, + const RangeT& Format) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::range_finder(SearchRange), + ::boost::algorithm::const_formatter(Format)); + } + + //! Replace range algorithm + /*! + Replace the given range in the input string. + The input sequence is modified in-place. + + \param Input An input string + \param SearchRange A range in the input to be substituted + \param Format A substitute string + */ + template + inline void replace_range( + SequenceT& Input, + const iterator_range< + BOOST_STRING_TYPENAME + range_iterator::type>& SearchRange, + const RangeT& Format) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::range_finder(SearchRange), + ::boost::algorithm::const_formatter(Format)); + } + +// replace_first --------------------------------------------------------------------// + + //! Replace first algorithm + /*! + Replace the first match of the search substring in the input + with the format string. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T, + typename Range3T> + inline OutputIteratorT replace_first_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + const Range3T& Format) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace first algorithm + /*! + \overload + */ + template + inline SequenceT replace_first_copy( + const SequenceT& Input, + const Range1T& Search, + const Range2T& Format ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace first algorithm + /*! + replace the first match of the search substring in the input + with the format string. The input sequence is modified in-place. + + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + */ + template + inline void replace_first( + SequenceT& Input, + const Range1T& Search, + const Range2T& Format ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::const_formatter(Format) ); + } + +// replace_first ( case insensitive ) ---------------------------------------------// + + //! Replace first algorithm ( case insensitive ) + /*! + Replace the first match of the search substring in the input + with the format string. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + Searching is case insensitive. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + \param Loc A locale used for case insensitive comparison + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T, + typename Range3T> + inline OutputIteratorT ireplace_first_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + const Range3T& Format, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace first algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ireplace_first_copy( + const SequenceT& Input, + const Range2T& Search, + const Range1T& Format, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace first algorithm ( case insensitive ) + /*! + Replace the first match of the search substring in the input + with the format string. Input sequence is modified in-place. + Searching is case insensitive. + + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + \param Loc A locale used for case insensitive comparison + */ + template + inline void ireplace_first( + SequenceT& Input, + const Range1T& Search, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + +// replace_last --------------------------------------------------------------------// + + //! Replace last algorithm + /*! + Replace the last match of the search string in the input + with the format string. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T, + typename Range3T> + inline OutputIteratorT replace_last_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + const Range3T& Format ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::last_finder(Search), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace last algorithm + /*! + \overload + */ + template + inline SequenceT replace_last_copy( + const SequenceT& Input, + const Range1T& Search, + const Range2T& Format ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::last_finder(Search), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace last algorithm + /*! + Replace the last match of the search string in the input + with the format string. Input sequence is modified in-place. + + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + */ + template + inline void replace_last( + SequenceT& Input, + const Range1T& Search, + const Range2T& Format ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::last_finder(Search), + ::boost::algorithm::const_formatter(Format) ); + } + +// replace_last ( case insensitive ) -----------------------------------------------// + + //! Replace last algorithm ( case insensitive ) + /*! + Replace the last match of the search string in the input + with the format string. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + Searching is case insensitive. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + \param Loc A locale used for case insensitive comparison + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T, + typename Range3T> + inline OutputIteratorT ireplace_last_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + const Range3T& Format, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::last_finder(Search, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace last algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ireplace_last_copy( + const SequenceT& Input, + const Range1T& Search, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::last_finder(Search, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace last algorithm ( case insensitive ) + /*! + Replace the last match of the search string in the input + with the format string.The input sequence is modified in-place. + Searching is case insensitive. + + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + \param Loc A locale used for case insensitive comparison + */ + template + inline void ireplace_last( + SequenceT& Input, + const Range1T& Search, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::last_finder(Search, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + +// replace_nth --------------------------------------------------------------------// + + //! Replace nth algorithm + /*! + Replace an Nth (zero-indexed) match of the search string in the input + with the format string. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Nth An index of the match to be replaced. The index is 0-based. + For negative N, matches are counted from the end of string. + \param Format A substitute string + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T, + typename Range3T> + inline OutputIteratorT replace_nth_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + int Nth, + const Range3T& Format ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::nth_finder(Search, Nth), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace nth algorithm + /*! + \overload + */ + template + inline SequenceT replace_nth_copy( + const SequenceT& Input, + const Range1T& Search, + int Nth, + const Range2T& Format ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::nth_finder(Search, Nth), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace nth algorithm + /*! + Replace an Nth (zero-indexed) match of the search string in the input + with the format string. Input sequence is modified in-place. + + \param Input An input string + \param Search A substring to be searched for + \param Nth An index of the match to be replaced. The index is 0-based. + For negative N, matches are counted from the end of string. + \param Format A substitute string + */ + template + inline void replace_nth( + SequenceT& Input, + const Range1T& Search, + int Nth, + const Range2T& Format ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::nth_finder(Search, Nth), + ::boost::algorithm::const_formatter(Format) ); + } + +// replace_nth ( case insensitive ) -----------------------------------------------// + + //! Replace nth algorithm ( case insensitive ) + /*! + Replace an Nth (zero-indexed) match of the search string in the input + with the format string. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + Searching is case insensitive. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Nth An index of the match to be replaced. The index is 0-based. + For negative N, matches are counted from the end of string. + \param Format A substitute string + \param Loc A locale used for case insensitive comparison + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T, + typename Range3T> + inline OutputIteratorT ireplace_nth_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + int Nth, + const Range3T& Format, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc) ), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace nth algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ireplace_nth_copy( + const SequenceT& Input, + const Range1T& Search, + int Nth, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace nth algorithm ( case insensitive ) + /*! + Replace an Nth (zero-indexed) match of the search string in the input + with the format string. Input sequence is modified in-place. + Searching is case insensitive. + + \param Input An input string + \param Search A substring to be searched for + \param Nth An index of the match to be replaced. The index is 0-based. + For negative N, matches are counted from the end of string. + \param Format A substitute string + \param Loc A locale used for case insensitive comparison + */ + template + inline void ireplace_nth( + SequenceT& Input, + const Range1T& Search, + int Nth, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + +// replace_all --------------------------------------------------------------------// + + //! Replace all algorithm + /*! + Replace all occurrences of the search string in the input + with the format string. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T, + typename Range3T> + inline OutputIteratorT replace_all_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + const Range3T& Format ) + { + return ::boost::algorithm::find_format_all_copy( + Output, + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace all algorithm + /*! + \overload + */ + template + inline SequenceT replace_all_copy( + const SequenceT& Input, + const Range1T& Search, + const Range2T& Format ) + { + return ::boost::algorithm::find_format_all_copy( + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace all algorithm + /*! + Replace all occurrences of the search string in the input + with the format string. The input sequence is modified in-place. + + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + */ + template + inline void replace_all( + SequenceT& Input, + const Range1T& Search, + const Range2T& Format ) + { + ::boost::algorithm::find_format_all( + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::const_formatter(Format) ); + } + +// replace_all ( case insensitive ) -----------------------------------------------// + + //! Replace all algorithm ( case insensitive ) + /*! + Replace all occurrences of the search string in the input + with the format string. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + Searching is case insensitive. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + \param Loc A locale used for case insensitive comparison + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T, + typename Range3T> + inline OutputIteratorT ireplace_all_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + const Range3T& Format, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_all_copy( + Output, + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace all algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ireplace_all_copy( + const SequenceT& Input, + const Range1T& Search, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_all_copy( + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace all algorithm ( case insensitive ) + /*! + Replace all occurrences of the search string in the input + with the format string.The input sequence is modified in-place. + Searching is case insensitive. + + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + \param Loc A locale used for case insensitive comparison + */ + template + inline void ireplace_all( + SequenceT& Input, + const Range1T& Search, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + ::boost::algorithm::find_format_all( + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + +// replace_head --------------------------------------------------------------------// + + //! Replace head algorithm + /*! + Replace the head of the input with the given format string. + The head is a prefix of a string of given size. + If the sequence is shorter then required, whole string if + considered to be the head. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param N Length of the head. + For N>=0, at most N characters are extracted. + For N<0, size(Input)-|N| characters are extracted. + \param Format A substitute string + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT replace_head_copy( + OutputIteratorT Output, + const Range1T& Input, + int N, + const Range2T& Format ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::head_finder(N), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace head algorithm + /*! + \overload + */ + template + inline SequenceT replace_head_copy( + const SequenceT& Input, + int N, + const RangeT& Format ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::head_finder(N), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace head algorithm + /*! + Replace the head of the input with the given format string. + The head is a prefix of a string of given size. + If the sequence is shorter then required, the whole string is + considered to be the head. The input sequence is modified in-place. + + \param Input An input string + \param N Length of the head. + For N>=0, at most N characters are extracted. + For N<0, size(Input)-|N| characters are extracted. + \param Format A substitute string + */ + template + inline void replace_head( + SequenceT& Input, + int N, + const RangeT& Format ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::head_finder(N), + ::boost::algorithm::const_formatter(Format) ); + } + +// replace_tail --------------------------------------------------------------------// + + //! Replace tail algorithm + /*! + Replace the tail of the input with the given format string. + The tail is a suffix of a string of given size. + If the sequence is shorter then required, whole string is + considered to be the tail. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param N Length of the tail. + For N>=0, at most N characters are extracted. + For N<0, size(Input)-|N| characters are extracted. + \param Format A substitute string + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT replace_tail_copy( + OutputIteratorT Output, + const Range1T& Input, + int N, + const Range2T& Format ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::tail_finder(N), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace tail algorithm + /*! + \overload + */ + template + inline SequenceT replace_tail_copy( + const SequenceT& Input, + int N, + const RangeT& Format ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::tail_finder(N), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace tail algorithm + /*! + Replace the tail of the input with the given format sequence. + The tail is a suffix of a string of given size. + If the sequence is shorter then required, the whole string is + considered to be the tail. The input sequence is modified in-place. + + \param Input An input string + \param N Length of the tail. + For N>=0, at most N characters are extracted. + For N<0, size(Input)-|N| characters are extracted. + \param Format A substitute string + */ + template + inline void replace_tail( + SequenceT& Input, + int N, + const RangeT& Format ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::tail_finder(N), + ::boost::algorithm::const_formatter(Format) ); + } + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::replace_range_copy; + using algorithm::replace_range; + using algorithm::replace_first_copy; + using algorithm::replace_first; + using algorithm::ireplace_first_copy; + using algorithm::ireplace_first; + using algorithm::replace_last_copy; + using algorithm::replace_last; + using algorithm::ireplace_last_copy; + using algorithm::ireplace_last; + using algorithm::replace_nth_copy; + using algorithm::replace_nth; + using algorithm::ireplace_nth_copy; + using algorithm::ireplace_nth; + using algorithm::replace_all_copy; + using algorithm::replace_all; + using algorithm::ireplace_all_copy; + using algorithm::ireplace_all; + using algorithm::replace_head_copy; + using algorithm::replace_head; + using algorithm::replace_tail_copy; + using algorithm::replace_tail; + +} // namespace boost + +#endif // BOOST_REPLACE_HPP diff --git a/boost/algorithm/string/sequence_traits.hpp b/boost/algorithm/string/sequence_traits.hpp new file mode 100644 index 0000000..be151f8 --- /dev/null +++ b/boost/algorithm/string/sequence_traits.hpp @@ -0,0 +1,120 @@ +// Boost string_algo library sequence_traits.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_SEQUENCE_TRAITS_HPP +#define BOOST_STRING_SEQUENCE_TRAITS_HPP + +#include +#include +#include + +/*! \file + Traits defined in this header are used by various algorithms to achieve + better performance for specific containers. + Traits provide fail-safe defaults. If a container supports some of these + features, it is possible to specialize the specific trait for this container. + For lacking compilers, it is possible of define an override for a specific tester + function. + + Due to a language restriction, it is not currently possible to define specializations for + stl containers without including the corresponding header. To decrease the overhead + needed by this inclusion, user can selectively include a specialization + header for a specific container. They are located in boost/algorithm/string/stl + directory. Alternatively she can include boost/algorithm/string/std_collection_traits.hpp + header which contains specializations for all stl containers. +*/ + +namespace boost { + namespace algorithm { + +// sequence traits -----------------------------------------------// + + + //! Native replace trait + /*! + This trait specifies that the sequence has \c std::string like replace method + */ + template< typename T > + class has_native_replace + { + + public: +# if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = false }; +# else + BOOST_STATIC_CONSTANT(bool, value=false); +# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + + + typedef mpl::bool_::value> type; + }; + + + //! Stable iterators trait + /*! + This trait specifies that the sequence has stable iterators. It means + that operations like insert/erase/replace do not invalidate iterators. + */ + template< typename T > + class has_stable_iterators + { + public: +# if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = false }; +# else + BOOST_STATIC_CONSTANT(bool, value=false); +# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + + typedef mpl::bool_::value> type; + }; + + + //! Const time insert trait + /*! + This trait specifies that the sequence's insert method has + constant time complexity. + */ + template< typename T > + class has_const_time_insert + { + public: +# if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = false }; +# else + BOOST_STATIC_CONSTANT(bool, value=false); +# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + + typedef mpl::bool_::value> type; + }; + + + //! Const time erase trait + /*! + This trait specifies that the sequence's erase method has + constant time complexity. + */ + template< typename T > + class has_const_time_erase + { + public: +# if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = false }; +# else + BOOST_STATIC_CONSTANT(bool, value=false); +# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + + typedef mpl::bool_::value> type; + }; + + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_SEQUENCE_TRAITS_HPP diff --git a/boost/algorithm/string/yes_no_type.hpp b/boost/algorithm/string/yes_no_type.hpp new file mode 100644 index 0000000..b76cc6c --- /dev/null +++ b/boost/algorithm/string/yes_no_type.hpp @@ -0,0 +1,33 @@ +// Boost string_algo library yes_no_type.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_YES_NO_TYPE_DETAIL_HPP +#define BOOST_STRING_YES_NO_TYPE_DETAIL_HPP + +namespace boost { + namespace algorithm { + + // taken from boost mailing-list + // when yes_no_type will become officially + // a part of boost distribution, this header + // will be deprecated + template struct size_descriptor + { + typedef char (& type)[I]; + }; + + typedef size_descriptor<1>::type yes_type; + typedef size_descriptor<2>::type no_type; + + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_YES_NO_TYPE_DETAIL_HPP diff --git a/boost/array.hpp b/boost/array.hpp new file mode 100644 index 0000000..99dc2c6 --- /dev/null +++ b/boost/array.hpp @@ -0,0 +1,457 @@ +/* The following code declares class array, + * an STL container (as wrapper) for arrays of constant size. + * + * See + * http://www.boost.org/libs/array/ + * for documentation. + * + * The original author site is at: http://www.josuttis.com/ + * + * (C) Copyright Nicolai M. Josuttis 2001. + * + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * 9 Jan 2013 - (mtc) Added constexpr + * 14 Apr 2012 - (mtc) Added support for boost::hash + * 28 Dec 2010 - (mtc) Added cbegin and cend (and crbegin and crend) for C++Ox compatibility. + * 10 Mar 2010 - (mtc) fill method added, matching resolution of the standard library working group. + * See or Trac issue #3168 + * Eventually, we should remove "assign" which is now a synonym for "fill" (Marshall Clow) + * 10 Mar 2010 - added workaround for SUNCC and !STLPort [trac #3893] (Marshall Clow) + * 29 Jan 2004 - c_array() added, BOOST_NO_PRIVATE_IN_AGGREGATE removed (Nico Josuttis) + * 23 Aug 2002 - fix for Non-MSVC compilers combined with MSVC libraries. + * 05 Aug 2001 - minor update (Nico Josuttis) + * 20 Jan 2001 - STLport fix (Beman Dawes) + * 29 Sep 2000 - Initial Revision (Nico Josuttis) + * + * Jan 29, 2004 + */ +#ifndef BOOST_ARRAY_HPP +#define BOOST_ARRAY_HPP + +#include + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +# pragma warning(push) +# pragma warning(disable:4996) // 'std::equal': Function call with parameters that may be unsafe +# pragma warning(disable:4510) // boost::array' : default constructor could not be generated +# pragma warning(disable:4610) // warning C4610: class 'boost::array' can never be instantiated - user defined constructor required +#endif + +#include +#include +#include +#include +#include + +// Handles broken standard libraries better than +#include +#include +#include + +// FIXES for broken compilers +#include + + +namespace boost { + + template + class array { + public: + T elems[N]; // fixed-size array of elements of type T + + public: + // type definitions + typedef T value_type; + typedef T* iterator; + typedef const T* const_iterator; + typedef T& reference; + typedef const T& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + // iterator support + iterator begin() { return elems; } + const_iterator begin() const { return elems; } + const_iterator cbegin() const { return elems; } + + iterator end() { return elems+N; } + const_iterator end() const { return elems+N; } + const_iterator cend() const { return elems+N; } + + // reverse iterator support +#if !defined(BOOST_MSVC_STD_ITERATOR) && !defined(BOOST_NO_STD_ITERATOR_TRAITS) + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; +#elif defined(_RWSTD_NO_CLASS_PARTIAL_SPEC) + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; +#else + // workaround for broken reverse_iterator implementations + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; +#endif + + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + const_reverse_iterator crbegin() const { + return const_reverse_iterator(end()); + } + + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + const_reverse_iterator crend() const { + return const_reverse_iterator(begin()); + } + + // operator[] + reference operator[](size_type i) + { + return BOOST_ASSERT_MSG( i < N, "out of range" ), elems[i]; + } + + /*BOOST_CONSTEXPR*/ const_reference operator[](size_type i) const + { + return BOOST_ASSERT_MSG( i < N, "out of range" ), elems[i]; + } + + // at() with range check + reference at(size_type i) { return rangecheck(i), elems[i]; } + /*BOOST_CONSTEXPR*/ const_reference at(size_type i) const { return rangecheck(i), elems[i]; } + + // front() and back() + reference front() + { + return elems[0]; + } + + BOOST_CONSTEXPR const_reference front() const + { + return elems[0]; + } + + reference back() + { + return elems[N-1]; + } + + BOOST_CONSTEXPR const_reference back() const + { + return elems[N-1]; + } + + // size is constant + static BOOST_CONSTEXPR size_type size() { return N; } + static BOOST_CONSTEXPR bool empty() { return false; } + static BOOST_CONSTEXPR size_type max_size() { return N; } + enum { static_size = N }; + + // swap (note: linear complexity) + void swap (array& y) { + for (size_type i = 0; i < N; ++i) + boost::swap(elems[i],y.elems[i]); + } + + // direct access to data (read-only) + const T* data() const { return elems; } + T* data() { return elems; } + + // use array as C array (direct read/write access to data) + T* c_array() { return elems; } + + // assignment with type conversion + template + array& operator= (const array& rhs) { + std::copy(rhs.begin(),rhs.end(), begin()); + return *this; + } + + // assign one value to all elements + void assign (const T& value) { fill ( value ); } // A synonym for fill + void fill (const T& value) + { + std::fill_n(begin(),size(),value); + } + + // check range (may be private because it is static) + static BOOST_CONSTEXPR bool rangecheck (size_type i) { + return i >= size() ? boost::throw_exception(std::out_of_range ("array<>: index out of range")), true : true; + } + + }; + + template< class T > + class array< T, 0 > { + + public: + // type definitions + typedef T value_type; + typedef T* iterator; + typedef const T* const_iterator; + typedef T& reference; + typedef const T& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + // iterator support + iterator begin() { return iterator( reinterpret_cast< T * >( this ) ); } + const_iterator begin() const { return const_iterator( reinterpret_cast< const T * >( this ) ); } + const_iterator cbegin() const { return const_iterator( reinterpret_cast< const T * >( this ) ); } + + iterator end() { return begin(); } + const_iterator end() const { return begin(); } + const_iterator cend() const { return cbegin(); } + + // reverse iterator support +#if !defined(BOOST_MSVC_STD_ITERATOR) && !defined(BOOST_NO_STD_ITERATOR_TRAITS) + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; +#elif defined(_RWSTD_NO_CLASS_PARTIAL_SPEC) + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; +#else + // workaround for broken reverse_iterator implementations + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; +#endif + + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + const_reverse_iterator crbegin() const { + return const_reverse_iterator(end()); + } + + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + const_reverse_iterator crend() const { + return const_reverse_iterator(begin()); + } + + // operator[] + reference operator[](size_type /*i*/) + { + return failed_rangecheck(); + } + + /*BOOST_CONSTEXPR*/ const_reference operator[](size_type /*i*/) const + { + return failed_rangecheck(); + } + + // at() with range check + reference at(size_type /*i*/) { return failed_rangecheck(); } + /*BOOST_CONSTEXPR*/ const_reference at(size_type /*i*/) const { return failed_rangecheck(); } + + // front() and back() + reference front() + { + return failed_rangecheck(); + } + + BOOST_CONSTEXPR const_reference front() const + { + return failed_rangecheck(); + } + + reference back() + { + return failed_rangecheck(); + } + + BOOST_CONSTEXPR const_reference back() const + { + return failed_rangecheck(); + } + + // size is constant + static BOOST_CONSTEXPR size_type size() { return 0; } + static BOOST_CONSTEXPR bool empty() { return true; } + static BOOST_CONSTEXPR size_type max_size() { return 0; } + enum { static_size = 0 }; + + void swap (array& /*y*/) { + } + + // direct access to data (read-only) + const T* data() const { return 0; } + T* data() { return 0; } + + // use array as C array (direct read/write access to data) + T* c_array() { return 0; } + + // assignment with type conversion + template + array& operator= (const array& ) { + return *this; + } + + // assign one value to all elements + void assign (const T& value) { fill ( value ); } + void fill (const T& ) {} + + // check range (may be private because it is static) + static reference failed_rangecheck () { + std::out_of_range e("attempt to access element of an empty array"); + boost::throw_exception(e); +#if defined(BOOST_NO_EXCEPTIONS) || (!defined(BOOST_MSVC) && !defined(__PATHSCALE__)) + // + // We need to return something here to keep + // some compilers happy: however we will never + // actually get here.... + // + static T placeholder; + return placeholder; +#endif + } + }; + + // comparisons + template + bool operator== (const array& x, const array& y) { + return std::equal(x.begin(), x.end(), y.begin()); + } + template + bool operator< (const array& x, const array& y) { + return std::lexicographical_compare(x.begin(),x.end(),y.begin(),y.end()); + } + template + bool operator!= (const array& x, const array& y) { + return !(x==y); + } + template + bool operator> (const array& x, const array& y) { + return y + bool operator<= (const array& x, const array& y) { + return !(y + bool operator>= (const array& x, const array& y) { + return !(x + inline void swap (array& x, array& y) { + x.swap(y); + } + +#if defined(__SUNPRO_CC) +// Trac ticket #4757; the Sun Solaris compiler can't handle +// syntax like 'T(&get_c_array(boost::array& arg))[N]' +// +// We can't just use this for all compilers, because the +// borland compilers can't handle this form. + namespace detail { + template struct c_array + { + typedef T type[N]; + }; + } + + // Specific for boost::array: simply returns its elems data member. + template + typename detail::c_array::type& get_c_array(boost::array& arg) + { + return arg.elems; + } + + // Specific for boost::array: simply returns its elems data member. + template + typename detail::c_array::type const& get_c_array(const boost::array& arg) + { + return arg.elems; + } +#else +// Specific for boost::array: simply returns its elems data member. + template + T(&get_c_array(boost::array& arg))[N] + { + return arg.elems; + } + + // Const version. + template + const T(&get_c_array(const boost::array& arg))[N] + { + return arg.elems; + } +#endif + +#if 0 + // Overload for std::array, assuming that std::array will have + // explicit conversion functions as discussed at the WG21 meeting + // in Summit, March 2009. + template + T(&get_c_array(std::array& arg))[N] + { + return static_cast(arg); + } + + // Const version. + template + const T(&get_c_array(const std::array& arg))[N] + { + return static_cast(arg); + } +#endif + + template std::size_t hash_range(It, It); + + template + std::size_t hash_value(const array& arr) + { + return boost::hash_range(arr.begin(), arr.end()); + } + + template + T &get(boost::array &arr) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG ( Idx < N, "boost::get<>(boost::array &) index out of range" ); + return arr[Idx]; + } + + template + const T &get(const boost::array &arr) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG ( Idx < N, "boost::get<>(const boost::array &) index out of range" ); + return arr[Idx]; + } + +} /* namespace boost */ + +#ifndef BOOST_NO_CXX11_HDR_ARRAY +// If we don't have std::array, I'm assuming that we don't have std::get +namespace std { + template + T &get(boost::array &arr) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG ( Idx < N, "std::get<>(boost::array &) index out of range" ); + return arr[Idx]; + } + + template + const T &get(const boost::array &arr) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG ( Idx < N, "std::get<>(const boost::array &) index out of range" ); + return arr[Idx]; + } +} +#endif + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +# pragma warning(pop) +#endif + +#endif /*BOOST_ARRAY_HPP*/ diff --git a/boost/asio.hpp b/boost/asio.hpp new file mode 100644 index 0000000..1ee7e12 --- /dev/null +++ b/boost/asio.hpp @@ -0,0 +1,146 @@ +// +// asio.hpp +// ~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See www.boost.org/libs/asio for documentation. +// + +#ifndef BOOST_ASIO_HPP +#define BOOST_ASIO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // BOOST_ASIO_HPP diff --git a/boost/asio/associated_allocator.hpp b/boost/asio/associated_allocator.hpp new file mode 100644 index 0000000..c70852b --- /dev/null +++ b/boost/asio/associated_allocator.hpp @@ -0,0 +1,133 @@ +// +// associated_allocator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_ASSOCIATED_ALLOCATOR_HPP +#define BOOST_ASIO_ASSOCIATED_ALLOCATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +struct associated_allocator_check +{ + typedef void type; +}; + +template +struct associated_allocator_impl +{ + typedef E type; + + static type get(const T&, const E& e) BOOST_ASIO_NOEXCEPT + { + return e; + } +}; + +template +struct associated_allocator_impl::type> +{ + typedef typename T::allocator_type type; + + static type get(const T& t, const E&) BOOST_ASIO_NOEXCEPT + { + return t.get_allocator(); + } +}; + +} // namespace detail + +/// Traits type used to obtain the allocator associated with an object. +/** + * A program may specialise this traits type if the @c T template parameter in + * the specialisation is a user-defined type. The template parameter @c + * Allocator shall be a type meeting the Allocator requirements. + * + * Specialisations shall meet the following requirements, where @c t is a const + * reference to an object of type @c T, and @c a is an object of type @c + * Allocator. + * + * @li Provide a nested typedef @c type that identifies a type meeting the + * Allocator requirements. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t) and with return type @c type. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t,a) and with return type @c type. + */ +template > +struct associated_allocator +{ + /// If @c T has a nested type @c allocator_type, T::allocator_type. + /// Otherwise @c Allocator. +#if defined(GENERATING_DOCUMENTATION) + typedef see_below type; +#else // defined(GENERATING_DOCUMENTATION) + typedef typename detail::associated_allocator_impl::type type; +#endif // defined(GENERATING_DOCUMENTATION) + + /// If @c T has a nested type @c allocator_type, returns + /// t.get_allocator(). Otherwise returns @c a. + static type get(const T& t, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return detail::associated_allocator_impl::get(t, a); + } +}; + +/// Helper function to obtain an object's associated allocator. +/** + * @returns associated_allocator::get(t) + */ +template +inline typename associated_allocator::type +get_associated_allocator(const T& t) BOOST_ASIO_NOEXCEPT +{ + return associated_allocator::get(t); +} + +/// Helper function to obtain an object's associated allocator. +/** + * @returns associated_allocator::get(t, a) + */ +template +inline typename associated_allocator::type +get_associated_allocator(const T& t, const Allocator& a) BOOST_ASIO_NOEXCEPT +{ + return associated_allocator::get(t, a); +} + +#if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) + +template > +using associated_allocator_t + = typename associated_allocator::type; + +#endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_ASSOCIATED_ALLOCATOR_HPP diff --git a/boost/asio/associated_executor.hpp b/boost/asio/associated_executor.hpp new file mode 100644 index 0000000..a44190b --- /dev/null +++ b/boost/asio/associated_executor.hpp @@ -0,0 +1,151 @@ +// +// associated_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_ASSOCIATED_EXECUTOR_HPP +#define BOOST_ASIO_ASSOCIATED_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +struct associated_executor_check +{ + typedef void type; +}; + +template +struct associated_executor_impl +{ + typedef E type; + + static type get(const T&, const E& e) BOOST_ASIO_NOEXCEPT + { + return e; + } +}; + +template +struct associated_executor_impl::type> +{ + typedef typename T::executor_type type; + + static type get(const T& t, const E&) BOOST_ASIO_NOEXCEPT + { + return t.get_executor(); + } +}; + +} // namespace detail + +/// Traits type used to obtain the executor associated with an object. +/** + * A program may specialise this traits type if the @c T template parameter in + * the specialisation is a user-defined type. The template parameter @c + * Executor shall be a type meeting the Executor requirements. + * + * Specialisations shall meet the following requirements, where @c t is a const + * reference to an object of type @c T, and @c e is an object of type @c + * Executor. + * + * @li Provide a nested typedef @c type that identifies a type meeting the + * Executor requirements. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t) and with return type @c type. + * + * @li Provide a noexcept static member function named @c get, callable as @c + * get(t,e) and with return type @c type. + */ +template +struct associated_executor +{ + /// If @c T has a nested type @c executor_type, T::executor_type. + /// Otherwise @c Executor. +#if defined(GENERATING_DOCUMENTATION) + typedef see_below type; +#else // defined(GENERATING_DOCUMENTATION) + typedef typename detail::associated_executor_impl::type type; +#endif // defined(GENERATING_DOCUMENTATION) + + /// If @c T has a nested type @c executor_type, returns + /// t.get_executor(). Otherwise returns @c ex. + static type get(const T& t, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return detail::associated_executor_impl::get(t, ex); + } +}; + +/// Helper function to obtain an object's associated executor. +/** + * @returns associated_executor::get(t) + */ +template +inline typename associated_executor::type +get_associated_executor(const T& t) BOOST_ASIO_NOEXCEPT +{ + return associated_executor::get(t); +} + +/// Helper function to obtain an object's associated executor. +/** + * @returns associated_executor::get(t, ex) + */ +template +inline typename associated_executor::type +get_associated_executor(const T& t, const Executor& ex, + typename enable_if::value>::type* = 0) BOOST_ASIO_NOEXCEPT +{ + return associated_executor::get(t, ex); +} + +/// Helper function to obtain an object's associated executor. +/** + * @returns associated_executor::get(t, ctx.get_executor()) + */ +template +inline typename associated_executor::type +get_associated_executor(const T& t, ExecutionContext& ctx, + typename enable_if::value>::type* = 0) BOOST_ASIO_NOEXCEPT +{ + return associated_executor::get(t, ctx.get_executor()); +} + +#if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) + +template +using associated_executor_t = typename associated_executor::type; + +#endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_ASSOCIATED_EXECUTOR_HPP diff --git a/boost/asio/async_result.hpp b/boost/asio/async_result.hpp new file mode 100644 index 0000000..4f3bb1e --- /dev/null +++ b/boost/asio/async_result.hpp @@ -0,0 +1,358 @@ +// +// async_result.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_ASYNC_RESULT_HPP +#define BOOST_ASIO_ASYNC_RESULT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +/// An interface for customising the behaviour of an initiating function. +/** + * The async_result traits class is used for determining: + * + * @li the concrete completion handler type to be called at the end of the + * asynchronous operation; + * + * @li the initiating function return type; and + * + * @li how the return value of the initiating function is obtained. + * + * The trait allows the handler and return types to be determined at the point + * where the specific completion handler signature is known. + * + * This template may be specialised for user-defined completion token types. + * The primary template assumes that the CompletionToken is the completion + * handler. + */ +template +class async_result +{ +public: + /// The concrete completion handler type for the specific signature. + typedef CompletionToken completion_handler_type; + + /// The return type of the initiating function. + typedef void return_type; + + /// Construct an async result from a given handler. + /** + * When using a specalised async_result, the constructor has an opportunity + * to initialise some state associated with the completion handler, which is + * then returned from the initiating function. + */ + explicit async_result(completion_handler_type& h) + { + (void)h; + } + + /// Obtain the value to be returned from the initiating function. + return_type get() + { + } + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) \ + || defined(GENERATING_DOCUMENTATION) + + /// Initiate the asynchronous operation that will produce the result, and + /// obtain the value to be returned from the initiating function. + template + static return_type initiate( + BOOST_ASIO_MOVE_ARG(Initiation) initiation, + BOOST_ASIO_MOVE_ARG(RawCompletionToken) token, + BOOST_ASIO_MOVE_ARG(Args)... args) + { + BOOST_ASIO_MOVE_CAST(Initiation)(initiation)( + BOOST_ASIO_MOVE_CAST(RawCompletionToken)(token), + BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + + template + static return_type initiate( + BOOST_ASIO_MOVE_ARG(Initiation) initiation, + BOOST_ASIO_MOVE_ARG(RawCompletionToken) token) + { + BOOST_ASIO_MOVE_CAST(Initiation)(initiation)( + BOOST_ASIO_MOVE_CAST(RawCompletionToken)(token)); + } + +#define BOOST_ASIO_PRIVATE_INITIATE_DEF(n) \ + template \ + static return_type initiate( \ + BOOST_ASIO_MOVE_ARG(Initiation) initiation, \ + BOOST_ASIO_MOVE_ARG(RawCompletionToken) token, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + BOOST_ASIO_MOVE_CAST(Initiation)(initiation)( \ + BOOST_ASIO_MOVE_CAST(RawCompletionToken)(token), \ + BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_INITIATE_DEF) +#undef BOOST_ASIO_PRIVATE_INITIATE_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + +private: + async_result(const async_result&) BOOST_ASIO_DELETED; + async_result& operator=(const async_result&) BOOST_ASIO_DELETED; +}; + +/// Helper template to deduce the handler type from a CompletionToken, capture +/// a local copy of the handler, and then create an async_result for the +/// handler. +template +struct async_completion +{ + /// The real handler type to be used for the asynchronous operation. + typedef typename boost::asio::async_result< + typename decay::type, + Signature>::completion_handler_type completion_handler_type; + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Constructor. + /** + * The constructor creates the concrete completion handler and makes the link + * between the handler and the asynchronous result. + */ + explicit async_completion(CompletionToken& token) + : completion_handler(static_cast::value, + completion_handler_type&, CompletionToken&&>::type>(token)), + result(completion_handler) + { + } +#else // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + explicit async_completion(typename decay::type& token) + : completion_handler(token), + result(completion_handler) + { + } + + explicit async_completion(const typename decay::type& token) + : completion_handler(token), + result(completion_handler) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// A copy of, or reference to, a real handler object. +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + typename conditional< + is_same::value, + completion_handler_type&, completion_handler_type>::type completion_handler; +#else // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + completion_handler_type completion_handler; +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// The result of the asynchronous operation's initiating function. + async_result::type, Signature> result; +}; + +namespace detail { + +template +struct async_result_helper + : async_result::type, Signature> +{ +}; + +struct async_result_memfns_base +{ + void initiate(); +}; + +template +struct async_result_memfns_derived + : T, async_result_memfns_base +{ +}; + +template +struct async_result_memfns_check +{ +}; + +template +char (&async_result_initiate_memfn_helper(...))[2]; + +template +char async_result_initiate_memfn_helper( + async_result_memfns_check< + void (async_result_memfns_base::*)(), + &async_result_memfns_derived::initiate>*); + +template +struct async_result_has_initiate_memfn + : integral_constant::type, Signature> + >(0)) != 1> +{ +}; + +} // namespace detail + +#if defined(GENERATING_DOCUMENTATION) +# define BOOST_ASIO_INITFN_RESULT_TYPE(ct, sig) \ + void_or_deduced +#elif defined(_MSC_VER) && (_MSC_VER < 1500) +# define BOOST_ASIO_INITFN_RESULT_TYPE(ct, sig) \ + typename ::boost::asio::detail::async_result_helper< \ + ct, sig>::return_type +#define BOOST_ASIO_HANDLER_TYPE(ct, sig) \ + typename ::boost::asio::detail::async_result_helper< \ + ct, sig>::completion_handler_type +#else +# define BOOST_ASIO_INITFN_RESULT_TYPE(ct, sig) \ + typename ::boost::asio::async_result< \ + typename ::boost::asio::decay::type, sig>::return_type +#define BOOST_ASIO_HANDLER_TYPE(ct, sig) \ + typename ::boost::asio::async_result< \ + typename ::boost::asio::decay::type, sig>::completion_handler_type +#endif + +#if defined(GENERATING_DOCUMENTATION) + +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature) +async_initiate(BOOST_ASIO_MOVE_ARG(Initiation) initiation, + BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken), + BOOST_ASIO_MOVE_ARG(Args)... args); + +#elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +inline typename enable_if< + detail::async_result_has_initiate_memfn::value, + BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type +async_initiate(BOOST_ASIO_MOVE_ARG(Initiation) initiation, + BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, + BOOST_ASIO_MOVE_ARG(Args)... args) +{ + return async_result::type, + Signature>::initiate(BOOST_ASIO_MOVE_CAST(Initiation)(initiation), + BOOST_ASIO_MOVE_CAST(CompletionToken)(token), + BOOST_ASIO_MOVE_CAST(Args)(args)...); +} + +template +inline typename enable_if< + !detail::async_result_has_initiate_memfn::value, + BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type +async_initiate(BOOST_ASIO_MOVE_ARG(Initiation) initiation, + BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, + BOOST_ASIO_MOVE_ARG(Args)... args) +{ + async_completion completion(token); + + BOOST_ASIO_MOVE_CAST(Initiation)(initiation)( + BOOST_ASIO_MOVE_CAST(BOOST_ASIO_HANDLER_TYPE(CompletionToken, + Signature))(completion.completion_handler), + BOOST_ASIO_MOVE_CAST(Args)(args)...); + + return completion.result.get(); +} + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +inline typename enable_if< + detail::async_result_has_initiate_memfn::value, + BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type +async_initiate(BOOST_ASIO_MOVE_ARG(Initiation) initiation, + BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token) +{ + return async_result::type, + Signature>::initiate(BOOST_ASIO_MOVE_CAST(Initiation)(initiation), + BOOST_ASIO_MOVE_CAST(CompletionToken)(token)); +} + +template +inline typename enable_if< + !detail::async_result_has_initiate_memfn::value, + BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type +async_initiate(BOOST_ASIO_MOVE_ARG(Initiation) initiation, + BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token) +{ + async_completion completion(token); + + BOOST_ASIO_MOVE_CAST(Initiation)(initiation)( + BOOST_ASIO_MOVE_CAST(BOOST_ASIO_HANDLER_TYPE(CompletionToken, + Signature))(completion.completion_handler)); + + return completion.result.get(); +} + +#define BOOST_ASIO_PRIVATE_INITIATE_DEF(n) \ + template \ + inline typename enable_if< \ + detail::async_result_has_initiate_memfn< \ + CompletionToken, Signature>::value, \ + BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type \ + async_initiate(BOOST_ASIO_MOVE_ARG(Initiation) initiation, \ + BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + return async_result::type, \ + Signature>::initiate(BOOST_ASIO_MOVE_CAST(Initiation)(initiation), \ + BOOST_ASIO_MOVE_CAST(CompletionToken)(token), \ + BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + \ + template \ + inline typename enable_if< \ + !detail::async_result_has_initiate_memfn< \ + CompletionToken, Signature>::value, \ + BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature)>::type \ + async_initiate(BOOST_ASIO_MOVE_ARG(Initiation) initiation, \ + BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + async_completion completion(token); \ + \ + BOOST_ASIO_MOVE_CAST(Initiation)(initiation)( \ + BOOST_ASIO_MOVE_CAST(BOOST_ASIO_HANDLER_TYPE(CompletionToken, \ + Signature))(completion.completion_handler), \ + BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + \ + return completion.result.get(); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_INITIATE_DEF) +#undef BOOST_ASIO_PRIVATE_INITIATE_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_ASYNC_RESULT_HPP diff --git a/boost/asio/awaitable.hpp b/boost/asio/awaitable.hpp new file mode 100644 index 0000000..83f8647 --- /dev/null +++ b/boost/asio/awaitable.hpp @@ -0,0 +1,125 @@ +// +// awaitable.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_AWAITABLE_HPP +#define BOOST_ASIO_AWAITABLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +using std::experimental::coroutine_handle; +using std::experimental::suspend_always; + +template class awaitable_thread; +template class awaitable_frame; + +} // namespace detail + +/// The return type of a coroutine or asynchronous operation. +template +class awaitable +{ +public: + /// The type of the awaited value. + typedef T value_type; + + /// The executor type that will be used for the coroutine. + typedef Executor executor_type; + + /// Default constructor. + constexpr awaitable() noexcept + : frame_(nullptr) + { + } + + /// Move constructor. + awaitable(awaitable&& other) noexcept + : frame_(std::exchange(other.frame_, nullptr)) + { + } + + /// Destructor + ~awaitable() + { + if (frame_) + frame_->destroy(); + } + + /// Checks if the awaitable refers to a future result. + bool valid() const noexcept + { + return !!frame_; + } + +#if !defined(GENERATING_DOCUMENTATION) + + // Support for co_await keyword. + bool await_ready() const noexcept + { + return false; + } + + // Support for co_await keyword. + template + void await_suspend( + detail::coroutine_handle> h) + { + frame_->push_frame(&h.promise()); + } + + // Support for co_await keyword. + T await_resume() + { + return frame_->get(); + } + +#endif // !defined(GENERATING_DOCUMENTATION) + +private: + template friend class detail::awaitable_thread; + template friend class detail::awaitable_frame; + + // Not copy constructible or copy assignable. + awaitable(const awaitable&) = delete; + awaitable& operator=(const awaitable&) = delete; + + // Construct the awaitable from a coroutine's frame object. + explicit awaitable(detail::awaitable_frame* a) + : frame_(a) + { + } + + detail::awaitable_frame* frame_; +}; + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_AWAITABLE_HPP diff --git a/boost/asio/basic_datagram_socket.hpp b/boost/asio/basic_datagram_socket.hpp new file mode 100644 index 0000000..b058f78 --- /dev/null +++ b/boost/asio/basic_datagram_socket.hpp @@ -0,0 +1,1117 @@ +// +// basic_datagram_socket.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BASIC_DATAGRAM_SOCKET_HPP +#define BOOST_ASIO_BASIC_DATAGRAM_SOCKET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +#if !defined(BOOST_ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL) +#define BOOST_ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL + +// Forward declaration with defaulted arguments. +template +class basic_datagram_socket; + +#endif // !defined(BOOST_ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL) + +/// Provides datagram-oriented socket functionality. +/** + * The basic_datagram_socket class template provides asynchronous and blocking + * datagram-oriented socket functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_datagram_socket + : public basic_socket +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the socket type to another executor. + template + struct rebind_executor + { + /// The socket type when rebound to the specified executor. + typedef basic_datagram_socket other; + }; + + /// The native representation of a socket. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef typename basic_socket::native_handle_type native_handle_type; +#endif + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// Construct a basic_datagram_socket without opening it. + /** + * This constructor creates a datagram socket without opening it. The open() + * function must be called before data can be sent or received on the socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + */ + explicit basic_datagram_socket(const executor_type& ex) + : basic_socket(ex) + { + } + + /// Construct a basic_datagram_socket without opening it. + /** + * This constructor creates a datagram socket without opening it. The open() + * function must be called before data can be sent or received on the socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + */ + template + explicit basic_datagram_socket(ExecutionContext& context, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_socket(context) + { + } + + /// Construct and open a basic_datagram_socket. + /** + * This constructor creates and opens a datagram socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_datagram_socket(const executor_type& ex, const protocol_type& protocol) + : basic_socket(ex, protocol) + { + } + + /// Construct and open a basic_datagram_socket. + /** + * This constructor creates and opens a datagram socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_datagram_socket(ExecutionContext& context, + const protocol_type& protocol, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_socket(context, protocol) + { + } + + /// Construct a basic_datagram_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a datagram socket and automatically opens it bound + * to the specified endpoint on the local machine. The protocol used is the + * protocol associated with the given endpoint. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the datagram + * socket will be bound. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_datagram_socket(const executor_type& ex, const endpoint_type& endpoint) + : basic_socket(ex, endpoint) + { + } + + /// Construct a basic_datagram_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a datagram socket and automatically opens it bound + * to the specified endpoint on the local machine. The protocol used is the + * protocol associated with the given endpoint. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the datagram + * socket will be bound. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_datagram_socket(ExecutionContext& context, + const endpoint_type& endpoint, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_socket(context, endpoint) + { + } + + /// Construct a basic_datagram_socket on an existing native socket. + /** + * This constructor creates a datagram socket object to hold an existing + * native socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_datagram_socket(const executor_type& ex, + const protocol_type& protocol, const native_handle_type& native_socket) + : basic_socket(ex, protocol, native_socket) + { + } + + /// Construct a basic_datagram_socket on an existing native socket. + /** + * This constructor creates a datagram socket object to hold an existing + * native socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_datagram_socket(ExecutionContext& context, + const protocol_type& protocol, const native_handle_type& native_socket, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_socket(context, protocol, native_socket) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_datagram_socket from another. + /** + * This constructor moves a datagram socket from one object to another. + * + * @param other The other basic_datagram_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_datagram_socket(const executor_type&) + * constructor. + */ + basic_datagram_socket(basic_datagram_socket&& other) + : basic_socket(std::move(other)) + { + } + + /// Move-assign a basic_datagram_socket from another. + /** + * This assignment operator moves a datagram socket from one object to + * another. + * + * @param other The other basic_datagram_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_datagram_socket(const executor_type&) + * constructor. + */ + basic_datagram_socket& operator=(basic_datagram_socket&& other) + { + basic_socket::operator=(std::move(other)); + return *this; + } + + /// Move-construct a basic_datagram_socket from a socket of another protocol + /// type. + /** + * This constructor moves a datagram socket from one object to another. + * + * @param other The other basic_datagram_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_datagram_socket(const executor_type&) + * constructor. + */ + template + basic_datagram_socket(basic_datagram_socket&& other, + typename enable_if< + is_convertible::value + && is_convertible::value + >::type* = 0) + : basic_socket(std::move(other)) + { + } + + /// Move-assign a basic_datagram_socket from a socket of another protocol + /// type. + /** + * This assignment operator moves a datagram socket from one object to + * another. + * + * @param other The other basic_datagram_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_datagram_socket(const executor_type&) + * constructor. + */ + template + typename enable_if< + is_convertible::value + && is_convertible::value, + basic_datagram_socket& + >::type operator=(basic_datagram_socket&& other) + { + basic_socket::operator=(std::move(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the socket. + /** + * This function destroys the socket, cancelling any outstanding asynchronous + * operations associated with the socket as if by calling @c cancel. + */ + ~basic_datagram_socket() + { + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the datagram socket. The function + * call will block until the data has been sent successfully or an error + * occurs. + * + * @param buffers One ore more data buffers to be sent on the socket. + * + * @returns The number of bytes sent. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected datagram socket. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code socket.send(boost::asio::buffer(data, size)); @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t send(const ConstBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, 0, ec); + boost::asio::detail::throw_error(ec, "send"); + return s; + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the datagram socket. The function + * call will block until the data has been sent successfully or an error + * occurs. + * + * @param buffers One ore more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @returns The number of bytes sent. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected datagram socket. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); + boost::asio::detail::throw_error(ec, "send"); + return s; + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the datagram socket. The function + * call will block until the data has been sent successfully or an error + * occurs. + * + * @param buffers One or more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes sent. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected datagram socket. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + return this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); + } + + /// Start an asynchronous send on a connected socket. + /** + * This function is used to asynchronously send data on the datagram socket. + * The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent on the socket. Although + * the buffers object may be copied as necessary, ownership of the underlying + * memory blocks is retained by the caller, which must guarantee that they + * remain valid until the handler is called. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The async_send operation can only be used with a connected socket. + * Use the async_send_to function to send data on an unconnected datagram + * socket. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_send(boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_send(const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + return async_initiate( + initiate_async_send(), handler, this, + buffers, socket_base::message_flags(0)); + } + + /// Start an asynchronous send on a connected socket. + /** + * This function is used to asynchronously send data on the datagram socket. + * The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent on the socket. Although + * the buffers object may be copied as necessary, ownership of the underlying + * memory blocks is retained by the caller, which must guarantee that they + * remain valid until the handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The async_send operation can only be used with a connected socket. + * Use the async_send_to function to send data on an unconnected datagram + * socket. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + return async_initiate( + initiate_async_send(), handler, this, buffers, flags); + } + + /// Send a datagram to the specified endpoint. + /** + * This function is used to send a datagram to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @returns The number of bytes sent. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * boost::asio::ip::udp::endpoint destination( + * boost::asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.send_to(boost::asio::buffer(data, size), destination); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().send_to( + this->impl_.get_implementation(), buffers, destination, 0, ec); + boost::asio::detail::throw_error(ec, "send_to"); + return s; + } + + /// Send a datagram to the specified endpoint. + /** + * This function is used to send a datagram to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @param flags Flags specifying how the send call is to be made. + * + * @returns The number of bytes sent. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().send_to( + this->impl_.get_implementation(), buffers, destination, flags, ec); + boost::asio::detail::throw_error(ec, "send_to"); + return s; + } + + /// Send a datagram to the specified endpoint. + /** + * This function is used to send a datagram to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes sent. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + boost::system::error_code& ec) + { + return this->impl_.get_service().send_to(this->impl_.get_implementation(), + buffers, destination, flags, ec); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send a datagram to the specified + * remote endpoint. The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param destination The remote endpoint to which the data will be sent. + * Copies will be made of the endpoint as required. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * boost::asio::ip::udp::endpoint destination( + * boost::asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.async_send_to( + * boost::asio::buffer(data, size), destination, handler); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + return async_initiate( + initiate_async_send_to(), handler, this, buffers, + destination, socket_base::message_flags(0)); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send a datagram to the specified + * remote endpoint. The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param destination The remote endpoint to which the data will be sent. + * Copies will be made of the endpoint as required. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + return async_initiate( + initiate_async_send_to(), handler, this, buffers, destination, flags); + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the datagram socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected datagram + * socket. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code socket.receive(boost::asio::buffer(data, size)); @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive(const MutableBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, 0, ec); + boost::asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the datagram socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected datagram + * socket. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, flags, ec); + boost::asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the datagram socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected datagram + * socket. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + return this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, flags, ec); + } + + /// Start an asynchronous receive on a connected socket. + /** + * This function is used to asynchronously receive data from the datagram + * socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The async_receive operation can only be used with a connected socket. + * Use the async_receive_from function to receive data on an unconnected + * datagram socket. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.async_receive(boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + return async_initiate( + initiate_async_receive(), handler, this, + buffers, socket_base::message_flags(0)); + } + + /// Start an asynchronous receive on a connected socket. + /** + * This function is used to asynchronously receive data from the datagram + * socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The async_receive operation can only be used with a connected socket. + * Use the async_receive_from function to receive data on an unconnected + * datagram socket. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + return async_initiate( + initiate_async_receive(), handler, this, buffers, flags); + } + + /// Receive a datagram with the endpoint of the sender. + /** + * This function is used to receive a datagram. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * boost::asio::ip::udp::endpoint sender_endpoint; + * socket.receive_from( + * boost::asio::buffer(data, size), sender_endpoint); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().receive_from( + this->impl_.get_implementation(), buffers, sender_endpoint, 0, ec); + boost::asio::detail::throw_error(ec, "receive_from"); + return s; + } + + /// Receive a datagram with the endpoint of the sender. + /** + * This function is used to receive a datagram. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().receive_from( + this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec); + boost::asio::detail::throw_error(ec, "receive_from"); + return s; + } + + /// Receive a datagram with the endpoint of the sender. + /** + * This function is used to receive a datagram. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + boost::system::error_code& ec) + { + return this->impl_.get_service().receive_from( + this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive a datagram. The function + * call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. Ownership of the sender_endpoint object + * is retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code socket.async_receive_from( + * boost::asio::buffer(data, size), sender_endpoint, handler); @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + return async_initiate( + initiate_async_receive_from(), handler, this, buffers, + &sender_endpoint, socket_base::message_flags(0)); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive a datagram. The function + * call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the datagram. Ownership of the sender_endpoint object + * is retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + return async_initiate( + initiate_async_receive_from(), handler, + this, buffers, &sender_endpoint, flags); + } + +private: + struct initiate_async_send + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + basic_datagram_socket* self, const ConstBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_send( + self->impl_.get_implementation(), buffers, flags, + handler2.value, self->impl_.get_implementation_executor()); + } + }; + + struct initiate_async_send_to + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + basic_datagram_socket* self, const ConstBufferSequence& buffers, + const endpoint_type& destination, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_send_to( + self->impl_.get_implementation(), buffers, destination, flags, + handler2.value, self->impl_.get_implementation_executor()); + } + }; + + struct initiate_async_receive + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + basic_datagram_socket* self, const MutableBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_receive( + self->impl_.get_implementation(), buffers, flags, + handler2.value, self->impl_.get_implementation_executor()); + } + }; + + struct initiate_async_receive_from + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + basic_datagram_socket* self, const MutableBufferSequence& buffers, + endpoint_type* sender_endpoint, socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_receive_from( + self->impl_.get_implementation(), buffers, *sender_endpoint, flags, + handler2.value, self->impl_.get_implementation_executor()); + } + }; +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BASIC_DATAGRAM_SOCKET_HPP diff --git a/boost/asio/basic_deadline_timer.hpp b/boost/asio/basic_deadline_timer.hpp new file mode 100644 index 0000000..75f0fcd --- /dev/null +++ b/boost/asio/basic_deadline_timer.hpp @@ -0,0 +1,668 @@ +// +// basic_deadline_timer.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BASIC_DEADLINE_TIMER_HPP +#define BOOST_ASIO_BASIC_DEADLINE_TIMER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ + || defined(GENERATING_DOCUMENTATION) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +/// Provides waitable timer functionality. +/** + * The basic_deadline_timer class template provides the ability to perform a + * blocking or asynchronous wait for a timer to expire. + * + * A deadline timer is always in one of two states: "expired" or "not expired". + * If the wait() or async_wait() function is called on an expired timer, the + * wait operation will complete immediately. + * + * Most applications will use the boost::asio::deadline_timer typedef. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Examples + * Performing a blocking wait: + * @code + * // Construct a timer without setting an expiry time. + * boost::asio::deadline_timer timer(my_context); + * + * // Set an expiry time relative to now. + * timer.expires_from_now(boost::posix_time::seconds(5)); + * + * // Wait for the timer to expire. + * timer.wait(); + * @endcode + * + * @par + * Performing an asynchronous wait: + * @code + * void handler(const boost::system::error_code& error) + * { + * if (!error) + * { + * // Timer expired. + * } + * } + * + * ... + * + * // Construct a timer with an absolute expiry time. + * boost::asio::deadline_timer timer(my_context, + * boost::posix_time::time_from_string("2005-12-07 23:59:59.000")); + * + * // Start an asynchronous wait. + * timer.async_wait(handler); + * @endcode + * + * @par Changing an active deadline_timer's expiry time + * + * Changing the expiry time of a timer while there are pending asynchronous + * waits causes those wait operations to be cancelled. To ensure that the action + * associated with the timer is performed only once, use something like this: + * used: + * + * @code + * void on_some_event() + * { + * if (my_timer.expires_from_now(seconds(5)) > 0) + * { + * // We managed to cancel the timer. Start new asynchronous wait. + * my_timer.async_wait(on_timeout); + * } + * else + * { + * // Too late, timer has already expired! + * } + * } + * + * void on_timeout(const boost::system::error_code& e) + * { + * if (e != boost::asio::error::operation_aborted) + * { + * // Timer was not cancelled, take necessary action. + * } + * } + * @endcode + * + * @li The boost::asio::basic_deadline_timer::expires_from_now() function + * cancels any pending asynchronous waits, and returns the number of + * asynchronous waits that were cancelled. If it returns 0 then you were too + * late and the wait handler has already been executed, or will soon be + * executed. If it returns 1 then the wait handler was successfully cancelled. + * + * @li If a wait handler is cancelled, the boost::system::error_code passed to + * it contains the value boost::asio::error::operation_aborted. + */ +template , + typename Executor = executor> +class basic_deadline_timer +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// The time traits type. + typedef TimeTraits traits_type; + + /// The time type. + typedef typename traits_type::time_type time_type; + + /// The duration type. + typedef typename traits_type::duration_type duration_type; + + /// Constructor. + /** + * This constructor creates a timer without setting an expiry time. The + * expires_at() or expires_from_now() functions must be called to set an + * expiry time before the timer can be waited on. + * + * @param ex The I/O executor that the timer will use, by default, to + * dispatch handlers for any asynchronous operations performed on the timer. + */ + explicit basic_deadline_timer(const executor_type& ex) + : impl_(ex) + { + } + + /// Constructor. + /** + * This constructor creates a timer without setting an expiry time. The + * expires_at() or expires_from_now() functions must be called to set an + * expiry time before the timer can be waited on. + * + * @param context An execution context which provides the I/O executor that + * the timer will use, by default, to dispatch handlers for any asynchronous + * operations performed on the timer. + */ + template + explicit basic_deadline_timer(ExecutionContext& context, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + } + + /// Constructor to set a particular expiry time as an absolute time. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param ex The I/O executor that the timer will use, by default, to + * dispatch handlers for any asynchronous operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, expressed + * as an absolute time. + */ + basic_deadline_timer(const executor_type& ex, const time_type& expiry_time) + : impl_(ex) + { + boost::system::error_code ec; + impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec); + boost::asio::detail::throw_error(ec, "expires_at"); + } + + /// Constructor to set a particular expiry time as an absolute time. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param context An execution context which provides the I/O executor that + * the timer will use, by default, to dispatch handlers for any asynchronous + * operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, expressed + * as an absolute time. + */ + template + basic_deadline_timer(ExecutionContext& context, const time_type& expiry_time, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + boost::system::error_code ec; + impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec); + boost::asio::detail::throw_error(ec, "expires_at"); + } + + /// Constructor to set a particular expiry time relative to now. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param ex The I/O executor that the timer will use, by default, to + * dispatch handlers for any asynchronous operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, relative to + * now. + */ + basic_deadline_timer(const executor_type& ex, + const duration_type& expiry_time) + : impl_(ex) + { + boost::system::error_code ec; + impl_.get_service().expires_from_now( + impl_.get_implementation(), expiry_time, ec); + boost::asio::detail::throw_error(ec, "expires_from_now"); + } + + /// Constructor to set a particular expiry time relative to now. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param context An execution context which provides the I/O executor that + * the timer will use, by default, to dispatch handlers for any asynchronous + * operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, relative to + * now. + */ + template + basic_deadline_timer(ExecutionContext& context, + const duration_type& expiry_time, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + boost::system::error_code ec; + impl_.get_service().expires_from_now( + impl_.get_implementation(), expiry_time, ec); + boost::asio::detail::throw_error(ec, "expires_from_now"); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_deadline_timer from another. + /** + * This constructor moves a timer from one object to another. + * + * @param other The other basic_deadline_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_deadline_timer(const executor_type&) + * constructor. + */ + basic_deadline_timer(basic_deadline_timer&& other) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_deadline_timer from another. + /** + * This assignment operator moves a timer from one object to another. Cancels + * any outstanding asynchronous operations associated with the target object. + * + * @param other The other basic_deadline_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_deadline_timer(const executor_type&) + * constructor. + */ + basic_deadline_timer& operator=(basic_deadline_timer&& other) + { + impl_ = std::move(other.impl_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the timer. + /** + * This function destroys the timer, cancelling any outstanding asynchronous + * wait operations associated with the timer as if by calling @c cancel. + */ + ~basic_deadline_timer() + { + } + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return impl_.get_executor(); + } + + /// Cancel any asynchronous operations that are waiting on the timer. + /** + * This function forces the completion of any pending asynchronous wait + * operations against the timer. The handler for each cancelled operation will + * be invoked with the boost::asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @return The number of asynchronous operations that were cancelled. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note If the timer has already expired when cancel() is called, then the + * handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel() + { + boost::system::error_code ec; + std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "cancel"); + return s; + } + + /// Cancel any asynchronous operations that are waiting on the timer. + /** + * This function forces the completion of any pending asynchronous wait + * operations against the timer. The handler for each cancelled operation will + * be invoked with the boost::asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. + * + * @note If the timer has already expired when cancel() is called, then the + * handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel(boost::system::error_code& ec) + { + return impl_.get_service().cancel(impl_.get_implementation(), ec); + } + + /// Cancels one asynchronous operation that is waiting on the timer. + /** + * This function forces the completion of one pending asynchronous wait + * operation against the timer. Handlers are cancelled in FIFO order. The + * handler for the cancelled operation will be invoked with the + * boost::asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @return The number of asynchronous operations that were cancelled. That is, + * either 0 or 1. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note If the timer has already expired when cancel_one() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel_one() + { + boost::system::error_code ec; + std::size_t s = impl_.get_service().cancel_one( + impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "cancel_one"); + return s; + } + + /// Cancels one asynchronous operation that is waiting on the timer. + /** + * This function forces the completion of one pending asynchronous wait + * operation against the timer. Handlers are cancelled in FIFO order. The + * handler for the cancelled operation will be invoked with the + * boost::asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. That is, + * either 0 or 1. + * + * @note If the timer has already expired when cancel_one() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel_one(boost::system::error_code& ec) + { + return impl_.get_service().cancel_one(impl_.get_implementation(), ec); + } + + /// Get the timer's expiry time as an absolute time. + /** + * This function may be used to obtain the timer's current expiry time. + * Whether the timer has expired or not does not affect this value. + */ + time_type expires_at() const + { + return impl_.get_service().expires_at(impl_.get_implementation()); + } + + /// Set the timer's expiry time as an absolute time. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the boost::asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @return The number of asynchronous operations that were cancelled. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note If the timer has already expired when expires_at() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_at(const time_type& expiry_time) + { + boost::system::error_code ec; + std::size_t s = impl_.get_service().expires_at( + impl_.get_implementation(), expiry_time, ec); + boost::asio::detail::throw_error(ec, "expires_at"); + return s; + } + + /// Set the timer's expiry time as an absolute time. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the boost::asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. + * + * @note If the timer has already expired when expires_at() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_at(const time_type& expiry_time, + boost::system::error_code& ec) + { + return impl_.get_service().expires_at( + impl_.get_implementation(), expiry_time, ec); + } + + /// Get the timer's expiry time relative to now. + /** + * This function may be used to obtain the timer's current expiry time. + * Whether the timer has expired or not does not affect this value. + */ + duration_type expires_from_now() const + { + return impl_.get_service().expires_from_now(impl_.get_implementation()); + } + + /// Set the timer's expiry time relative to now. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the boost::asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @return The number of asynchronous operations that were cancelled. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note If the timer has already expired when expires_from_now() is called, + * then the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_from_now(const duration_type& expiry_time) + { + boost::system::error_code ec; + std::size_t s = impl_.get_service().expires_from_now( + impl_.get_implementation(), expiry_time, ec); + boost::asio::detail::throw_error(ec, "expires_from_now"); + return s; + } + + /// Set the timer's expiry time relative to now. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the boost::asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. + * + * @note If the timer has already expired when expires_from_now() is called, + * then the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_from_now(const duration_type& expiry_time, + boost::system::error_code& ec) + { + return impl_.get_service().expires_from_now( + impl_.get_implementation(), expiry_time, ec); + } + + /// Perform a blocking wait on the timer. + /** + * This function is used to wait for the timer to expire. This function + * blocks and does not return until the timer has expired. + * + * @throws boost::system::system_error Thrown on failure. + */ + void wait() + { + boost::system::error_code ec; + impl_.get_service().wait(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "wait"); + } + + /// Perform a blocking wait on the timer. + /** + * This function is used to wait for the timer to expire. This function + * blocks and does not return until the timer has expired. + * + * @param ec Set to indicate what error occurred, if any. + */ + void wait(boost::system::error_code& ec) + { + impl_.get_service().wait(impl_.get_implementation(), ec); + } + + /// Start an asynchronous wait on the timer. + /** + * This function may be used to initiate an asynchronous wait against the + * timer. It always returns immediately. + * + * For each call to async_wait(), the supplied handler will be called exactly + * once. The handler will be called when: + * + * @li The timer has expired. + * + * @li The timer was cancelled, in which case the handler is passed the error + * code boost::asio::error::operation_aborted. + * + * @param handler The handler to be called when the timer expires. Copies + * will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error // Result of operation. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + void (boost::system::error_code)) + async_wait(BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + { + return async_initiate( + initiate_async_wait(), handler, this); + } + +private: + // Disallow copying and assignment. + basic_deadline_timer(const basic_deadline_timer&) BOOST_ASIO_DELETED; + basic_deadline_timer& operator=( + const basic_deadline_timer&) BOOST_ASIO_DELETED; + + struct initiate_async_wait + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler, + basic_deadline_timer* self) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WaitHandler. + BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_wait( + self->impl_.get_implementation(), handler2.value, + self->impl_.get_implementation_executor()); + } + }; + + detail::io_object_impl< + detail::deadline_timer_service, Executor> impl_; +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_BASIC_DEADLINE_TIMER_HPP diff --git a/boost/asio/basic_io_object.hpp b/boost/asio/basic_io_object.hpp new file mode 100644 index 0000000..a9f44d1 --- /dev/null +++ b/boost/asio/basic_io_object.hpp @@ -0,0 +1,292 @@ +// +// basic_io_object.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BASIC_IO_OBJECT_HPP +#define BOOST_ASIO_BASIC_IO_OBJECT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { + +#if defined(BOOST_ASIO_HAS_MOVE) +namespace detail +{ + // Type trait used to determine whether a service supports move. + template + class service_has_move + { + private: + typedef IoObjectService service_type; + typedef typename service_type::implementation_type implementation_type; + + template + static auto asio_service_has_move_eval(T* t, U* u) + -> decltype(t->move_construct(*u, *u), char()); + static char (&asio_service_has_move_eval(...))[2]; + + public: + static const bool value = + sizeof(asio_service_has_move_eval( + static_cast(0), + static_cast(0))) == 1; + }; +} +#endif // defined(BOOST_ASIO_HAS_MOVE) + +/// Base class for all I/O objects. +/** + * @note All I/O objects are non-copyable. However, when using C++0x, certain + * I/O objects do support move construction and move assignment. + */ +#if !defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) +template +#else +template ::value> +#endif +class basic_io_object +{ +public: + /// The type of the service that will be used to provide I/O operations. + typedef IoObjectService service_type; + + /// The underlying implementation type of I/O object. + typedef typename service_type::implementation_type implementation_type; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_context() + { + return service_.get_io_context(); + } + + /// (Deprecated: Use get_executor().) Get the io_context associated with the + /// object. + /** + * This function may be used to obtain the io_context object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_context object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + boost::asio::io_context& get_io_service() + { + return service_.get_io_context(); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// The type of the executor associated with the object. + typedef boost::asio::io_context::executor_type executor_type; + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return service_.get_io_context().get_executor(); + } + +protected: + /// Construct a basic_io_object. + /** + * Performs: + * @code get_service().construct(get_implementation()); @endcode + */ + explicit basic_io_object(boost::asio::io_context& io_context) + : service_(boost::asio::use_service(io_context)) + { + service_.construct(implementation_); + } + +#if defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_io_object. + /** + * Performs: + * @code get_service().move_construct( + * get_implementation(), other.get_implementation()); @endcode + * + * @note Available only for services that support movability, + */ + basic_io_object(basic_io_object&& other); + + /// Move-assign a basic_io_object. + /** + * Performs: + * @code get_service().move_assign(get_implementation(), + * other.get_service(), other.get_implementation()); @endcode + * + * @note Available only for services that support movability, + */ + basic_io_object& operator=(basic_io_object&& other); + + /// Perform a converting move-construction of a basic_io_object. + template + basic_io_object(IoObjectService1& other_service, + typename IoObjectService1::implementation_type& other_implementation); +#endif // defined(GENERATING_DOCUMENTATION) + + /// Protected destructor to prevent deletion through this type. + /** + * Performs: + * @code get_service().destroy(get_implementation()); @endcode + */ + ~basic_io_object() + { + service_.destroy(implementation_); + } + + /// Get the service associated with the I/O object. + service_type& get_service() + { + return service_; + } + + /// Get the service associated with the I/O object. + const service_type& get_service() const + { + return service_; + } + + /// Get the underlying implementation of the I/O object. + implementation_type& get_implementation() + { + return implementation_; + } + + /// Get the underlying implementation of the I/O object. + const implementation_type& get_implementation() const + { + return implementation_; + } + +private: + basic_io_object(const basic_io_object&); + basic_io_object& operator=(const basic_io_object&); + + // The service associated with the I/O object. + service_type& service_; + + /// The underlying implementation of the I/O object. + implementation_type implementation_; +}; + +#if defined(BOOST_ASIO_HAS_MOVE) +// Specialisation for movable objects. +template +class basic_io_object +{ +public: + typedef IoObjectService service_type; + typedef typename service_type::implementation_type implementation_type; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + boost::asio::io_context& get_io_context() + { + return service_->get_io_context(); + } + + boost::asio::io_context& get_io_service() + { + return service_->get_io_context(); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + typedef boost::asio::io_context::executor_type executor_type; + + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return service_->get_io_context().get_executor(); + } + +protected: + explicit basic_io_object(boost::asio::io_context& io_context) + : service_(&boost::asio::use_service(io_context)) + { + service_->construct(implementation_); + } + + basic_io_object(basic_io_object&& other) + : service_(&other.get_service()) + { + service_->move_construct(implementation_, other.implementation_); + } + + template + basic_io_object(IoObjectService1& other_service, + typename IoObjectService1::implementation_type& other_implementation) + : service_(&boost::asio::use_service( + other_service.get_io_context())) + { + service_->converting_move_construct(implementation_, + other_service, other_implementation); + } + + ~basic_io_object() + { + service_->destroy(implementation_); + } + + basic_io_object& operator=(basic_io_object&& other) + { + service_->move_assign(implementation_, + *other.service_, other.implementation_); + service_ = other.service_; + return *this; + } + + service_type& get_service() + { + return *service_; + } + + const service_type& get_service() const + { + return *service_; + } + + implementation_type& get_implementation() + { + return implementation_; + } + + const implementation_type& get_implementation() const + { + return implementation_; + } + +private: + basic_io_object(const basic_io_object&); + void operator=(const basic_io_object&); + + IoObjectService* service_; + implementation_type implementation_; +}; +#endif // defined(BOOST_ASIO_HAS_MOVE) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BASIC_IO_OBJECT_HPP diff --git a/boost/asio/basic_raw_socket.hpp b/boost/asio/basic_raw_socket.hpp new file mode 100644 index 0000000..cc45d37 --- /dev/null +++ b/boost/asio/basic_raw_socket.hpp @@ -0,0 +1,1109 @@ +// +// basic_raw_socket.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BASIC_RAW_SOCKET_HPP +#define BOOST_ASIO_BASIC_RAW_SOCKET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +#if !defined(BOOST_ASIO_BASIC_RAW_SOCKET_FWD_DECL) +#define BOOST_ASIO_BASIC_RAW_SOCKET_FWD_DECL + +// Forward declaration with defaulted arguments. +template +class basic_raw_socket; + +#endif // !defined(BOOST_ASIO_BASIC_RAW_SOCKET_FWD_DECL) + +/// Provides raw-oriented socket functionality. +/** + * The basic_raw_socket class template provides asynchronous and blocking + * raw-oriented socket functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_raw_socket + : public basic_socket +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the socket type to another executor. + template + struct rebind_executor + { + /// The socket type when rebound to the specified executor. + typedef basic_raw_socket other; + }; + + /// The native representation of a socket. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef typename basic_socket::native_handle_type native_handle_type; +#endif + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// Construct a basic_raw_socket without opening it. + /** + * This constructor creates a raw socket without opening it. The open() + * function must be called before data can be sent or received on the socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + */ + explicit basic_raw_socket(const executor_type& ex) + : basic_socket(ex) + { + } + + /// Construct a basic_raw_socket without opening it. + /** + * This constructor creates a raw socket without opening it. The open() + * function must be called before data can be sent or received on the socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + */ + template + explicit basic_raw_socket(ExecutionContext& context, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_socket(context) + { + } + + /// Construct and open a basic_raw_socket. + /** + * This constructor creates and opens a raw socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_raw_socket(const executor_type& ex, const protocol_type& protocol) + : basic_socket(ex, protocol) + { + } + + /// Construct and open a basic_raw_socket. + /** + * This constructor creates and opens a raw socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_raw_socket(ExecutionContext& context, const protocol_type& protocol, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_socket(context, protocol) + { + } + + /// Construct a basic_raw_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a raw socket and automatically opens it bound + * to the specified endpoint on the local machine. The protocol used is the + * protocol associated with the given endpoint. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the raw + * socket will be bound. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_raw_socket(const executor_type& ex, const endpoint_type& endpoint) + : basic_socket(ex, endpoint) + { + } + + /// Construct a basic_raw_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a raw socket and automatically opens it bound + * to the specified endpoint on the local machine. The protocol used is the + * protocol associated with the given endpoint. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the raw + * socket will be bound. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_raw_socket(ExecutionContext& context, const endpoint_type& endpoint, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_socket(context, endpoint) + { + } + + /// Construct a basic_raw_socket on an existing native socket. + /** + * This constructor creates a raw socket object to hold an existing + * native socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_raw_socket(const executor_type& ex, + const protocol_type& protocol, const native_handle_type& native_socket) + : basic_socket(ex, protocol, native_socket) + { + } + + /// Construct a basic_raw_socket on an existing native socket. + /** + * This constructor creates a raw socket object to hold an existing + * native socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_raw_socket(ExecutionContext& context, + const protocol_type& protocol, const native_handle_type& native_socket, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_socket(context, protocol, native_socket) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_raw_socket from another. + /** + * This constructor moves a raw socket from one object to another. + * + * @param other The other basic_raw_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_raw_socket(const executor_type&) + * constructor. + */ + basic_raw_socket(basic_raw_socket&& other) + : basic_socket(std::move(other)) + { + } + + /// Move-assign a basic_raw_socket from another. + /** + * This assignment operator moves a raw socket from one object to another. + * + * @param other The other basic_raw_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_raw_socket(const executor_type&) + * constructor. + */ + basic_raw_socket& operator=(basic_raw_socket&& other) + { + basic_socket::operator=(std::move(other)); + return *this; + } + + /// Move-construct a basic_raw_socket from a socket of another protocol + /// type. + /** + * This constructor moves a raw socket from one object to another. + * + * @param other The other basic_raw_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_raw_socket(const executor_type&) + * constructor. + */ + template + basic_raw_socket(basic_raw_socket&& other, + typename enable_if< + is_convertible::value + && is_convertible::value + >::type* = 0) + : basic_socket(std::move(other)) + { + } + + /// Move-assign a basic_raw_socket from a socket of another protocol type. + /** + * This assignment operator moves a raw socket from one object to another. + * + * @param other The other basic_raw_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_raw_socket(const executor_type&) + * constructor. + */ + template + typename enable_if< + is_convertible::value + && is_convertible::value, + basic_raw_socket& + >::type operator=(basic_raw_socket&& other) + { + basic_socket::operator=(std::move(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the socket. + /** + * This function destroys the socket, cancelling any outstanding asynchronous + * operations associated with the socket as if by calling @c cancel. + */ + ~basic_raw_socket() + { + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an error occurs. + * + * @param buffers One ore more data buffers to be sent on the socket. + * + * @returns The number of bytes sent. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected raw socket. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code socket.send(boost::asio::buffer(data, size)); @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t send(const ConstBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, 0, ec); + boost::asio::detail::throw_error(ec, "send"); + return s; + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an error occurs. + * + * @param buffers One ore more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @returns The number of bytes sent. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected raw socket. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); + boost::asio::detail::throw_error(ec, "send"); + return s; + } + + /// Send some data on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes sent. + * + * @note The send operation can only be used with a connected socket. Use + * the send_to function to send data on an unconnected raw socket. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + return this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); + } + + /// Start an asynchronous send on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. Although + * the buffers object may be copied as necessary, ownership of the underlying + * memory blocks is retained by the caller, which must guarantee that they + * remain valid until the handler is called. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The async_send operation can only be used with a connected socket. + * Use the async_send_to function to send data on an unconnected raw + * socket. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_send(boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_send(const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + return async_initiate( + initiate_async_send(), handler, this, + buffers, socket_base::message_flags(0)); + } + + /// Start an asynchronous send on a connected socket. + /** + * This function is used to send data on the raw socket. The function call + * will block until the data has been sent successfully or an error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. Although + * the buffers object may be copied as necessary, ownership of the underlying + * memory blocks is retained by the caller, which must guarantee that they + * remain valid until the handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The async_send operation can only be used with a connected socket. + * Use the async_send_to function to send data on an unconnected raw + * socket. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + return async_initiate( + initiate_async_send(), handler, this, buffers, flags); + } + + /// Send raw data to the specified endpoint. + /** + * This function is used to send raw data to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @returns The number of bytes sent. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * boost::asio::ip::udp::endpoint destination( + * boost::asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.send_to(boost::asio::buffer(data, size), destination); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().send_to( + this->impl_.get_implementation(), buffers, destination, 0, ec); + boost::asio::detail::throw_error(ec, "send_to"); + return s; + } + + /// Send raw data to the specified endpoint. + /** + * This function is used to send raw data to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @param flags Flags specifying how the send call is to be made. + * + * @returns The number of bytes sent. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().send_to( + this->impl_.get_implementation(), buffers, destination, flags, ec); + boost::asio::detail::throw_error(ec, "send_to"); + return s; + } + + /// Send raw data to the specified endpoint. + /** + * This function is used to send raw data to the specified remote endpoint. + * The function call will block until the data has been sent successfully or + * an error occurs. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * + * @param destination The remote endpoint to which the data will be sent. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes sent. + */ + template + std::size_t send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + boost::system::error_code& ec) + { + return this->impl_.get_service().send_to(this->impl_.get_implementation(), + buffers, destination, flags, ec); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send raw data to the specified + * remote endpoint. The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param destination The remote endpoint to which the data will be sent. + * Copies will be made of the endpoint as required. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * boost::asio::ip::udp::endpoint destination( + * boost::asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.async_send_to( + * boost::asio::buffer(data, size), destination, handler); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + return async_initiate( + initiate_async_send_to(), handler, this, buffers, + destination, socket_base::message_flags(0)); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send raw data to the specified + * remote endpoint. The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent to the remote endpoint. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param destination The remote endpoint to which the data will be sent. + * Copies will be made of the endpoint as required. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + return async_initiate( + initiate_async_send_to(), handler, this, buffers, destination, flags); + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the raw socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected raw + * socket. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code socket.receive(boost::asio::buffer(data, size)); @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive(const MutableBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, 0, ec); + boost::asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the raw socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected raw + * socket. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, flags, ec); + boost::asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the raw socket. The function + * call will block until data has been received successfully or an error + * occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. + * + * @note The receive operation can only be used with a connected socket. Use + * the receive_from function to receive data on an unconnected raw + * socket. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + return this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, flags, ec); + } + + /// Start an asynchronous receive on a connected socket. + /** + * This function is used to asynchronously receive data from the raw + * socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The async_receive operation can only be used with a connected socket. + * Use the async_receive_from function to receive data on an unconnected + * raw socket. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.async_receive(boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + return async_initiate( + initiate_async_receive(), handler, this, + buffers, socket_base::message_flags(0)); + } + + /// Start an asynchronous receive on a connected socket. + /** + * This function is used to asynchronously receive data from the raw + * socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The async_receive operation can only be used with a connected socket. + * Use the async_receive_from function to receive data on an unconnected + * raw socket. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + return async_initiate( + initiate_async_receive(), handler, this, buffers, flags); + } + + /// Receive raw data with the endpoint of the sender. + /** + * This function is used to receive raw data. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * boost::asio::ip::udp::endpoint sender_endpoint; + * socket.receive_from( + * boost::asio::buffer(data, size), sender_endpoint); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().receive_from( + this->impl_.get_implementation(), buffers, sender_endpoint, 0, ec); + boost::asio::detail::throw_error(ec, "receive_from"); + return s; + } + + /// Receive raw data with the endpoint of the sender. + /** + * This function is used to receive raw data. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().receive_from( + this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec); + boost::asio::detail::throw_error(ec, "receive_from"); + return s; + } + + /// Receive raw data with the endpoint of the sender. + /** + * This function is used to receive raw data. The function call will block + * until data has been received successfully or an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. + */ + template + std::size_t receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + boost::system::error_code& ec) + { + return this->impl_.get_service().receive_from( + this->impl_.get_implementation(), buffers, sender_endpoint, flags, ec); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive raw data. The function + * call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. Ownership of the sender_endpoint object + * is retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code socket.async_receive_from( + * boost::asio::buffer(data, size), 0, sender_endpoint, handler); @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + return async_initiate( + initiate_async_receive_from(), handler, this, buffers, + &sender_endpoint, socket_base::message_flags(0)); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive raw data. The function + * call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param sender_endpoint An endpoint object that receives the endpoint of + * the remote sender of the data. Ownership of the sender_endpoint object + * is retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + return async_initiate( + initiate_async_receive_from(), handler, + this, buffers, &sender_endpoint, flags); + } + +private: + struct initiate_async_send + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + basic_raw_socket* self, const ConstBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_send( + self->impl_.get_implementation(), buffers, flags, + handler2.value, self->impl_.get_implementation_executor()); + } + }; + + struct initiate_async_send_to + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + basic_raw_socket* self, const ConstBufferSequence& buffers, + const endpoint_type& destination, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_send_to( + self->impl_.get_implementation(), buffers, destination, flags, + handler2.value, self->impl_.get_implementation_executor()); + } + }; + + struct initiate_async_receive + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + basic_raw_socket* self, const MutableBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_receive( + self->impl_.get_implementation(), buffers, flags, + handler2.value, self->impl_.get_implementation_executor()); + } + }; + + struct initiate_async_receive_from + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + basic_raw_socket* self, const MutableBufferSequence& buffers, + endpoint_type* sender_endpoint, socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_receive_from( + self->impl_.get_implementation(), buffers, *sender_endpoint, flags, + handler2.value, self->impl_.get_implementation_executor()); + } + }; +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BASIC_RAW_SOCKET_HPP diff --git a/boost/asio/basic_seq_packet_socket.hpp b/boost/asio/basic_seq_packet_socket.hpp new file mode 100644 index 0000000..7c3903e --- /dev/null +++ b/boost/asio/basic_seq_packet_socket.hpp @@ -0,0 +1,714 @@ +// +// basic_seq_packet_socket.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BASIC_SEQ_PACKET_SOCKET_HPP +#define BOOST_ASIO_BASIC_SEQ_PACKET_SOCKET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +#if !defined(BOOST_ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL) +#define BOOST_ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL + +// Forward declaration with defaulted arguments. +template +class basic_seq_packet_socket; + +#endif // !defined(BOOST_ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL) + +/// Provides sequenced packet socket functionality. +/** + * The basic_seq_packet_socket class template provides asynchronous and blocking + * sequenced packet socket functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_seq_packet_socket + : public basic_socket +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the socket type to another executor. + template + struct rebind_executor + { + /// The socket type when rebound to the specified executor. + typedef basic_seq_packet_socket other; + }; + + /// The native representation of a socket. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef typename basic_socket::native_handle_type native_handle_type; +#endif + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// Construct a basic_seq_packet_socket without opening it. + /** + * This constructor creates a sequenced packet socket without opening it. The + * socket needs to be opened and then connected or accepted before data can + * be sent or received on it. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + */ + explicit basic_seq_packet_socket(const executor_type& ex) + : basic_socket(ex) + { + } + + /// Construct a basic_seq_packet_socket without opening it. + /** + * This constructor creates a sequenced packet socket without opening it. The + * socket needs to be opened and then connected or accepted before data can + * be sent or received on it. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + */ + template + explicit basic_seq_packet_socket(ExecutionContext& context, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_socket(context) + { + } + + /// Construct and open a basic_seq_packet_socket. + /** + * This constructor creates and opens a sequenced_packet socket. The socket + * needs to be connected or accepted before data can be sent or received on + * it. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_seq_packet_socket(const executor_type& ex, + const protocol_type& protocol) + : basic_socket(ex, protocol) + { + } + + /// Construct and open a basic_seq_packet_socket. + /** + * This constructor creates and opens a sequenced_packet socket. The socket + * needs to be connected or accepted before data can be sent or received on + * it. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_seq_packet_socket(ExecutionContext& context, + const protocol_type& protocol, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_socket(context, protocol) + { + } + + /// Construct a basic_seq_packet_socket, opening it and binding it to the + /// given local endpoint. + /** + * This constructor creates a sequenced packet socket and automatically opens + * it bound to the specified endpoint on the local machine. The protocol used + * is the protocol associated with the given endpoint. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the sequenced + * packet socket will be bound. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_seq_packet_socket(const executor_type& ex, + const endpoint_type& endpoint) + : basic_socket(ex, endpoint) + { + } + + /// Construct a basic_seq_packet_socket, opening it and binding it to the + /// given local endpoint. + /** + * This constructor creates a sequenced packet socket and automatically opens + * it bound to the specified endpoint on the local machine. The protocol used + * is the protocol associated with the given endpoint. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the sequenced + * packet socket will be bound. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_seq_packet_socket(ExecutionContext& context, + const endpoint_type& endpoint, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_socket(context, endpoint) + { + } + + /// Construct a basic_seq_packet_socket on an existing native socket. + /** + * This constructor creates a sequenced packet socket object to hold an + * existing native socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_seq_packet_socket(const executor_type& ex, + const protocol_type& protocol, const native_handle_type& native_socket) + : basic_socket(ex, protocol, native_socket) + { + } + + /// Construct a basic_seq_packet_socket on an existing native socket. + /** + * This constructor creates a sequenced packet socket object to hold an + * existing native socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_seq_packet_socket(ExecutionContext& context, + const protocol_type& protocol, const native_handle_type& native_socket, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_socket(context, protocol, native_socket) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_seq_packet_socket from another. + /** + * This constructor moves a sequenced packet socket from one object to + * another. + * + * @param other The other basic_seq_packet_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_seq_packet_socket(const executor_type&) + * constructor. + */ + basic_seq_packet_socket(basic_seq_packet_socket&& other) + : basic_socket(std::move(other)) + { + } + + /// Move-assign a basic_seq_packet_socket from another. + /** + * This assignment operator moves a sequenced packet socket from one object to + * another. + * + * @param other The other basic_seq_packet_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_seq_packet_socket(const executor_type&) + * constructor. + */ + basic_seq_packet_socket& operator=(basic_seq_packet_socket&& other) + { + basic_socket::operator=(std::move(other)); + return *this; + } + + /// Move-construct a basic_seq_packet_socket from a socket of another protocol + /// type. + /** + * This constructor moves a sequenced packet socket from one object to + * another. + * + * @param other The other basic_seq_packet_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_seq_packet_socket(const executor_type&) + * constructor. + */ + template + basic_seq_packet_socket(basic_seq_packet_socket&& other, + typename enable_if< + is_convertible::value + && is_convertible::value + >::type* = 0) + : basic_socket(std::move(other)) + { + } + + /// Move-assign a basic_seq_packet_socket from a socket of another protocol + /// type. + /** + * This assignment operator moves a sequenced packet socket from one object to + * another. + * + * @param other The other basic_seq_packet_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_seq_packet_socket(const executor_type&) + * constructor. + */ + template + typename enable_if< + is_convertible::value + && is_convertible::value, + basic_seq_packet_socket& + >::type operator=(basic_seq_packet_socket&& other) + { + basic_socket::operator=(std::move(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the socket. + /** + * This function destroys the socket, cancelling any outstanding asynchronous + * operations associated with the socket as if by calling @c cancel. + */ + ~basic_seq_packet_socket() + { + } + + /// Send some data on the socket. + /** + * This function is used to send data on the sequenced packet socket. The + * function call will block until the data has been sent successfully, or an + * until error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @returns The number of bytes sent. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.send(boost::asio::buffer(data, size), 0); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); + boost::asio::detail::throw_error(ec, "send"); + return s; + } + + /// Send some data on the socket. + /** + * This function is used to send data on the sequenced packet socket. The + * function call will block the data has been sent successfully, or an until + * error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes sent. Returns 0 if an error occurred. + * + * @note The send operation may not transmit all of the data to the peer. + * Consider using the @ref write function if you need to ensure that all data + * is written before the blocking operation completes. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + return this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send data on the sequenced packet + * socket. The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent on the socket. Although + * the buffers object may be copied as necessary, ownership of the underlying + * memory blocks is retained by the caller, which must guarantee that they + * remain valid until the handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_send(boost::asio::buffer(data, size), 0, handler); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + return async_initiate( + initiate_async_send(), handler, this, buffers, flags); + } + + /// Receive some data on the socket. + /** + * This function is used to receive data on the sequenced packet socket. The + * function call will block until data has been received successfully, or + * until an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param out_flags After the receive call completes, contains flags + * associated with the received data. For example, if the + * socket_base::message_end_of_record bit is set then the received data marks + * the end of a record. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.receive(boost::asio::buffer(data, size), out_flags); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags& out_flags) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().receive_with_flags( + this->impl_.get_implementation(), buffers, 0, out_flags, ec); + boost::asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on the socket. + /** + * This function is used to receive data on the sequenced packet socket. The + * function call will block until data has been received successfully, or + * until an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param in_flags Flags specifying how the receive call is to be made. + * + * @param out_flags After the receive call completes, contains flags + * associated with the received data. For example, if the + * socket_base::message_end_of_record bit is set then the received data marks + * the end of a record. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The receive operation may not receive all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that the + * requested amount of data is read before the blocking operation completes. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.receive(boost::asio::buffer(data, size), 0, out_flags); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().receive_with_flags( + this->impl_.get_implementation(), buffers, in_flags, out_flags, ec); + boost::asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the sequenced packet socket. The + * function call will block until data has been received successfully, or + * until an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param in_flags Flags specifying how the receive call is to be made. + * + * @param out_flags After the receive call completes, contains flags + * associated with the received data. For example, if the + * socket_base::message_end_of_record bit is set then the received data marks + * the end of a record. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. Returns 0 if an error occurred. + * + * @note The receive operation may not receive all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that the + * requested amount of data is read before the blocking operation completes. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, boost::system::error_code& ec) + { + return this->impl_.get_service().receive_with_flags( + this->impl_.get_implementation(), buffers, in_flags, out_flags, ec); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive data from the sequenced + * packet socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param out_flags Once the asynchronous operation completes, contains flags + * associated with the received data. For example, if the + * socket_base::message_end_of_record bit is set then the received data marks + * the end of a record. The caller must guarantee that the referenced + * variable remains valid until the handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.async_receive(boost::asio::buffer(data, size), out_flags, handler); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + socket_base::message_flags& out_flags, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + return async_initiate( + initiate_async_receive_with_flags(), handler, this, + buffers, socket_base::message_flags(0), &out_flags); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive data from the sequenced + * data socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param in_flags Flags specifying how the receive call is to be made. + * + * @param out_flags Once the asynchronous operation completes, contains flags + * associated with the received data. For example, if the + * socket_base::message_end_of_record bit is set then the received data marks + * the end of a record. The caller must guarantee that the referenced + * variable remains valid until the handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.async_receive( + * boost::asio::buffer(data, size), + * 0, out_flags, handler); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + return async_initiate( + initiate_async_receive_with_flags(), handler, + this, buffers, in_flags, &out_flags); + } + +private: + struct initiate_async_send + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + basic_seq_packet_socket* self, const ConstBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_send( + self->impl_.get_implementation(), buffers, flags, + handler2.value, self->impl_.get_implementation_executor()); + } + }; + + struct initiate_async_receive_with_flags + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + basic_seq_packet_socket* self, const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags* out_flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_receive_with_flags( + self->impl_.get_implementation(), buffers, in_flags, *out_flags, + handler2.value, self->impl_.get_implementation_executor()); + } + }; +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BASIC_SEQ_PACKET_SOCKET_HPP diff --git a/boost/asio/basic_serial_port.hpp b/boost/asio/basic_serial_port.hpp new file mode 100644 index 0000000..55144ee --- /dev/null +++ b/boost/asio/basic_serial_port.hpp @@ -0,0 +1,861 @@ +// +// basic_serial_port.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BASIC_SERIAL_PORT_HPP +#define BOOST_ASIO_BASIC_SERIAL_PORT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ + || defined(GENERATING_DOCUMENTATION) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#else +# include +#endif + +#if defined(BOOST_ASIO_HAS_MOVE) +# include +#endif // defined(BOOST_ASIO_HAS_MOVE) + +#include + +namespace boost { +namespace asio { + +/// Provides serial port functionality. +/** + * The basic_serial_port class provides a wrapper over serial port + * functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_serial_port + : public serial_port_base +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// The native representation of a serial port. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#elif defined(BOOST_ASIO_HAS_IOCP) + typedef detail::win_iocp_serial_port_service::native_handle_type + native_handle_type; +#else + typedef detail::reactive_serial_port_service::native_handle_type + native_handle_type; +#endif + + /// A basic_basic_serial_port is always the lowest layer. + typedef basic_serial_port lowest_layer_type; + + /// Construct a basic_serial_port without opening it. + /** + * This constructor creates a serial port without opening it. + * + * @param ex The I/O executor that the serial port will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * serial port. + */ + explicit basic_serial_port(const executor_type& ex) + : impl_(ex) + { + } + + /// Construct a basic_serial_port without opening it. + /** + * This constructor creates a serial port without opening it. + * + * @param context An execution context which provides the I/O executor that + * the serial port will use, by default, to dispatch handlers for any + * asynchronous operations performed on the serial port. + */ + template + explicit basic_serial_port(ExecutionContext& context, + typename enable_if< + is_convertible::value, + basic_serial_port + >::type* = 0) + : impl_(context) + { + } + + /// Construct and open a basic_serial_port. + /** + * This constructor creates and opens a serial port for the specified device + * name. + * + * @param ex The I/O executor that the serial port will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * serial port. + * + * @param device The platform-specific device name for this serial + * port. + */ + basic_serial_port(const executor_type& ex, const char* device) + : impl_(ex) + { + boost::system::error_code ec; + impl_.get_service().open(impl_.get_implementation(), device, ec); + boost::asio::detail::throw_error(ec, "open"); + } + + /// Construct and open a basic_serial_port. + /** + * This constructor creates and opens a serial port for the specified device + * name. + * + * @param context An execution context which provides the I/O executor that + * the serial port will use, by default, to dispatch handlers for any + * asynchronous operations performed on the serial port. + * + * @param device The platform-specific device name for this serial + * port. + */ + template + basic_serial_port(ExecutionContext& context, const char* device, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + boost::system::error_code ec; + impl_.get_service().open(impl_.get_implementation(), device, ec); + boost::asio::detail::throw_error(ec, "open"); + } + + /// Construct and open a basic_serial_port. + /** + * This constructor creates and opens a serial port for the specified device + * name. + * + * @param ex The I/O executor that the serial port will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * serial port. + * + * @param device The platform-specific device name for this serial + * port. + */ + basic_serial_port(const executor_type& ex, const std::string& device) + : impl_(ex) + { + boost::system::error_code ec; + impl_.get_service().open(impl_.get_implementation(), device, ec); + boost::asio::detail::throw_error(ec, "open"); + } + + /// Construct and open a basic_serial_port. + /** + * This constructor creates and opens a serial port for the specified device + * name. + * + * @param context An execution context which provides the I/O executor that + * the serial port will use, by default, to dispatch handlers for any + * asynchronous operations performed on the serial port. + * + * @param device The platform-specific device name for this serial + * port. + */ + template + basic_serial_port(ExecutionContext& context, const std::string& device, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + boost::system::error_code ec; + impl_.get_service().open(impl_.get_implementation(), device, ec); + boost::asio::detail::throw_error(ec, "open"); + } + + /// Construct a basic_serial_port on an existing native serial port. + /** + * This constructor creates a serial port object to hold an existing native + * serial port. + * + * @param ex The I/O executor that the serial port will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * serial port. + * + * @param native_serial_port A native serial port. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_serial_port(const executor_type& ex, + const native_handle_type& native_serial_port) + : impl_(ex) + { + boost::system::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + native_serial_port, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + + /// Construct a basic_serial_port on an existing native serial port. + /** + * This constructor creates a serial port object to hold an existing native + * serial port. + * + * @param context An execution context which provides the I/O executor that + * the serial port will use, by default, to dispatch handlers for any + * asynchronous operations performed on the serial port. + * + * @param native_serial_port A native serial port. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_serial_port(ExecutionContext& context, + const native_handle_type& native_serial_port, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + boost::system::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + native_serial_port, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_serial_port from another. + /** + * This constructor moves a serial port from one object to another. + * + * @param other The other basic_serial_port object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_serial_port(const executor_type&) + * constructor. + */ + basic_serial_port(basic_serial_port&& other) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_serial_port from another. + /** + * This assignment operator moves a serial port from one object to another. + * + * @param other The other basic_serial_port object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_serial_port(const executor_type&) + * constructor. + */ + basic_serial_port& operator=(basic_serial_port&& other) + { + impl_ = std::move(other.impl_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the serial port. + /** + * This function destroys the serial port, cancelling any outstanding + * asynchronous wait operations associated with the serial port as if by + * calling @c cancel. + */ + ~basic_serial_port() + { + } + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return impl_.get_executor(); + } + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * layers. Since a basic_serial_port cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A reference to the lowest layer in the stack of layers. Ownership + * is not transferred to the caller. + */ + lowest_layer_type& lowest_layer() + { + return *this; + } + + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since a basic_serial_port cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } + + /// Open the serial port using the specified device name. + /** + * This function opens the serial port for the specified device name. + * + * @param device The platform-specific device name. + * + * @throws boost::system::system_error Thrown on failure. + */ + void open(const std::string& device) + { + boost::system::error_code ec; + impl_.get_service().open(impl_.get_implementation(), device, ec); + boost::asio::detail::throw_error(ec, "open"); + } + + /// Open the serial port using the specified device name. + /** + * This function opens the serial port using the given platform-specific + * device name. + * + * @param device The platform-specific device name. + * + * @param ec Set the indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID open(const std::string& device, + boost::system::error_code& ec) + { + impl_.get_service().open(impl_.get_implementation(), device, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Assign an existing native serial port to the serial port. + /* + * This function opens the serial port to hold an existing native serial port. + * + * @param native_serial_port A native serial port. + * + * @throws boost::system::system_error Thrown on failure. + */ + void assign(const native_handle_type& native_serial_port) + { + boost::system::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + native_serial_port, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + + /// Assign an existing native serial port to the serial port. + /* + * This function opens the serial port to hold an existing native serial port. + * + * @param native_serial_port A native serial port. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& native_serial_port, + boost::system::error_code& ec) + { + impl_.get_service().assign(impl_.get_implementation(), + native_serial_port, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the serial port is open. + bool is_open() const + { + return impl_.get_service().is_open(impl_.get_implementation()); + } + + /// Close the serial port. + /** + * This function is used to close the serial port. Any asynchronous read or + * write operations will be cancelled immediately, and will complete with the + * boost::asio::error::operation_aborted error. + * + * @throws boost::system::system_error Thrown on failure. + */ + void close() + { + boost::system::error_code ec; + impl_.get_service().close(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "close"); + } + + /// Close the serial port. + /** + * This function is used to close the serial port. Any asynchronous read or + * write operations will be cancelled immediately, and will complete with the + * boost::asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) + { + impl_.get_service().close(impl_.get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get the native serial port representation. + /** + * This function may be used to obtain the underlying representation of the + * serial port. This is intended to allow access to native serial port + * functionality that is not otherwise provided. + */ + native_handle_type native_handle() + { + return impl_.get_service().native_handle(impl_.get_implementation()); + } + + /// Cancel all asynchronous operations associated with the serial port. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. + * + * @throws boost::system::system_error Thrown on failure. + */ + void cancel() + { + boost::system::error_code ec; + impl_.get_service().cancel(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the serial port. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) + { + impl_.get_service().cancel(impl_.get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Send a break sequence to the serial port. + /** + * This function causes a break sequence of platform-specific duration to be + * sent out the serial port. + * + * @throws boost::system::system_error Thrown on failure. + */ + void send_break() + { + boost::system::error_code ec; + impl_.get_service().send_break(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "send_break"); + } + + /// Send a break sequence to the serial port. + /** + * This function causes a break sequence of platform-specific duration to be + * sent out the serial port. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID send_break(boost::system::error_code& ec) + { + impl_.get_service().send_break(impl_.get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Set an option on the serial port. + /** + * This function is used to set an option on the serial port. + * + * @param option The option value to be set on the serial port. + * + * @throws boost::system::system_error Thrown on failure. + * + * @sa SettableSerialPortOption @n + * boost::asio::serial_port_base::baud_rate @n + * boost::asio::serial_port_base::flow_control @n + * boost::asio::serial_port_base::parity @n + * boost::asio::serial_port_base::stop_bits @n + * boost::asio::serial_port_base::character_size + */ + template + void set_option(const SettableSerialPortOption& option) + { + boost::system::error_code ec; + impl_.get_service().set_option(impl_.get_implementation(), option, ec); + boost::asio::detail::throw_error(ec, "set_option"); + } + + /// Set an option on the serial port. + /** + * This function is used to set an option on the serial port. + * + * @param option The option value to be set on the serial port. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa SettableSerialPortOption @n + * boost::asio::serial_port_base::baud_rate @n + * boost::asio::serial_port_base::flow_control @n + * boost::asio::serial_port_base::parity @n + * boost::asio::serial_port_base::stop_bits @n + * boost::asio::serial_port_base::character_size + */ + template + BOOST_ASIO_SYNC_OP_VOID set_option(const SettableSerialPortOption& option, + boost::system::error_code& ec) + { + impl_.get_service().set_option(impl_.get_implementation(), option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get an option from the serial port. + /** + * This function is used to get the current value of an option on the serial + * port. + * + * @param option The option value to be obtained from the serial port. + * + * @throws boost::system::system_error Thrown on failure. + * + * @sa GettableSerialPortOption @n + * boost::asio::serial_port_base::baud_rate @n + * boost::asio::serial_port_base::flow_control @n + * boost::asio::serial_port_base::parity @n + * boost::asio::serial_port_base::stop_bits @n + * boost::asio::serial_port_base::character_size + */ + template + void get_option(GettableSerialPortOption& option) const + { + boost::system::error_code ec; + impl_.get_service().get_option(impl_.get_implementation(), option, ec); + boost::asio::detail::throw_error(ec, "get_option"); + } + + /// Get an option from the serial port. + /** + * This function is used to get the current value of an option on the serial + * port. + * + * @param option The option value to be obtained from the serial port. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa GettableSerialPortOption @n + * boost::asio::serial_port_base::baud_rate @n + * boost::asio::serial_port_base::flow_control @n + * boost::asio::serial_port_base::parity @n + * boost::asio::serial_port_base::stop_bits @n + * boost::asio::serial_port_base::character_size + */ + template + BOOST_ASIO_SYNC_OP_VOID get_option(GettableSerialPortOption& option, + boost::system::error_code& ec) const + { + impl_.get_service().get_option(impl_.get_implementation(), option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Write some data to the serial port. + /** + * This function is used to write data to the serial port. The function call + * will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the serial port. + * + * @returns The number of bytes written. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * basic_serial_port.write_some(boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t write_some(const ConstBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = impl_.get_service().write_some( + impl_.get_implementation(), buffers, ec); + boost::asio::detail::throw_error(ec, "write_some"); + return s; + } + + /// Write some data to the serial port. + /** + * This function is used to write data to the serial port. The function call + * will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the serial port. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. Returns 0 if an error occurred. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + */ + template + std::size_t write_some(const ConstBufferSequence& buffers, + boost::system::error_code& ec) + { + return impl_.get_service().write_some( + impl_.get_implementation(), buffers, ec); + } + + /// Start an asynchronous write. + /** + * This function is used to asynchronously write data to the serial port. + * The function call always returns immediately. + * + * @param buffers One or more data buffers to be written to the serial port. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes written. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The write operation may not transmit all of the data to the peer. + * Consider using the @ref async_write function if you need to ensure that all + * data is written before the asynchronous operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * basic_serial_port.async_write_some( + * boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_write_some(const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + return async_initiate( + initiate_async_write_some(), handler, this, buffers); + } + + /// Read some data from the serial port. + /** + * This function is used to read data from the serial port. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @returns The number of bytes read. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * basic_serial_port.read_some(boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t read_some(const MutableBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = impl_.get_service().read_some( + impl_.get_implementation(), buffers, ec); + boost::asio::detail::throw_error(ec, "read_some"); + return s; + } + + /// Read some data from the serial port. + /** + * This function is used to read data from the serial port. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. Returns 0 if an error occurred. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + */ + template + std::size_t read_some(const MutableBufferSequence& buffers, + boost::system::error_code& ec) + { + return impl_.get_service().read_some( + impl_.get_implementation(), buffers, ec); + } + + /// Start an asynchronous read. + /** + * This function is used to asynchronously read data from the serial port. + * The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes read. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The read operation may not read all of the requested number of bytes. + * Consider using the @ref async_read function if you need to ensure that the + * requested amount of data is read before the asynchronous operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * basic_serial_port.async_read_some( + * boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_read_some(const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + return async_initiate( + initiate_async_read_some(), handler, this, buffers); + } + +private: + // Disallow copying and assignment. + basic_serial_port(const basic_serial_port&) BOOST_ASIO_DELETED; + basic_serial_port& operator=(const basic_serial_port&) BOOST_ASIO_DELETED; + + struct initiate_async_write_some + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + basic_serial_port* self, const ConstBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_write_some( + self->impl_.get_implementation(), buffers, handler2.value, + self->impl_.get_implementation_executor()); + } + }; + + struct initiate_async_read_some + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + basic_serial_port* self, const MutableBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_read_some( + self->impl_.get_implementation(), buffers, handler2.value, + self->impl_.get_implementation_executor()); + } + }; + +#if defined(BOOST_ASIO_HAS_IOCP) + detail::io_object_impl impl_; +#else + detail::io_object_impl impl_; +#endif +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_BASIC_SERIAL_PORT_HPP diff --git a/boost/asio/basic_signal_set.hpp b/boost/asio/basic_signal_set.hpp new file mode 100644 index 0000000..175b4f4 --- /dev/null +++ b/boost/asio/basic_signal_set.hpp @@ -0,0 +1,543 @@ +// +// basic_signal_set.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BASIC_SIGNAL_SET_HPP +#define BOOST_ASIO_BASIC_SIGNAL_SET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace asio { + +/// Provides signal functionality. +/** + * The basic_signal_set class provides the ability to perform an asynchronous + * wait for one or more signals to occur. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Example + * Performing an asynchronous wait: + * @code + * void handler( + * const boost::system::error_code& error, + * int signal_number) + * { + * if (!error) + * { + * // A signal occurred. + * } + * } + * + * ... + * + * // Construct a signal set registered for process termination. + * boost::asio::signal_set signals(my_context, SIGINT, SIGTERM); + * + * // Start an asynchronous wait for one of the signals to occur. + * signals.async_wait(handler); + * @endcode + * + * @par Queueing of signal notifications + * + * If a signal is registered with a signal_set, and the signal occurs when + * there are no waiting handlers, then the signal notification is queued. The + * next async_wait operation on that signal_set will dequeue the notification. + * If multiple notifications are queued, subsequent async_wait operations + * dequeue them one at a time. Signal notifications are dequeued in order of + * ascending signal number. + * + * If a signal number is removed from a signal_set (using the @c remove or @c + * erase member functions) then any queued notifications for that signal are + * discarded. + * + * @par Multiple registration of signals + * + * The same signal number may be registered with different signal_set objects. + * When the signal occurs, one handler is called for each signal_set object. + * + * Note that multiple registration only works for signals that are registered + * using Asio. The application must not also register a signal handler using + * functions such as @c signal() or @c sigaction(). + * + * @par Signal masking on POSIX platforms + * + * POSIX allows signals to be blocked using functions such as @c sigprocmask() + * and @c pthread_sigmask(). For signals to be delivered, programs must ensure + * that any signals registered using signal_set objects are unblocked in at + * least one thread. + */ +template +class basic_signal_set +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Construct a signal set without adding any signals. + /** + * This constructor creates a signal set without registering for any signals. + * + * @param ex The I/O executor that the signal set will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * signal set. + */ + explicit basic_signal_set(const executor_type& ex) + : impl_(ex) + { + } + + /// Construct a signal set without adding any signals. + /** + * This constructor creates a signal set without registering for any signals. + * + * @param context An execution context which provides the I/O executor that + * the signal set will use, by default, to dispatch handlers for any + * asynchronous operations performed on the signal set. + */ + template + explicit basic_signal_set(ExecutionContext& context, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + } + + /// Construct a signal set and add one signal. + /** + * This constructor creates a signal set and registers for one signal. + * + * @param ex The I/O executor that the signal set will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * signal set. + * + * @param signal_number_1 The signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code boost::asio::signal_set signals(ex); + * signals.add(signal_number_1); @endcode + */ + basic_signal_set(const executor_type& ex, int signal_number_1) + : impl_(ex) + { + boost::system::error_code ec; + impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); + boost::asio::detail::throw_error(ec, "add"); + } + + /// Construct a signal set and add one signal. + /** + * This constructor creates a signal set and registers for one signal. + * + * @param context An execution context which provides the I/O executor that + * the signal set will use, by default, to dispatch handlers for any + * asynchronous operations performed on the signal set. + * + * @param signal_number_1 The signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code boost::asio::signal_set signals(context); + * signals.add(signal_number_1); @endcode + */ + template + basic_signal_set(ExecutionContext& context, int signal_number_1, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + boost::system::error_code ec; + impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); + boost::asio::detail::throw_error(ec, "add"); + } + + /// Construct a signal set and add two signals. + /** + * This constructor creates a signal set and registers for two signals. + * + * @param ex The I/O executor that the signal set will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * signal set. + * + * @param signal_number_1 The first signal number to be added. + * + * @param signal_number_2 The second signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code boost::asio::signal_set signals(ex); + * signals.add(signal_number_1); + * signals.add(signal_number_2); @endcode + */ + basic_signal_set(const executor_type& ex, int signal_number_1, + int signal_number_2) + : impl_(ex) + { + boost::system::error_code ec; + impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); + boost::asio::detail::throw_error(ec, "add"); + impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec); + boost::asio::detail::throw_error(ec, "add"); + } + + /// Construct a signal set and add two signals. + /** + * This constructor creates a signal set and registers for two signals. + * + * @param context An execution context which provides the I/O executor that + * the signal set will use, by default, to dispatch handlers for any + * asynchronous operations performed on the signal set. + * + * @param signal_number_1 The first signal number to be added. + * + * @param signal_number_2 The second signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code boost::asio::signal_set signals(context); + * signals.add(signal_number_1); + * signals.add(signal_number_2); @endcode + */ + template + basic_signal_set(ExecutionContext& context, int signal_number_1, + int signal_number_2, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + boost::system::error_code ec; + impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); + boost::asio::detail::throw_error(ec, "add"); + impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec); + boost::asio::detail::throw_error(ec, "add"); + } + + /// Construct a signal set and add three signals. + /** + * This constructor creates a signal set and registers for three signals. + * + * @param ex The I/O executor that the signal set will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * signal set. + * + * @param signal_number_1 The first signal number to be added. + * + * @param signal_number_2 The second signal number to be added. + * + * @param signal_number_3 The third signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code boost::asio::signal_set signals(ex); + * signals.add(signal_number_1); + * signals.add(signal_number_2); + * signals.add(signal_number_3); @endcode + */ + basic_signal_set(const executor_type& ex, int signal_number_1, + int signal_number_2, int signal_number_3) + : impl_(ex) + { + boost::system::error_code ec; + impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); + boost::asio::detail::throw_error(ec, "add"); + impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec); + boost::asio::detail::throw_error(ec, "add"); + impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec); + boost::asio::detail::throw_error(ec, "add"); + } + + /// Construct a signal set and add three signals. + /** + * This constructor creates a signal set and registers for three signals. + * + * @param context An execution context which provides the I/O executor that + * the signal set will use, by default, to dispatch handlers for any + * asynchronous operations performed on the signal set. + * + * @param signal_number_1 The first signal number to be added. + * + * @param signal_number_2 The second signal number to be added. + * + * @param signal_number_3 The third signal number to be added. + * + * @note This constructor is equivalent to performing: + * @code boost::asio::signal_set signals(context); + * signals.add(signal_number_1); + * signals.add(signal_number_2); + * signals.add(signal_number_3); @endcode + */ + template + basic_signal_set(ExecutionContext& context, int signal_number_1, + int signal_number_2, int signal_number_3, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + boost::system::error_code ec; + impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec); + boost::asio::detail::throw_error(ec, "add"); + impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec); + boost::asio::detail::throw_error(ec, "add"); + impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec); + boost::asio::detail::throw_error(ec, "add"); + } + + /// Destroys the signal set. + /** + * This function destroys the signal set, cancelling any outstanding + * asynchronous wait operations associated with the signal set as if by + * calling @c cancel. + */ + ~basic_signal_set() + { + } + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return impl_.get_executor(); + } + + /// Add a signal to a signal_set. + /** + * This function adds the specified signal to the set. It has no effect if the + * signal is already in the set. + * + * @param signal_number The signal to be added to the set. + * + * @throws boost::system::system_error Thrown on failure. + */ + void add(int signal_number) + { + boost::system::error_code ec; + impl_.get_service().add(impl_.get_implementation(), signal_number, ec); + boost::asio::detail::throw_error(ec, "add"); + } + + /// Add a signal to a signal_set. + /** + * This function adds the specified signal to the set. It has no effect if the + * signal is already in the set. + * + * @param signal_number The signal to be added to the set. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID add(int signal_number, + boost::system::error_code& ec) + { + impl_.get_service().add(impl_.get_implementation(), signal_number, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Remove a signal from a signal_set. + /** + * This function removes the specified signal from the set. It has no effect + * if the signal is not in the set. + * + * @param signal_number The signal to be removed from the set. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note Removes any notifications that have been queued for the specified + * signal number. + */ + void remove(int signal_number) + { + boost::system::error_code ec; + impl_.get_service().remove(impl_.get_implementation(), signal_number, ec); + boost::asio::detail::throw_error(ec, "remove"); + } + + /// Remove a signal from a signal_set. + /** + * This function removes the specified signal from the set. It has no effect + * if the signal is not in the set. + * + * @param signal_number The signal to be removed from the set. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Removes any notifications that have been queued for the specified + * signal number. + */ + BOOST_ASIO_SYNC_OP_VOID remove(int signal_number, + boost::system::error_code& ec) + { + impl_.get_service().remove(impl_.get_implementation(), signal_number, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Remove all signals from a signal_set. + /** + * This function removes all signals from the set. It has no effect if the set + * is already empty. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note Removes all queued notifications. + */ + void clear() + { + boost::system::error_code ec; + impl_.get_service().clear(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "clear"); + } + + /// Remove all signals from a signal_set. + /** + * This function removes all signals from the set. It has no effect if the set + * is already empty. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Removes all queued notifications. + */ + BOOST_ASIO_SYNC_OP_VOID clear(boost::system::error_code& ec) + { + impl_.get_service().clear(impl_.get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Cancel all operations associated with the signal set. + /** + * This function forces the completion of any pending asynchronous wait + * operations against the signal set. The handler for each cancelled + * operation will be invoked with the boost::asio::error::operation_aborted + * error code. + * + * Cancellation does not alter the set of registered signals. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note If a registered signal occurred before cancel() is called, then the + * handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + void cancel() + { + boost::system::error_code ec; + impl_.get_service().cancel(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all operations associated with the signal set. + /** + * This function forces the completion of any pending asynchronous wait + * operations against the signal set. The handler for each cancelled + * operation will be invoked with the boost::asio::error::operation_aborted + * error code. + * + * Cancellation does not alter the set of registered signals. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note If a registered signal occurred before cancel() is called, then the + * handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) + { + impl_.get_service().cancel(impl_.get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Start an asynchronous operation to wait for a signal to be delivered. + /** + * This function may be used to initiate an asynchronous wait against the + * signal set. It always returns immediately. + * + * For each call to async_wait(), the supplied handler will be called exactly + * once. The handler will be called when: + * + * @li One of the registered signals in the signal set occurs; or + * + * @li The signal set was cancelled, in which case the handler is passed the + * error code boost::asio::error::operation_aborted. + * + * @param handler The handler to be called when the signal occurs. Copies + * will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * int signal_number // Indicates which signal occurred. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(SignalHandler, + void (boost::system::error_code, int)) + async_wait(BOOST_ASIO_MOVE_ARG(SignalHandler) handler) + { + return async_initiate( + initiate_async_wait(), handler, this); + } + +private: + // Disallow copying and assignment. + basic_signal_set(const basic_signal_set&) BOOST_ASIO_DELETED; + basic_signal_set& operator=(const basic_signal_set&) BOOST_ASIO_DELETED; + + struct initiate_async_wait + { + template + void operator()(BOOST_ASIO_MOVE_ARG(SignalHandler) handler, + basic_signal_set* self) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a SignalHandler. + BOOST_ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_wait( + self->impl_.get_implementation(), handler2.value, + self->impl_.get_implementation_executor()); + } + }; + + detail::io_object_impl impl_; +}; + +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_BASIC_SIGNAL_SET_HPP diff --git a/boost/asio/basic_socket.hpp b/boost/asio/basic_socket.hpp new file mode 100644 index 0000000..4f15f58 --- /dev/null +++ b/boost/asio/basic_socket.hpp @@ -0,0 +1,1858 @@ +// +// basic_socket.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BASIC_SOCKET_HPP +#define BOOST_ASIO_BASIC_SOCKET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +# include +#elif defined(BOOST_ASIO_HAS_IOCP) +# include +#else +# include +#endif + +#if defined(BOOST_ASIO_HAS_MOVE) +# include +#endif // defined(BOOST_ASIO_HAS_MOVE) + +#include + +namespace boost { +namespace asio { + +#if !defined(BOOST_ASIO_BASIC_SOCKET_FWD_DECL) +#define BOOST_ASIO_BASIC_SOCKET_FWD_DECL + +// Forward declaration with defaulted arguments. +template +class basic_socket; + +#endif // !defined(BOOST_ASIO_BASIC_SOCKET_FWD_DECL) + +/// Provides socket functionality. +/** + * The basic_socket class template provides functionality that is common to both + * stream-oriented and datagram-oriented sockets. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_socket + : public socket_base +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the socket type to another executor. + template + struct rebind_executor + { + /// The socket type when rebound to the specified executor. + typedef basic_socket other; + }; + + /// The native representation of a socket. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#elif defined(BOOST_ASIO_WINDOWS_RUNTIME) + typedef typename detail::null_socket_service< + Protocol>::native_handle_type native_handle_type; +#elif defined(BOOST_ASIO_HAS_IOCP) + typedef typename detail::win_iocp_socket_service< + Protocol>::native_handle_type native_handle_type; +#else + typedef typename detail::reactive_socket_service< + Protocol>::native_handle_type native_handle_type; +#endif + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) + /// A basic_socket is always the lowest layer. + typedef basic_socket lowest_layer_type; +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + + /// Construct a basic_socket without opening it. + /** + * This constructor creates a socket without opening it. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + */ + explicit basic_socket(const executor_type& ex) + : impl_(ex) + { + } + + /// Construct a basic_socket without opening it. + /** + * This constructor creates a socket without opening it. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + */ + template + explicit basic_socket(ExecutionContext& context, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + } + + /// Construct and open a basic_socket. + /** + * This constructor creates and opens a socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_socket(const executor_type& ex, const protocol_type& protocol) + : impl_(ex) + { + boost::system::error_code ec; + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + boost::asio::detail::throw_error(ec, "open"); + } + + /// Construct and open a basic_socket. + /** + * This constructor creates and opens a socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_socket(ExecutionContext& context, const protocol_type& protocol, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + boost::system::error_code ec; + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + boost::asio::detail::throw_error(ec, "open"); + } + + /// Construct a basic_socket, opening it and binding it to the given local + /// endpoint. + /** + * This constructor creates a socket and automatically opens it bound to the + * specified endpoint on the local machine. The protocol used is the protocol + * associated with the given endpoint. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the socket will + * be bound. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_socket(const executor_type& ex, const endpoint_type& endpoint) + : impl_(ex) + { + boost::system::error_code ec; + const protocol_type protocol = endpoint.protocol(); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + boost::asio::detail::throw_error(ec, "open"); + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); + boost::asio::detail::throw_error(ec, "bind"); + } + + /// Construct a basic_socket, opening it and binding it to the given local + /// endpoint. + /** + * This constructor creates a socket and automatically opens it bound to the + * specified endpoint on the local machine. The protocol used is the protocol + * associated with the given endpoint. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the socket will + * be bound. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_socket(ExecutionContext& context, const endpoint_type& endpoint, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + boost::system::error_code ec; + const protocol_type protocol = endpoint.protocol(); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + boost::asio::detail::throw_error(ec, "open"); + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); + boost::asio::detail::throw_error(ec, "bind"); + } + + /// Construct a basic_socket on an existing native socket. + /** + * This constructor creates a socket object to hold an existing native socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket A native socket. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_socket(const executor_type& ex, const protocol_type& protocol, + const native_handle_type& native_socket) + : impl_(ex) + { + boost::system::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + protocol, native_socket, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + + /// Construct a basic_socket on an existing native socket. + /** + * This constructor creates a socket object to hold an existing native socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket A native socket. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_socket(ExecutionContext& context, const protocol_type& protocol, + const native_handle_type& native_socket, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + boost::system::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + protocol, native_socket, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_socket from another. + /** + * This constructor moves a socket from one object to another. + * + * @param other The other basic_socket object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket(const executor_type&) constructor. + */ + basic_socket(basic_socket&& other) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_socket from another. + /** + * This assignment operator moves a socket from one object to another. + * + * @param other The other basic_socket object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket(const executor_type&) constructor. + */ + basic_socket& operator=(basic_socket&& other) + { + impl_ = std::move(other.impl_); + return *this; + } + + // All sockets have access to each other's implementations. + template + friend class basic_socket; + + /// Move-construct a basic_socket from a socket of another protocol type. + /** + * This constructor moves a socket from one object to another. + * + * @param other The other basic_socket object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket(const executor_type&) constructor. + */ + template + basic_socket(basic_socket&& other, + typename enable_if< + is_convertible::value + && is_convertible::value + >::type* = 0) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_socket from a socket of another protocol type. + /** + * This assignment operator moves a socket from one object to another. + * + * @param other The other basic_socket object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket(const executor_type&) constructor. + */ + template + typename enable_if< + is_convertible::value + && is_convertible::value, + basic_socket& + >::type operator=(basic_socket && other) + { + basic_socket tmp(std::move(other)); + impl_ = std::move(tmp.impl_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return impl_.get_executor(); + } + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * layers. Since a basic_socket cannot contain any further layers, it simply + * returns a reference to itself. + * + * @return A reference to the lowest layer in the stack of layers. Ownership + * is not transferred to the caller. + */ + lowest_layer_type& lowest_layer() + { + return *this; + } + + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since a basic_socket cannot contain any further layers, it simply + * returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + + /// Open the socket using the specified protocol. + /** + * This function opens the socket so that it will use the specified protocol. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * socket.open(boost::asio::ip::tcp::v4()); + * @endcode + */ + void open(const protocol_type& protocol = protocol_type()) + { + boost::system::error_code ec; + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + boost::asio::detail::throw_error(ec, "open"); + } + + /// Open the socket using the specified protocol. + /** + * This function opens the socket so that it will use the specified protocol. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * boost::system::error_code ec; + * socket.open(boost::asio::ip::tcp::v4(), ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + BOOST_ASIO_SYNC_OP_VOID open(const protocol_type& protocol, + boost::system::error_code& ec) + { + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Assign an existing native socket to the socket. + /* + * This function opens the socket to hold an existing native socket. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param native_socket A native socket. + * + * @throws boost::system::system_error Thrown on failure. + */ + void assign(const protocol_type& protocol, + const native_handle_type& native_socket) + { + boost::system::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + protocol, native_socket, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + + /// Assign an existing native socket to the socket. + /* + * This function opens the socket to hold an existing native socket. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param native_socket A native socket. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID assign(const protocol_type& protocol, + const native_handle_type& native_socket, boost::system::error_code& ec) + { + impl_.get_service().assign(impl_.get_implementation(), + protocol, native_socket, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the socket is open. + bool is_open() const + { + return impl_.get_service().is_open(impl_.get_implementation()); + } + + /// Close the socket. + /** + * This function is used to close the socket. Any asynchronous send, receive + * or connect operations will be cancelled immediately, and will complete + * with the boost::asio::error::operation_aborted error. + * + * @throws boost::system::system_error Thrown on failure. Note that, even if + * the function indicates an error, the underlying descriptor is closed. + * + * @note For portable behaviour with respect to graceful closure of a + * connected socket, call shutdown() before closing the socket. + */ + void close() + { + boost::system::error_code ec; + impl_.get_service().close(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "close"); + } + + /// Close the socket. + /** + * This function is used to close the socket. Any asynchronous send, receive + * or connect operations will be cancelled immediately, and will complete + * with the boost::asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. Note that, even if + * the function indicates an error, the underlying descriptor is closed. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::system::error_code ec; + * socket.close(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + * + * @note For portable behaviour with respect to graceful closure of a + * connected socket, call shutdown() before closing the socket. + */ + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) + { + impl_.get_service().close(impl_.get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Release ownership of the underlying native socket. + /** + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the boost::asio::error::operation_aborted error. Ownership + * of the native socket is then transferred to the caller. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with boost::asio::error::operation_not_supported on + * these platforms. + */ +#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release() + { + boost::system::error_code ec; + native_handle_type s = impl_.get_service().release( + impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "release"); + return s; + } + + /// Release ownership of the underlying native socket. + /** + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the boost::asio::error::operation_aborted error. Ownership + * of the native socket is then transferred to the caller. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with boost::asio::error::operation_not_supported on + * these platforms. + */ +#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release(boost::system::error_code& ec) + { + return impl_.get_service().release(impl_.get_implementation(), ec); + } + + /// Get the native socket representation. + /** + * This function may be used to obtain the underlying representation of the + * socket. This is intended to allow access to native socket functionality + * that is not otherwise provided. + */ + native_handle_type native_handle() + { + return impl_.get_service().native_handle(impl_.get_implementation()); + } + + /// Cancel all asynchronous operations associated with the socket. + /** + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the boost::asio::error::operation_aborted error. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note Calls to cancel() will always fail with + * boost::asio::error::operation_not_supported when run on Windows XP, Windows + * Server 2003, and earlier versions of Windows, unless + * BOOST_ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has + * two issues that should be considered before enabling its use: + * + * @li It will only cancel asynchronous operations that were initiated in the + * current thread. + * + * @li It can appear to complete without error, but the request to cancel the + * unfinished operations may be silently ignored by the operating system. + * Whether it works or not seems to depend on the drivers that are installed. + * + * For portable cancellation, consider using one of the following + * alternatives: + * + * @li Disable asio's I/O completion port backend by defining + * BOOST_ASIO_DISABLE_IOCP. + * + * @li Use the close() function to simultaneously cancel the outstanding + * operations and close the socket. + * + * When running on Windows Vista, Windows Server 2008, and later, the + * CancelIoEx function is always used. This function does not have the + * problems described above. + */ +#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \ + && !defined(BOOST_ASIO_ENABLE_CANCELIO) + __declspec(deprecated("By default, this function always fails with " + "operation_not_supported when used on Windows XP, Windows Server 2003, " + "or earlier. Consult documentation for details.")) +#endif + void cancel() + { + boost::system::error_code ec; + impl_.get_service().cancel(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the socket. + /** + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the boost::asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note Calls to cancel() will always fail with + * boost::asio::error::operation_not_supported when run on Windows XP, Windows + * Server 2003, and earlier versions of Windows, unless + * BOOST_ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has + * two issues that should be considered before enabling its use: + * + * @li It will only cancel asynchronous operations that were initiated in the + * current thread. + * + * @li It can appear to complete without error, but the request to cancel the + * unfinished operations may be silently ignored by the operating system. + * Whether it works or not seems to depend on the drivers that are installed. + * + * For portable cancellation, consider using one of the following + * alternatives: + * + * @li Disable asio's I/O completion port backend by defining + * BOOST_ASIO_DISABLE_IOCP. + * + * @li Use the close() function to simultaneously cancel the outstanding + * operations and close the socket. + * + * When running on Windows Vista, Windows Server 2008, and later, the + * CancelIoEx function is always used. This function does not have the + * problems described above. + */ +#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \ + && !defined(BOOST_ASIO_ENABLE_CANCELIO) + __declspec(deprecated("By default, this function always fails with " + "operation_not_supported when used on Windows XP, Windows Server 2003, " + "or earlier. Consult documentation for details.")) +#endif + BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) + { + impl_.get_service().cancel(impl_.get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the socket is at the out-of-band data mark. + /** + * This function is used to check whether the socket input is currently + * positioned at the out-of-band data mark. + * + * @return A bool indicating whether the socket is at the out-of-band data + * mark. + * + * @throws boost::system::system_error Thrown on failure. + */ + bool at_mark() const + { + boost::system::error_code ec; + bool b = impl_.get_service().at_mark(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "at_mark"); + return b; + } + + /// Determine whether the socket is at the out-of-band data mark. + /** + * This function is used to check whether the socket input is currently + * positioned at the out-of-band data mark. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return A bool indicating whether the socket is at the out-of-band data + * mark. + */ + bool at_mark(boost::system::error_code& ec) const + { + return impl_.get_service().at_mark(impl_.get_implementation(), ec); + } + + /// Determine the number of bytes available for reading. + /** + * This function is used to determine the number of bytes that may be read + * without blocking. + * + * @return The number of bytes that may be read without blocking, or 0 if an + * error occurs. + * + * @throws boost::system::system_error Thrown on failure. + */ + std::size_t available() const + { + boost::system::error_code ec; + std::size_t s = impl_.get_service().available( + impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "available"); + return s; + } + + /// Determine the number of bytes available for reading. + /** + * This function is used to determine the number of bytes that may be read + * without blocking. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of bytes that may be read without blocking, or 0 if an + * error occurs. + */ + std::size_t available(boost::system::error_code& ec) const + { + return impl_.get_service().available(impl_.get_implementation(), ec); + } + + /// Bind the socket to the given local endpoint. + /** + * This function binds the socket to the specified endpoint on the local + * machine. + * + * @param endpoint An endpoint on the local machine to which the socket will + * be bound. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * socket.open(boost::asio::ip::tcp::v4()); + * socket.bind(boost::asio::ip::tcp::endpoint( + * boost::asio::ip::tcp::v4(), 12345)); + * @endcode + */ + void bind(const endpoint_type& endpoint) + { + boost::system::error_code ec; + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); + boost::asio::detail::throw_error(ec, "bind"); + } + + /// Bind the socket to the given local endpoint. + /** + * This function binds the socket to the specified endpoint on the local + * machine. + * + * @param endpoint An endpoint on the local machine to which the socket will + * be bound. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * socket.open(boost::asio::ip::tcp::v4()); + * boost::system::error_code ec; + * socket.bind(boost::asio::ip::tcp::endpoint( + * boost::asio::ip::tcp::v4(), 12345), ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + BOOST_ASIO_SYNC_OP_VOID bind(const endpoint_type& endpoint, + boost::system::error_code& ec) + { + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Connect the socket to the specified endpoint. + /** + * This function is used to connect a socket to the specified remote endpoint. + * The function call will block until the connection is successfully made or + * an error occurs. + * + * The socket is automatically opened if it is not already open. If the + * connect fails, and the socket was automatically opened, the socket is + * not returned to the closed state. + * + * @param peer_endpoint The remote endpoint to which the socket will be + * connected. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * boost::asio::ip::tcp::endpoint endpoint( + * boost::asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.connect(endpoint); + * @endcode + */ + void connect(const endpoint_type& peer_endpoint) + { + boost::system::error_code ec; + if (!is_open()) + { + impl_.get_service().open(impl_.get_implementation(), + peer_endpoint.protocol(), ec); + boost::asio::detail::throw_error(ec, "connect"); + } + impl_.get_service().connect(impl_.get_implementation(), peer_endpoint, ec); + boost::asio::detail::throw_error(ec, "connect"); + } + + /// Connect the socket to the specified endpoint. + /** + * This function is used to connect a socket to the specified remote endpoint. + * The function call will block until the connection is successfully made or + * an error occurs. + * + * The socket is automatically opened if it is not already open. If the + * connect fails, and the socket was automatically opened, the socket is + * not returned to the closed state. + * + * @param peer_endpoint The remote endpoint to which the socket will be + * connected. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * boost::asio::ip::tcp::endpoint endpoint( + * boost::asio::ip::address::from_string("1.2.3.4"), 12345); + * boost::system::error_code ec; + * socket.connect(endpoint, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + BOOST_ASIO_SYNC_OP_VOID connect(const endpoint_type& peer_endpoint, + boost::system::error_code& ec) + { + if (!is_open()) + { + impl_.get_service().open(impl_.get_implementation(), + peer_endpoint.protocol(), ec); + if (ec) + { + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + } + + impl_.get_service().connect(impl_.get_implementation(), peer_endpoint, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Start an asynchronous connect. + /** + * This function is used to asynchronously connect a socket to the specified + * remote endpoint. The function call always returns immediately. + * + * The socket is automatically opened if it is not already open. If the + * connect fails, and the socket was automatically opened, the socket is + * not returned to the closed state. + * + * @param peer_endpoint The remote endpoint to which the socket will be + * connected. Copies will be made of the endpoint object as required. + * + * @param handler The handler to be called when the connection operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error // Result of operation + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * @code + * void connect_handler(const boost::system::error_code& error) + * { + * if (!error) + * { + * // Connect succeeded. + * } + * } + * + * ... + * + * boost::asio::ip::tcp::socket socket(my_context); + * boost::asio::ip::tcp::endpoint endpoint( + * boost::asio::ip::address::from_string("1.2.3.4"), 12345); + * socket.async_connect(endpoint, connect_handler); + * @endcode + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ConnectHandler, + void (boost::system::error_code)) + async_connect(const endpoint_type& peer_endpoint, + BOOST_ASIO_MOVE_ARG(ConnectHandler) handler) + { + boost::system::error_code open_ec; + if (!is_open()) + { + const protocol_type protocol = peer_endpoint.protocol(); + impl_.get_service().open(impl_.get_implementation(), protocol, open_ec); + } + + return async_initiate( + initiate_async_connect(), handler, this, peer_endpoint, open_ec); + } + + /// Set an option on the socket. + /** + * This function is used to set an option on the socket. + * + * @param option The new option value to be set on the socket. + * + * @throws boost::system::system_error Thrown on failure. + * + * @sa SettableSocketOption @n + * boost::asio::socket_base::broadcast @n + * boost::asio::socket_base::do_not_route @n + * boost::asio::socket_base::keep_alive @n + * boost::asio::socket_base::linger @n + * boost::asio::socket_base::receive_buffer_size @n + * boost::asio::socket_base::receive_low_watermark @n + * boost::asio::socket_base::reuse_address @n + * boost::asio::socket_base::send_buffer_size @n + * boost::asio::socket_base::send_low_watermark @n + * boost::asio::ip::multicast::join_group @n + * boost::asio::ip::multicast::leave_group @n + * boost::asio::ip::multicast::enable_loopback @n + * boost::asio::ip::multicast::outbound_interface @n + * boost::asio::ip::multicast::hops @n + * boost::asio::ip::tcp::no_delay + * + * @par Example + * Setting the IPPROTO_TCP/TCP_NODELAY option: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::ip::tcp::no_delay option(true); + * socket.set_option(option); + * @endcode + */ + template + void set_option(const SettableSocketOption& option) + { + boost::system::error_code ec; + impl_.get_service().set_option(impl_.get_implementation(), option, ec); + boost::asio::detail::throw_error(ec, "set_option"); + } + + /// Set an option on the socket. + /** + * This function is used to set an option on the socket. + * + * @param option The new option value to be set on the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa SettableSocketOption @n + * boost::asio::socket_base::broadcast @n + * boost::asio::socket_base::do_not_route @n + * boost::asio::socket_base::keep_alive @n + * boost::asio::socket_base::linger @n + * boost::asio::socket_base::receive_buffer_size @n + * boost::asio::socket_base::receive_low_watermark @n + * boost::asio::socket_base::reuse_address @n + * boost::asio::socket_base::send_buffer_size @n + * boost::asio::socket_base::send_low_watermark @n + * boost::asio::ip::multicast::join_group @n + * boost::asio::ip::multicast::leave_group @n + * boost::asio::ip::multicast::enable_loopback @n + * boost::asio::ip::multicast::outbound_interface @n + * boost::asio::ip::multicast::hops @n + * boost::asio::ip::tcp::no_delay + * + * @par Example + * Setting the IPPROTO_TCP/TCP_NODELAY option: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::ip::tcp::no_delay option(true); + * boost::system::error_code ec; + * socket.set_option(option, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + BOOST_ASIO_SYNC_OP_VOID set_option(const SettableSocketOption& option, + boost::system::error_code& ec) + { + impl_.get_service().set_option(impl_.get_implementation(), option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get an option from the socket. + /** + * This function is used to get the current value of an option on the socket. + * + * @param option The option value to be obtained from the socket. + * + * @throws boost::system::system_error Thrown on failure. + * + * @sa GettableSocketOption @n + * boost::asio::socket_base::broadcast @n + * boost::asio::socket_base::do_not_route @n + * boost::asio::socket_base::keep_alive @n + * boost::asio::socket_base::linger @n + * boost::asio::socket_base::receive_buffer_size @n + * boost::asio::socket_base::receive_low_watermark @n + * boost::asio::socket_base::reuse_address @n + * boost::asio::socket_base::send_buffer_size @n + * boost::asio::socket_base::send_low_watermark @n + * boost::asio::ip::multicast::join_group @n + * boost::asio::ip::multicast::leave_group @n + * boost::asio::ip::multicast::enable_loopback @n + * boost::asio::ip::multicast::outbound_interface @n + * boost::asio::ip::multicast::hops @n + * boost::asio::ip::tcp::no_delay + * + * @par Example + * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::ip::tcp::socket::keep_alive option; + * socket.get_option(option); + * bool is_set = option.value(); + * @endcode + */ + template + void get_option(GettableSocketOption& option) const + { + boost::system::error_code ec; + impl_.get_service().get_option(impl_.get_implementation(), option, ec); + boost::asio::detail::throw_error(ec, "get_option"); + } + + /// Get an option from the socket. + /** + * This function is used to get the current value of an option on the socket. + * + * @param option The option value to be obtained from the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa GettableSocketOption @n + * boost::asio::socket_base::broadcast @n + * boost::asio::socket_base::do_not_route @n + * boost::asio::socket_base::keep_alive @n + * boost::asio::socket_base::linger @n + * boost::asio::socket_base::receive_buffer_size @n + * boost::asio::socket_base::receive_low_watermark @n + * boost::asio::socket_base::reuse_address @n + * boost::asio::socket_base::send_buffer_size @n + * boost::asio::socket_base::send_low_watermark @n + * boost::asio::ip::multicast::join_group @n + * boost::asio::ip::multicast::leave_group @n + * boost::asio::ip::multicast::enable_loopback @n + * boost::asio::ip::multicast::outbound_interface @n + * boost::asio::ip::multicast::hops @n + * boost::asio::ip::tcp::no_delay + * + * @par Example + * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::ip::tcp::socket::keep_alive option; + * boost::system::error_code ec; + * socket.get_option(option, ec); + * if (ec) + * { + * // An error occurred. + * } + * bool is_set = option.value(); + * @endcode + */ + template + BOOST_ASIO_SYNC_OP_VOID get_option(GettableSocketOption& option, + boost::system::error_code& ec) const + { + impl_.get_service().get_option(impl_.get_implementation(), option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Perform an IO control command on the socket. + /** + * This function is used to execute an IO control command on the socket. + * + * @param command The IO control command to be performed on the socket. + * + * @throws boost::system::system_error Thrown on failure. + * + * @sa IoControlCommand @n + * boost::asio::socket_base::bytes_readable @n + * boost::asio::socket_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::ip::tcp::socket::bytes_readable command; + * socket.io_control(command); + * std::size_t bytes_readable = command.get(); + * @endcode + */ + template + void io_control(IoControlCommand& command) + { + boost::system::error_code ec; + impl_.get_service().io_control(impl_.get_implementation(), command, ec); + boost::asio::detail::throw_error(ec, "io_control"); + } + + /// Perform an IO control command on the socket. + /** + * This function is used to execute an IO control command on the socket. + * + * @param command The IO control command to be performed on the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa IoControlCommand @n + * boost::asio::socket_base::bytes_readable @n + * boost::asio::socket_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::ip::tcp::socket::bytes_readable command; + * boost::system::error_code ec; + * socket.io_control(command, ec); + * if (ec) + * { + * // An error occurred. + * } + * std::size_t bytes_readable = command.get(); + * @endcode + */ + template + BOOST_ASIO_SYNC_OP_VOID io_control(IoControlCommand& command, + boost::system::error_code& ec) + { + impl_.get_service().io_control(impl_.get_implementation(), command, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Gets the non-blocking mode of the socket. + /** + * @returns @c true if the socket's synchronous operations will fail with + * boost::asio::error::would_block if they are unable to perform the requested + * operation immediately. If @c false, synchronous operations will block + * until complete. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * boost::asio::error::would_block. + */ + bool non_blocking() const + { + return impl_.get_service().non_blocking(impl_.get_implementation()); + } + + /// Sets the non-blocking mode of the socket. + /** + * @param mode If @c true, the socket's synchronous operations will fail with + * boost::asio::error::would_block if they are unable to perform the requested + * operation immediately. If @c false, synchronous operations will block + * until complete. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * boost::asio::error::would_block. + */ + void non_blocking(bool mode) + { + boost::system::error_code ec; + impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); + boost::asio::detail::throw_error(ec, "non_blocking"); + } + + /// Sets the non-blocking mode of the socket. + /** + * @param mode If @c true, the socket's synchronous operations will fail with + * boost::asio::error::would_block if they are unable to perform the requested + * operation immediately. If @c false, synchronous operations will block + * until complete. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * boost::asio::error::would_block. + */ + BOOST_ASIO_SYNC_OP_VOID non_blocking( + bool mode, boost::system::error_code& ec) + { + impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Gets the non-blocking mode of the native socket implementation. + /** + * This function is used to retrieve the non-blocking mode of the underlying + * native socket. This mode has no effect on the behaviour of the socket + * object's synchronous operations. + * + * @returns @c true if the underlying socket is in non-blocking mode and + * direct system calls may fail with boost::asio::error::would_block (or the + * equivalent system error). + * + * @note The current non-blocking mode is cached by the socket object. + * Consequently, the return value may be incorrect if the non-blocking mode + * was set directly on the native socket. + * + * @par Example + * This function is intended to allow the encapsulation of arbitrary + * non-blocking system calls as asynchronous operations, in a way that is + * transparent to the user of the socket object. The following example + * illustrates how Linux's @c sendfile system call might be encapsulated: + * @code template + * struct sendfile_op + * { + * tcp::socket& sock_; + * int fd_; + * Handler handler_; + * off_t offset_; + * std::size_t total_bytes_transferred_; + * + * // Function call operator meeting WriteHandler requirements. + * // Used as the handler for the async_write_some operation. + * void operator()(boost::system::error_code ec, std::size_t) + * { + * // Put the underlying socket into non-blocking mode. + * if (!ec) + * if (!sock_.native_non_blocking()) + * sock_.native_non_blocking(true, ec); + * + * if (!ec) + * { + * for (;;) + * { + * // Try the system call. + * errno = 0; + * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536); + * ec = boost::system::error_code(n < 0 ? errno : 0, + * boost::asio::error::get_system_category()); + * total_bytes_transferred_ += ec ? 0 : n; + * + * // Retry operation immediately if interrupted by signal. + * if (ec == boost::asio::error::interrupted) + * continue; + * + * // Check if we need to run the operation again. + * if (ec == boost::asio::error::would_block + * || ec == boost::asio::error::try_again) + * { + * // We have to wait for the socket to become ready again. + * sock_.async_wait(tcp::socket::wait_write, *this); + * return; + * } + * + * if (ec || n == 0) + * { + * // An error occurred, or we have reached the end of the file. + * // Either way we must exit the loop so we can call the handler. + * break; + * } + * + * // Loop around to try calling sendfile again. + * } + * } + * + * // Pass result back to user's handler. + * handler_(ec, total_bytes_transferred_); + * } + * }; + * + * template + * void async_sendfile(tcp::socket& sock, int fd, Handler h) + * { + * sendfile_op op = { sock, fd, h, 0, 0 }; + * sock.async_wait(tcp::socket::wait_write, op); + * } @endcode + */ + bool native_non_blocking() const + { + return impl_.get_service().native_non_blocking(impl_.get_implementation()); + } + + /// Sets the non-blocking mode of the native socket implementation. + /** + * This function is used to modify the non-blocking mode of the underlying + * native socket. It has no effect on the behaviour of the socket object's + * synchronous operations. + * + * @param mode If @c true, the underlying socket is put into non-blocking + * mode and direct system calls may fail with boost::asio::error::would_block + * (or the equivalent system error). + * + * @throws boost::system::system_error Thrown on failure. If the @c mode is + * @c false, but the current value of @c non_blocking() is @c true, this + * function fails with boost::asio::error::invalid_argument, as the + * combination does not make sense. + * + * @par Example + * This function is intended to allow the encapsulation of arbitrary + * non-blocking system calls as asynchronous operations, in a way that is + * transparent to the user of the socket object. The following example + * illustrates how Linux's @c sendfile system call might be encapsulated: + * @code template + * struct sendfile_op + * { + * tcp::socket& sock_; + * int fd_; + * Handler handler_; + * off_t offset_; + * std::size_t total_bytes_transferred_; + * + * // Function call operator meeting WriteHandler requirements. + * // Used as the handler for the async_write_some operation. + * void operator()(boost::system::error_code ec, std::size_t) + * { + * // Put the underlying socket into non-blocking mode. + * if (!ec) + * if (!sock_.native_non_blocking()) + * sock_.native_non_blocking(true, ec); + * + * if (!ec) + * { + * for (;;) + * { + * // Try the system call. + * errno = 0; + * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536); + * ec = boost::system::error_code(n < 0 ? errno : 0, + * boost::asio::error::get_system_category()); + * total_bytes_transferred_ += ec ? 0 : n; + * + * // Retry operation immediately if interrupted by signal. + * if (ec == boost::asio::error::interrupted) + * continue; + * + * // Check if we need to run the operation again. + * if (ec == boost::asio::error::would_block + * || ec == boost::asio::error::try_again) + * { + * // We have to wait for the socket to become ready again. + * sock_.async_wait(tcp::socket::wait_write, *this); + * return; + * } + * + * if (ec || n == 0) + * { + * // An error occurred, or we have reached the end of the file. + * // Either way we must exit the loop so we can call the handler. + * break; + * } + * + * // Loop around to try calling sendfile again. + * } + * } + * + * // Pass result back to user's handler. + * handler_(ec, total_bytes_transferred_); + * } + * }; + * + * template + * void async_sendfile(tcp::socket& sock, int fd, Handler h) + * { + * sendfile_op op = { sock, fd, h, 0, 0 }; + * sock.async_wait(tcp::socket::wait_write, op); + * } @endcode + */ + void native_non_blocking(bool mode) + { + boost::system::error_code ec; + impl_.get_service().native_non_blocking( + impl_.get_implementation(), mode, ec); + boost::asio::detail::throw_error(ec, "native_non_blocking"); + } + + /// Sets the non-blocking mode of the native socket implementation. + /** + * This function is used to modify the non-blocking mode of the underlying + * native socket. It has no effect on the behaviour of the socket object's + * synchronous operations. + * + * @param mode If @c true, the underlying socket is put into non-blocking + * mode and direct system calls may fail with boost::asio::error::would_block + * (or the equivalent system error). + * + * @param ec Set to indicate what error occurred, if any. If the @c mode is + * @c false, but the current value of @c non_blocking() is @c true, this + * function fails with boost::asio::error::invalid_argument, as the + * combination does not make sense. + * + * @par Example + * This function is intended to allow the encapsulation of arbitrary + * non-blocking system calls as asynchronous operations, in a way that is + * transparent to the user of the socket object. The following example + * illustrates how Linux's @c sendfile system call might be encapsulated: + * @code template + * struct sendfile_op + * { + * tcp::socket& sock_; + * int fd_; + * Handler handler_; + * off_t offset_; + * std::size_t total_bytes_transferred_; + * + * // Function call operator meeting WriteHandler requirements. + * // Used as the handler for the async_write_some operation. + * void operator()(boost::system::error_code ec, std::size_t) + * { + * // Put the underlying socket into non-blocking mode. + * if (!ec) + * if (!sock_.native_non_blocking()) + * sock_.native_non_blocking(true, ec); + * + * if (!ec) + * { + * for (;;) + * { + * // Try the system call. + * errno = 0; + * int n = ::sendfile(sock_.native_handle(), fd_, &offset_, 65536); + * ec = boost::system::error_code(n < 0 ? errno : 0, + * boost::asio::error::get_system_category()); + * total_bytes_transferred_ += ec ? 0 : n; + * + * // Retry operation immediately if interrupted by signal. + * if (ec == boost::asio::error::interrupted) + * continue; + * + * // Check if we need to run the operation again. + * if (ec == boost::asio::error::would_block + * || ec == boost::asio::error::try_again) + * { + * // We have to wait for the socket to become ready again. + * sock_.async_wait(tcp::socket::wait_write, *this); + * return; + * } + * + * if (ec || n == 0) + * { + * // An error occurred, or we have reached the end of the file. + * // Either way we must exit the loop so we can call the handler. + * break; + * } + * + * // Loop around to try calling sendfile again. + * } + * } + * + * // Pass result back to user's handler. + * handler_(ec, total_bytes_transferred_); + * } + * }; + * + * template + * void async_sendfile(tcp::socket& sock, int fd, Handler h) + * { + * sendfile_op op = { sock, fd, h, 0, 0 }; + * sock.async_wait(tcp::socket::wait_write, op); + * } @endcode + */ + BOOST_ASIO_SYNC_OP_VOID native_non_blocking( + bool mode, boost::system::error_code& ec) + { + impl_.get_service().native_non_blocking( + impl_.get_implementation(), mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get the local endpoint of the socket. + /** + * This function is used to obtain the locally bound endpoint of the socket. + * + * @returns An object that represents the local endpoint of the socket. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::ip::tcp::endpoint endpoint = socket.local_endpoint(); + * @endcode + */ + endpoint_type local_endpoint() const + { + boost::system::error_code ec; + endpoint_type ep = impl_.get_service().local_endpoint( + impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "local_endpoint"); + return ep; + } + + /// Get the local endpoint of the socket. + /** + * This function is used to obtain the locally bound endpoint of the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns An object that represents the local endpoint of the socket. + * Returns a default-constructed endpoint object if an error occurred. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::system::error_code ec; + * boost::asio::ip::tcp::endpoint endpoint = socket.local_endpoint(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + endpoint_type local_endpoint(boost::system::error_code& ec) const + { + return impl_.get_service().local_endpoint(impl_.get_implementation(), ec); + } + + /// Get the remote endpoint of the socket. + /** + * This function is used to obtain the remote endpoint of the socket. + * + * @returns An object that represents the remote endpoint of the socket. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(); + * @endcode + */ + endpoint_type remote_endpoint() const + { + boost::system::error_code ec; + endpoint_type ep = impl_.get_service().remote_endpoint( + impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "remote_endpoint"); + return ep; + } + + /// Get the remote endpoint of the socket. + /** + * This function is used to obtain the remote endpoint of the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns An object that represents the remote endpoint of the socket. + * Returns a default-constructed endpoint object if an error occurred. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::system::error_code ec; + * boost::asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + endpoint_type remote_endpoint(boost::system::error_code& ec) const + { + return impl_.get_service().remote_endpoint(impl_.get_implementation(), ec); + } + + /// Disable sends or receives on the socket. + /** + * This function is used to disable send operations, receive operations, or + * both. + * + * @param what Determines what types of operation will no longer be allowed. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * Shutting down the send side of the socket: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send); + * @endcode + */ + void shutdown(shutdown_type what) + { + boost::system::error_code ec; + impl_.get_service().shutdown(impl_.get_implementation(), what, ec); + boost::asio::detail::throw_error(ec, "shutdown"); + } + + /// Disable sends or receives on the socket. + /** + * This function is used to disable send operations, receive operations, or + * both. + * + * @param what Determines what types of operation will no longer be allowed. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * Shutting down the send side of the socket: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::system::error_code ec; + * socket.shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + BOOST_ASIO_SYNC_OP_VOID shutdown(shutdown_type what, + boost::system::error_code& ec) + { + impl_.get_service().shutdown(impl_.get_implementation(), what, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Wait for the socket to become ready to read, ready to write, or to have + /// pending error conditions. + /** + * This function is used to perform a blocking wait for a socket to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired socket state. + * + * @par Example + * Waiting for a socket to become readable. + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * socket.wait(boost::asio::ip::tcp::socket::wait_read); + * @endcode + */ + void wait(wait_type w) + { + boost::system::error_code ec; + impl_.get_service().wait(impl_.get_implementation(), w, ec); + boost::asio::detail::throw_error(ec, "wait"); + } + + /// Wait for the socket to become ready to read, ready to write, or to have + /// pending error conditions. + /** + * This function is used to perform a blocking wait for a socket to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired socket state. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * Waiting for a socket to become readable. + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::system::error_code ec; + * socket.wait(boost::asio::ip::tcp::socket::wait_read, ec); + * @endcode + */ + BOOST_ASIO_SYNC_OP_VOID wait(wait_type w, boost::system::error_code& ec) + { + impl_.get_service().wait(impl_.get_implementation(), w, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Asynchronously wait for the socket to become ready to read, ready to + /// write, or to have pending error conditions. + /** + * This function is used to perform an asynchronous wait for a socket to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired socket state. + * + * @param handler The handler to be called when the wait operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error // Result of operation + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * @code + * void wait_handler(const boost::system::error_code& error) + * { + * if (!error) + * { + * // Wait succeeded. + * } + * } + * + * ... + * + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * socket.async_wait(boost::asio::ip::tcp::socket::wait_read, wait_handler); + * @endcode + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + void (boost::system::error_code)) + async_wait(wait_type w, BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + { + return async_initiate( + initiate_async_wait(), handler, this, w); + } + +protected: + /// Protected destructor to prevent deletion through this type. + /** + * This function destroys the socket, cancelling any outstanding asynchronous + * operations associated with the socket as if by calling @c cancel. + */ + ~basic_socket() + { + } + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + detail::io_object_impl< + detail::null_socket_service, Executor> impl_; +#elif defined(BOOST_ASIO_HAS_IOCP) + detail::io_object_impl< + detail::win_iocp_socket_service, Executor> impl_; +#else + detail::io_object_impl< + detail::reactive_socket_service, Executor> impl_; +#endif + +private: + // Disallow copying and assignment. + basic_socket(const basic_socket&) BOOST_ASIO_DELETED; + basic_socket& operator=(const basic_socket&) BOOST_ASIO_DELETED; + + struct initiate_async_connect + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ConnectHandler) handler, + basic_socket* self, const endpoint_type& peer_endpoint, + const boost::system::error_code& open_ec) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ConnectHandler. + BOOST_ASIO_CONNECT_HANDLER_CHECK(ConnectHandler, handler) type_check; + + if (open_ec) + { + boost::asio::post(self->impl_.get_executor(), + boost::asio::detail::bind_handler( + BOOST_ASIO_MOVE_CAST(ConnectHandler)(handler), open_ec)); + } + else + { + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_connect( + self->impl_.get_implementation(), peer_endpoint, + handler2.value, self->impl_.get_implementation_executor()); + } + } + }; + + struct initiate_async_wait + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler, + basic_socket* self, wait_type w) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WaitHandler. + BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_wait( + self->impl_.get_implementation(), w, handler2.value, + self->impl_.get_implementation_executor()); + } + }; +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BASIC_SOCKET_HPP diff --git a/boost/asio/basic_socket_acceptor.hpp b/boost/asio/basic_socket_acceptor.hpp new file mode 100644 index 0000000..12613b8 --- /dev/null +++ b/boost/asio/basic_socket_acceptor.hpp @@ -0,0 +1,2380 @@ +// +// basic_socket_acceptor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_HPP +#define BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +# include +#elif defined(BOOST_ASIO_HAS_IOCP) +# include +#else +# include +#endif + +#if defined(BOOST_ASIO_HAS_MOVE) +# include +#endif // defined(BOOST_ASIO_HAS_MOVE) + +#include + +namespace boost { +namespace asio { + +#if !defined(BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL) +#define BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL + +// Forward declaration with defaulted arguments. +template +class basic_socket_acceptor; + +#endif // !defined(BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL) + +/// Provides the ability to accept new connections. +/** + * The basic_socket_acceptor class template is used for accepting new socket + * connections. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Example + * Opening a socket acceptor with the SO_REUSEADDR option enabled: + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port); + * acceptor.open(endpoint.protocol()); + * acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + * acceptor.bind(endpoint); + * acceptor.listen(); + * @endcode + */ +template +class basic_socket_acceptor + : public socket_base +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// The native representation of an acceptor. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#elif defined(BOOST_ASIO_WINDOWS_RUNTIME) + typedef typename detail::null_socket_service< + Protocol>::native_handle_type native_handle_type; +#elif defined(BOOST_ASIO_HAS_IOCP) + typedef typename detail::win_iocp_socket_service< + Protocol>::native_handle_type native_handle_type; +#else + typedef typename detail::reactive_socket_service< + Protocol>::native_handle_type native_handle_type; +#endif + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// Construct an acceptor without opening it. + /** + * This constructor creates an acceptor without opening it to listen for new + * connections. The open() function must be called before the acceptor can + * accept new socket connections. + * + * @param ex The I/O executor that the acceptor will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * acceptor. + */ + explicit basic_socket_acceptor(const executor_type& ex) + : impl_(ex) + { + } + + /// Construct an acceptor without opening it. + /** + * This constructor creates an acceptor without opening it to listen for new + * connections. The open() function must be called before the acceptor can + * accept new socket connections. + * + * @param context An execution context which provides the I/O executor that + * the acceptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the acceptor. + */ + template + explicit basic_socket_acceptor(ExecutionContext& context, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + } + + /// Construct an open acceptor. + /** + * This constructor creates an acceptor and automatically opens it. + * + * @param ex The I/O executor that the acceptor will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * acceptor. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_socket_acceptor(const executor_type& ex, const protocol_type& protocol) + : impl_(ex) + { + boost::system::error_code ec; + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + boost::asio::detail::throw_error(ec, "open"); + } + + /// Construct an open acceptor. + /** + * This constructor creates an acceptor and automatically opens it. + * + * @param context An execution context which provides the I/O executor that + * the acceptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the acceptor. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_socket_acceptor(ExecutionContext& context, + const protocol_type& protocol, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + boost::system::error_code ec; + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + boost::asio::detail::throw_error(ec, "open"); + } + + /// Construct an acceptor opened on the given endpoint. + /** + * This constructor creates an acceptor and automatically opens it to listen + * for new connections on the specified endpoint. + * + * @param ex The I/O executor that the acceptor will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * acceptor. + * + * @param endpoint An endpoint on the local machine on which the acceptor + * will listen for new connections. + * + * @param reuse_addr Whether the constructor should set the socket option + * socket_base::reuse_address. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note This constructor is equivalent to the following code: + * @code + * basic_socket_acceptor acceptor(my_context); + * acceptor.open(endpoint.protocol()); + * if (reuse_addr) + * acceptor.set_option(socket_base::reuse_address(true)); + * acceptor.bind(endpoint); + * acceptor.listen(); + * @endcode + */ + basic_socket_acceptor(const executor_type& ex, + const endpoint_type& endpoint, bool reuse_addr = true) + : impl_(ex) + { + boost::system::error_code ec; + const protocol_type protocol = endpoint.protocol(); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + boost::asio::detail::throw_error(ec, "open"); + if (reuse_addr) + { + impl_.get_service().set_option(impl_.get_implementation(), + socket_base::reuse_address(true), ec); + boost::asio::detail::throw_error(ec, "set_option"); + } + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); + boost::asio::detail::throw_error(ec, "bind"); + impl_.get_service().listen(impl_.get_implementation(), + socket_base::max_listen_connections, ec); + boost::asio::detail::throw_error(ec, "listen"); + } + + /// Construct an acceptor opened on the given endpoint. + /** + * This constructor creates an acceptor and automatically opens it to listen + * for new connections on the specified endpoint. + * + * @param context An execution context which provides the I/O executor that + * the acceptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the acceptor. + * + * @param endpoint An endpoint on the local machine on which the acceptor + * will listen for new connections. + * + * @param reuse_addr Whether the constructor should set the socket option + * socket_base::reuse_address. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note This constructor is equivalent to the following code: + * @code + * basic_socket_acceptor acceptor(my_context); + * acceptor.open(endpoint.protocol()); + * if (reuse_addr) + * acceptor.set_option(socket_base::reuse_address(true)); + * acceptor.bind(endpoint); + * acceptor.listen(); + * @endcode + */ + template + basic_socket_acceptor(ExecutionContext& context, + const endpoint_type& endpoint, bool reuse_addr = true, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + boost::system::error_code ec; + const protocol_type protocol = endpoint.protocol(); + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + boost::asio::detail::throw_error(ec, "open"); + if (reuse_addr) + { + impl_.get_service().set_option(impl_.get_implementation(), + socket_base::reuse_address(true), ec); + boost::asio::detail::throw_error(ec, "set_option"); + } + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); + boost::asio::detail::throw_error(ec, "bind"); + impl_.get_service().listen(impl_.get_implementation(), + socket_base::max_listen_connections, ec); + boost::asio::detail::throw_error(ec, "listen"); + } + + /// Construct a basic_socket_acceptor on an existing native acceptor. + /** + * This constructor creates an acceptor object to hold an existing native + * acceptor. + * + * @param ex The I/O executor that the acceptor will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * acceptor. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_acceptor A native acceptor. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_socket_acceptor(const executor_type& ex, + const protocol_type& protocol, const native_handle_type& native_acceptor) + : impl_(ex) + { + boost::system::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + protocol, native_acceptor, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + + /// Construct a basic_socket_acceptor on an existing native acceptor. + /** + * This constructor creates an acceptor object to hold an existing native + * acceptor. + * + * @param context An execution context which provides the I/O executor that + * the acceptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the acceptor. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_acceptor A native acceptor. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_socket_acceptor(ExecutionContext& context, + const protocol_type& protocol, const native_handle_type& native_acceptor, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + boost::system::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + protocol, native_acceptor, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_socket_acceptor from another. + /** + * This constructor moves an acceptor from one object to another. + * + * @param other The other basic_socket_acceptor object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket_acceptor(const executor_type&) + * constructor. + */ + basic_socket_acceptor(basic_socket_acceptor&& other) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_socket_acceptor from another. + /** + * This assignment operator moves an acceptor from one object to another. + * + * @param other The other basic_socket_acceptor object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket_acceptor(const executor_type&) + * constructor. + */ + basic_socket_acceptor& operator=(basic_socket_acceptor&& other) + { + impl_ = std::move(other.impl_); + return *this; + } + + // All socket acceptors have access to each other's implementations. + template + friend class basic_socket_acceptor; + + /// Move-construct a basic_socket_acceptor from an acceptor of another + /// protocol type. + /** + * This constructor moves an acceptor from one object to another. + * + * @param other The other basic_socket_acceptor object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket_acceptor(const executor_type&) + * constructor. + */ + template + basic_socket_acceptor(basic_socket_acceptor&& other, + typename enable_if< + is_convertible::value + && is_convertible::value + >::type* = 0) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_socket_acceptor from an acceptor of another protocol + /// type. + /** + * This assignment operator moves an acceptor from one object to another. + * + * @param other The other basic_socket_acceptor object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_socket_acceptor(const executor_type&) + * constructor. + */ + template + typename enable_if< + is_convertible::value + && is_convertible::value, + basic_socket_acceptor& + >::type operator=(basic_socket_acceptor&& other) + { + basic_socket_acceptor tmp(std::move(other)); + impl_ = std::move(tmp.impl_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the acceptor. + /** + * This function destroys the acceptor, cancelling any outstanding + * asynchronous operations associated with the acceptor as if by calling + * @c cancel. + */ + ~basic_socket_acceptor() + { + } + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return impl_.get_executor(); + } + + /// Open the acceptor using the specified protocol. + /** + * This function opens the socket acceptor so that it will use the specified + * protocol. + * + * @param protocol An object specifying which protocol is to be used. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * acceptor.open(boost::asio::ip::tcp::v4()); + * @endcode + */ + void open(const protocol_type& protocol = protocol_type()) + { + boost::system::error_code ec; + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + boost::asio::detail::throw_error(ec, "open"); + } + + /// Open the acceptor using the specified protocol. + /** + * This function opens the socket acceptor so that it will use the specified + * protocol. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * boost::system::error_code ec; + * acceptor.open(boost::asio::ip::tcp::v4(), ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + BOOST_ASIO_SYNC_OP_VOID open(const protocol_type& protocol, + boost::system::error_code& ec) + { + impl_.get_service().open(impl_.get_implementation(), protocol, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Assigns an existing native acceptor to the acceptor. + /* + * This function opens the acceptor to hold an existing native acceptor. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param native_acceptor A native acceptor. + * + * @throws boost::system::system_error Thrown on failure. + */ + void assign(const protocol_type& protocol, + const native_handle_type& native_acceptor) + { + boost::system::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + protocol, native_acceptor, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + + /// Assigns an existing native acceptor to the acceptor. + /* + * This function opens the acceptor to hold an existing native acceptor. + * + * @param protocol An object specifying which protocol is to be used. + * + * @param native_acceptor A native acceptor. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID assign(const protocol_type& protocol, + const native_handle_type& native_acceptor, boost::system::error_code& ec) + { + impl_.get_service().assign(impl_.get_implementation(), + protocol, native_acceptor, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the acceptor is open. + bool is_open() const + { + return impl_.get_service().is_open(impl_.get_implementation()); + } + + /// Bind the acceptor to the given local endpoint. + /** + * This function binds the socket acceptor to the specified endpoint on the + * local machine. + * + * @param endpoint An endpoint on the local machine to which the socket + * acceptor will be bound. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 12345); + * acceptor.open(endpoint.protocol()); + * acceptor.bind(endpoint); + * @endcode + */ + void bind(const endpoint_type& endpoint) + { + boost::system::error_code ec; + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); + boost::asio::detail::throw_error(ec, "bind"); + } + + /// Bind the acceptor to the given local endpoint. + /** + * This function binds the socket acceptor to the specified endpoint on the + * local machine. + * + * @param endpoint An endpoint on the local machine to which the socket + * acceptor will be bound. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), 12345); + * acceptor.open(endpoint.protocol()); + * boost::system::error_code ec; + * acceptor.bind(endpoint, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + BOOST_ASIO_SYNC_OP_VOID bind(const endpoint_type& endpoint, + boost::system::error_code& ec) + { + impl_.get_service().bind(impl_.get_implementation(), endpoint, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Place the acceptor into the state where it will listen for new + /// connections. + /** + * This function puts the socket acceptor into the state where it may accept + * new connections. + * + * @param backlog The maximum length of the queue of pending connections. + * + * @throws boost::system::system_error Thrown on failure. + */ + void listen(int backlog = socket_base::max_listen_connections) + { + boost::system::error_code ec; + impl_.get_service().listen(impl_.get_implementation(), backlog, ec); + boost::asio::detail::throw_error(ec, "listen"); + } + + /// Place the acceptor into the state where it will listen for new + /// connections. + /** + * This function puts the socket acceptor into the state where it may accept + * new connections. + * + * @param backlog The maximum length of the queue of pending connections. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::system::error_code ec; + * acceptor.listen(boost::asio::socket_base::max_listen_connections, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + BOOST_ASIO_SYNC_OP_VOID listen(int backlog, boost::system::error_code& ec) + { + impl_.get_service().listen(impl_.get_implementation(), backlog, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Close the acceptor. + /** + * This function is used to close the acceptor. Any asynchronous accept + * operations will be cancelled immediately. + * + * A subsequent call to open() is required before the acceptor can again be + * used to again perform socket accept operations. + * + * @throws boost::system::system_error Thrown on failure. + */ + void close() + { + boost::system::error_code ec; + impl_.get_service().close(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "close"); + } + + /// Close the acceptor. + /** + * This function is used to close the acceptor. Any asynchronous accept + * operations will be cancelled immediately. + * + * A subsequent call to open() is required before the acceptor can again be + * used to again perform socket accept operations. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::system::error_code ec; + * acceptor.close(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) + { + impl_.get_service().close(impl_.get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Release ownership of the underlying native acceptor. + /** + * This function causes all outstanding asynchronous accept operations to + * finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. Ownership of the + * native acceptor is then transferred to the caller. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with boost::asio::error::operation_not_supported on + * these platforms. + */ +#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release() + { + boost::system::error_code ec; + native_handle_type s = impl_.get_service().release( + impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "release"); + return s; + } + + /// Release ownership of the underlying native acceptor. + /** + * This function causes all outstanding asynchronous accept operations to + * finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. Ownership of the + * native acceptor is then transferred to the caller. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note This function is unsupported on Windows versions prior to Windows + * 8.1, and will fail with boost::asio::error::operation_not_supported on + * these platforms. + */ +#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1400) \ + && (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603) + __declspec(deprecated("This function always fails with " + "operation_not_supported when used on Windows versions " + "prior to Windows 8.1.")) +#endif + native_handle_type release(boost::system::error_code& ec) + { + return impl_.get_service().release(impl_.get_implementation(), ec); + } + + /// Get the native acceptor representation. + /** + * This function may be used to obtain the underlying representation of the + * acceptor. This is intended to allow access to native acceptor functionality + * that is not otherwise provided. + */ + native_handle_type native_handle() + { + return impl_.get_service().native_handle(impl_.get_implementation()); + } + + /// Cancel all asynchronous operations associated with the acceptor. + /** + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the boost::asio::error::operation_aborted error. + * + * @throws boost::system::system_error Thrown on failure. + */ + void cancel() + { + boost::system::error_code ec; + impl_.get_service().cancel(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the acceptor. + /** + * This function causes all outstanding asynchronous connect, send and receive + * operations to finish immediately, and the handlers for cancelled operations + * will be passed the boost::asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) + { + impl_.get_service().cancel(impl_.get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Set an option on the acceptor. + /** + * This function is used to set an option on the acceptor. + * + * @param option The new option value to be set on the acceptor. + * + * @throws boost::system::system_error Thrown on failure. + * + * @sa SettableSocketOption @n + * boost::asio::socket_base::reuse_address + * boost::asio::socket_base::enable_connection_aborted + * + * @par Example + * Setting the SOL_SOCKET/SO_REUSEADDR option: + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::acceptor::reuse_address option(true); + * acceptor.set_option(option); + * @endcode + */ + template + void set_option(const SettableSocketOption& option) + { + boost::system::error_code ec; + impl_.get_service().set_option(impl_.get_implementation(), option, ec); + boost::asio::detail::throw_error(ec, "set_option"); + } + + /// Set an option on the acceptor. + /** + * This function is used to set an option on the acceptor. + * + * @param option The new option value to be set on the acceptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa SettableSocketOption @n + * boost::asio::socket_base::reuse_address + * boost::asio::socket_base::enable_connection_aborted + * + * @par Example + * Setting the SOL_SOCKET/SO_REUSEADDR option: + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::acceptor::reuse_address option(true); + * boost::system::error_code ec; + * acceptor.set_option(option, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + BOOST_ASIO_SYNC_OP_VOID set_option(const SettableSocketOption& option, + boost::system::error_code& ec) + { + impl_.get_service().set_option(impl_.get_implementation(), option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get an option from the acceptor. + /** + * This function is used to get the current value of an option on the + * acceptor. + * + * @param option The option value to be obtained from the acceptor. + * + * @throws boost::system::system_error Thrown on failure. + * + * @sa GettableSocketOption @n + * boost::asio::socket_base::reuse_address + * + * @par Example + * Getting the value of the SOL_SOCKET/SO_REUSEADDR option: + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::acceptor::reuse_address option; + * acceptor.get_option(option); + * bool is_set = option.get(); + * @endcode + */ + template + void get_option(GettableSocketOption& option) const + { + boost::system::error_code ec; + impl_.get_service().get_option(impl_.get_implementation(), option, ec); + boost::asio::detail::throw_error(ec, "get_option"); + } + + /// Get an option from the acceptor. + /** + * This function is used to get the current value of an option on the + * acceptor. + * + * @param option The option value to be obtained from the acceptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa GettableSocketOption @n + * boost::asio::socket_base::reuse_address + * + * @par Example + * Getting the value of the SOL_SOCKET/SO_REUSEADDR option: + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::acceptor::reuse_address option; + * boost::system::error_code ec; + * acceptor.get_option(option, ec); + * if (ec) + * { + * // An error occurred. + * } + * bool is_set = option.get(); + * @endcode + */ + template + BOOST_ASIO_SYNC_OP_VOID get_option(GettableSocketOption& option, + boost::system::error_code& ec) const + { + impl_.get_service().get_option(impl_.get_implementation(), option, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Perform an IO control command on the acceptor. + /** + * This function is used to execute an IO control command on the acceptor. + * + * @param command The IO control command to be performed on the acceptor. + * + * @throws boost::system::system_error Thrown on failure. + * + * @sa IoControlCommand @n + * boost::asio::socket_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::acceptor::non_blocking_io command(true); + * socket.io_control(command); + * @endcode + */ + template + void io_control(IoControlCommand& command) + { + boost::system::error_code ec; + impl_.get_service().io_control(impl_.get_implementation(), command, ec); + boost::asio::detail::throw_error(ec, "io_control"); + } + + /// Perform an IO control command on the acceptor. + /** + * This function is used to execute an IO control command on the acceptor. + * + * @param command The IO control command to be performed on the acceptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa IoControlCommand @n + * boost::asio::socket_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::acceptor::non_blocking_io command(true); + * boost::system::error_code ec; + * socket.io_control(command, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + BOOST_ASIO_SYNC_OP_VOID io_control(IoControlCommand& command, + boost::system::error_code& ec) + { + impl_.get_service().io_control(impl_.get_implementation(), command, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Gets the non-blocking mode of the acceptor. + /** + * @returns @c true if the acceptor's synchronous operations will fail with + * boost::asio::error::would_block if they are unable to perform the requested + * operation immediately. If @c false, synchronous operations will block + * until complete. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * boost::asio::error::would_block. + */ + bool non_blocking() const + { + return impl_.get_service().non_blocking(impl_.get_implementation()); + } + + /// Sets the non-blocking mode of the acceptor. + /** + * @param mode If @c true, the acceptor's synchronous operations will fail + * with boost::asio::error::would_block if they are unable to perform the + * requested operation immediately. If @c false, synchronous operations will + * block until complete. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * boost::asio::error::would_block. + */ + void non_blocking(bool mode) + { + boost::system::error_code ec; + impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); + boost::asio::detail::throw_error(ec, "non_blocking"); + } + + /// Sets the non-blocking mode of the acceptor. + /** + * @param mode If @c true, the acceptor's synchronous operations will fail + * with boost::asio::error::would_block if they are unable to perform the + * requested operation immediately. If @c false, synchronous operations will + * block until complete. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * boost::asio::error::would_block. + */ + BOOST_ASIO_SYNC_OP_VOID non_blocking( + bool mode, boost::system::error_code& ec) + { + impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Gets the non-blocking mode of the native acceptor implementation. + /** + * This function is used to retrieve the non-blocking mode of the underlying + * native acceptor. This mode has no effect on the behaviour of the acceptor + * object's synchronous operations. + * + * @returns @c true if the underlying acceptor is in non-blocking mode and + * direct system calls may fail with boost::asio::error::would_block (or the + * equivalent system error). + * + * @note The current non-blocking mode is cached by the acceptor object. + * Consequently, the return value may be incorrect if the non-blocking mode + * was set directly on the native acceptor. + */ + bool native_non_blocking() const + { + return impl_.get_service().native_non_blocking(impl_.get_implementation()); + } + + /// Sets the non-blocking mode of the native acceptor implementation. + /** + * This function is used to modify the non-blocking mode of the underlying + * native acceptor. It has no effect on the behaviour of the acceptor object's + * synchronous operations. + * + * @param mode If @c true, the underlying acceptor is put into non-blocking + * mode and direct system calls may fail with boost::asio::error::would_block + * (or the equivalent system error). + * + * @throws boost::system::system_error Thrown on failure. If the @c mode is + * @c false, but the current value of @c non_blocking() is @c true, this + * function fails with boost::asio::error::invalid_argument, as the + * combination does not make sense. + */ + void native_non_blocking(bool mode) + { + boost::system::error_code ec; + impl_.get_service().native_non_blocking( + impl_.get_implementation(), mode, ec); + boost::asio::detail::throw_error(ec, "native_non_blocking"); + } + + /// Sets the non-blocking mode of the native acceptor implementation. + /** + * This function is used to modify the non-blocking mode of the underlying + * native acceptor. It has no effect on the behaviour of the acceptor object's + * synchronous operations. + * + * @param mode If @c true, the underlying acceptor is put into non-blocking + * mode and direct system calls may fail with boost::asio::error::would_block + * (or the equivalent system error). + * + * @param ec Set to indicate what error occurred, if any. If the @c mode is + * @c false, but the current value of @c non_blocking() is @c true, this + * function fails with boost::asio::error::invalid_argument, as the + * combination does not make sense. + */ + BOOST_ASIO_SYNC_OP_VOID native_non_blocking( + bool mode, boost::system::error_code& ec) + { + impl_.get_service().native_non_blocking( + impl_.get_implementation(), mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get the local endpoint of the acceptor. + /** + * This function is used to obtain the locally bound endpoint of the acceptor. + * + * @returns An object that represents the local endpoint of the acceptor. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(); + * @endcode + */ + endpoint_type local_endpoint() const + { + boost::system::error_code ec; + endpoint_type ep = impl_.get_service().local_endpoint( + impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "local_endpoint"); + return ep; + } + + /// Get the local endpoint of the acceptor. + /** + * This function is used to obtain the locally bound endpoint of the acceptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns An object that represents the local endpoint of the acceptor. + * Returns a default-constructed endpoint object if an error occurred and the + * error handler did not throw an exception. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::system::error_code ec; + * boost::asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + endpoint_type local_endpoint(boost::system::error_code& ec) const + { + return impl_.get_service().local_endpoint(impl_.get_implementation(), ec); + } + + /// Wait for the acceptor to become ready to read, ready to write, or to have + /// pending error conditions. + /** + * This function is used to perform a blocking wait for an acceptor to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired acceptor state. + * + * @par Example + * Waiting for an acceptor to become readable. + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * acceptor.wait(boost::asio::ip::tcp::acceptor::wait_read); + * @endcode + */ + void wait(wait_type w) + { + boost::system::error_code ec; + impl_.get_service().wait(impl_.get_implementation(), w, ec); + boost::asio::detail::throw_error(ec, "wait"); + } + + /// Wait for the acceptor to become ready to read, ready to write, or to have + /// pending error conditions. + /** + * This function is used to perform a blocking wait for an acceptor to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired acceptor state. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * Waiting for an acceptor to become readable. + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::system::error_code ec; + * acceptor.wait(boost::asio::ip::tcp::acceptor::wait_read, ec); + * @endcode + */ + BOOST_ASIO_SYNC_OP_VOID wait(wait_type w, boost::system::error_code& ec) + { + impl_.get_service().wait(impl_.get_implementation(), w, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Asynchronously wait for the acceptor to become ready to read, ready to + /// write, or to have pending error conditions. + /** + * This function is used to perform an asynchronous wait for an acceptor to + * enter a ready to read, write or error condition state. + * + * @param w Specifies the desired acceptor state. + * + * @param handler The handler to be called when the wait operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error // Result of operation + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * @code + * void wait_handler(const boost::system::error_code& error) + * { + * if (!error) + * { + * // Wait succeeded. + * } + * } + * + * ... + * + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * acceptor.async_wait( + * boost::asio::ip::tcp::acceptor::wait_read, + * wait_handler); + * @endcode + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + void (boost::system::error_code)) + async_wait(wait_type w, BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + { + return async_initiate( + initiate_async_wait(), handler, this, w); + } + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer into the + * given socket. The function call will block until a new connection has been + * accepted successfully or an error occurs. + * + * @param peer The socket into which the new connection will be accepted. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::socket socket(my_context); + * acceptor.accept(socket); + * @endcode + */ + template + void accept(basic_socket& peer, + typename enable_if< + is_convertible::value + >::type* = 0) + { + boost::system::error_code ec; + impl_.get_service().accept(impl_.get_implementation(), + peer, static_cast(0), ec); + boost::asio::detail::throw_error(ec, "accept"); + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer into the + * given socket. The function call will block until a new connection has been + * accepted successfully or an error occurs. + * + * @param peer The socket into which the new connection will be accepted. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::socket socket(my_context); + * boost::system::error_code ec; + * acceptor.accept(socket, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + BOOST_ASIO_SYNC_OP_VOID accept( + basic_socket& peer, boost::system::error_code& ec, + typename enable_if< + is_convertible::value + >::type* = 0) + { + impl_.get_service().accept(impl_.get_implementation(), + peer, static_cast(0), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection into a + * socket. The function call always returns immediately. + * + * @param peer The socket into which the new connection will be accepted. + * Ownership of the peer object is retained by the caller, which must + * guarantee that it is valid until the handler is called. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error // Result of operation. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * @code + * void accept_handler(const boost::system::error_code& error) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::socket socket(my_context); + * acceptor.async_accept(socket, accept_handler); + * @endcode + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(AcceptHandler, + void (boost::system::error_code)) + async_accept(basic_socket& peer, + BOOST_ASIO_MOVE_ARG(AcceptHandler) handler, + typename enable_if< + is_convertible::value + >::type* = 0) + { + return async_initiate( + initiate_async_accept(), handler, this, + &peer, static_cast(0)); + } + + /// Accept a new connection and obtain the endpoint of the peer + /** + * This function is used to accept a new connection from a peer into the + * given socket, and additionally provide the endpoint of the remote peer. + * The function call will block until a new connection has been accepted + * successfully or an error occurs. + * + * @param peer The socket into which the new connection will be accepted. + * + * @param peer_endpoint An endpoint object which will receive the endpoint of + * the remote peer. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::socket socket(my_context); + * boost::asio::ip::tcp::endpoint endpoint; + * acceptor.accept(socket, endpoint); + * @endcode + */ + template + void accept(basic_socket& peer, + endpoint_type& peer_endpoint) + { + boost::system::error_code ec; + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); + boost::asio::detail::throw_error(ec, "accept"); + } + + /// Accept a new connection and obtain the endpoint of the peer + /** + * This function is used to accept a new connection from a peer into the + * given socket, and additionally provide the endpoint of the remote peer. + * The function call will block until a new connection has been accepted + * successfully or an error occurs. + * + * @param peer The socket into which the new connection will be accepted. + * + * @param peer_endpoint An endpoint object which will receive the endpoint of + * the remote peer. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::socket socket(my_context); + * boost::asio::ip::tcp::endpoint endpoint; + * boost::system::error_code ec; + * acceptor.accept(socket, endpoint, ec); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + BOOST_ASIO_SYNC_OP_VOID accept(basic_socket& peer, + endpoint_type& peer_endpoint, boost::system::error_code& ec) + { + impl_.get_service().accept( + impl_.get_implementation(), peer, &peer_endpoint, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection into a + * socket, and additionally obtain the endpoint of the remote peer. The + * function call always returns immediately. + * + * @param peer The socket into which the new connection will be accepted. + * Ownership of the peer object is retained by the caller, which must + * guarantee that it is valid until the handler is called. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. Ownership of the peer_endpoint object is + * retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error // Result of operation. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(AcceptHandler, + void (boost::system::error_code)) + async_accept(basic_socket& peer, + endpoint_type& peer_endpoint, BOOST_ASIO_MOVE_ARG(AcceptHandler) handler) + { + return async_initiate( + initiate_async_accept(), handler, this, &peer, &peer_endpoint); + } +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @returns A socket object representing the newly accepted connection. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::socket socket(acceptor.accept()); + * @endcode + */ + typename Protocol::socket accept() + { + boost::system::error_code ec; + typename Protocol::socket peer(impl_.get_executor()); + impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); + boost::asio::detail::throw_error(ec, "accept"); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns On success, a socket object representing the newly accepted + * connection. On error, a socket object where is_open() is false. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::socket socket(acceptor.accept(ec)); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + typename Protocol::socket accept(boost::system::error_code& ec) + { + typename Protocol::socket peer(impl_.get_executor()); + impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); + return peer; + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection. The + * function call always returns immediately. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * typename Protocol::socket peer // On success, the newly accepted socket. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * @code + * void accept_handler(const boost::system::error_code& error, + * boost::asio::ip::tcp::socket peer) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * acceptor.async_accept(accept_handler); + * @endcode + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, + void (boost::system::error_code, typename Protocol::socket)) + async_accept(BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler) + { + return async_initiate( + initiate_async_move_accept(), handler, this, + impl_.get_executor(), static_cast(0), + static_cast(0)); + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param ex The I/O executor object to be used for the newly + * accepted socket. + * + * @returns A socket object representing the newly accepted connection. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::socket socket(acceptor.accept()); + * @endcode + */ + template + typename Protocol::socket::template rebind_executor::other + accept(const Executor1& ex, + typename enable_if< + is_executor::value + >::type* = 0) + { + boost::system::error_code ec; + typename Protocol::socket::template + rebind_executor::other peer(ex); + impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); + boost::asio::detail::throw_error(ec, "accept"); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param context The I/O execution context object to be used for the newly + * accepted socket. + * + * @returns A socket object representing the newly accepted connection. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::socket socket(acceptor.accept()); + * @endcode + */ + template + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other + accept(ExecutionContext& context, + typename enable_if< + is_convertible::value + >::type* = 0) + { + boost::system::error_code ec; + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other peer(context); + impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); + boost::asio::detail::throw_error(ec, "accept"); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param ex The I/O executor object to be used for the newly accepted + * socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns On success, a socket object representing the newly accepted + * connection. On error, a socket object where is_open() is false. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::socket socket(acceptor.accept(my_context2, ec)); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + typename Protocol::socket::template rebind_executor::other + accept(const Executor1& ex, boost::system::error_code& ec, + typename enable_if< + is_executor::value + >::type* = 0) + { + typename Protocol::socket::template + rebind_executor::other peer(ex); + impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param context The I/O execution context object to be used for the newly + * accepted socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns On success, a socket object representing the newly accepted + * connection. On error, a socket object where is_open() is false. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::socket socket(acceptor.accept(my_context2, ec)); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other + accept(ExecutionContext& context, boost::system::error_code& ec, + typename enable_if< + is_convertible::value + >::type* = 0) + { + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other peer(context); + impl_.get_service().accept(impl_.get_implementation(), peer, 0, ec); + return peer; + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection. The + * function call always returns immediately. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param ex The I/O executor object to be used for the newly accepted + * socket. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * typename Protocol::socket::template rebind_executor< + * Executor1>::other peer // On success, the newly accepted socket. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * @code + * void accept_handler(const boost::system::error_code& error, + * boost::asio::ip::tcp::socket peer) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * acceptor.async_accept(my_context2, accept_handler); + * @endcode + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, + void (boost::system::error_code, + typename Protocol::socket::template rebind_executor< + Executor1>::other)) + async_accept(const Executor1& ex, + BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler, + typename enable_if< + is_executor::value + >::type* = 0) + { + typedef typename Protocol::socket::template rebind_executor< + Executor1>::other other_socket_type; + + return async_initiate( + initiate_async_move_accept(), handler, this, + ex, static_cast(0), + static_cast(0)); + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection. The + * function call always returns immediately. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param context The I/O execution context object to be used for the newly + * accepted socket. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * typename Protocol::socket::template rebind_executor< + * typename ExecutionContext::executor_type>::other peer + * // On success, the newly accepted socket. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * @code + * void accept_handler(const boost::system::error_code& error, + * boost::asio::ip::tcp::socket peer) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * acceptor.async_accept(my_context2, accept_handler); + * @endcode + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, + void (boost::system::error_code, + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other)) + async_accept(ExecutionContext& context, + BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler, + typename enable_if< + is_convertible::value + >::type* = 0) + { + typedef typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other other_socket_type; + + return async_initiate( + initiate_async_move_accept(), handler, this, + context.get_executor(), static_cast(0), + static_cast(0)); + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. + * + * @returns A socket object representing the newly accepted connection. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::endpoint endpoint; + * boost::asio::ip::tcp::socket socket(acceptor.accept(endpoint)); + * @endcode + */ + typename Protocol::socket accept(endpoint_type& peer_endpoint) + { + boost::system::error_code ec; + typename Protocol::socket peer(impl_.get_executor()); + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); + boost::asio::detail::throw_error(ec, "accept"); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns On success, a socket object representing the newly accepted + * connection. On error, a socket object where is_open() is false. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::endpoint endpoint; + * boost::asio::ip::tcp::socket socket(acceptor.accept(endpoint, ec)); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + typename Protocol::socket accept( + endpoint_type& peer_endpoint, boost::system::error_code& ec) + { + typename Protocol::socket peer(impl_.get_executor()); + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); + return peer; + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection. The + * function call always returns immediately. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. Ownership of the peer_endpoint object is + * retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * typename Protocol::socket peer // On success, the newly accepted socket. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * @code + * void accept_handler(const boost::system::error_code& error, + * boost::asio::ip::tcp::socket peer) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::endpoint endpoint; + * acceptor.async_accept(endpoint, accept_handler); + * @endcode + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, + void (boost::system::error_code, typename Protocol::socket)) + async_accept(endpoint_type& peer_endpoint, + BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler) + { + return async_initiate( + initiate_async_move_accept(), handler, this, + impl_.get_executor(), &peer_endpoint, + static_cast(0)); + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param ex The I/O executor object to be used for the newly accepted + * socket. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. + * + * @returns A socket object representing the newly accepted connection. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::endpoint endpoint; + * boost::asio::ip::tcp::socket socket( + * acceptor.accept(my_context2, endpoint)); + * @endcode + */ + template + typename Protocol::socket::template rebind_executor::other + accept(const Executor1& ex, endpoint_type& peer_endpoint, + typename enable_if< + is_executor::value + >::type* = 0) + { + boost::system::error_code ec; + typename Protocol::socket::template + rebind_executor::other peer(ex); + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); + boost::asio::detail::throw_error(ec, "accept"); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param context The I/O execution context object to be used for the newly + * accepted socket. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. + * + * @returns A socket object representing the newly accepted connection. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::endpoint endpoint; + * boost::asio::ip::tcp::socket socket( + * acceptor.accept(my_context2, endpoint)); + * @endcode + */ + template + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other + accept(ExecutionContext& context, endpoint_type& peer_endpoint, + typename enable_if< + is_convertible::value + >::type* = 0) + { + boost::system::error_code ec; + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other peer(context); + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); + boost::asio::detail::throw_error(ec, "accept"); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param ex The I/O executor object to be used for the newly accepted + * socket. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns On success, a socket object representing the newly accepted + * connection. On error, a socket object where is_open() is false. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::endpoint endpoint; + * boost::asio::ip::tcp::socket socket( + * acceptor.accept(my_context2, endpoint, ec)); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + typename Protocol::socket::template rebind_executor::other + accept(const executor_type& ex, + endpoint_type& peer_endpoint, boost::system::error_code& ec, + typename enable_if< + is_executor::value + >::type* = 0) + { + typename Protocol::socket::template + rebind_executor::other peer(ex); + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); + return peer; + } + + /// Accept a new connection. + /** + * This function is used to accept a new connection from a peer. The function + * call will block until a new connection has been accepted successfully or + * an error occurs. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param context The I/O execution context object to be used for the newly + * accepted socket. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns On success, a socket object representing the newly accepted + * connection. On error, a socket object where is_open() is false. + * + * @par Example + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::endpoint endpoint; + * boost::asio::ip::tcp::socket socket( + * acceptor.accept(my_context2, endpoint, ec)); + * if (ec) + * { + * // An error occurred. + * } + * @endcode + */ + template + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other + accept(ExecutionContext& context, + endpoint_type& peer_endpoint, boost::system::error_code& ec, + typename enable_if< + is_convertible::value + >::type* = 0) + { + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other peer(context); + impl_.get_service().accept(impl_.get_implementation(), + peer, &peer_endpoint, ec); + return peer; + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection. The + * function call always returns immediately. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param ex The I/O executor object to be used for the newly accepted + * socket. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. Ownership of the peer_endpoint object is + * retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * typename Protocol::socket::template rebind_executor< + * Executor1>::other peer // On success, the newly accepted socket. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * @code + * void accept_handler(const boost::system::error_code& error, + * boost::asio::ip::tcp::socket peer) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::endpoint endpoint; + * acceptor.async_accept(my_context2, endpoint, accept_handler); + * @endcode + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, + void (boost::system::error_code, + typename Protocol::socket::template rebind_executor< + Executor1>::other)) + async_accept(const Executor1& ex, endpoint_type& peer_endpoint, + BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler, + typename enable_if< + is_executor::value + >::type* = 0) + { + typedef typename Protocol::socket::template rebind_executor< + Executor1>::other other_socket_type; + + return async_initiate( + initiate_async_move_accept(), handler, this, + ex, &peer_endpoint, + static_cast(0)); + } + + /// Start an asynchronous accept. + /** + * This function is used to asynchronously accept a new connection. The + * function call always returns immediately. + * + * This overload requires that the Protocol template parameter satisfy the + * AcceptableProtocol type requirements. + * + * @param context The I/O execution context object to be used for the newly + * accepted socket. + * + * @param peer_endpoint An endpoint object into which the endpoint of the + * remote peer will be written. Ownership of the peer_endpoint object is + * retained by the caller, which must guarantee that it is valid until the + * handler is called. + * + * @param handler The handler to be called when the accept operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * typename Protocol::socket::template rebind_executor< + * typename ExecutionContext::executor_type>::other peer + * // On success, the newly accepted socket. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * @code + * void accept_handler(const boost::system::error_code& error, + * boost::asio::ip::tcp::socket peer) + * { + * if (!error) + * { + * // Accept succeeded. + * } + * } + * + * ... + * + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::ip::tcp::endpoint endpoint; + * acceptor.async_accept(my_context2, endpoint, accept_handler); + * @endcode + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(MoveAcceptHandler, + void (boost::system::error_code, + typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other)) + async_accept(ExecutionContext& context, + endpoint_type& peer_endpoint, + BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler, + typename enable_if< + is_convertible::value + >::type* = 0) + { + typedef typename Protocol::socket::template rebind_executor< + typename ExecutionContext::executor_type>::other other_socket_type; + + return async_initiate( + initiate_async_move_accept(), handler, this, + context.get_executor(), &peer_endpoint, + static_cast(0)); + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + +private: + // Disallow copying and assignment. + basic_socket_acceptor(const basic_socket_acceptor&) BOOST_ASIO_DELETED; + basic_socket_acceptor& operator=( + const basic_socket_acceptor&) BOOST_ASIO_DELETED; + + struct initiate_async_wait + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler, + basic_socket_acceptor* self, wait_type w) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WaitHandler. + BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_wait( + self->impl_.get_implementation(), w, handler2.value, + self->impl_.get_implementation_executor()); + } + }; + + struct initiate_async_accept + { + template + void operator()(BOOST_ASIO_MOVE_ARG(AcceptHandler) handler, + basic_socket_acceptor* self, basic_socket* peer, + endpoint_type* peer_endpoint) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a AcceptHandler. + BOOST_ASIO_ACCEPT_HANDLER_CHECK(AcceptHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_accept( + self->impl_.get_implementation(), *peer, peer_endpoint, + handler2.value, self->impl_.get_implementation_executor()); + } + }; + + struct initiate_async_move_accept + { + template + void operator()(BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler, + basic_socket_acceptor* self, const Executor1& peer_ex, + endpoint_type* peer_endpoint, Socket*) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a MoveAcceptHandler. + BOOST_ASIO_MOVE_ACCEPT_HANDLER_CHECK( + MoveAcceptHandler, handler, Socket) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_move_accept( + self->impl_.get_implementation(), peer_ex, peer_endpoint, + handler2.value, self->impl_.get_implementation_executor()); + } + }; + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + detail::io_object_impl< + detail::null_socket_service, Executor> impl_; +#elif defined(BOOST_ASIO_HAS_IOCP) + detail::io_object_impl< + detail::win_iocp_socket_service, Executor> impl_; +#else + detail::io_object_impl< + detail::reactive_socket_service, Executor> impl_; +#endif +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_HPP diff --git a/boost/asio/basic_socket_iostream.hpp b/boost/asio/basic_socket_iostream.hpp new file mode 100644 index 0000000..b6d449d --- /dev/null +++ b/boost/asio/basic_socket_iostream.hpp @@ -0,0 +1,409 @@ +// +// basic_socket_iostream.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BASIC_SOCKET_IOSTREAM_HPP +#define BOOST_ASIO_BASIC_SOCKET_IOSTREAM_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +#include +#include +#include + +#if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +# include + +// A macro that should expand to: +// template +// explicit basic_socket_iostream(T1 x1, ..., Tn xn) +// : std::basic_iostream( +// &this->detail::socket_iostream_base< +// Protocol, Clock, WaitTraits>::streambuf_) +// { +// if (rdbuf()->connect(x1, ..., xn) == 0) +// this->setstate(std::ios_base::failbit); +// } +// This macro should only persist within this file. + +# define BOOST_ASIO_PRIVATE_CTR_DEF(n) \ + template \ + explicit basic_socket_iostream(BOOST_ASIO_VARIADIC_BYVAL_PARAMS(n)) \ + : std::basic_iostream( \ + &this->detail::socket_iostream_base< \ + Protocol, Clock, WaitTraits>::streambuf_) \ + { \ + this->setf(std::ios_base::unitbuf); \ + if (rdbuf()->connect(BOOST_ASIO_VARIADIC_BYVAL_ARGS(n)) == 0) \ + this->setstate(std::ios_base::failbit); \ + } \ + /**/ + +// A macro that should expand to: +// template +// void connect(T1 x1, ..., Tn xn) +// { +// if (rdbuf()->connect(x1, ..., xn) == 0) +// this->setstate(std::ios_base::failbit); +// } +// This macro should only persist within this file. + +# define BOOST_ASIO_PRIVATE_CONNECT_DEF(n) \ + template \ + void connect(BOOST_ASIO_VARIADIC_BYVAL_PARAMS(n)) \ + { \ + if (rdbuf()->connect(BOOST_ASIO_VARIADIC_BYVAL_ARGS(n)) == 0) \ + this->setstate(std::ios_base::failbit); \ + } \ + /**/ + +#endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#include + +namespace boost { +namespace asio { +namespace detail { + +// A separate base class is used to ensure that the streambuf is initialised +// prior to the basic_socket_iostream's basic_iostream base class. +template +class socket_iostream_base +{ +protected: + socket_iostream_base() + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + socket_iostream_base(socket_iostream_base&& other) + : streambuf_(std::move(other.streambuf_)) + { + } + + socket_iostream_base(basic_stream_socket s) + : streambuf_(std::move(s)) + { + } + + socket_iostream_base& operator=(socket_iostream_base&& other) + { + streambuf_ = std::move(other.streambuf_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + basic_socket_streambuf streambuf_; +}; + +} // namespace detail + +#if !defined(BOOST_ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL) +#define BOOST_ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL + +// Forward declaration with defaulted arguments. +template > +#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + typename Clock = chrono::steady_clock, + typename WaitTraits = wait_traits > +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) +class basic_socket_iostream; + +#endif // !defined(BOOST_ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL) + +/// Iostream interface for a socket. +#if defined(GENERATING_DOCUMENTATION) +template > +#else // defined(GENERATING_DOCUMENTATION) +template +#endif // defined(GENERATING_DOCUMENTATION) +class basic_socket_iostream + : private detail::socket_iostream_base, + public std::basic_iostream +{ +private: + // These typedefs are intended keep this class's implementation independent + // of whether it's using Boost.DateClock, Boost.Chrono or std::chrono. +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ + && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + typedef WaitTraits traits_helper; +#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + typedef detail::chrono_time_traits traits_helper; +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + +public: + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// The clock type. + typedef Clock clock_type; + +#if defined(GENERATING_DOCUMENTATION) + /// (Deprecated: Use time_point.) The time type. + typedef typename WaitTraits::time_type time_type; + + /// The time type. + typedef typename WaitTraits::time_point time_point; + + /// (Deprecated: Use duration.) The duration type. + typedef typename WaitTraits::duration_type duration_type; + + /// The duration type. + typedef typename WaitTraits::duration duration; +#else +# if !defined(BOOST_ASIO_NO_DEPRECATED) + typedef typename traits_helper::time_type time_type; + typedef typename traits_helper::duration_type duration_type; +# endif // !defined(BOOST_ASIO_NO_DEPRECATED) + typedef typename traits_helper::time_type time_point; + typedef typename traits_helper::duration_type duration; +#endif + + /// Construct a basic_socket_iostream without establishing a connection. + basic_socket_iostream() + : std::basic_iostream( + &this->detail::socket_iostream_base< + Protocol, Clock, WaitTraits>::streambuf_) + { + this->setf(std::ios_base::unitbuf); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Construct a basic_socket_iostream from the supplied socket. + explicit basic_socket_iostream(basic_stream_socket s) + : detail::socket_iostream_base< + Protocol, Clock, WaitTraits>(std::move(s)), + std::basic_iostream( + &this->detail::socket_iostream_base< + Protocol, Clock, WaitTraits>::streambuf_) + { + this->setf(std::ios_base::unitbuf); + } + +#if defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE) \ + || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_socket_iostream from another. + basic_socket_iostream(basic_socket_iostream&& other) + : detail::socket_iostream_base< + Protocol, Clock, WaitTraits>(std::move(other)), + std::basic_iostream(std::move(other)) + { + this->set_rdbuf(&this->detail::socket_iostream_base< + Protocol, Clock, WaitTraits>::streambuf_); + } + + /// Move-assign a basic_socket_iostream from another. + basic_socket_iostream& operator=(basic_socket_iostream&& other) + { + std::basic_iostream::operator=(std::move(other)); + detail::socket_iostream_base< + Protocol, Clock, WaitTraits>::operator=(std::move(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE) + // || defined(GENERATING_DOCUMENTATION) +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + +#if defined(GENERATING_DOCUMENTATION) + /// Establish a connection to an endpoint corresponding to a resolver query. + /** + * This constructor automatically establishes a connection based on the + * supplied resolver query parameters. The arguments are used to construct + * a resolver query object. + */ + template + explicit basic_socket_iostream(T1 t1, ..., TN tn); +#elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + template + explicit basic_socket_iostream(T... x) + : std::basic_iostream( + &this->detail::socket_iostream_base< + Protocol, Clock, WaitTraits>::streambuf_) + { + this->setf(std::ios_base::unitbuf); + if (rdbuf()->connect(x...) == 0) + this->setstate(std::ios_base::failbit); + } +#else + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CTR_DEF) +#endif + +#if defined(GENERATING_DOCUMENTATION) + /// Establish a connection to an endpoint corresponding to a resolver query. + /** + * This function automatically establishes a connection based on the supplied + * resolver query parameters. The arguments are used to construct a resolver + * query object. + */ + template + void connect(T1 t1, ..., TN tn); +#elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + template + void connect(T... x) + { + if (rdbuf()->connect(x...) == 0) + this->setstate(std::ios_base::failbit); + } +#else + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CONNECT_DEF) +#endif + + /// Close the connection. + void close() + { + if (rdbuf()->close() == 0) + this->setstate(std::ios_base::failbit); + } + + /// Return a pointer to the underlying streambuf. + basic_socket_streambuf* rdbuf() const + { + return const_cast*>( + &this->detail::socket_iostream_base< + Protocol, Clock, WaitTraits>::streambuf_); + } + + /// Get a reference to the underlying socket. + basic_socket& socket() + { + return rdbuf()->socket(); + } + + /// Get the last error associated with the stream. + /** + * @return An \c error_code corresponding to the last error from the stream. + * + * @par Example + * To print the error associated with a failure to establish a connection: + * @code tcp::iostream s("www.boost.org", "http"); + * if (!s) + * { + * std::cout << "Error: " << s.error().message() << std::endl; + * } @endcode + */ + const boost::system::error_code& error() const + { + return rdbuf()->error(); + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use expiry().) Get the stream's expiry time as an absolute + /// time. + /** + * @return An absolute time value representing the stream's expiry time. + */ + time_point expires_at() const + { + return rdbuf()->expires_at(); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Get the stream's expiry time as an absolute time. + /** + * @return An absolute time value representing the stream's expiry time. + */ + time_point expiry() const + { + return rdbuf()->expiry(); + } + + /// Set the stream's expiry time as an absolute time. + /** + * This function sets the expiry time associated with the stream. Stream + * operations performed after this time (where the operations cannot be + * completed using the internal buffers) will fail with the error + * boost::asio::error::operation_aborted. + * + * @param expiry_time The expiry time to be used for the stream. + */ + void expires_at(const time_point& expiry_time) + { + rdbuf()->expires_at(expiry_time); + } + + /// Set the stream's expiry time relative to now. + /** + * This function sets the expiry time associated with the stream. Stream + * operations performed after this time (where the operations cannot be + * completed using the internal buffers) will fail with the error + * boost::asio::error::operation_aborted. + * + * @param expiry_time The expiry time to be used for the timer. + */ + void expires_after(const duration& expiry_time) + { + rdbuf()->expires_after(expiry_time); + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use expiry().) Get the stream's expiry time relative to now. + /** + * @return A relative time value representing the stream's expiry time. + */ + duration expires_from_now() const + { + return rdbuf()->expires_from_now(); + } + + /// (Deprecated: Use expires_after().) Set the stream's expiry time relative + /// to now. + /** + * This function sets the expiry time associated with the stream. Stream + * operations performed after this time (where the operations cannot be + * completed using the internal buffers) will fail with the error + * boost::asio::error::operation_aborted. + * + * @param expiry_time The expiry time to be used for the timer. + */ + void expires_from_now(const duration& expiry_time) + { + rdbuf()->expires_from_now(expiry_time); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +private: + // Disallow copying and assignment. + basic_socket_iostream(const basic_socket_iostream&) BOOST_ASIO_DELETED; + basic_socket_iostream& operator=( + const basic_socket_iostream&) BOOST_ASIO_DELETED; +}; + +} // namespace asio +} // namespace boost + +#include + +#if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +# undef BOOST_ASIO_PRIVATE_CTR_DEF +# undef BOOST_ASIO_PRIVATE_CONNECT_DEF +#endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +#endif // BOOST_ASIO_BASIC_SOCKET_IOSTREAM_HPP diff --git a/boost/asio/basic_socket_streambuf.hpp b/boost/asio/basic_socket_streambuf.hpp new file mode 100644 index 0000000..9910602 --- /dev/null +++ b/boost/asio/basic_socket_streambuf.hpp @@ -0,0 +1,689 @@ +// +// basic_socket_streambuf.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP +#define BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ + && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) +# include +#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) +# include +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + +#if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +# include + +// A macro that should expand to: +// template +// basic_socket_streambuf* connect(T1 x1, ..., Tn xn) +// { +// init_buffers(); +// typedef typename Protocol::resolver resolver_type; +// resolver_type resolver(socket().get_executor()); +// connect_to_endpoints( +// resolver.resolve(x1, ..., xn, ec_)); +// return !ec_ ? this : 0; +// } +// This macro should only persist within this file. + +# define BOOST_ASIO_PRIVATE_CONNECT_DEF(n) \ + template \ + basic_socket_streambuf* connect(BOOST_ASIO_VARIADIC_BYVAL_PARAMS(n)) \ + { \ + init_buffers(); \ + typedef typename Protocol::resolver resolver_type; \ + resolver_type resolver(socket().get_executor()); \ + connect_to_endpoints( \ + resolver.resolve(BOOST_ASIO_VARIADIC_BYVAL_ARGS(n), ec_)); \ + return !ec_ ? this : 0; \ + } \ + /**/ + +#endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#include + +namespace boost { +namespace asio { +namespace detail { + +// A separate base class is used to ensure that the io_context member is +// initialised prior to the basic_socket_streambuf's basic_socket base class. +class socket_streambuf_io_context +{ +protected: + socket_streambuf_io_context(io_context* ctx) + : default_io_context_(ctx) + { + } + + shared_ptr default_io_context_; +}; + +// A separate base class is used to ensure that the dynamically allocated +// buffers are constructed prior to the basic_socket_streambuf's basic_socket +// base class. This makes moving the socket is the last potentially throwing +// step in the streambuf's move constructor, giving the constructor a strong +// exception safety guarantee. +class socket_streambuf_buffers +{ +protected: + socket_streambuf_buffers() + : get_buffer_(buffer_size), + put_buffer_(buffer_size) + { + } + + enum { buffer_size = 512 }; + std::vector get_buffer_; + std::vector put_buffer_; +}; + +} // namespace detail + +#if !defined(BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL) +#define BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL + +// Forward declaration with defaulted arguments. +template > +#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + typename Clock = chrono::steady_clock, + typename WaitTraits = wait_traits > +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) +class basic_socket_streambuf; + +#endif // !defined(BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL) + +/// Iostream streambuf for a socket. +#if defined(GENERATING_DOCUMENTATION) +template > +#else // defined(GENERATING_DOCUMENTATION) +template +#endif // defined(GENERATING_DOCUMENTATION) +class basic_socket_streambuf + : public std::streambuf, + private detail::socket_streambuf_io_context, + private detail::socket_streambuf_buffers, +#if defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + private basic_socket +#else // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + public basic_socket +#endif // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) +{ +private: + // These typedefs are intended keep this class's implementation independent + // of whether it's using Boost.DateClock, Boost.Chrono or std::chrono. +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ + && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + typedef WaitTraits traits_helper; +#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + typedef detail::chrono_time_traits traits_helper; +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + +public: + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// The clock type. + typedef Clock clock_type; + +#if defined(GENERATING_DOCUMENTATION) + /// (Deprecated: Use time_point.) The time type. + typedef typename WaitTraits::time_type time_type; + + /// The time type. + typedef typename WaitTraits::time_point time_point; + + /// (Deprecated: Use duration.) The duration type. + typedef typename WaitTraits::duration_type duration_type; + + /// The duration type. + typedef typename WaitTraits::duration duration; +#else +# if !defined(BOOST_ASIO_NO_DEPRECATED) + typedef typename traits_helper::time_type time_type; + typedef typename traits_helper::duration_type duration_type; +# endif // !defined(BOOST_ASIO_NO_DEPRECATED) + typedef typename traits_helper::time_type time_point; + typedef typename traits_helper::duration_type duration; +#endif + + /// Construct a basic_socket_streambuf without establishing a connection. + basic_socket_streambuf() + : detail::socket_streambuf_io_context(new io_context), + basic_socket(*default_io_context_), + expiry_time_(max_expiry_time()) + { + init_buffers(); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Construct a basic_socket_streambuf from the supplied socket. + explicit basic_socket_streambuf(basic_stream_socket s) + : detail::socket_streambuf_io_context(0), + basic_socket(std::move(s)), + expiry_time_(max_expiry_time()) + { + init_buffers(); + } + + /// Move-construct a basic_socket_streambuf from another. + basic_socket_streambuf(basic_socket_streambuf&& other) + : detail::socket_streambuf_io_context(other), + basic_socket(std::move(other.socket())), + ec_(other.ec_), + expiry_time_(other.expiry_time_) + { + get_buffer_.swap(other.get_buffer_); + put_buffer_.swap(other.put_buffer_); + setg(other.eback(), other.gptr(), other.egptr()); + setp(other.pptr(), other.epptr()); + other.ec_ = boost::system::error_code(); + other.expiry_time_ = max_expiry_time(); + other.init_buffers(); + } + + /// Move-assign a basic_socket_streambuf from another. + basic_socket_streambuf& operator=(basic_socket_streambuf&& other) + { + this->close(); + socket() = std::move(other.socket()); + detail::socket_streambuf_io_context::operator=(other); + ec_ = other.ec_; + expiry_time_ = other.expiry_time_; + get_buffer_.swap(other.get_buffer_); + put_buffer_.swap(other.put_buffer_); + setg(other.eback(), other.gptr(), other.egptr()); + setp(other.pptr(), other.epptr()); + other.ec_ = boost::system::error_code(); + other.expiry_time_ = max_expiry_time(); + other.put_buffer_.resize(buffer_size); + other.init_buffers(); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destructor flushes buffered data. + virtual ~basic_socket_streambuf() + { + if (pptr() != pbase()) + overflow(traits_type::eof()); + } + + /// Establish a connection. + /** + * This function establishes a connection to the specified endpoint. + * + * @return \c this if a connection was successfully established, a null + * pointer otherwise. + */ + basic_socket_streambuf* connect(const endpoint_type& endpoint) + { + init_buffers(); + ec_ = boost::system::error_code(); + this->connect_to_endpoints(&endpoint, &endpoint + 1); + return !ec_ ? this : 0; + } + +#if defined(GENERATING_DOCUMENTATION) + /// Establish a connection. + /** + * This function automatically establishes a connection based on the supplied + * resolver query parameters. The arguments are used to construct a resolver + * query object. + * + * @return \c this if a connection was successfully established, a null + * pointer otherwise. + */ + template + basic_socket_streambuf* connect(T1 t1, ..., TN tn); +#elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + template + basic_socket_streambuf* connect(T... x) + { + init_buffers(); + typedef typename Protocol::resolver resolver_type; + resolver_type resolver(socket().get_executor()); + connect_to_endpoints(resolver.resolve(x..., ec_)); + return !ec_ ? this : 0; + } +#else + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CONNECT_DEF) +#endif + + /// Close the connection. + /** + * @return \c this if a connection was successfully established, a null + * pointer otherwise. + */ + basic_socket_streambuf* close() + { + sync(); + socket().close(ec_); + if (!ec_) + init_buffers(); + return !ec_ ? this : 0; + } + + /// Get a reference to the underlying socket. + basic_socket& socket() + { + return *this; + } + + /// Get the last error associated with the stream buffer. + /** + * @return An \c error_code corresponding to the last error from the stream + * buffer. + */ + const boost::system::error_code& error() const + { + return ec_; + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use error().) Get the last error associated with the stream + /// buffer. + /** + * @return An \c error_code corresponding to the last error from the stream + * buffer. + */ + const boost::system::error_code& puberror() const + { + return error(); + } + + /// (Deprecated: Use expiry().) Get the stream buffer's expiry time as an + /// absolute time. + /** + * @return An absolute time value representing the stream buffer's expiry + * time. + */ + time_point expires_at() const + { + return expiry_time_; + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Get the stream buffer's expiry time as an absolute time. + /** + * @return An absolute time value representing the stream buffer's expiry + * time. + */ + time_point expiry() const + { + return expiry_time_; + } + + /// Set the stream buffer's expiry time as an absolute time. + /** + * This function sets the expiry time associated with the stream. Stream + * operations performed after this time (where the operations cannot be + * completed using the internal buffers) will fail with the error + * boost::asio::error::operation_aborted. + * + * @param expiry_time The expiry time to be used for the stream. + */ + void expires_at(const time_point& expiry_time) + { + expiry_time_ = expiry_time; + } + + /// Set the stream buffer's expiry time relative to now. + /** + * This function sets the expiry time associated with the stream. Stream + * operations performed after this time (where the operations cannot be + * completed using the internal buffers) will fail with the error + * boost::asio::error::operation_aborted. + * + * @param expiry_time The expiry time to be used for the timer. + */ + void expires_after(const duration& expiry_time) + { + expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time); + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use expiry().) Get the stream buffer's expiry time relative + /// to now. + /** + * @return A relative time value representing the stream buffer's expiry time. + */ + duration expires_from_now() const + { + return traits_helper::subtract(expires_at(), traits_helper::now()); + } + + /// (Deprecated: Use expires_after().) Set the stream buffer's expiry time + /// relative to now. + /** + * This function sets the expiry time associated with the stream. Stream + * operations performed after this time (where the operations cannot be + * completed using the internal buffers) will fail with the error + * boost::asio::error::operation_aborted. + * + * @param expiry_time The expiry time to be used for the timer. + */ + void expires_from_now(const duration& expiry_time) + { + expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +protected: + int_type underflow() + { +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + ec_ = boost::asio::error::operation_not_supported; + return traits_type::eof(); +#else // defined(BOOST_ASIO_WINDOWS_RUNTIME) + if (gptr() != egptr()) + return traits_type::eof(); + + for (;;) + { + // Check if we are past the expiry time. + if (traits_helper::less_than(expiry_time_, traits_helper::now())) + { + ec_ = boost::asio::error::timed_out; + return traits_type::eof(); + } + + // Try to complete the operation without blocking. + if (!socket().native_non_blocking()) + socket().native_non_blocking(true, ec_); + detail::buffer_sequence_adapter + bufs(boost::asio::buffer(get_buffer_) + putback_max); + detail::signed_size_type bytes = detail::socket_ops::recv( + socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_); + + // Check if operation succeeded. + if (bytes > 0) + { + setg(&get_buffer_[0], &get_buffer_[0] + putback_max, + &get_buffer_[0] + putback_max + bytes); + return traits_type::to_int_type(*gptr()); + } + + // Check for EOF. + if (bytes == 0) + { + ec_ = boost::asio::error::eof; + return traits_type::eof(); + } + + // Operation failed. + if (ec_ != boost::asio::error::would_block + && ec_ != boost::asio::error::try_again) + return traits_type::eof(); + + // Wait for socket to become ready. + if (detail::socket_ops::poll_read( + socket().native_handle(), 0, timeout(), ec_) < 0) + return traits_type::eof(); + } +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + } + + int_type overflow(int_type c) + { +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + ec_ = boost::asio::error::operation_not_supported; + return traits_type::eof(); +#else // defined(BOOST_ASIO_WINDOWS_RUNTIME) + char_type ch = traits_type::to_char_type(c); + + // Determine what needs to be sent. + const_buffer output_buffer; + if (put_buffer_.empty()) + { + if (traits_type::eq_int_type(c, traits_type::eof())) + return traits_type::not_eof(c); // Nothing to do. + output_buffer = boost::asio::buffer(&ch, sizeof(char_type)); + } + else + { + output_buffer = boost::asio::buffer(pbase(), + (pptr() - pbase()) * sizeof(char_type)); + } + + while (output_buffer.size() > 0) + { + // Check if we are past the expiry time. + if (traits_helper::less_than(expiry_time_, traits_helper::now())) + { + ec_ = boost::asio::error::timed_out; + return traits_type::eof(); + } + + // Try to complete the operation without blocking. + if (!socket().native_non_blocking()) + socket().native_non_blocking(true, ec_); + detail::buffer_sequence_adapter< + const_buffer, const_buffer> bufs(output_buffer); + detail::signed_size_type bytes = detail::socket_ops::send( + socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_); + + // Check if operation succeeded. + if (bytes > 0) + { + output_buffer += static_cast(bytes); + continue; + } + + // Operation failed. + if (ec_ != boost::asio::error::would_block + && ec_ != boost::asio::error::try_again) + return traits_type::eof(); + + // Wait for socket to become ready. + if (detail::socket_ops::poll_write( + socket().native_handle(), 0, timeout(), ec_) < 0) + return traits_type::eof(); + } + + if (!put_buffer_.empty()) + { + setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size()); + + // If the new character is eof then our work here is done. + if (traits_type::eq_int_type(c, traits_type::eof())) + return traits_type::not_eof(c); + + // Add the new character to the output buffer. + *pptr() = ch; + pbump(1); + } + + return c; +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + } + + int sync() + { + return overflow(traits_type::eof()); + } + + std::streambuf* setbuf(char_type* s, std::streamsize n) + { + if (pptr() == pbase() && s == 0 && n == 0) + { + put_buffer_.clear(); + setp(0, 0); + sync(); + return this; + } + + return 0; + } + +private: + // Disallow copying and assignment. + basic_socket_streambuf(const basic_socket_streambuf&) BOOST_ASIO_DELETED; + basic_socket_streambuf& operator=( + const basic_socket_streambuf&) BOOST_ASIO_DELETED; + + void init_buffers() + { + setg(&get_buffer_[0], + &get_buffer_[0] + putback_max, + &get_buffer_[0] + putback_max); + + if (put_buffer_.empty()) + setp(0, 0); + else + setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size()); + } + + int timeout() const + { + int64_t msec = traits_helper::to_posix_duration( + traits_helper::subtract(expiry_time_, + traits_helper::now())).total_milliseconds(); + if (msec > (std::numeric_limits::max)()) + msec = (std::numeric_limits::max)(); + else if (msec < 0) + msec = 0; + return static_cast(msec); + } + + template + void connect_to_endpoints(const EndpointSequence& endpoints) + { + this->connect_to_endpoints(endpoints.begin(), endpoints.end()); + } + + template + void connect_to_endpoints(EndpointIterator begin, EndpointIterator end) + { +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + ec_ = boost::asio::error::operation_not_supported; +#else // defined(BOOST_ASIO_WINDOWS_RUNTIME) + if (ec_) + return; + + ec_ = boost::asio::error::not_found; + for (EndpointIterator i = begin; i != end; ++i) + { + // Check if we are past the expiry time. + if (traits_helper::less_than(expiry_time_, traits_helper::now())) + { + ec_ = boost::asio::error::timed_out; + return; + } + + // Close and reopen the socket. + typename Protocol::endpoint ep(*i); + socket().close(ec_); + socket().open(ep.protocol(), ec_); + if (ec_) + continue; + + // Try to complete the operation without blocking. + if (!socket().native_non_blocking()) + socket().native_non_blocking(true, ec_); + detail::socket_ops::connect(socket().native_handle(), + ep.data(), ep.size(), ec_); + + // Check if operation succeeded. + if (!ec_) + return; + + // Operation failed. + if (ec_ != boost::asio::error::in_progress + && ec_ != boost::asio::error::would_block) + continue; + + // Wait for socket to become ready. + if (detail::socket_ops::poll_connect( + socket().native_handle(), timeout(), ec_) < 0) + continue; + + // Get the error code from the connect operation. + int connect_error = 0; + size_t connect_error_len = sizeof(connect_error); + if (detail::socket_ops::getsockopt(socket().native_handle(), 0, + SOL_SOCKET, SO_ERROR, &connect_error, &connect_error_len, ec_) + == detail::socket_error_retval) + return; + + // Check the result of the connect operation. + ec_ = boost::system::error_code(connect_error, + boost::asio::error::get_system_category()); + if (!ec_) + return; + } +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + } + + // Helper function to get the maximum expiry time. + static time_point max_expiry_time() + { +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ + && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + return boost::posix_time::pos_infin; +#else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + return (time_point::max)(); +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) + } + + enum { putback_max = 8 }; + boost::system::error_code ec_; + time_point expiry_time_; +}; + +} // namespace asio +} // namespace boost + +#include + +#if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +# undef BOOST_ASIO_PRIVATE_CONNECT_DEF +#endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +#endif // BOOST_ASIO_BASIC_SOCKET_STREAMBUF_HPP diff --git a/boost/asio/basic_stream_socket.hpp b/boost/asio/basic_stream_socket.hpp new file mode 100644 index 0000000..18d9dac --- /dev/null +++ b/boost/asio/basic_stream_socket.hpp @@ -0,0 +1,995 @@ +// +// basic_stream_socket.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BASIC_STREAM_SOCKET_HPP +#define BOOST_ASIO_BASIC_STREAM_SOCKET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +#if !defined(BOOST_ASIO_BASIC_STREAM_SOCKET_FWD_DECL) +#define BOOST_ASIO_BASIC_STREAM_SOCKET_FWD_DECL + +// Forward declaration with defaulted arguments. +template +class basic_stream_socket; + +#endif // !defined(BOOST_ASIO_BASIC_STREAM_SOCKET_FWD_DECL) + +/// Provides stream-oriented socket functionality. +/** + * The basic_stream_socket class template provides asynchronous and blocking + * stream-oriented socket functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Concepts: + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. + */ +template +class basic_stream_socket + : public basic_socket +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// Rebinds the socket type to another executor. + template + struct rebind_executor + { + /// The socket type when rebound to the specified executor. + typedef basic_stream_socket other; + }; + + /// The native representation of a socket. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef typename basic_socket::native_handle_type native_handle_type; +#endif + + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// Construct a basic_stream_socket without opening it. + /** + * This constructor creates a stream socket without opening it. The socket + * needs to be opened and then connected or accepted before data can be sent + * or received on it. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + */ + explicit basic_stream_socket(const executor_type& ex) + : basic_socket(ex) + { + } + + /// Construct a basic_stream_socket without opening it. + /** + * This constructor creates a stream socket without opening it. The socket + * needs to be opened and then connected or accepted before data can be sent + * or received on it. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + */ + template + explicit basic_stream_socket(ExecutionContext& context, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_socket(context) + { + } + + /// Construct and open a basic_stream_socket. + /** + * This constructor creates and opens a stream socket. The socket needs to be + * connected or accepted before data can be sent or received on it. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_stream_socket(const executor_type& ex, const protocol_type& protocol) + : basic_socket(ex, protocol) + { + } + + /// Construct and open a basic_stream_socket. + /** + * This constructor creates and opens a stream socket. The socket needs to be + * connected or accepted before data can be sent or received on it. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_stream_socket(ExecutionContext& context, const protocol_type& protocol, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_socket(context, protocol) + { + } + + /// Construct a basic_stream_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a stream socket and automatically opens it bound + * to the specified endpoint on the local machine. The protocol used is the + * protocol associated with the given endpoint. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the stream + * socket will be bound. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_stream_socket(const executor_type& ex, const endpoint_type& endpoint) + : basic_socket(ex, endpoint) + { + } + + /// Construct a basic_stream_socket, opening it and binding it to the given + /// local endpoint. + /** + * This constructor creates a stream socket and automatically opens it bound + * to the specified endpoint on the local machine. The protocol used is the + * protocol associated with the given endpoint. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param endpoint An endpoint on the local machine to which the stream + * socket will be bound. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_stream_socket(ExecutionContext& context, const endpoint_type& endpoint, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_socket(context, endpoint) + { + } + + /// Construct a basic_stream_socket on an existing native socket. + /** + * This constructor creates a stream socket object to hold an existing native + * socket. + * + * @param ex The I/O executor that the socket will use, by default, to + * dispatch handlers for any asynchronous operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_stream_socket(const executor_type& ex, + const protocol_type& protocol, const native_handle_type& native_socket) + : basic_socket(ex, protocol, native_socket) + { + } + + /// Construct a basic_stream_socket on an existing native socket. + /** + * This constructor creates a stream socket object to hold an existing native + * socket. + * + * @param context An execution context which provides the I/O executor that + * the socket will use, by default, to dispatch handlers for any asynchronous + * operations performed on the socket. + * + * @param protocol An object specifying protocol parameters to be used. + * + * @param native_socket The new underlying socket implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_stream_socket(ExecutionContext& context, + const protocol_type& protocol, const native_handle_type& native_socket, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_socket(context, protocol, native_socket) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_stream_socket from another. + /** + * This constructor moves a stream socket from one object to another. + * + * @param other The other basic_stream_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_socket(const executor_type&) + * constructor. + */ + basic_stream_socket(basic_stream_socket&& other) + : basic_socket(std::move(other)) + { + } + + /// Move-assign a basic_stream_socket from another. + /** + * This assignment operator moves a stream socket from one object to another. + * + * @param other The other basic_stream_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_socket(const executor_type&) + * constructor. + */ + basic_stream_socket& operator=(basic_stream_socket&& other) + { + basic_socket::operator=(std::move(other)); + return *this; + } + + /// Move-construct a basic_stream_socket from a socket of another protocol + /// type. + /** + * This constructor moves a stream socket from one object to another. + * + * @param other The other basic_stream_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_socket(const executor_type&) + * constructor. + */ + template + basic_stream_socket(basic_stream_socket&& other, + typename enable_if< + is_convertible::value + && is_convertible::value + >::type* = 0) + : basic_socket(std::move(other)) + { + } + + /// Move-assign a basic_stream_socket from a socket of another protocol type. + /** + * This assignment operator moves a stream socket from one object to another. + * + * @param other The other basic_stream_socket object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_socket(const executor_type&) + * constructor. + */ + template + typename enable_if< + is_convertible::value + && is_convertible::value, + basic_stream_socket& + >::type operator=(basic_stream_socket&& other) + { + basic_socket::operator=(std::move(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the socket. + /** + * This function destroys the socket, cancelling any outstanding asynchronous + * operations associated with the socket as if by calling @c cancel. + */ + ~basic_stream_socket() + { + } + + /// Send some data on the socket. + /** + * This function is used to send data on the stream socket. The function + * call will block until one or more bytes of the data has been sent + * successfully, or an until error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. + * + * @returns The number of bytes sent. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The send operation may not transmit all of the data to the peer. + * Consider using the @ref write function if you need to ensure that all data + * is written before the blocking operation completes. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.send(boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t send(const ConstBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, 0, ec); + boost::asio::detail::throw_error(ec, "send"); + return s; + } + + /// Send some data on the socket. + /** + * This function is used to send data on the stream socket. The function + * call will block until one or more bytes of the data has been sent + * successfully, or an until error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @returns The number of bytes sent. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The send operation may not transmit all of the data to the peer. + * Consider using the @ref write function if you need to ensure that all data + * is written before the blocking operation completes. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.send(boost::asio::buffer(data, size), 0); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); + boost::asio::detail::throw_error(ec, "send"); + return s; + } + + /// Send some data on the socket. + /** + * This function is used to send data on the stream socket. The function + * call will block until one or more bytes of the data has been sent + * successfully, or an until error occurs. + * + * @param buffers One or more data buffers to be sent on the socket. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes sent. Returns 0 if an error occurred. + * + * @note The send operation may not transmit all of the data to the peer. + * Consider using the @ref write function if you need to ensure that all data + * is written before the blocking operation completes. + */ + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + return this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, flags, ec); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send data on the stream socket. + * The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent on the socket. Although + * the buffers object may be copied as necessary, ownership of the underlying + * memory blocks is retained by the caller, which must guarantee that they + * remain valid until the handler is called. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The send operation may not transmit all of the data to the peer. + * Consider using the @ref async_write function if you need to ensure that all + * data is written before the asynchronous operation completes. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_send(boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_send(const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + return async_initiate( + initiate_async_send(), handler, this, + buffers, socket_base::message_flags(0)); + } + + /// Start an asynchronous send. + /** + * This function is used to asynchronously send data on the stream socket. + * The function call always returns immediately. + * + * @param buffers One or more data buffers to be sent on the socket. Although + * the buffers object may be copied as necessary, ownership of the underlying + * memory blocks is retained by the caller, which must guarantee that they + * remain valid until the handler is called. + * + * @param flags Flags specifying how the send call is to be made. + * + * @param handler The handler to be called when the send operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The send operation may not transmit all of the data to the peer. + * Consider using the @ref async_write function if you need to ensure that all + * data is written before the asynchronous operation completes. + * + * @par Example + * To send a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_send(boost::asio::buffer(data, size), 0, handler); + * @endcode + * See the @ref buffer documentation for information on sending multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + return async_initiate( + initiate_async_send(), handler, this, buffers, flags); + } + + /// Receive some data on the socket. + /** + * This function is used to receive data on the stream socket. The function + * call will block until one or more bytes of data has been received + * successfully, or until an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The receive operation may not receive all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that the + * requested amount of data is read before the blocking operation completes. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.receive(boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive(const MutableBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, 0, ec); + boost::asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on the socket. + /** + * This function is used to receive data on the stream socket. The function + * call will block until one or more bytes of data has been received + * successfully, or until an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @returns The number of bytes received. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The receive operation may not receive all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that the + * requested amount of data is read before the blocking operation completes. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.receive(boost::asio::buffer(data, size), 0); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, flags, ec); + boost::asio::detail::throw_error(ec, "receive"); + return s; + } + + /// Receive some data on a connected socket. + /** + * This function is used to receive data on the stream socket. The function + * call will block until one or more bytes of data has been received + * successfully, or until an error occurs. + * + * @param buffers One or more buffers into which the data will be received. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes received. Returns 0 if an error occurred. + * + * @note The receive operation may not receive all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that the + * requested amount of data is read before the blocking operation completes. + */ + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + return this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, flags, ec); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive data from the stream + * socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The receive operation may not receive all of the requested number of + * bytes. Consider using the @ref async_read function if you need to ensure + * that the requested amount of data is received before the asynchronous + * operation completes. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.async_receive(boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + return async_initiate( + initiate_async_receive(), handler, this, + buffers, socket_base::message_flags(0)); + } + + /// Start an asynchronous receive. + /** + * This function is used to asynchronously receive data from the stream + * socket. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be received. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param flags Flags specifying how the receive call is to be made. + * + * @param handler The handler to be called when the receive operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The receive operation may not receive all of the requested number of + * bytes. Consider using the @ref async_read function if you need to ensure + * that the requested amount of data is received before the asynchronous + * operation completes. + * + * @par Example + * To receive into a single data buffer use the @ref buffer function as + * follows: + * @code + * socket.async_receive(boost::asio::buffer(data, size), 0, handler); + * @endcode + * See the @ref buffer documentation for information on receiving into + * multiple buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + return async_initiate( + initiate_async_receive(), handler, this, buffers, flags); + } + + /// Write some data to the socket. + /** + * This function is used to write data to the stream socket. The function call + * will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the socket. + * + * @returns The number of bytes written. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * socket.write_some(boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t write_some(const ConstBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, 0, ec); + boost::asio::detail::throw_error(ec, "write_some"); + return s; + } + + /// Write some data to the socket. + /** + * This function is used to write data to the stream socket. The function call + * will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the socket. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. Returns 0 if an error occurred. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + */ + template + std::size_t write_some(const ConstBufferSequence& buffers, + boost::system::error_code& ec) + { + return this->impl_.get_service().send( + this->impl_.get_implementation(), buffers, 0, ec); + } + + /// Start an asynchronous write. + /** + * This function is used to asynchronously write data to the stream socket. + * The function call always returns immediately. + * + * @param buffers One or more data buffers to be written to the socket. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes written. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The write operation may not transmit all of the data to the peer. + * Consider using the @ref async_write function if you need to ensure that all + * data is written before the asynchronous operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_write_some(boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_write_some(const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + return async_initiate( + initiate_async_send(), handler, this, + buffers, socket_base::message_flags(0)); + } + + /// Read some data from the socket. + /** + * This function is used to read data from the stream socket. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @returns The number of bytes read. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * socket.read_some(boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t read_some(const MutableBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, 0, ec); + boost::asio::detail::throw_error(ec, "read_some"); + return s; + } + + /// Read some data from the socket. + /** + * This function is used to read data from the stream socket. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. Returns 0 if an error occurred. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + */ + template + std::size_t read_some(const MutableBufferSequence& buffers, + boost::system::error_code& ec) + { + return this->impl_.get_service().receive( + this->impl_.get_implementation(), buffers, 0, ec); + } + + /// Start an asynchronous read. + /** + * This function is used to asynchronously read data from the stream socket. + * The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes read. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The read operation may not read all of the requested number of bytes. + * Consider using the @ref async_read function if you need to ensure that the + * requested amount of data is read before the asynchronous operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * socket.async_read_some(boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_read_some(const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + return async_initiate( + initiate_async_receive(), handler, this, + buffers, socket_base::message_flags(0)); + } + +private: + struct initiate_async_send + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + basic_stream_socket* self, const ConstBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_send( + self->impl_.get_implementation(), buffers, flags, + handler2.value, self->impl_.get_implementation_executor()); + } + }; + + struct initiate_async_receive + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + basic_stream_socket* self, const MutableBufferSequence& buffers, + socket_base::message_flags flags) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_receive( + self->impl_.get_implementation(), buffers, flags, + handler2.value, self->impl_.get_implementation_executor()); + } + }; +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BASIC_STREAM_SOCKET_HPP diff --git a/boost/asio/basic_streambuf.hpp b/boost/asio/basic_streambuf.hpp new file mode 100644 index 0000000..e2e9bf9 --- /dev/null +++ b/boost/asio/basic_streambuf.hpp @@ -0,0 +1,454 @@ +// +// basic_streambuf.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BASIC_STREAMBUF_HPP +#define BOOST_ASIO_BASIC_STREAMBUF_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +/// Automatically resizable buffer class based on std::streambuf. +/** + * The @c basic_streambuf class is derived from @c std::streambuf to associate + * the streambuf's input and output sequences with one or more character + * arrays. These character arrays are internal to the @c basic_streambuf + * object, but direct access to the array elements is provided to permit them + * to be used efficiently with I/O operations. Characters written to the output + * sequence of a @c basic_streambuf object are appended to the input sequence + * of the same object. + * + * The @c basic_streambuf class's public interface is intended to permit the + * following implementation strategies: + * + * @li A single contiguous character array, which is reallocated as necessary + * to accommodate changes in the size of the character sequence. This is the + * implementation approach currently used in Asio. + * + * @li A sequence of one or more character arrays, where each array is of the + * same size. Additional character array objects are appended to the sequence + * to accommodate changes in the size of the character sequence. + * + * @li A sequence of one or more character arrays of varying sizes. Additional + * character array objects are appended to the sequence to accommodate changes + * in the size of the character sequence. + * + * The constructor for basic_streambuf accepts a @c size_t argument specifying + * the maximum of the sum of the sizes of the input sequence and output + * sequence. During the lifetime of the @c basic_streambuf object, the following + * invariant holds: + * @code size() <= max_size()@endcode + * Any member function that would, if successful, cause the invariant to be + * violated shall throw an exception of class @c std::length_error. + * + * The constructor for @c basic_streambuf takes an Allocator argument. A copy + * of this argument is used for any memory allocation performed, by the + * constructor and by all member functions, during the lifetime of each @c + * basic_streambuf object. + * + * @par Examples + * Writing directly from an streambuf to a socket: + * @code + * boost::asio::streambuf b; + * std::ostream os(&b); + * os << "Hello, World!\n"; + * + * // try sending some data in input sequence + * size_t n = sock.send(b.data()); + * + * b.consume(n); // sent data is removed from input sequence + * @endcode + * + * Reading from a socket directly into a streambuf: + * @code + * boost::asio::streambuf b; + * + * // reserve 512 bytes in output sequence + * boost::asio::streambuf::mutable_buffers_type bufs = b.prepare(512); + * + * size_t n = sock.receive(bufs); + * + * // received data is "committed" from output sequence to input sequence + * b.commit(n); + * + * std::istream is(&b); + * std::string s; + * is >> s; + * @endcode + */ +#if defined(GENERATING_DOCUMENTATION) +template > +#else +template +#endif +class basic_streambuf + : public std::streambuf, + private noncopyable +{ +public: +#if defined(GENERATING_DOCUMENTATION) + /// The type used to represent the input sequence as a list of buffers. + typedef implementation_defined const_buffers_type; + + /// The type used to represent the output sequence as a list of buffers. + typedef implementation_defined mutable_buffers_type; +#else + typedef BOOST_ASIO_CONST_BUFFER const_buffers_type; + typedef BOOST_ASIO_MUTABLE_BUFFER mutable_buffers_type; +#endif + + /// Construct a basic_streambuf object. + /** + * Constructs a streambuf with the specified maximum size. The initial size + * of the streambuf's input sequence is 0. + */ + explicit basic_streambuf( + std::size_t maximum_size = (std::numeric_limits::max)(), + const Allocator& allocator = Allocator()) + : max_size_(maximum_size), + buffer_(allocator) + { + std::size_t pend = (std::min)(max_size_, buffer_delta); + buffer_.resize((std::max)(pend, 1)); + setg(&buffer_[0], &buffer_[0], &buffer_[0]); + setp(&buffer_[0], &buffer_[0] + pend); + } + + /// Get the size of the input sequence. + /** + * @returns The size of the input sequence. The value is equal to that + * calculated for @c s in the following code: + * @code + * size_t s = 0; + * const_buffers_type bufs = data(); + * const_buffers_type::const_iterator i = bufs.begin(); + * while (i != bufs.end()) + * { + * const_buffer buf(*i++); + * s += buf.size(); + * } + * @endcode + */ + std::size_t size() const BOOST_ASIO_NOEXCEPT + { + return pptr() - gptr(); + } + + /// Get the maximum size of the basic_streambuf. + /** + * @returns The allowed maximum of the sum of the sizes of the input sequence + * and output sequence. + */ + std::size_t max_size() const BOOST_ASIO_NOEXCEPT + { + return max_size_; + } + + /// Get the current capacity of the basic_streambuf. + /** + * @returns The current total capacity of the streambuf, i.e. for both the + * input sequence and output sequence. + */ + std::size_t capacity() const BOOST_ASIO_NOEXCEPT + { + return buffer_.capacity(); + } + + /// Get a list of buffers that represents the input sequence. + /** + * @returns An object of type @c const_buffers_type that satisfies + * ConstBufferSequence requirements, representing all character arrays in the + * input sequence. + * + * @note The returned object is invalidated by any @c basic_streambuf member + * function that modifies the input sequence or output sequence. + */ + const_buffers_type data() const BOOST_ASIO_NOEXCEPT + { + return boost::asio::buffer(boost::asio::const_buffer(gptr(), + (pptr() - gptr()) * sizeof(char_type))); + } + + /// Get a list of buffers that represents the output sequence, with the given + /// size. + /** + * Ensures that the output sequence can accommodate @c n characters, + * reallocating character array objects as necessary. + * + * @returns An object of type @c mutable_buffers_type that satisfies + * MutableBufferSequence requirements, representing character array objects + * at the start of the output sequence such that the sum of the buffer sizes + * is @c n. + * + * @throws std::length_error If size() + n > max_size(). + * + * @note The returned object is invalidated by any @c basic_streambuf member + * function that modifies the input sequence or output sequence. + */ + mutable_buffers_type prepare(std::size_t n) + { + reserve(n); + return boost::asio::buffer(boost::asio::mutable_buffer( + pptr(), n * sizeof(char_type))); + } + + /// Move characters from the output sequence to the input sequence. + /** + * Appends @c n characters from the start of the output sequence to the input + * sequence. The beginning of the output sequence is advanced by @c n + * characters. + * + * Requires a preceding call prepare(x) where x >= n, and + * no intervening operations that modify the input or output sequence. + * + * @note If @c n is greater than the size of the output sequence, the entire + * output sequence is moved to the input sequence and no error is issued. + */ + void commit(std::size_t n) + { + n = std::min(n, epptr() - pptr()); + pbump(static_cast(n)); + setg(eback(), gptr(), pptr()); + } + + /// Remove characters from the input sequence. + /** + * Removes @c n characters from the beginning of the input sequence. + * + * @note If @c n is greater than the size of the input sequence, the entire + * input sequence is consumed and no error is issued. + */ + void consume(std::size_t n) + { + if (egptr() < pptr()) + setg(&buffer_[0], gptr(), pptr()); + if (gptr() + n > pptr()) + n = pptr() - gptr(); + gbump(static_cast(n)); + } + +protected: + enum { buffer_delta = 128 }; + + /// Override std::streambuf behaviour. + /** + * Behaves according to the specification of @c std::streambuf::underflow(). + */ + int_type underflow() + { + if (gptr() < pptr()) + { + setg(&buffer_[0], gptr(), pptr()); + return traits_type::to_int_type(*gptr()); + } + else + { + return traits_type::eof(); + } + } + + /// Override std::streambuf behaviour. + /** + * Behaves according to the specification of @c std::streambuf::overflow(), + * with the specialisation that @c std::length_error is thrown if appending + * the character to the input sequence would require the condition + * size() > max_size() to be true. + */ + int_type overflow(int_type c) + { + if (!traits_type::eq_int_type(c, traits_type::eof())) + { + if (pptr() == epptr()) + { + std::size_t buffer_size = pptr() - gptr(); + if (buffer_size < max_size_ && max_size_ - buffer_size < buffer_delta) + { + reserve(max_size_ - buffer_size); + } + else + { + reserve(buffer_delta); + } + } + + *pptr() = traits_type::to_char_type(c); + pbump(1); + return c; + } + + return traits_type::not_eof(c); + } + + void reserve(std::size_t n) + { + // Get current stream positions as offsets. + std::size_t gnext = gptr() - &buffer_[0]; + std::size_t pnext = pptr() - &buffer_[0]; + std::size_t pend = epptr() - &buffer_[0]; + + // Check if there is already enough space in the put area. + if (n <= pend - pnext) + { + return; + } + + // Shift existing contents of get area to start of buffer. + if (gnext > 0) + { + pnext -= gnext; + std::memmove(&buffer_[0], &buffer_[0] + gnext, pnext); + } + + // Ensure buffer is large enough to hold at least the specified size. + if (n > pend - pnext) + { + if (n <= max_size_ && pnext <= max_size_ - n) + { + pend = pnext + n; + buffer_.resize((std::max)(pend, 1)); + } + else + { + std::length_error ex("boost::asio::streambuf too long"); + boost::asio::detail::throw_exception(ex); + } + } + + // Update stream positions. + setg(&buffer_[0], &buffer_[0], &buffer_[0] + pnext); + setp(&buffer_[0] + pnext, &buffer_[0] + pend); + } + +private: + std::size_t max_size_; + std::vector buffer_; + + // Helper function to get the preferred size for reading data. + friend std::size_t read_size_helper( + basic_streambuf& sb, std::size_t max_size) + { + return std::min( + std::max(512, sb.buffer_.capacity() - sb.size()), + std::min(max_size, sb.max_size() - sb.size())); + } +}; + +/// Adapts basic_streambuf to the dynamic buffer sequence type requirements. +#if defined(GENERATING_DOCUMENTATION) +template > +#else +template +#endif +class basic_streambuf_ref +{ +public: + /// The type used to represent the input sequence as a list of buffers. + typedef typename basic_streambuf::const_buffers_type + const_buffers_type; + + /// The type used to represent the output sequence as a list of buffers. + typedef typename basic_streambuf::mutable_buffers_type + mutable_buffers_type; + + /// Construct a basic_streambuf_ref for the given basic_streambuf object. + explicit basic_streambuf_ref(basic_streambuf& sb) + : sb_(sb) + { + } + + /// Copy construct a basic_streambuf_ref. + basic_streambuf_ref(const basic_streambuf_ref& other) BOOST_ASIO_NOEXCEPT + : sb_(other.sb_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move construct a basic_streambuf_ref. + basic_streambuf_ref(basic_streambuf_ref&& other) BOOST_ASIO_NOEXCEPT + : sb_(other.sb_) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Get the size of the input sequence. + std::size_t size() const BOOST_ASIO_NOEXCEPT + { + return sb_.size(); + } + + /// Get the maximum size of the dynamic buffer. + std::size_t max_size() const BOOST_ASIO_NOEXCEPT + { + return sb_.max_size(); + } + + /// Get the current capacity of the dynamic buffer. + std::size_t capacity() const BOOST_ASIO_NOEXCEPT + { + return sb_.capacity(); + } + + /// Get a list of buffers that represents the input sequence. + const_buffers_type data() const BOOST_ASIO_NOEXCEPT + { + return sb_.data(); + } + + /// Get a list of buffers that represents the output sequence, with the given + /// size. + mutable_buffers_type prepare(std::size_t n) + { + return sb_.prepare(n); + } + + /// Move bytes from the output sequence to the input sequence. + void commit(std::size_t n) + { + return sb_.commit(n); + } + + /// Remove characters from the input sequence. + void consume(std::size_t n) + { + return sb_.consume(n); + } + +private: + basic_streambuf& sb_; +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +#endif // BOOST_ASIO_BASIC_STREAMBUF_HPP diff --git a/boost/asio/basic_streambuf_fwd.hpp b/boost/asio/basic_streambuf_fwd.hpp new file mode 100644 index 0000000..68907ef --- /dev/null +++ b/boost/asio/basic_streambuf_fwd.hpp @@ -0,0 +1,38 @@ +// +// basic_streambuf_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BASIC_STREAMBUF_FWD_HPP +#define BOOST_ASIO_BASIC_STREAMBUF_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +#include + +namespace boost { +namespace asio { + +template > +class basic_streambuf; + +template > +class basic_streambuf_ref; + +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +#endif // BOOST_ASIO_BASIC_STREAMBUF_FWD_HPP diff --git a/boost/asio/basic_waitable_timer.hpp b/boost/asio/basic_waitable_timer.hpp new file mode 100644 index 0000000..45373f7 --- /dev/null +++ b/boost/asio/basic_waitable_timer.hpp @@ -0,0 +1,738 @@ +// +// basic_waitable_timer.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BASIC_WAITABLE_TIMER_HPP +#define BOOST_ASIO_BASIC_WAITABLE_TIMER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_MOVE) +# include +#endif // defined(BOOST_ASIO_HAS_MOVE) + +#include + +namespace boost { +namespace asio { + +#if !defined(BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL) +#define BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL + +// Forward declaration with defaulted arguments. +template , + typename Executor = executor> +class basic_waitable_timer; + +#endif // !defined(BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL) + +/// Provides waitable timer functionality. +/** + * The basic_waitable_timer class template provides the ability to perform a + * blocking or asynchronous wait for a timer to expire. + * + * A waitable timer is always in one of two states: "expired" or "not expired". + * If the wait() or async_wait() function is called on an expired timer, the + * wait operation will complete immediately. + * + * Most applications will use one of the boost::asio::steady_timer, + * boost::asio::system_timer or boost::asio::high_resolution_timer typedefs. + * + * @note This waitable timer functionality is for use with the C++11 standard + * library's @c <chrono> facility, or with the Boost.Chrono library. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Examples + * Performing a blocking wait (C++11): + * @code + * // Construct a timer without setting an expiry time. + * boost::asio::steady_timer timer(my_context); + * + * // Set an expiry time relative to now. + * timer.expires_after(std::chrono::seconds(5)); + * + * // Wait for the timer to expire. + * timer.wait(); + * @endcode + * + * @par + * Performing an asynchronous wait (C++11): + * @code + * void handler(const boost::system::error_code& error) + * { + * if (!error) + * { + * // Timer expired. + * } + * } + * + * ... + * + * // Construct a timer with an absolute expiry time. + * boost::asio::steady_timer timer(my_context, + * std::chrono::steady_clock::now() + std::chrono::seconds(60)); + * + * // Start an asynchronous wait. + * timer.async_wait(handler); + * @endcode + * + * @par Changing an active waitable timer's expiry time + * + * Changing the expiry time of a timer while there are pending asynchronous + * waits causes those wait operations to be cancelled. To ensure that the action + * associated with the timer is performed only once, use something like this: + * used: + * + * @code + * void on_some_event() + * { + * if (my_timer.expires_after(seconds(5)) > 0) + * { + * // We managed to cancel the timer. Start new asynchronous wait. + * my_timer.async_wait(on_timeout); + * } + * else + * { + * // Too late, timer has already expired! + * } + * } + * + * void on_timeout(const boost::system::error_code& e) + * { + * if (e != boost::asio::error::operation_aborted) + * { + * // Timer was not cancelled, take necessary action. + * } + * } + * @endcode + * + * @li The boost::asio::basic_waitable_timer::expires_after() function + * cancels any pending asynchronous waits, and returns the number of + * asynchronous waits that were cancelled. If it returns 0 then you were too + * late and the wait handler has already been executed, or will soon be + * executed. If it returns 1 then the wait handler was successfully cancelled. + * + * @li If a wait handler is cancelled, the boost::system::error_code passed to + * it contains the value boost::asio::error::operation_aborted. + */ +template +class basic_waitable_timer +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// The clock type. + typedef Clock clock_type; + + /// The duration type of the clock. + typedef typename clock_type::duration duration; + + /// The time point type of the clock. + typedef typename clock_type::time_point time_point; + + /// The wait traits type. + typedef WaitTraits traits_type; + + /// Constructor. + /** + * This constructor creates a timer without setting an expiry time. The + * expires_at() or expires_after() functions must be called to set an expiry + * time before the timer can be waited on. + * + * @param ex The I/O executor that the timer will use, by default, to + * dispatch handlers for any asynchronous operations performed on the timer. + */ + explicit basic_waitable_timer(const executor_type& ex) + : impl_(ex) + { + } + + /// Constructor. + /** + * This constructor creates a timer without setting an expiry time. The + * expires_at() or expires_after() functions must be called to set an expiry + * time before the timer can be waited on. + * + * @param context An execution context which provides the I/O executor that + * the timer will use, by default, to dispatch handlers for any asynchronous + * operations performed on the timer. + */ + template + explicit basic_waitable_timer(ExecutionContext& context, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + } + + /// Constructor to set a particular expiry time as an absolute time. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param ex The I/O executor object that the timer will use, by default, to + * dispatch handlers for any asynchronous operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, expressed + * as an absolute time. + */ + basic_waitable_timer(const executor_type& ex, const time_point& expiry_time) + : impl_(ex) + { + boost::system::error_code ec; + impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec); + boost::asio::detail::throw_error(ec, "expires_at"); + } + + /// Constructor to set a particular expiry time as an absolute time. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param context An execution context which provides the I/O executor that + * the timer will use, by default, to dispatch handlers for any asynchronous + * operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, expressed + * as an absolute time. + */ + template + explicit basic_waitable_timer(ExecutionContext& context, + const time_point& expiry_time, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + boost::system::error_code ec; + impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec); + boost::asio::detail::throw_error(ec, "expires_at"); + } + + /// Constructor to set a particular expiry time relative to now. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param ex The I/O executor that the timer will use, by default, to + * dispatch handlers for any asynchronous operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, relative to + * now. + */ + basic_waitable_timer(const executor_type& ex, const duration& expiry_time) + : impl_(ex) + { + boost::system::error_code ec; + impl_.get_service().expires_after( + impl_.get_implementation(), expiry_time, ec); + boost::asio::detail::throw_error(ec, "expires_after"); + } + + /// Constructor to set a particular expiry time relative to now. + /** + * This constructor creates a timer and sets the expiry time. + * + * @param context An execution context which provides the I/O executor that + * the timer will use, by default, to dispatch handlers for any asynchronous + * operations performed on the timer. + * + * @param expiry_time The expiry time to be used for the timer, relative to + * now. + */ + template + explicit basic_waitable_timer(ExecutionContext& context, + const duration& expiry_time, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + boost::system::error_code ec; + impl_.get_service().expires_after( + impl_.get_implementation(), expiry_time, ec); + boost::asio::detail::throw_error(ec, "expires_after"); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_waitable_timer from another. + /** + * This constructor moves a timer from one object to another. + * + * @param other The other basic_waitable_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_waitable_timer(const executor_type&) + * constructor. + */ + basic_waitable_timer(basic_waitable_timer&& other) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_waitable_timer from another. + /** + * This assignment operator moves a timer from one object to another. Cancels + * any outstanding asynchronous operations associated with the target object. + * + * @param other The other basic_waitable_timer object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_waitable_timer(const executor_type&) + * constructor. + */ + basic_waitable_timer& operator=(basic_waitable_timer&& other) + { + impl_ = std::move(other.impl_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the timer. + /** + * This function destroys the timer, cancelling any outstanding asynchronous + * wait operations associated with the timer as if by calling @c cancel. + */ + ~basic_waitable_timer() + { + } + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return impl_.get_executor(); + } + + /// Cancel any asynchronous operations that are waiting on the timer. + /** + * This function forces the completion of any pending asynchronous wait + * operations against the timer. The handler for each cancelled operation will + * be invoked with the boost::asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @return The number of asynchronous operations that were cancelled. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note If the timer has already expired when cancel() is called, then the + * handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel() + { + boost::system::error_code ec; + std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "cancel"); + return s; + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use non-error_code overload.) Cancel any asynchronous + /// operations that are waiting on the timer. + /** + * This function forces the completion of any pending asynchronous wait + * operations against the timer. The handler for each cancelled operation will + * be invoked with the boost::asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. + * + * @note If the timer has already expired when cancel() is called, then the + * handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel(boost::system::error_code& ec) + { + return impl_.get_service().cancel(impl_.get_implementation(), ec); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Cancels one asynchronous operation that is waiting on the timer. + /** + * This function forces the completion of one pending asynchronous wait + * operation against the timer. Handlers are cancelled in FIFO order. The + * handler for the cancelled operation will be invoked with the + * boost::asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @return The number of asynchronous operations that were cancelled. That is, + * either 0 or 1. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note If the timer has already expired when cancel_one() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel_one() + { + boost::system::error_code ec; + std::size_t s = impl_.get_service().cancel_one( + impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "cancel_one"); + return s; + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use non-error_code overload.) Cancels one asynchronous + /// operation that is waiting on the timer. + /** + * This function forces the completion of one pending asynchronous wait + * operation against the timer. Handlers are cancelled in FIFO order. The + * handler for the cancelled operation will be invoked with the + * boost::asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. That is, + * either 0 or 1. + * + * @note If the timer has already expired when cancel_one() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t cancel_one(boost::system::error_code& ec) + { + return impl_.get_service().cancel_one(impl_.get_implementation(), ec); + } + + /// (Deprecated: Use expiry().) Get the timer's expiry time as an absolute + /// time. + /** + * This function may be used to obtain the timer's current expiry time. + * Whether the timer has expired or not does not affect this value. + */ + time_point expires_at() const + { + return impl_.get_service().expires_at(impl_.get_implementation()); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Get the timer's expiry time as an absolute time. + /** + * This function may be used to obtain the timer's current expiry time. + * Whether the timer has expired or not does not affect this value. + */ + time_point expiry() const + { + return impl_.get_service().expiry(impl_.get_implementation()); + } + + /// Set the timer's expiry time as an absolute time. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the boost::asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @return The number of asynchronous operations that were cancelled. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note If the timer has already expired when expires_at() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_at(const time_point& expiry_time) + { + boost::system::error_code ec; + std::size_t s = impl_.get_service().expires_at( + impl_.get_implementation(), expiry_time, ec); + boost::asio::detail::throw_error(ec, "expires_at"); + return s; + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use non-error_code overload.) Set the timer's expiry time as + /// an absolute time. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the boost::asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. + * + * @note If the timer has already expired when expires_at() is called, then + * the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_at(const time_point& expiry_time, + boost::system::error_code& ec) + { + return impl_.get_service().expires_at( + impl_.get_implementation(), expiry_time, ec); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Set the timer's expiry time relative to now. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the boost::asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @return The number of asynchronous operations that were cancelled. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note If the timer has already expired when expires_after() is called, + * then the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_after(const duration& expiry_time) + { + boost::system::error_code ec; + std::size_t s = impl_.get_service().expires_after( + impl_.get_implementation(), expiry_time, ec); + boost::asio::detail::throw_error(ec, "expires_after"); + return s; + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use expiry().) Get the timer's expiry time relative to now. + /** + * This function may be used to obtain the timer's current expiry time. + * Whether the timer has expired or not does not affect this value. + */ + duration expires_from_now() const + { + return impl_.get_service().expires_from_now(impl_.get_implementation()); + } + + /// (Deprecated: Use expires_after().) Set the timer's expiry time relative + /// to now. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the boost::asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @return The number of asynchronous operations that were cancelled. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note If the timer has already expired when expires_from_now() is called, + * then the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_from_now(const duration& expiry_time) + { + boost::system::error_code ec; + std::size_t s = impl_.get_service().expires_from_now( + impl_.get_implementation(), expiry_time, ec); + boost::asio::detail::throw_error(ec, "expires_from_now"); + return s; + } + + /// (Deprecated: Use expires_after().) Set the timer's expiry time relative + /// to now. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the boost::asio::error::operation_aborted error code. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. + * + * @note If the timer has already expired when expires_from_now() is called, + * then the handlers for asynchronous wait operations will: + * + * @li have already been invoked; or + * + * @li have been queued for invocation in the near future. + * + * These handlers can no longer be cancelled, and therefore are passed an + * error code that indicates the successful completion of the wait operation. + */ + std::size_t expires_from_now(const duration& expiry_time, + boost::system::error_code& ec) + { + return impl_.get_service().expires_from_now( + impl_.get_implementation(), expiry_time, ec); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Perform a blocking wait on the timer. + /** + * This function is used to wait for the timer to expire. This function + * blocks and does not return until the timer has expired. + * + * @throws boost::system::system_error Thrown on failure. + */ + void wait() + { + boost::system::error_code ec; + impl_.get_service().wait(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "wait"); + } + + /// Perform a blocking wait on the timer. + /** + * This function is used to wait for the timer to expire. This function + * blocks and does not return until the timer has expired. + * + * @param ec Set to indicate what error occurred, if any. + */ + void wait(boost::system::error_code& ec) + { + impl_.get_service().wait(impl_.get_implementation(), ec); + } + + /// Start an asynchronous wait on the timer. + /** + * This function may be used to initiate an asynchronous wait against the + * timer. It always returns immediately. + * + * For each call to async_wait(), the supplied handler will be called exactly + * once. The handler will be called when: + * + * @li The timer has expired. + * + * @li The timer was cancelled, in which case the handler is passed the error + * code boost::asio::error::operation_aborted. + * + * @param handler The handler to be called when the timer expires. Copies + * will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error // Result of operation. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + void (boost::system::error_code)) + async_wait(BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + { + return async_initiate( + initiate_async_wait(), handler, this); + } + +private: + // Disallow copying and assignment. + basic_waitable_timer(const basic_waitable_timer&) BOOST_ASIO_DELETED; + basic_waitable_timer& operator=( + const basic_waitable_timer&) BOOST_ASIO_DELETED; + + struct initiate_async_wait + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler, + basic_waitable_timer* self) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WaitHandler. + BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_wait( + self->impl_.get_implementation(), handler2.value, + self->impl_.get_implementation_executor()); + } + }; + + detail::io_object_impl< + detail::deadline_timer_service< + detail::chrono_time_traits >, + executor_type > impl_; +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BASIC_WAITABLE_TIMER_HPP diff --git a/boost/asio/bind_executor.hpp b/boost/asio/bind_executor.hpp new file mode 100644 index 0000000..cd14980 --- /dev/null +++ b/boost/asio/bind_executor.hpp @@ -0,0 +1,582 @@ +// +// bind_executor.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BIND_EXECUTOR_HPP +#define BOOST_ASIO_BIND_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +struct executor_binder_check +{ + typedef void type; +}; + +// Helper to automatically define nested typedef result_type. + +template +struct executor_binder_result_type +{ +protected: + typedef void result_type_or_void; +}; + +template +struct executor_binder_result_type::type> +{ + typedef typename T::result_type result_type; +protected: + typedef result_type result_type_or_void; +}; + +template +struct executor_binder_result_type +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template +struct executor_binder_result_type +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template +struct executor_binder_result_type +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template +struct executor_binder_result_type +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template +struct executor_binder_result_type +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +template +struct executor_binder_result_type +{ + typedef R result_type; +protected: + typedef result_type result_type_or_void; +}; + +// Helper to automatically define nested typedef argument_type. + +template +struct executor_binder_argument_type {}; + +template +struct executor_binder_argument_type::type> +{ + typedef typename T::argument_type argument_type; +}; + +template +struct executor_binder_argument_type +{ + typedef A1 argument_type; +}; + +template +struct executor_binder_argument_type +{ + typedef A1 argument_type; +}; + +// Helper to automatically define nested typedefs first_argument_type and +// second_argument_type. + +template +struct executor_binder_argument_types {}; + +template +struct executor_binder_argument_types::type> +{ + typedef typename T::first_argument_type first_argument_type; + typedef typename T::second_argument_type second_argument_type; +}; + +template +struct executor_binder_argument_type +{ + typedef A1 first_argument_type; + typedef A2 second_argument_type; +}; + +template +struct executor_binder_argument_type +{ + typedef A1 first_argument_type; + typedef A2 second_argument_type; +}; + +// Helper to: +// - Apply the empty base optimisation to the executor. +// - Perform uses_executor construction of the target type, if required. + +template +class executor_binder_base; + +template +class executor_binder_base + : protected Executor +{ +protected: + template + executor_binder_base(BOOST_ASIO_MOVE_ARG(E) e, BOOST_ASIO_MOVE_ARG(U) u) + : executor_(BOOST_ASIO_MOVE_CAST(E)(e)), + target_(executor_arg_t(), executor_, BOOST_ASIO_MOVE_CAST(U)(u)) + { + } + + Executor executor_; + T target_; +}; + +template +class executor_binder_base +{ +protected: + template + executor_binder_base(BOOST_ASIO_MOVE_ARG(E) e, BOOST_ASIO_MOVE_ARG(U) u) + : executor_(BOOST_ASIO_MOVE_CAST(E)(e)), + target_(BOOST_ASIO_MOVE_CAST(U)(u)) + { + } + + Executor executor_; + T target_; +}; + +// Helper to enable SFINAE on zero-argument operator() below. + +template +struct executor_binder_result_of0 +{ + typedef void type; +}; + +template +struct executor_binder_result_of0::type>::type> +{ + typedef typename result_of::type type; +}; + +} // namespace detail + +/// A call wrapper type to bind an executor of type @c Executor to an object of +/// type @c T. +template +class executor_binder +#if !defined(GENERATING_DOCUMENTATION) + : public detail::executor_binder_result_type, + public detail::executor_binder_argument_type, + public detail::executor_binder_argument_types, + private detail::executor_binder_base< + T, Executor, uses_executor::value> +#endif // !defined(GENERATING_DOCUMENTATION) +{ +public: + /// The type of the target object. + typedef T target_type; + + /// The type of the associated executor. + typedef Executor executor_type; + +#if defined(GENERATING_DOCUMENTATION) + /// The return type if a function. + /** + * The type of @c result_type is based on the type @c T of the wrapper's + * target object: + * + * @li if @c T is a pointer to function type, @c result_type is a synonym for + * the return type of @c T; + * + * @li if @c T is a class type with a member type @c result_type, then @c + * result_type is a synonym for @c T::result_type; + * + * @li otherwise @c result_type is not defined. + */ + typedef see_below result_type; + + /// The type of the function's argument. + /** + * The type of @c argument_type is based on the type @c T of the wrapper's + * target object: + * + * @li if @c T is a pointer to a function type accepting a single argument, + * @c argument_type is a synonym for the return type of @c T; + * + * @li if @c T is a class type with a member type @c argument_type, then @c + * argument_type is a synonym for @c T::argument_type; + * + * @li otherwise @c argument_type is not defined. + */ + typedef see_below argument_type; + + /// The type of the function's first argument. + /** + * The type of @c first_argument_type is based on the type @c T of the + * wrapper's target object: + * + * @li if @c T is a pointer to a function type accepting two arguments, @c + * first_argument_type is a synonym for the return type of @c T; + * + * @li if @c T is a class type with a member type @c first_argument_type, + * then @c first_argument_type is a synonym for @c T::first_argument_type; + * + * @li otherwise @c first_argument_type is not defined. + */ + typedef see_below first_argument_type; + + /// The type of the function's second argument. + /** + * The type of @c second_argument_type is based on the type @c T of the + * wrapper's target object: + * + * @li if @c T is a pointer to a function type accepting two arguments, @c + * second_argument_type is a synonym for the return type of @c T; + * + * @li if @c T is a class type with a member type @c first_argument_type, + * then @c second_argument_type is a synonym for @c T::second_argument_type; + * + * @li otherwise @c second_argument_type is not defined. + */ + typedef see_below second_argument_type; +#endif // defined(GENERATING_DOCUMENTATION) + + /// Construct an executor wrapper for the specified object. + /** + * This constructor is only valid if the type @c T is constructible from type + * @c U. + */ + template + executor_binder(executor_arg_t, const executor_type& e, + BOOST_ASIO_MOVE_ARG(U) u) + : base_type(e, BOOST_ASIO_MOVE_CAST(U)(u)) + { + } + + /// Copy constructor. + executor_binder(const executor_binder& other) + : base_type(other.get_executor(), other.get()) + { + } + + /// Construct a copy, but specify a different executor. + executor_binder(executor_arg_t, const executor_type& e, + const executor_binder& other) + : base_type(e, other.get()) + { + } + + /// Construct a copy of a different executor wrapper type. + /** + * This constructor is only valid if the @c Executor type is constructible + * from type @c OtherExecutor, and the type @c T is constructible from type + * @c U. + */ + template + executor_binder(const executor_binder& other) + : base_type(other.get_executor(), other.get()) + { + } + + /// Construct a copy of a different executor wrapper type, but specify a + /// different executor. + /** + * This constructor is only valid if the type @c T is constructible from type + * @c U. + */ + template + executor_binder(executor_arg_t, const executor_type& e, + const executor_binder& other) + : base_type(e, other.get()) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Move constructor. + executor_binder(executor_binder&& other) + : base_type(BOOST_ASIO_MOVE_CAST(executor_type)(other.get_executor()), + BOOST_ASIO_MOVE_CAST(T)(other.get())) + { + } + + /// Move construct the target object, but specify a different executor. + executor_binder(executor_arg_t, const executor_type& e, + executor_binder&& other) + : base_type(e, BOOST_ASIO_MOVE_CAST(T)(other.get())) + { + } + + /// Move construct from a different executor wrapper type. + template + executor_binder(executor_binder&& other) + : base_type(BOOST_ASIO_MOVE_CAST(OtherExecutor)(other.get_executor()), + BOOST_ASIO_MOVE_CAST(U)(other.get())) + { + } + + /// Move construct from a different executor wrapper type, but specify a + /// different executor. + template + executor_binder(executor_arg_t, const executor_type& e, + executor_binder&& other) + : base_type(e, BOOST_ASIO_MOVE_CAST(U)(other.get())) + { + } + +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destructor. + ~executor_binder() + { + } + + /// Obtain a reference to the target object. + target_type& get() BOOST_ASIO_NOEXCEPT + { + return this->target_; + } + + /// Obtain a reference to the target object. + const target_type& get() const BOOST_ASIO_NOEXCEPT + { + return this->target_; + } + + /// Obtain the associated executor. + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return this->executor_; + } + +#if defined(GENERATING_DOCUMENTATION) + + template auto operator()(Args&& ...); + template auto operator()(Args&& ...) const; + +#elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + /// Forwarding function call operator. + template + typename result_of::type operator()( + BOOST_ASIO_MOVE_ARG(Args)... args) + { + return this->target_(BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + + /// Forwarding function call operator. + template + typename result_of::type operator()( + BOOST_ASIO_MOVE_ARG(Args)... args) const + { + return this->target_(BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + +#elif defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER) + + typename detail::executor_binder_result_of0::type operator()() + { + return this->target_(); + } + + typename detail::executor_binder_result_of0::type operator()() const + { + return this->target_(); + } + +#define BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF(n) \ + template \ + typename result_of::type operator()( \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + return this->target_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + \ + template \ + typename result_of::type operator()( \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) const \ + { \ + return this->target_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF) +#undef BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF + +#else // defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER) + + typedef typename detail::executor_binder_result_type::result_type_or_void + result_type_or_void; + + result_type_or_void operator()() + { + return this->target_(); + } + + result_type_or_void operator()() const + { + return this->target_(); + } + +#define BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF(n) \ + template \ + result_type_or_void operator()( \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + return this->target_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + \ + template \ + result_type_or_void operator()( \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) const \ + { \ + return this->target_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF) +#undef BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF + +#endif // defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER) + +private: + typedef detail::executor_binder_base::value> base_type; +}; + +/// Associate an object of type @c T with an executor of type @c Executor. +template +inline executor_binder::type, Executor> +bind_executor(const Executor& ex, BOOST_ASIO_MOVE_ARG(T) t, + typename enable_if::value>::type* = 0) +{ + return executor_binder::type, Executor>( + executor_arg_t(), ex, BOOST_ASIO_MOVE_CAST(T)(t)); +} + +/// Associate an object of type @c T with an execution context's executor. +template +inline executor_binder::type, + typename ExecutionContext::executor_type> +bind_executor(ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(T) t, + typename enable_if::value>::type* = 0) +{ + return executor_binder::type, + typename ExecutionContext::executor_type>( + executor_arg_t(), ctx.get_executor(), BOOST_ASIO_MOVE_CAST(T)(t)); +} + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct uses_executor, Executor> + : true_type {}; + +template +class async_result, Signature> +{ +public: + typedef executor_binder< + typename async_result::completion_handler_type, Executor> + completion_handler_type; + + typedef typename async_result::return_type return_type; + + explicit async_result(executor_binder& b) + : target_(b.get()) + { + } + + return_type get() + { + return target_.get(); + } + +private: + async_result(const async_result&) BOOST_ASIO_DELETED; + async_result& operator=(const async_result&) BOOST_ASIO_DELETED; + + async_result target_; +}; + +template +struct associated_allocator, Allocator> +{ + typedef typename associated_allocator::type type; + + static type get(const executor_binder& b, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(b.get(), a); + } +}; + +template +struct associated_executor, Executor1> +{ + typedef Executor type; + + static type get(const executor_binder& b, + const Executor1& = Executor1()) BOOST_ASIO_NOEXCEPT + { + return b.get_executor(); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BIND_EXECUTOR_HPP diff --git a/boost/asio/buffer.hpp b/boost/asio/buffer.hpp new file mode 100644 index 0000000..1f12cac --- /dev/null +++ b/boost/asio/buffer.hpp @@ -0,0 +1,2498 @@ +// +// buffer.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BUFFER_HPP +#define BOOST_ASIO_BUFFER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1700) +# if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0) +# if !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING) +# define BOOST_ASIO_ENABLE_BUFFER_DEBUGGING +# endif // !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING) +# endif // defined(_HAS_ITERATOR_DEBUGGING) +#endif // defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC >= 1700) + +#if defined(__GNUC__) +# if defined(_GLIBCXX_DEBUG) +# if !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING) +# define BOOST_ASIO_ENABLE_BUFFER_DEBUGGING +# endif // !defined(BOOST_ASIO_DISABLE_BUFFER_DEBUGGING) +# endif // defined(_GLIBCXX_DEBUG) +#endif // defined(__GNUC__) + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) +# include +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + +#if defined(BOOST_ASIO_HAS_BOOST_WORKAROUND) +# include +# if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) \ + || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) +# define BOOST_ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND +# endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) + // || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) +#endif // defined(BOOST_ASIO_HAS_BOOST_WORKAROUND) + +#if defined(BOOST_ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) +# include +#endif // defined(BOOST_ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) + +#include + +namespace boost { +namespace asio { + +class mutable_buffer; +class const_buffer; + +/// Holds a buffer that can be modified. +/** + * The mutable_buffer class provides a safe representation of a buffer that can + * be modified. It does not own the underlying data, and so is cheap to copy or + * assign. + * + * @par Accessing Buffer Contents + * + * The contents of a buffer may be accessed using the @c data() and @c size() + * member functions: + * + * @code boost::asio::mutable_buffer b1 = ...; + * std::size_t s1 = b1.size(); + * unsigned char* p1 = static_cast(b1.data()); + * @endcode + * + * The @c data() member function permits violations of type safety, so uses of + * it in application code should be carefully considered. + */ +class mutable_buffer +{ +public: + /// Construct an empty buffer. + mutable_buffer() BOOST_ASIO_NOEXCEPT + : data_(0), + size_(0) + { + } + + /// Construct a buffer to represent a given memory range. + mutable_buffer(void* data, std::size_t size) BOOST_ASIO_NOEXCEPT + : data_(data), + size_(size) + { + } + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + mutable_buffer(void* data, std::size_t size, + boost::asio::detail::function debug_check) + : data_(data), + size_(size), + debug_check_(debug_check) + { + } + + const boost::asio::detail::function& get_debug_check() const + { + return debug_check_; + } +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + + /// Get a pointer to the beginning of the memory range. + void* data() const BOOST_ASIO_NOEXCEPT + { +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + if (size_ && debug_check_) + debug_check_(); +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + return data_; + } + + /// Get the size of the memory range. + std::size_t size() const BOOST_ASIO_NOEXCEPT + { + return size_; + } + + /// Move the start of the buffer by the specified number of bytes. + mutable_buffer& operator+=(std::size_t n) BOOST_ASIO_NOEXCEPT + { + std::size_t offset = n < size_ ? n : size_; + data_ = static_cast(data_) + offset; + size_ -= offset; + return *this; + } + +private: + void* data_; + std::size_t size_; + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + boost::asio::detail::function debug_check_; +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING +}; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + +/// (Deprecated: Use mutable_buffer.) Adapts a single modifiable buffer so that +/// it meets the requirements of the MutableBufferSequence concept. +class mutable_buffers_1 + : public mutable_buffer +{ +public: + /// The type for each element in the list of buffers. + typedef mutable_buffer value_type; + + /// A random-access iterator type that may be used to read elements. + typedef const mutable_buffer* const_iterator; + + /// Construct to represent a given memory range. + mutable_buffers_1(void* data, std::size_t size) BOOST_ASIO_NOEXCEPT + : mutable_buffer(data, size) + { + } + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + mutable_buffers_1(void* data, std::size_t size, + boost::asio::detail::function debug_check) + : mutable_buffer(data, size, debug_check) + { + } +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + + /// Construct to represent a single modifiable buffer. + explicit mutable_buffers_1(const mutable_buffer& b) BOOST_ASIO_NOEXCEPT + : mutable_buffer(b) + { + } + + /// Get a random-access iterator to the first element. + const_iterator begin() const BOOST_ASIO_NOEXCEPT + { + return this; + } + + /// Get a random-access iterator for one past the last element. + const_iterator end() const BOOST_ASIO_NOEXCEPT + { + return begin() + 1; + } +}; + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +/// Holds a buffer that cannot be modified. +/** + * The const_buffer class provides a safe representation of a buffer that cannot + * be modified. It does not own the underlying data, and so is cheap to copy or + * assign. + * + * @par Accessing Buffer Contents + * + * The contents of a buffer may be accessed using the @c data() and @c size() + * member functions: + * + * @code boost::asio::const_buffer b1 = ...; + * std::size_t s1 = b1.size(); + * const unsigned char* p1 = static_cast(b1.data()); + * @endcode + * + * The @c data() member function permits violations of type safety, so uses of + * it in application code should be carefully considered. + */ +class const_buffer +{ +public: + /// Construct an empty buffer. + const_buffer() BOOST_ASIO_NOEXCEPT + : data_(0), + size_(0) + { + } + + /// Construct a buffer to represent a given memory range. + const_buffer(const void* data, std::size_t size) BOOST_ASIO_NOEXCEPT + : data_(data), + size_(size) + { + } + + /// Construct a non-modifiable buffer from a modifiable one. + const_buffer(const mutable_buffer& b) BOOST_ASIO_NOEXCEPT + : data_(b.data()), + size_(b.size()) +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , debug_check_(b.get_debug_check()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + { + } + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + const_buffer(const void* data, std::size_t size, + boost::asio::detail::function debug_check) + : data_(data), + size_(size), + debug_check_(debug_check) + { + } + + const boost::asio::detail::function& get_debug_check() const + { + return debug_check_; + } +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + + /// Get a pointer to the beginning of the memory range. + const void* data() const BOOST_ASIO_NOEXCEPT + { +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + if (size_ && debug_check_) + debug_check_(); +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + return data_; + } + + /// Get the size of the memory range. + std::size_t size() const BOOST_ASIO_NOEXCEPT + { + return size_; + } + + /// Move the start of the buffer by the specified number of bytes. + const_buffer& operator+=(std::size_t n) BOOST_ASIO_NOEXCEPT + { + std::size_t offset = n < size_ ? n : size_; + data_ = static_cast(data_) + offset; + size_ -= offset; + return *this; + } + +private: + const void* data_; + std::size_t size_; + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + boost::asio::detail::function debug_check_; +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING +}; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + +/// (Deprecated: Use const_buffer.) Adapts a single non-modifiable buffer so +/// that it meets the requirements of the ConstBufferSequence concept. +class const_buffers_1 + : public const_buffer +{ +public: + /// The type for each element in the list of buffers. + typedef const_buffer value_type; + + /// A random-access iterator type that may be used to read elements. + typedef const const_buffer* const_iterator; + + /// Construct to represent a given memory range. + const_buffers_1(const void* data, std::size_t size) BOOST_ASIO_NOEXCEPT + : const_buffer(data, size) + { + } + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + const_buffers_1(const void* data, std::size_t size, + boost::asio::detail::function debug_check) + : const_buffer(data, size, debug_check) + { + } +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + + /// Construct to represent a single non-modifiable buffer. + explicit const_buffers_1(const const_buffer& b) BOOST_ASIO_NOEXCEPT + : const_buffer(b) + { + } + + /// Get a random-access iterator to the first element. + const_iterator begin() const BOOST_ASIO_NOEXCEPT + { + return this; + } + + /// Get a random-access iterator for one past the last element. + const_iterator end() const BOOST_ASIO_NOEXCEPT + { + return begin() + 1; + } +}; + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +/// (Deprecated: Use the socket/descriptor wait() and async_wait() member +/// functions.) An implementation of both the ConstBufferSequence and +/// MutableBufferSequence concepts to represent a null buffer sequence. +class null_buffers +{ +public: + /// The type for each element in the list of buffers. + typedef mutable_buffer value_type; + + /// A random-access iterator type that may be used to read elements. + typedef const mutable_buffer* const_iterator; + + /// Get a random-access iterator to the first element. + const_iterator begin() const BOOST_ASIO_NOEXCEPT + { + return &buf_; + } + + /// Get a random-access iterator for one past the last element. + const_iterator end() const BOOST_ASIO_NOEXCEPT + { + return &buf_; + } + +private: + mutable_buffer buf_; +}; + +/** @defgroup buffer_sequence_begin boost::asio::buffer_sequence_begin + * + * @brief The boost::asio::buffer_sequence_begin function returns an iterator + * pointing to the first element in a buffer sequence. + */ +/*@{*/ + +/// Get an iterator to the first element in a buffer sequence. +template +inline const mutable_buffer* buffer_sequence_begin(const MutableBuffer& b, + typename enable_if< + is_convertible::value + >::type* = 0) BOOST_ASIO_NOEXCEPT +{ + return static_cast(detail::addressof(b)); +} + +/// Get an iterator to the first element in a buffer sequence. +template +inline const const_buffer* buffer_sequence_begin(const ConstBuffer& b, + typename enable_if< + is_convertible::value + >::type* = 0) BOOST_ASIO_NOEXCEPT +{ + return static_cast(detail::addressof(b)); +} + +#if defined(BOOST_ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) + +/// Get an iterator to the first element in a buffer sequence. +template +inline auto buffer_sequence_begin(C& c, + typename enable_if< + !is_convertible::value + && !is_convertible::value + >::type* = 0) BOOST_ASIO_NOEXCEPT -> decltype(c.begin()) +{ + return c.begin(); +} + +/// Get an iterator to the first element in a buffer sequence. +template +inline auto buffer_sequence_begin(const C& c, + typename enable_if< + !is_convertible::value + && !is_convertible::value + >::type* = 0) BOOST_ASIO_NOEXCEPT -> decltype(c.begin()) +{ + return c.begin(); +} + +#else // defined(BOOST_ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) + +template +inline typename C::iterator buffer_sequence_begin(C& c, + typename enable_if< + !is_convertible::value + && !is_convertible::value + >::type* = 0) BOOST_ASIO_NOEXCEPT +{ + return c.begin(); +} + +template +inline typename C::const_iterator buffer_sequence_begin(const C& c, + typename enable_if< + !is_convertible::value + && !is_convertible::value + >::type* = 0) BOOST_ASIO_NOEXCEPT +{ + return c.begin(); +} + +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) + +/*@}*/ + +/** @defgroup buffer_sequence_end boost::asio::buffer_sequence_end + * + * @brief The boost::asio::buffer_sequence_end function returns an iterator + * pointing to one past the end element in a buffer sequence. + */ +/*@{*/ + +/// Get an iterator to one past the end element in a buffer sequence. +template +inline const mutable_buffer* buffer_sequence_end(const MutableBuffer& b, + typename enable_if< + is_convertible::value + >::type* = 0) BOOST_ASIO_NOEXCEPT +{ + return static_cast(detail::addressof(b)) + 1; +} + +/// Get an iterator to one past the end element in a buffer sequence. +template +inline const const_buffer* buffer_sequence_end(const ConstBuffer& b, + typename enable_if< + is_convertible::value + >::type* = 0) BOOST_ASIO_NOEXCEPT +{ + return static_cast(detail::addressof(b)) + 1; +} + +#if defined(BOOST_ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) + +/// Get an iterator to one past the end element in a buffer sequence. +template +inline auto buffer_sequence_end(C& c, + typename enable_if< + !is_convertible::value + && !is_convertible::value + >::type* = 0) BOOST_ASIO_NOEXCEPT -> decltype(c.end()) +{ + return c.end(); +} + +/// Get an iterator to one past the end element in a buffer sequence. +template +inline auto buffer_sequence_end(const C& c, + typename enable_if< + !is_convertible::value + && !is_convertible::value + >::type* = 0) BOOST_ASIO_NOEXCEPT -> decltype(c.end()) +{ + return c.end(); +} + +#else // defined(BOOST_ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) + +template +inline typename C::iterator buffer_sequence_end(C& c, + typename enable_if< + !is_convertible::value + && !is_convertible::value + >::type* = 0) BOOST_ASIO_NOEXCEPT +{ + return c.end(); +} + +template +inline typename C::const_iterator buffer_sequence_end(const C& c, + typename enable_if< + !is_convertible::value + && !is_convertible::value + >::type* = 0) BOOST_ASIO_NOEXCEPT +{ + return c.end(); +} + +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) + +/*@}*/ + +namespace detail { + +// Tag types used to select appropriately optimised overloads. +struct one_buffer {}; +struct multiple_buffers {}; + +// Helper trait to detect single buffers. +template +struct buffer_sequence_cardinality : + conditional< + is_same::value +#if !defined(BOOST_ASIO_NO_DEPRECATED) + || is_same::value + || is_same::value +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + || is_same::value, + one_buffer, multiple_buffers>::type {}; + +template +inline std::size_t buffer_size(one_buffer, + Iterator begin, Iterator) BOOST_ASIO_NOEXCEPT +{ + return const_buffer(*begin).size(); +} + +template +inline std::size_t buffer_size(multiple_buffers, + Iterator begin, Iterator end) BOOST_ASIO_NOEXCEPT +{ + std::size_t total_buffer_size = 0; + + Iterator iter = begin; + for (; iter != end; ++iter) + { + const_buffer b(*iter); + total_buffer_size += b.size(); + } + + return total_buffer_size; +} + +} // namespace detail + +/// Get the total number of bytes in a buffer sequence. +/** + * The @c buffer_size function determines the total size of all buffers in the + * buffer sequence, as if computed as follows: + * + * @code size_t total_size = 0; + * auto i = boost::asio::buffer_sequence_begin(buffers); + * auto end = boost::asio::buffer_sequence_end(buffers); + * for (; i != end; ++i) + * { + * const_buffer b(*i); + * total_size += b.size(); + * } + * return total_size; @endcode + * + * The @c BufferSequence template parameter may meet either of the @c + * ConstBufferSequence or @c MutableBufferSequence type requirements. + */ +template +inline std::size_t buffer_size(const BufferSequence& b) BOOST_ASIO_NOEXCEPT +{ + return detail::buffer_size( + detail::buffer_sequence_cardinality(), + boost::asio::buffer_sequence_begin(b), + boost::asio::buffer_sequence_end(b)); +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + +/** @defgroup buffer_cast boost::asio::buffer_cast + * + * @brief (Deprecated: Use the @c data() member function.) The + * boost::asio::buffer_cast function is used to obtain a pointer to the + * underlying memory region associated with a buffer. + * + * @par Examples: + * + * To access the memory of a non-modifiable buffer, use: + * @code boost::asio::const_buffer b1 = ...; + * const unsigned char* p1 = boost::asio::buffer_cast(b1); + * @endcode + * + * To access the memory of a modifiable buffer, use: + * @code boost::asio::mutable_buffer b2 = ...; + * unsigned char* p2 = boost::asio::buffer_cast(b2); + * @endcode + * + * The boost::asio::buffer_cast function permits violations of type safety, so + * uses of it in application code should be carefully considered. + */ +/*@{*/ + +/// Cast a non-modifiable buffer to a specified pointer to POD type. +template +inline PointerToPodType buffer_cast(const mutable_buffer& b) BOOST_ASIO_NOEXCEPT +{ + return static_cast(b.data()); +} + +/// Cast a non-modifiable buffer to a specified pointer to POD type. +template +inline PointerToPodType buffer_cast(const const_buffer& b) BOOST_ASIO_NOEXCEPT +{ + return static_cast(b.data()); +} + +/*@}*/ + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +/// Create a new modifiable buffer that is offset from the start of another. +/** + * @relates mutable_buffer + */ +inline mutable_buffer operator+(const mutable_buffer& b, + std::size_t n) BOOST_ASIO_NOEXCEPT +{ + std::size_t offset = n < b.size() ? n : b.size(); + char* new_data = static_cast(b.data()) + offset; + std::size_t new_size = b.size() - offset; + return mutable_buffer(new_data, new_size +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new modifiable buffer that is offset from the start of another. +/** + * @relates mutable_buffer + */ +inline mutable_buffer operator+(std::size_t n, + const mutable_buffer& b) BOOST_ASIO_NOEXCEPT +{ + return b + n; +} + +/// Create a new non-modifiable buffer that is offset from the start of another. +/** + * @relates const_buffer + */ +inline const_buffer operator+(const const_buffer& b, + std::size_t n) BOOST_ASIO_NOEXCEPT +{ + std::size_t offset = n < b.size() ? n : b.size(); + const char* new_data = static_cast(b.data()) + offset; + std::size_t new_size = b.size() - offset; + return const_buffer(new_data, new_size +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new non-modifiable buffer that is offset from the start of another. +/** + * @relates const_buffer + */ +inline const_buffer operator+(std::size_t n, + const const_buffer& b) BOOST_ASIO_NOEXCEPT +{ + return b + n; +} + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) +namespace detail { + +template +class buffer_debug_check +{ +public: + buffer_debug_check(Iterator iter) + : iter_(iter) + { + } + + ~buffer_debug_check() + { +#if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC == 1400) + // MSVC 8's string iterator checking may crash in a std::string::iterator + // object's destructor when the iterator points to an already-destroyed + // std::string object, unless the iterator is cleared first. + iter_ = Iterator(); +#endif // defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC == 1400) + } + + void operator()() + { + (void)*iter_; + } + +private: + Iterator iter_; +}; + +} // namespace detail +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + +/** @defgroup buffer boost::asio::buffer + * + * @brief The boost::asio::buffer function is used to create a buffer object to + * represent raw memory, an array of POD elements, a vector of POD elements, + * or a std::string. + * + * A buffer object represents a contiguous region of memory as a 2-tuple + * consisting of a pointer and size in bytes. A tuple of the form {void*, + * size_t} specifies a mutable (modifiable) region of memory. Similarly, a + * tuple of the form {const void*, size_t} specifies a const + * (non-modifiable) region of memory. These two forms correspond to the classes + * mutable_buffer and const_buffer, respectively. To mirror C++'s conversion + * rules, a mutable_buffer is implicitly convertible to a const_buffer, and the + * opposite conversion is not permitted. + * + * The simplest use case involves reading or writing a single buffer of a + * specified size: + * + * @code sock.send(boost::asio::buffer(data, size)); @endcode + * + * In the above example, the return value of boost::asio::buffer meets the + * requirements of the ConstBufferSequence concept so that it may be directly + * passed to the socket's write function. A buffer created for modifiable + * memory also meets the requirements of the MutableBufferSequence concept. + * + * An individual buffer may be created from a builtin array, std::vector, + * std::array or boost::array of POD elements. This helps prevent buffer + * overruns by automatically determining the size of the buffer: + * + * @code char d1[128]; + * size_t bytes_transferred = sock.receive(boost::asio::buffer(d1)); + * + * std::vector d2(128); + * bytes_transferred = sock.receive(boost::asio::buffer(d2)); + * + * std::array d3; + * bytes_transferred = sock.receive(boost::asio::buffer(d3)); + * + * boost::array d4; + * bytes_transferred = sock.receive(boost::asio::buffer(d4)); @endcode + * + * In all three cases above, the buffers created are exactly 128 bytes long. + * Note that a vector is @e never automatically resized when creating or using + * a buffer. The buffer size is determined using the vector's size() + * member function, and not its capacity. + * + * @par Accessing Buffer Contents + * + * The contents of a buffer may be accessed using the @c data() and @c size() + * member functions: + * + * @code boost::asio::mutable_buffer b1 = ...; + * std::size_t s1 = b1.size(); + * unsigned char* p1 = static_cast(b1.data()); + * + * boost::asio::const_buffer b2 = ...; + * std::size_t s2 = b2.size(); + * const void* p2 = b2.data(); @endcode + * + * The @c data() member function permits violations of type safety, so + * uses of it in application code should be carefully considered. + * + * For convenience, a @ref buffer_size function is provided that works with + * both buffers and buffer sequences (that is, types meeting the + * ConstBufferSequence or MutableBufferSequence type requirements). In this + * case, the function returns the total size of all buffers in the sequence. + * + * @par Buffer Copying + * + * The @ref buffer_copy function may be used to copy raw bytes between + * individual buffers and buffer sequences. +* + * In particular, when used with the @ref buffer_size function, the @ref + * buffer_copy function can be used to linearise a sequence of buffers. For + * example: + * + * @code vector buffers = ...; + * + * vector data(boost::asio::buffer_size(buffers)); + * boost::asio::buffer_copy(boost::asio::buffer(data), buffers); @endcode + * + * Note that @ref buffer_copy is implemented in terms of @c memcpy, and + * consequently it cannot be used to copy between overlapping memory regions. + * + * @par Buffer Invalidation + * + * A buffer object does not have any ownership of the memory it refers to. It + * is the responsibility of the application to ensure the memory region remains + * valid until it is no longer required for an I/O operation. When the memory + * is no longer available, the buffer is said to have been invalidated. + * + * For the boost::asio::buffer overloads that accept an argument of type + * std::vector, the buffer objects returned are invalidated by any vector + * operation that also invalidates all references, pointers and iterators + * referring to the elements in the sequence (C++ Std, 23.2.4) + * + * For the boost::asio::buffer overloads that accept an argument of type + * std::basic_string, the buffer objects returned are invalidated according to + * the rules defined for invalidation of references, pointers and iterators + * referring to elements of the sequence (C++ Std, 21.3). + * + * @par Buffer Arithmetic + * + * Buffer objects may be manipulated using simple arithmetic in a safe way + * which helps prevent buffer overruns. Consider an array initialised as + * follows: + * + * @code boost::array a = { 'a', 'b', 'c', 'd', 'e' }; @endcode + * + * A buffer object @c b1 created using: + * + * @code b1 = boost::asio::buffer(a); @endcode + * + * represents the entire array, { 'a', 'b', 'c', 'd', 'e' }. An + * optional second argument to the boost::asio::buffer function may be used to + * limit the size, in bytes, of the buffer: + * + * @code b2 = boost::asio::buffer(a, 3); @endcode + * + * such that @c b2 represents the data { 'a', 'b', 'c' }. Even if the + * size argument exceeds the actual size of the array, the size of the buffer + * object created will be limited to the array size. + * + * An offset may be applied to an existing buffer to create a new one: + * + * @code b3 = b1 + 2; @endcode + * + * where @c b3 will set to represent { 'c', 'd', 'e' }. If the offset + * exceeds the size of the existing buffer, the newly created buffer will be + * empty. + * + * Both an offset and size may be specified to create a buffer that corresponds + * to a specific range of bytes within an existing buffer: + * + * @code b4 = boost::asio::buffer(b1 + 1, 3); @endcode + * + * so that @c b4 will refer to the bytes { 'b', 'c', 'd' }. + * + * @par Buffers and Scatter-Gather I/O + * + * To read or write using multiple buffers (i.e. scatter-gather I/O), multiple + * buffer objects may be assigned into a container that supports the + * MutableBufferSequence (for read) or ConstBufferSequence (for write) concepts: + * + * @code + * char d1[128]; + * std::vector d2(128); + * boost::array d3; + * + * boost::array bufs1 = { + * boost::asio::buffer(d1), + * boost::asio::buffer(d2), + * boost::asio::buffer(d3) }; + * bytes_transferred = sock.receive(bufs1); + * + * std::vector bufs2; + * bufs2.push_back(boost::asio::buffer(d1)); + * bufs2.push_back(boost::asio::buffer(d2)); + * bufs2.push_back(boost::asio::buffer(d3)); + * bytes_transferred = sock.send(bufs2); @endcode + */ +/*@{*/ + +#if defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) +# define BOOST_ASIO_MUTABLE_BUFFER mutable_buffer +# define BOOST_ASIO_CONST_BUFFER const_buffer +#else // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) +# define BOOST_ASIO_MUTABLE_BUFFER mutable_buffers_1 +# define BOOST_ASIO_CONST_BUFFER const_buffers_1 +#endif // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) + +/// Create a new modifiable buffer from an existing buffer. +/** + * @returns mutable_buffer(b). + */ +inline BOOST_ASIO_MUTABLE_BUFFER buffer( + const mutable_buffer& b) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_MUTABLE_BUFFER(b); +} + +/// Create a new modifiable buffer from an existing buffer. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * b.data(), + * min(b.size(), max_size_in_bytes)); @endcode + */ +inline BOOST_ASIO_MUTABLE_BUFFER buffer(const mutable_buffer& b, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_MUTABLE_BUFFER( + mutable_buffer(b.data(), + b.size() < max_size_in_bytes + ? b.size() : max_size_in_bytes +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + )); +} + +/// Create a new non-modifiable buffer from an existing buffer. +/** + * @returns const_buffer(b). + */ +inline BOOST_ASIO_CONST_BUFFER buffer( + const const_buffer& b) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_CONST_BUFFER(b); +} + +/// Create a new non-modifiable buffer from an existing buffer. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * b.data(), + * min(b.size(), max_size_in_bytes)); @endcode + */ +inline BOOST_ASIO_CONST_BUFFER buffer(const const_buffer& b, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_CONST_BUFFER(b.data(), + b.size() < max_size_in_bytes + ? b.size() : max_size_in_bytes +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new modifiable buffer that represents the given memory range. +/** + * @returns mutable_buffer(data, size_in_bytes). + */ +inline BOOST_ASIO_MUTABLE_BUFFER buffer(void* data, + std::size_t size_in_bytes) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_MUTABLE_BUFFER(data, size_in_bytes); +} + +/// Create a new non-modifiable buffer that represents the given memory range. +/** + * @returns const_buffer(data, size_in_bytes). + */ +inline BOOST_ASIO_CONST_BUFFER buffer(const void* data, + std::size_t size_in_bytes) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_CONST_BUFFER(data, size_in_bytes); +} + +/// Create a new modifiable buffer that represents the given POD array. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * static_cast(data), + * N * sizeof(PodType)); @endcode + */ +template +inline BOOST_ASIO_MUTABLE_BUFFER buffer(PodType (&data)[N]) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_MUTABLE_BUFFER(data, N * sizeof(PodType)); +} + +/// Create a new modifiable buffer that represents the given POD array. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * static_cast(data), + * min(N * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline BOOST_ASIO_MUTABLE_BUFFER buffer(PodType (&data)[N], + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_MUTABLE_BUFFER(data, + N * sizeof(PodType) < max_size_in_bytes + ? N * sizeof(PodType) : max_size_in_bytes); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * static_cast(data), + * N * sizeof(PodType)); @endcode + */ +template +inline BOOST_ASIO_CONST_BUFFER buffer( + const PodType (&data)[N]) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_CONST_BUFFER(data, N * sizeof(PodType)); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * static_cast(data), + * min(N * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline BOOST_ASIO_CONST_BUFFER buffer(const PodType (&data)[N], + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_CONST_BUFFER(data, + N * sizeof(PodType) < max_size_in_bytes + ? N * sizeof(PodType) : max_size_in_bytes); +} + +#if defined(BOOST_ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) + +// Borland C++ and Sun Studio think the overloads: +// +// unspecified buffer(boost::array& array ...); +// +// and +// +// unspecified buffer(boost::array& array ...); +// +// are ambiguous. This will be worked around by using a buffer_types traits +// class that contains typedefs for the appropriate buffer and container +// classes, based on whether PodType is const or non-const. + +namespace detail { + +template +struct buffer_types_base; + +template <> +struct buffer_types_base +{ + typedef mutable_buffer buffer_type; + typedef BOOST_ASIO_MUTABLE_BUFFER container_type; +}; + +template <> +struct buffer_types_base +{ + typedef const_buffer buffer_type; + typedef BOOST_ASIO_CONST_BUFFER container_type; +}; + +template +struct buffer_types + : public buffer_types_base::value> +{ +}; + +} // namespace detail + +template +inline typename detail::buffer_types::container_type +buffer(boost::array& data) BOOST_ASIO_NOEXCEPT +{ + typedef typename boost::asio::detail::buffer_types::buffer_type + buffer_type; + typedef typename boost::asio::detail::buffer_types::container_type + container_type; + return container_type( + buffer_type(data.c_array(), data.size() * sizeof(PodType))); +} + +template +inline typename detail::buffer_types::container_type +buffer(boost::array& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT +{ + typedef typename boost::asio::detail::buffer_types::buffer_type + buffer_type; + typedef typename boost::asio::detail::buffer_types::container_type + container_type; + return container_type( + buffer_type(data.c_array(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes)); +} + +#else // defined(BOOST_ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) + +/// Create a new modifiable buffer that represents the given POD array. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.data(), + * data.size() * sizeof(PodType)); @endcode + */ +template +inline BOOST_ASIO_MUTABLE_BUFFER buffer( + boost::array& data) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_MUTABLE_BUFFER( + data.c_array(), data.size() * sizeof(PodType)); +} + +/// Create a new modifiable buffer that represents the given POD array. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.data(), + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline BOOST_ASIO_MUTABLE_BUFFER buffer(boost::array& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_MUTABLE_BUFFER(data.c_array(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.data(), + * data.size() * sizeof(PodType)); @endcode + */ +template +inline BOOST_ASIO_CONST_BUFFER buffer( + boost::array& data) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType)); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.data(), + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline BOOST_ASIO_CONST_BUFFER buffer(boost::array& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_CONST_BUFFER(data.data(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes); +} + +#endif // defined(BOOST_ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.data(), + * data.size() * sizeof(PodType)); @endcode + */ +template +inline BOOST_ASIO_CONST_BUFFER buffer( + const boost::array& data) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType)); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.data(), + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline BOOST_ASIO_CONST_BUFFER buffer(const boost::array& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_CONST_BUFFER(data.data(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes); +} + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) || defined(GENERATING_DOCUMENTATION) + +/// Create a new modifiable buffer that represents the given POD array. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.data(), + * data.size() * sizeof(PodType)); @endcode + */ +template +inline BOOST_ASIO_MUTABLE_BUFFER buffer( + std::array& data) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_MUTABLE_BUFFER(data.data(), data.size() * sizeof(PodType)); +} + +/// Create a new modifiable buffer that represents the given POD array. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.data(), + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline BOOST_ASIO_MUTABLE_BUFFER buffer(std::array& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_MUTABLE_BUFFER(data.data(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.data(), + * data.size() * sizeof(PodType)); @endcode + */ +template +inline BOOST_ASIO_CONST_BUFFER buffer( + std::array& data) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType)); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.data(), + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline BOOST_ASIO_CONST_BUFFER buffer(std::array& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_CONST_BUFFER(data.data(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.data(), + * data.size() * sizeof(PodType)); @endcode + */ +template +inline BOOST_ASIO_CONST_BUFFER buffer( + const std::array& data) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(PodType)); +} + +/// Create a new non-modifiable buffer that represents the given POD array. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.data(), + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + */ +template +inline BOOST_ASIO_CONST_BUFFER buffer(const std::array& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_CONST_BUFFER(data.data(), + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes); +} + +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) || defined(GENERATING_DOCUMENTATION) + +/// Create a new modifiable buffer that represents the given POD vector. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.size() ? &data[0] : 0, + * data.size() * sizeof(PodType)); @endcode + * + * @note The buffer is invalidated by any vector operation that would also + * invalidate iterators. + */ +template +inline BOOST_ASIO_MUTABLE_BUFFER buffer( + std::vector& data) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_MUTABLE_BUFFER( + data.size() ? &data[0] : 0, data.size() * sizeof(PodType) +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::vector::iterator + >(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new modifiable buffer that represents the given POD vector. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.size() ? &data[0] : 0, + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + * + * @note The buffer is invalidated by any vector operation that would also + * invalidate iterators. + */ +template +inline BOOST_ASIO_MUTABLE_BUFFER buffer(std::vector& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0, + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::vector::iterator + >(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new non-modifiable buffer that represents the given POD vector. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.size() ? &data[0] : 0, + * data.size() * sizeof(PodType)); @endcode + * + * @note The buffer is invalidated by any vector operation that would also + * invalidate iterators. + */ +template +inline BOOST_ASIO_CONST_BUFFER buffer( + const std::vector& data) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_CONST_BUFFER( + data.size() ? &data[0] : 0, data.size() * sizeof(PodType) +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::vector::const_iterator + >(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new non-modifiable buffer that represents the given POD vector. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.size() ? &data[0] : 0, + * min(data.size() * sizeof(PodType), max_size_in_bytes)); @endcode + * + * @note The buffer is invalidated by any vector operation that would also + * invalidate iterators. + */ +template +inline BOOST_ASIO_CONST_BUFFER buffer( + const std::vector& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_CONST_BUFFER(data.size() ? &data[0] : 0, + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::vector::const_iterator + >(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new modifiable buffer that represents the given string. +/** + * @returns mutable_buffer(data.size() ? &data[0] : 0, + * data.size() * sizeof(Elem)). + * + * @note The buffer is invalidated by any non-const operation called on the + * given string object. + */ +template +inline BOOST_ASIO_MUTABLE_BUFFER buffer( + std::basic_string& data) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0, + data.size() * sizeof(Elem) +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::basic_string::iterator + >(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new modifiable buffer that represents the given string. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.size() ? &data[0] : 0, + * min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode + * + * @note The buffer is invalidated by any non-const operation called on the + * given string object. + */ +template +inline BOOST_ASIO_MUTABLE_BUFFER buffer( + std::basic_string& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_MUTABLE_BUFFER(data.size() ? &data[0] : 0, + data.size() * sizeof(Elem) < max_size_in_bytes + ? data.size() * sizeof(Elem) : max_size_in_bytes +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::basic_string::iterator + >(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new non-modifiable buffer that represents the given string. +/** + * @returns const_buffer(data.data(), data.size() * sizeof(Elem)). + * + * @note The buffer is invalidated by any non-const operation called on the + * given string object. + */ +template +inline BOOST_ASIO_CONST_BUFFER buffer( + const std::basic_string& data) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_CONST_BUFFER(data.data(), data.size() * sizeof(Elem) +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::basic_string::const_iterator + >(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new non-modifiable buffer that represents the given string. +/** + * @returns A const_buffer value equivalent to: + * @code const_buffer( + * data.data(), + * min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode + * + * @note The buffer is invalidated by any non-const operation called on the + * given string object. + */ +template +inline BOOST_ASIO_CONST_BUFFER buffer( + const std::basic_string& data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_CONST_BUFFER(data.data(), + data.size() * sizeof(Elem) < max_size_in_bytes + ? data.size() * sizeof(Elem) : max_size_in_bytes +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::basic_string::const_iterator + >(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +#if defined(BOOST_ASIO_HAS_STRING_VIEW) \ + || defined(GENERATING_DOCUMENTATION) + +/// Create a new modifiable buffer that represents the given string_view. +/** + * @returns mutable_buffer(data.size() ? &data[0] : 0, + * data.size() * sizeof(Elem)). + */ +template +inline BOOST_ASIO_CONST_BUFFER buffer( + basic_string_view data) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_CONST_BUFFER(data.size() ? &data[0] : 0, + data.size() * sizeof(Elem) +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename basic_string_view::iterator + >(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +/// Create a new non-modifiable buffer that represents the given string. +/** + * @returns A mutable_buffer value equivalent to: + * @code mutable_buffer( + * data.size() ? &data[0] : 0, + * min(data.size() * sizeof(Elem), max_size_in_bytes)); @endcode + */ +template +inline BOOST_ASIO_CONST_BUFFER buffer( + basic_string_view data, + std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT +{ + return BOOST_ASIO_CONST_BUFFER(data.size() ? &data[0] : 0, + data.size() * sizeof(Elem) < max_size_in_bytes + ? data.size() * sizeof(Elem) : max_size_in_bytes +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename basic_string_view::iterator + >(data.begin()) +#endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING + ); +} + +#endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + // || defined(GENERATING_DOCUMENTATION) + +/*@}*/ + +/// Adapt a basic_string to the DynamicBuffer requirements. +/** + * Requires that sizeof(Elem) == 1. + */ +template +class dynamic_string_buffer +{ +public: + /// The type used to represent a sequence of constant buffers that refers to + /// the underlying memory. + typedef BOOST_ASIO_CONST_BUFFER const_buffers_type; + + /// The type used to represent a sequence of mutable buffers that refers to + /// the underlying memory. + typedef BOOST_ASIO_MUTABLE_BUFFER mutable_buffers_type; + + /// Construct a dynamic buffer from a string. + /** + * @param s The string to be used as backing storage for the dynamic buffer. + * The object stores a reference to the string and the user is responsible + * for ensuring that the string object remains valid while the + * dynamic_string_buffer object, and copies of the object, are in use. + * + * @b DynamicBuffer_v1: Any existing data in the string is treated as the + * dynamic buffer's input sequence. + * + * @param maximum_size Specifies a maximum size for the buffer, in bytes. + */ + explicit dynamic_string_buffer(std::basic_string& s, + std::size_t maximum_size = + (std::numeric_limits::max)()) BOOST_ASIO_NOEXCEPT + : string_(s), +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + size_((std::numeric_limits::max)()), +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + max_size_(maximum_size) + { + } + + /// @b DynamicBuffer_v2: Copy construct a dynamic buffer. + dynamic_string_buffer(const dynamic_string_buffer& other) BOOST_ASIO_NOEXCEPT + : string_(other.string_), +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + size_(other.size_), +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + max_size_(other.max_size_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move construct a dynamic buffer. + dynamic_string_buffer(dynamic_string_buffer&& other) BOOST_ASIO_NOEXCEPT + : string_(other.string_), +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + size_(other.size_), +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + max_size_(other.max_size_) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// @b DynamicBuffer_v1: Get the size of the input sequence. + /// @b DynamicBuffer_v2: Get the current size of the underlying memory. + /** + * @returns @b DynamicBuffer_v1 The current size of the input sequence. + * @b DynamicBuffer_v2: The current size of the underlying string if less than + * max_size(). Otherwise returns max_size(). + */ + std::size_t size() const BOOST_ASIO_NOEXCEPT + { +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + if (size_ != (std::numeric_limits::max)()) + return size_; +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + return (std::min)(string_.size(), max_size()); + } + + /// Get the maximum size of the dynamic buffer. + /** + * @returns The allowed maximum size of the underlying memory. + */ + std::size_t max_size() const BOOST_ASIO_NOEXCEPT + { + return max_size_; + } + + /// Get the maximum size that the buffer may grow to without triggering + /// reallocation. + /** + * @returns The current capacity of the underlying string if less than + * max_size(). Otherwise returns max_size(). + */ + std::size_t capacity() const BOOST_ASIO_NOEXCEPT + { + return (std::min)(string_.capacity(), max_size()); + } + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + /// @b DynamicBuffer_v1: Get a list of buffers that represents the input + /// sequence. + /** + * @returns An object of type @c const_buffers_type that satisfies + * ConstBufferSequence requirements, representing the basic_string memory in + * the input sequence. + * + * @note The returned object is invalidated by any @c dynamic_string_buffer + * or @c basic_string member function that resizes or erases the string. + */ + const_buffers_type data() const BOOST_ASIO_NOEXCEPT + { + return const_buffers_type(boost::asio::buffer(string_, size_)); + } +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + + /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the + /// underlying memory. + /** + * @param pos Position of the first byte to represent in the buffer sequence + * + * @param n The number of bytes to return in the buffer sequence. If the + * underlying memory is shorter, the buffer sequence represents as many bytes + * as are available. + * + * @returns An object of type @c mutable_buffers_type that satisfies + * MutableBufferSequence requirements, representing the basic_string memory. + * + * @note The returned object is invalidated by any @c dynamic_string_buffer + * or @c basic_string member function that resizes or erases the string. + */ + mutable_buffers_type data(std::size_t pos, std::size_t n) BOOST_ASIO_NOEXCEPT + { + return mutable_buffers_type(boost::asio::buffer( + boost::asio::buffer(string_, max_size_) + pos, n)); + } + + /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the + /// underlying memory. + /** + * @param pos Position of the first byte to represent in the buffer sequence + * + * @param n The number of bytes to return in the buffer sequence. If the + * underlying memory is shorter, the buffer sequence represents as many bytes + * as are available. + * + * @note The returned object is invalidated by any @c dynamic_string_buffer + * or @c basic_string member function that resizes or erases the string. + */ + const_buffers_type data(std::size_t pos, + std::size_t n) const BOOST_ASIO_NOEXCEPT + { + return const_buffers_type(boost::asio::buffer( + boost::asio::buffer(string_, max_size_) + pos, n)); + } + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + /// @b DynamicBuffer_v1: Get a list of buffers that represents the output + /// sequence, with the given size. + /** + * Ensures that the output sequence can accommodate @c n bytes, resizing the + * basic_string object as necessary. + * + * @returns An object of type @c mutable_buffers_type that satisfies + * MutableBufferSequence requirements, representing basic_string memory + * at the start of the output sequence of size @c n. + * + * @throws std::length_error If size() + n > max_size(). + * + * @note The returned object is invalidated by any @c dynamic_string_buffer + * or @c basic_string member function that modifies the input sequence or + * output sequence. + */ + mutable_buffers_type prepare(std::size_t n) + { + if (size() > max_size() || max_size() - size() < n) + { + std::length_error ex("dynamic_string_buffer too long"); + boost::asio::detail::throw_exception(ex); + } + + if (size_ == (std::numeric_limits::max)()) + size_ = string_.size(); // Enable v1 behaviour. + + string_.resize(size_ + n); + + return boost::asio::buffer(boost::asio::buffer(string_) + size_, n); + } + + /// @b DynamicBuffer_v1: Move bytes from the output sequence to the input + /// sequence. + /** + * @param n The number of bytes to append from the start of the output + * sequence to the end of the input sequence. The remainder of the output + * sequence is discarded. + * + * Requires a preceding call prepare(x) where x >= n, and + * no intervening operations that modify the input or output sequence. + * + * @note If @c n is greater than the size of the output sequence, the entire + * output sequence is moved to the input sequence and no error is issued. + */ + void commit(std::size_t n) + { + size_ += (std::min)(n, string_.size() - size_); + string_.resize(size_); + } +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + + /// @b DynamicBuffer_v2: Grow the underlying memory by the specified number of + /// bytes. + /** + * Resizes the string to accommodate an additional @c n bytes at the end. + * + * @throws std::length_error If size() + n > max_size(). + */ + void grow(std::size_t n) + { + if (size() > max_size() || max_size() - size() < n) + { + std::length_error ex("dynamic_string_buffer too long"); + boost::asio::detail::throw_exception(ex); + } + + string_.resize(size() + n); + } + + /// @b DynamicBuffer_v2: Shrink the underlying memory by the specified number + /// of bytes. + /** + * Erases @c n bytes from the end of the string by resizing the basic_string + * object. If @c n is greater than the current size of the string, the string + * is emptied. + */ + void shrink(std::size_t n) + { + string_.resize(n > size() ? 0 : size() - n); + } + + /// @b DynamicBuffer_v1: Remove characters from the input sequence. + /// @b DynamicBuffer_v2: Consume the specified number of bytes from the + /// beginning of the underlying memory. + /** + * @b DynamicBuffer_v1: Removes @c n characters from the beginning of the + * input sequence. @note If @c n is greater than the size of the input + * sequence, the entire input sequence is consumed and no error is issued. + * + * @b DynamicBuffer_v2: Erases @c n bytes from the beginning of the string. + * If @c n is greater than the current size of the string, the string is + * emptied. + */ + void consume(std::size_t n) + { +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + if (size_ != (std::numeric_limits::max)()) + { + std::size_t consume_length = (std::min)(n, size_); + string_.erase(0, consume_length); + size_ -= consume_length; + return; + } +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + string_.erase(0, n); + } + +private: + std::basic_string& string_; +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + std::size_t size_; +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + const std::size_t max_size_; +}; + +/// Adapt a vector to the DynamicBuffer requirements. +/** + * Requires that sizeof(Elem) == 1. + */ +template +class dynamic_vector_buffer +{ +public: + /// The type used to represent a sequence of constant buffers that refers to + /// the underlying memory. + typedef BOOST_ASIO_CONST_BUFFER const_buffers_type; + + /// The type used to represent a sequence of mutable buffers that refers to + /// the underlying memory. + typedef BOOST_ASIO_MUTABLE_BUFFER mutable_buffers_type; + + /// Construct a dynamic buffer from a vector. + /** + * @param v The vector to be used as backing storage for the dynamic buffer. + * The object stores a reference to the vector and the user is responsible + * for ensuring that the vector object remains valid while the + * dynamic_vector_buffer object, and copies of the object, are in use. + * + * @param maximum_size Specifies a maximum size for the buffer, in bytes. + */ + explicit dynamic_vector_buffer(std::vector& v, + std::size_t maximum_size = + (std::numeric_limits::max)()) BOOST_ASIO_NOEXCEPT + : vector_(v), +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + size_((std::numeric_limits::max)()), +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + max_size_(maximum_size) + { + } + + /// @b DynamicBuffer_v2: Copy construct a dynamic buffer. + dynamic_vector_buffer(const dynamic_vector_buffer& other) BOOST_ASIO_NOEXCEPT + : vector_(other.vector_), +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + size_(other.size_), +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + max_size_(other.max_size_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move construct a dynamic buffer. + dynamic_vector_buffer(dynamic_vector_buffer&& other) BOOST_ASIO_NOEXCEPT + : vector_(other.vector_), +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + size_(other.size_), +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + max_size_(other.max_size_) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// @b DynamicBuffer_v1: Get the size of the input sequence. + /// @b DynamicBuffer_v2: Get the current size of the underlying memory. + /** + * @returns @b DynamicBuffer_v1 The current size of the input sequence. + * @b DynamicBuffer_v2: The current size of the underlying vector if less than + * max_size(). Otherwise returns max_size(). + */ + std::size_t size() const BOOST_ASIO_NOEXCEPT + { +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + if (size_ != (std::numeric_limits::max)()) + return size_; +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + return (std::min)(vector_.size(), max_size()); + } + + /// Get the maximum size of the dynamic buffer. + /** + * @returns @b DynamicBuffer_v1: The allowed maximum of the sum of the sizes + * of the input sequence and output sequence. @b DynamicBuffer_v2: The allowed + * maximum size of the underlying memory. + */ + std::size_t max_size() const BOOST_ASIO_NOEXCEPT + { + return max_size_; + } + + /// Get the maximum size that the buffer may grow to without triggering + /// reallocation. + /** + * @returns @b DynamicBuffer_v1: The current total capacity of the buffer, + * i.e. for both the input sequence and output sequence. @b DynamicBuffer_v2: + * The current capacity of the underlying vector if less than max_size(). + * Otherwise returns max_size(). + */ + std::size_t capacity() const BOOST_ASIO_NOEXCEPT + { + return (std::min)(vector_.capacity(), max_size()); + } + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + /// @b DynamicBuffer_v1: Get a list of buffers that represents the input + /// sequence. + /** + * @returns An object of type @c const_buffers_type that satisfies + * ConstBufferSequence requirements, representing the vector memory in the + * input sequence. + * + * @note The returned object is invalidated by any @c dynamic_vector_buffer + * or @c vector member function that modifies the input sequence or output + * sequence. + */ + const_buffers_type data() const BOOST_ASIO_NOEXCEPT + { + return const_buffers_type(boost::asio::buffer(vector_, size_)); + } +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + + /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the + /// underlying memory. + /** + * @param pos Position of the first byte to represent in the buffer sequence + * + * @param n The number of bytes to return in the buffer sequence. If the + * underlying memory is shorter, the buffer sequence represents as many bytes + * as are available. + * + * @returns An object of type @c mutable_buffers_type that satisfies + * MutableBufferSequence requirements, representing the vector memory. + * + * @note The returned object is invalidated by any @c dynamic_vector_buffer + * or @c vector member function that resizes or erases the vector. + */ + mutable_buffers_type data(std::size_t pos, std::size_t n) BOOST_ASIO_NOEXCEPT + { + return mutable_buffers_type(boost::asio::buffer( + boost::asio::buffer(vector_, max_size_) + pos, n)); + } + + /// @b DynamicBuffer_v2: Get a sequence of buffers that represents the + /// underlying memory. + /** + * @param pos Position of the first byte to represent in the buffer sequence + * + * @param n The number of bytes to return in the buffer sequence. If the + * underlying memory is shorter, the buffer sequence represents as many bytes + * as are available. + * + * @note The returned object is invalidated by any @c dynamic_vector_buffer + * or @c vector member function that resizes or erases the vector. + */ + const_buffers_type data(std::size_t pos, + std::size_t n) const BOOST_ASIO_NOEXCEPT + { + return const_buffers_type(boost::asio::buffer( + boost::asio::buffer(vector_, max_size_) + pos, n)); + } + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + /// @b DynamicBuffer_v1: Get a list of buffers that represents the output + /// sequence, with the given size. + /** + * Ensures that the output sequence can accommodate @c n bytes, resizing the + * vector object as necessary. + * + * @returns An object of type @c mutable_buffers_type that satisfies + * MutableBufferSequence requirements, representing vector memory at the + * start of the output sequence of size @c n. + * + * @throws std::length_error If size() + n > max_size(). + * + * @note The returned object is invalidated by any @c dynamic_vector_buffer + * or @c vector member function that modifies the input sequence or output + * sequence. + */ + mutable_buffers_type prepare(std::size_t n) + { + if (size () > max_size() || max_size() - size() < n) + { + std::length_error ex("dynamic_vector_buffer too long"); + boost::asio::detail::throw_exception(ex); + } + + if (size_ == (std::numeric_limits::max)()) + size_ = vector_.size(); // Enable v1 behaviour. + + vector_.resize(size_ + n); + + return boost::asio::buffer(boost::asio::buffer(vector_) + size_, n); + } + + /// @b DynamicBuffer_v1: Move bytes from the output sequence to the input + /// sequence. + /** + * @param n The number of bytes to append from the start of the output + * sequence to the end of the input sequence. The remainder of the output + * sequence is discarded. + * + * Requires a preceding call prepare(x) where x >= n, and + * no intervening operations that modify the input or output sequence. + * + * @note If @c n is greater than the size of the output sequence, the entire + * output sequence is moved to the input sequence and no error is issued. + */ + void commit(std::size_t n) + { + size_ += (std::min)(n, vector_.size() - size_); + vector_.resize(size_); + } +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + + /// @b DynamicBuffer_v2: Grow the underlying memory by the specified number of + /// bytes. + /** + * Resizes the vector to accommodate an additional @c n bytes at the end. + * + * @throws std::length_error If size() + n > max_size(). + */ + void grow(std::size_t n) + { + if (size() > max_size() || max_size() - size() < n) + { + std::length_error ex("dynamic_vector_buffer too long"); + boost::asio::detail::throw_exception(ex); + } + + vector_.resize(size() + n); + } + + /// @b DynamicBuffer_v2: Shrink the underlying memory by the specified number + /// of bytes. + /** + * Erases @c n bytes from the end of the vector by resizing the vector + * object. If @c n is greater than the current size of the vector, the vector + * is emptied. + */ + void shrink(std::size_t n) + { + vector_.resize(n > size() ? 0 : size() - n); + } + + /// @b DynamicBuffer_v1: Remove characters from the input sequence. + /// @b DynamicBuffer_v2: Consume the specified number of bytes from the + /// beginning of the underlying memory. + /** + * @b DynamicBuffer_v1: Removes @c n characters from the beginning of the + * input sequence. @note If @c n is greater than the size of the input + * sequence, the entire input sequence is consumed and no error is issued. + * + * @b DynamicBuffer_v2: Erases @c n bytes from the beginning of the vector. + * If @c n is greater than the current size of the vector, the vector is + * emptied. + */ + void consume(std::size_t n) + { +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + if (size_ != (std::numeric_limits::max)()) + { + std::size_t consume_length = (std::min)(n, size_); + vector_.erase(vector_.begin(), vector_.begin() + consume_length); + size_ -= consume_length; + return; + } +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + vector_.erase(vector_.begin(), vector_.begin() + (std::min)(size(), n)); + } + +private: + std::vector& vector_; +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + std::size_t size_; +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + const std::size_t max_size_; +}; + +/** @defgroup dynamic_buffer boost::asio::dynamic_buffer + * + * @brief The boost::asio::dynamic_buffer function is used to create a + * dynamically resized buffer from a @c std::basic_string or @c std::vector. + */ +/*@{*/ + +/// Create a new dynamic buffer that represents the given string. +/** + * @returns dynamic_string_buffer(data). + */ +template +inline dynamic_string_buffer dynamic_buffer( + std::basic_string& data) BOOST_ASIO_NOEXCEPT +{ + return dynamic_string_buffer(data); +} + +/// Create a new dynamic buffer that represents the given string. +/** + * @returns dynamic_string_buffer(data, + * max_size). + */ +template +inline dynamic_string_buffer dynamic_buffer( + std::basic_string& data, + std::size_t max_size) BOOST_ASIO_NOEXCEPT +{ + return dynamic_string_buffer(data, max_size); +} + +/// Create a new dynamic buffer that represents the given vector. +/** + * @returns dynamic_vector_buffer(data). + */ +template +inline dynamic_vector_buffer dynamic_buffer( + std::vector& data) BOOST_ASIO_NOEXCEPT +{ + return dynamic_vector_buffer(data); +} + +/// Create a new dynamic buffer that represents the given vector. +/** + * @returns dynamic_vector_buffer(data, max_size). + */ +template +inline dynamic_vector_buffer dynamic_buffer( + std::vector& data, + std::size_t max_size) BOOST_ASIO_NOEXCEPT +{ + return dynamic_vector_buffer(data, max_size); +} + +/*@}*/ + +/** @defgroup buffer_copy boost::asio::buffer_copy + * + * @brief The boost::asio::buffer_copy function is used to copy bytes from a + * source buffer (or buffer sequence) to a target buffer (or buffer sequence). + * + * The @c buffer_copy function is available in two forms: + * + * @li A 2-argument form: @c buffer_copy(target, source) + * + * @li A 3-argument form: @c buffer_copy(target, source, max_bytes_to_copy) + * + * Both forms return the number of bytes actually copied. The number of bytes + * copied is the lesser of: + * + * @li @c buffer_size(target) + * + * @li @c buffer_size(source) + * + * @li @c If specified, @c max_bytes_to_copy. + * + * This prevents buffer overflow, regardless of the buffer sizes used in the + * copy operation. + * + * Note that @ref buffer_copy is implemented in terms of @c memcpy, and + * consequently it cannot be used to copy between overlapping memory regions. + */ +/*@{*/ + +namespace detail { + +inline std::size_t buffer_copy_1(const mutable_buffer& target, + const const_buffer& source) +{ + using namespace std; // For memcpy. + std::size_t target_size = target.size(); + std::size_t source_size = source.size(); + std::size_t n = target_size < source_size ? target_size : source_size; + if (n > 0) + memcpy(target.data(), source.data(), n); + return n; +} + +template +inline std::size_t buffer_copy(one_buffer, one_buffer, + TargetIterator target_begin, TargetIterator, + SourceIterator source_begin, SourceIterator) BOOST_ASIO_NOEXCEPT +{ + return (buffer_copy_1)(*target_begin, *source_begin); +} + +template +inline std::size_t buffer_copy(one_buffer, one_buffer, + TargetIterator target_begin, TargetIterator, + SourceIterator source_begin, SourceIterator, + std::size_t max_bytes_to_copy) BOOST_ASIO_NOEXCEPT +{ + return (buffer_copy_1)(*target_begin, + boost::asio::buffer(*source_begin, max_bytes_to_copy)); +} + +template +std::size_t buffer_copy(one_buffer, multiple_buffers, + TargetIterator target_begin, TargetIterator, + SourceIterator source_begin, SourceIterator source_end, + std::size_t max_bytes_to_copy + = (std::numeric_limits::max)()) BOOST_ASIO_NOEXCEPT +{ + std::size_t total_bytes_copied = 0; + SourceIterator source_iter = source_begin; + + for (mutable_buffer target_buffer( + boost::asio::buffer(*target_begin, max_bytes_to_copy)); + target_buffer.size() && source_iter != source_end; ++source_iter) + { + const_buffer source_buffer(*source_iter); + std::size_t bytes_copied = (buffer_copy_1)(target_buffer, source_buffer); + total_bytes_copied += bytes_copied; + target_buffer += bytes_copied; + } + + return total_bytes_copied; +} + +template +std::size_t buffer_copy(multiple_buffers, one_buffer, + TargetIterator target_begin, TargetIterator target_end, + SourceIterator source_begin, SourceIterator, + std::size_t max_bytes_to_copy + = (std::numeric_limits::max)()) BOOST_ASIO_NOEXCEPT +{ + std::size_t total_bytes_copied = 0; + TargetIterator target_iter = target_begin; + + for (const_buffer source_buffer( + boost::asio::buffer(*source_begin, max_bytes_to_copy)); + source_buffer.size() && target_iter != target_end; ++target_iter) + { + mutable_buffer target_buffer(*target_iter); + std::size_t bytes_copied = (buffer_copy_1)(target_buffer, source_buffer); + total_bytes_copied += bytes_copied; + source_buffer += bytes_copied; + } + + return total_bytes_copied; +} + +template +std::size_t buffer_copy(multiple_buffers, multiple_buffers, + TargetIterator target_begin, TargetIterator target_end, + SourceIterator source_begin, SourceIterator source_end) BOOST_ASIO_NOEXCEPT +{ + std::size_t total_bytes_copied = 0; + + TargetIterator target_iter = target_begin; + std::size_t target_buffer_offset = 0; + + SourceIterator source_iter = source_begin; + std::size_t source_buffer_offset = 0; + + while (target_iter != target_end && source_iter != source_end) + { + mutable_buffer target_buffer = + mutable_buffer(*target_iter) + target_buffer_offset; + + const_buffer source_buffer = + const_buffer(*source_iter) + source_buffer_offset; + + std::size_t bytes_copied = (buffer_copy_1)(target_buffer, source_buffer); + total_bytes_copied += bytes_copied; + + if (bytes_copied == target_buffer.size()) + { + ++target_iter; + target_buffer_offset = 0; + } + else + target_buffer_offset += bytes_copied; + + if (bytes_copied == source_buffer.size()) + { + ++source_iter; + source_buffer_offset = 0; + } + else + source_buffer_offset += bytes_copied; + } + + return total_bytes_copied; +} + +template +std::size_t buffer_copy(multiple_buffers, multiple_buffers, + TargetIterator target_begin, TargetIterator target_end, + SourceIterator source_begin, SourceIterator source_end, + std::size_t max_bytes_to_copy) BOOST_ASIO_NOEXCEPT +{ + std::size_t total_bytes_copied = 0; + + TargetIterator target_iter = target_begin; + std::size_t target_buffer_offset = 0; + + SourceIterator source_iter = source_begin; + std::size_t source_buffer_offset = 0; + + while (total_bytes_copied != max_bytes_to_copy + && target_iter != target_end && source_iter != source_end) + { + mutable_buffer target_buffer = + mutable_buffer(*target_iter) + target_buffer_offset; + + const_buffer source_buffer = + const_buffer(*source_iter) + source_buffer_offset; + + std::size_t bytes_copied = (buffer_copy_1)( + target_buffer, boost::asio::buffer(source_buffer, + max_bytes_to_copy - total_bytes_copied)); + total_bytes_copied += bytes_copied; + + if (bytes_copied == target_buffer.size()) + { + ++target_iter; + target_buffer_offset = 0; + } + else + target_buffer_offset += bytes_copied; + + if (bytes_copied == source_buffer.size()) + { + ++source_iter; + source_buffer_offset = 0; + } + else + source_buffer_offset += bytes_copied; + } + + return total_bytes_copied; +} + +} // namespace detail + +/// Copies bytes from a source buffer sequence to a target buffer sequence. +/** + * @param target A modifiable buffer sequence representing the memory regions to + * which the bytes will be copied. + * + * @param source A non-modifiable buffer sequence representing the memory + * regions from which the bytes will be copied. + * + * @returns The number of bytes copied. + * + * @note The number of bytes copied is the lesser of: + * + * @li @c buffer_size(target) + * + * @li @c buffer_size(source) + * + * This function is implemented in terms of @c memcpy, and consequently it + * cannot be used to copy between overlapping memory regions. + */ +template +inline std::size_t buffer_copy(const MutableBufferSequence& target, + const ConstBufferSequence& source) BOOST_ASIO_NOEXCEPT +{ + return detail::buffer_copy( + detail::buffer_sequence_cardinality(), + detail::buffer_sequence_cardinality(), + boost::asio::buffer_sequence_begin(target), + boost::asio::buffer_sequence_end(target), + boost::asio::buffer_sequence_begin(source), + boost::asio::buffer_sequence_end(source)); +} + +/// Copies a limited number of bytes from a source buffer sequence to a target +/// buffer sequence. +/** + * @param target A modifiable buffer sequence representing the memory regions to + * which the bytes will be copied. + * + * @param source A non-modifiable buffer sequence representing the memory + * regions from which the bytes will be copied. + * + * @param max_bytes_to_copy The maximum number of bytes to be copied. + * + * @returns The number of bytes copied. + * + * @note The number of bytes copied is the lesser of: + * + * @li @c buffer_size(target) + * + * @li @c buffer_size(source) + * + * @li @c max_bytes_to_copy + * + * This function is implemented in terms of @c memcpy, and consequently it + * cannot be used to copy between overlapping memory regions. + */ +template +inline std::size_t buffer_copy(const MutableBufferSequence& target, + const ConstBufferSequence& source, + std::size_t max_bytes_to_copy) BOOST_ASIO_NOEXCEPT +{ + return detail::buffer_copy( + detail::buffer_sequence_cardinality(), + detail::buffer_sequence_cardinality(), + boost::asio::buffer_sequence_begin(target), + boost::asio::buffer_sequence_end(target), + boost::asio::buffer_sequence_begin(source), + boost::asio::buffer_sequence_end(source), max_bytes_to_copy); +} + +/*@}*/ + +} // namespace asio +} // namespace boost + +#include +#include +#include + +namespace boost { +namespace asio { + +/// Trait to determine whether a type satisfies the MutableBufferSequence +/// requirements. +template +struct is_mutable_buffer_sequence +#if defined(GENERATING_DOCUMENTATION) + : integral_constant +#else // defined(GENERATING_DOCUMENTATION) + : boost::asio::detail::is_buffer_sequence +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +/// Trait to determine whether a type satisfies the ConstBufferSequence +/// requirements. +template +struct is_const_buffer_sequence +#if defined(GENERATING_DOCUMENTATION) + : integral_constant +#else // defined(GENERATING_DOCUMENTATION) + : boost::asio::detail::is_buffer_sequence +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +/// Trait to determine whether a type satisfies the DynamicBuffer_v1 +/// requirements. +template +struct is_dynamic_buffer_v1 +#if defined(GENERATING_DOCUMENTATION) + : integral_constant +#else // defined(GENERATING_DOCUMENTATION) + : boost::asio::detail::is_dynamic_buffer_v1 +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Trait to determine whether a type satisfies the DynamicBuffer_v2 +/// requirements. +template +struct is_dynamic_buffer_v2 +#if defined(GENERATING_DOCUMENTATION) + : integral_constant +#else // defined(GENERATING_DOCUMENTATION) + : boost::asio::detail::is_dynamic_buffer_v2 +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +/// Trait to determine whether a type satisfies the DynamicBuffer requirements. +/** + * If @c BOOST_ASIO_NO_DYNAMIC_BUFFER_V1 is not defined, determines whether the + * type satisfies the DynamicBuffer_v1 requirements. Otherwise, if @c + * BOOST_ASIO_NO_DYNAMIC_BUFFER_V1 is defined, determines whether the type + * satisfies the DynamicBuffer_v2 requirements. + */ +template +struct is_dynamic_buffer +#if defined(GENERATING_DOCUMENTATION) + : integral_constant +#elif defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + : boost::asio::is_dynamic_buffer_v2 +#else // defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + : boost::asio::is_dynamic_buffer_v1 +#endif // defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) +{ +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BUFFER_HPP diff --git a/boost/asio/buffered_read_stream.hpp b/boost/asio/buffered_read_stream.hpp new file mode 100644 index 0000000..cd1e062 --- /dev/null +++ b/boost/asio/buffered_read_stream.hpp @@ -0,0 +1,242 @@ +// +// buffered_read_stream.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BUFFERED_READ_STREAM_HPP +#define BOOST_ASIO_BUFFERED_READ_STREAM_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +/// Adds buffering to the read-related operations of a stream. +/** + * The buffered_read_stream class template can be used to add buffering to the + * synchronous and asynchronous read operations of a stream. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Concepts: + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. + */ +template +class buffered_read_stream + : private noncopyable +{ +public: + /// The type of the next layer. + typedef typename remove_reference::type next_layer_type; + + /// The type of the lowest layer. + typedef typename next_layer_type::lowest_layer_type lowest_layer_type; + + /// The type of the executor associated with the object. + typedef typename lowest_layer_type::executor_type executor_type; + +#if defined(GENERATING_DOCUMENTATION) + /// The default buffer size. + static const std::size_t default_buffer_size = implementation_defined; +#else + BOOST_ASIO_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024); +#endif + + /// Construct, passing the specified argument to initialise the next layer. + template + explicit buffered_read_stream(Arg& a) + : next_layer_(a), + storage_(default_buffer_size) + { + } + + /// Construct, passing the specified argument to initialise the next layer. + template + buffered_read_stream(Arg& a, std::size_t buffer_size) + : next_layer_(a), + storage_(buffer_size) + { + } + + /// Get a reference to the next layer. + next_layer_type& next_layer() + { + return next_layer_; + } + + /// Get a reference to the lowest layer. + lowest_layer_type& lowest_layer() + { + return next_layer_.lowest_layer(); + } + + /// Get a const reference to the lowest layer. + const lowest_layer_type& lowest_layer() const + { + return next_layer_.lowest_layer(); + } + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return next_layer_.lowest_layer().get_executor(); + } + + /// Close the stream. + void close() + { + next_layer_.close(); + } + + /// Close the stream. + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) + { + next_layer_.close(ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Write the given data to the stream. Returns the number of bytes written. + /// Throws an exception on failure. + template + std::size_t write_some(const ConstBufferSequence& buffers) + { + return next_layer_.write_some(buffers); + } + + /// Write the given data to the stream. Returns the number of bytes written, + /// or 0 if an error occurred. + template + std::size_t write_some(const ConstBufferSequence& buffers, + boost::system::error_code& ec) + { + return next_layer_.write_some(buffers, ec); + } + + /// Start an asynchronous write. The data being written must be valid for the + /// lifetime of the asynchronous operation. + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_write_some(const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + return next_layer_.async_write_some(buffers, + BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + } + + /// Fill the buffer with some data. Returns the number of bytes placed in the + /// buffer as a result of the operation. Throws an exception on failure. + std::size_t fill(); + + /// Fill the buffer with some data. Returns the number of bytes placed in the + /// buffer as a result of the operation, or 0 if an error occurred. + std::size_t fill(boost::system::error_code& ec); + + /// Start an asynchronous fill. + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_fill(BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + + /// Read some data from the stream. Returns the number of bytes read. Throws + /// an exception on failure. + template + std::size_t read_some(const MutableBufferSequence& buffers); + + /// Read some data from the stream. Returns the number of bytes read or 0 if + /// an error occurred. + template + std::size_t read_some(const MutableBufferSequence& buffers, + boost::system::error_code& ec); + + /// Start an asynchronous read. The buffer into which the data will be read + /// must be valid for the lifetime of the asynchronous operation. + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_read_some(const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + + /// Peek at the incoming data on the stream. Returns the number of bytes read. + /// Throws an exception on failure. + template + std::size_t peek(const MutableBufferSequence& buffers); + + /// Peek at the incoming data on the stream. Returns the number of bytes read, + /// or 0 if an error occurred. + template + std::size_t peek(const MutableBufferSequence& buffers, + boost::system::error_code& ec); + + /// Determine the amount of data that may be read without blocking. + std::size_t in_avail() + { + return storage_.size(); + } + + /// Determine the amount of data that may be read without blocking. + std::size_t in_avail(boost::system::error_code& ec) + { + ec = boost::system::error_code(); + return storage_.size(); + } + +private: + /// Copy data out of the internal buffer to the specified target buffer. + /// Returns the number of bytes copied. + template + std::size_t copy(const MutableBufferSequence& buffers) + { + std::size_t bytes_copied = boost::asio::buffer_copy( + buffers, storage_.data(), storage_.size()); + storage_.consume(bytes_copied); + return bytes_copied; + } + + /// Copy data from the internal buffer to the specified target buffer, without + /// removing the data from the internal buffer. Returns the number of bytes + /// copied. + template + std::size_t peek_copy(const MutableBufferSequence& buffers) + { + return boost::asio::buffer_copy(buffers, storage_.data(), storage_.size()); + } + + /// The next layer. + Stream next_layer_; + + // The data in the buffer. + detail::buffered_stream_storage storage_; +}; + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // BOOST_ASIO_BUFFERED_READ_STREAM_HPP diff --git a/boost/asio/buffered_read_stream_fwd.hpp b/boost/asio/buffered_read_stream_fwd.hpp new file mode 100644 index 0000000..f250c92 --- /dev/null +++ b/boost/asio/buffered_read_stream_fwd.hpp @@ -0,0 +1,27 @@ +// +// buffered_read_stream_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BUFFERED_READ_STREAM_FWD_HPP +#define BOOST_ASIO_BUFFERED_READ_STREAM_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +namespace boost { +namespace asio { + +template +class buffered_read_stream; + +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_BUFFERED_READ_STREAM_FWD_HPP diff --git a/boost/asio/buffered_stream.hpp b/boost/asio/buffered_stream.hpp new file mode 100644 index 0000000..d28abf1 --- /dev/null +++ b/boost/asio/buffered_stream.hpp @@ -0,0 +1,263 @@ +// +// buffered_stream.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BUFFERED_STREAM_HPP +#define BOOST_ASIO_BUFFERED_STREAM_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +/// Adds buffering to the read- and write-related operations of a stream. +/** + * The buffered_stream class template can be used to add buffering to the + * synchronous and asynchronous read and write operations of a stream. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Concepts: + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. + */ +template +class buffered_stream + : private noncopyable +{ +public: + /// The type of the next layer. + typedef typename remove_reference::type next_layer_type; + + /// The type of the lowest layer. + typedef typename next_layer_type::lowest_layer_type lowest_layer_type; + + /// The type of the executor associated with the object. + typedef typename lowest_layer_type::executor_type executor_type; + + /// Construct, passing the specified argument to initialise the next layer. + template + explicit buffered_stream(Arg& a) + : inner_stream_impl_(a), + stream_impl_(inner_stream_impl_) + { + } + + /// Construct, passing the specified argument to initialise the next layer. + template + explicit buffered_stream(Arg& a, std::size_t read_buffer_size, + std::size_t write_buffer_size) + : inner_stream_impl_(a, write_buffer_size), + stream_impl_(inner_stream_impl_, read_buffer_size) + { + } + + /// Get a reference to the next layer. + next_layer_type& next_layer() + { + return stream_impl_.next_layer().next_layer(); + } + + /// Get a reference to the lowest layer. + lowest_layer_type& lowest_layer() + { + return stream_impl_.lowest_layer(); + } + + /// Get a const reference to the lowest layer. + const lowest_layer_type& lowest_layer() const + { + return stream_impl_.lowest_layer(); + } + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return stream_impl_.lowest_layer().get_executor(); + } + + /// Close the stream. + void close() + { + stream_impl_.close(); + } + + /// Close the stream. + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) + { + stream_impl_.close(ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Flush all data from the buffer to the next layer. Returns the number of + /// bytes written to the next layer on the last write operation. Throws an + /// exception on failure. + std::size_t flush() + { + return stream_impl_.next_layer().flush(); + } + + /// Flush all data from the buffer to the next layer. Returns the number of + /// bytes written to the next layer on the last write operation, or 0 if an + /// error occurred. + std::size_t flush(boost::system::error_code& ec) + { + return stream_impl_.next_layer().flush(ec); + } + + /// Start an asynchronous flush. + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_flush(BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + return stream_impl_.next_layer().async_flush( + BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + } + + /// Write the given data to the stream. Returns the number of bytes written. + /// Throws an exception on failure. + template + std::size_t write_some(const ConstBufferSequence& buffers) + { + return stream_impl_.write_some(buffers); + } + + /// Write the given data to the stream. Returns the number of bytes written, + /// or 0 if an error occurred. + template + std::size_t write_some(const ConstBufferSequence& buffers, + boost::system::error_code& ec) + { + return stream_impl_.write_some(buffers, ec); + } + + /// Start an asynchronous write. The data being written must be valid for the + /// lifetime of the asynchronous operation. + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_write_some(const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + return stream_impl_.async_write_some(buffers, + BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); + } + + /// Fill the buffer with some data. Returns the number of bytes placed in the + /// buffer as a result of the operation. Throws an exception on failure. + std::size_t fill() + { + return stream_impl_.fill(); + } + + /// Fill the buffer with some data. Returns the number of bytes placed in the + /// buffer as a result of the operation, or 0 if an error occurred. + std::size_t fill(boost::system::error_code& ec) + { + return stream_impl_.fill(ec); + } + + /// Start an asynchronous fill. + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_fill(BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + return stream_impl_.async_fill(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + } + + /// Read some data from the stream. Returns the number of bytes read. Throws + /// an exception on failure. + template + std::size_t read_some(const MutableBufferSequence& buffers) + { + return stream_impl_.read_some(buffers); + } + + /// Read some data from the stream. Returns the number of bytes read or 0 if + /// an error occurred. + template + std::size_t read_some(const MutableBufferSequence& buffers, + boost::system::error_code& ec) + { + return stream_impl_.read_some(buffers, ec); + } + + /// Start an asynchronous read. The buffer into which the data will be read + /// must be valid for the lifetime of the asynchronous operation. + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_read_some(const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + return stream_impl_.async_read_some(buffers, + BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + } + + /// Peek at the incoming data on the stream. Returns the number of bytes read. + /// Throws an exception on failure. + template + std::size_t peek(const MutableBufferSequence& buffers) + { + return stream_impl_.peek(buffers); + } + + /// Peek at the incoming data on the stream. Returns the number of bytes read, + /// or 0 if an error occurred. + template + std::size_t peek(const MutableBufferSequence& buffers, + boost::system::error_code& ec) + { + return stream_impl_.peek(buffers, ec); + } + + /// Determine the amount of data that may be read without blocking. + std::size_t in_avail() + { + return stream_impl_.in_avail(); + } + + /// Determine the amount of data that may be read without blocking. + std::size_t in_avail(boost::system::error_code& ec) + { + return stream_impl_.in_avail(ec); + } + +private: + // The buffered write stream. + typedef buffered_write_stream write_stream_type; + write_stream_type inner_stream_impl_; + + // The buffered read stream. + typedef buffered_read_stream read_stream_type; + read_stream_type stream_impl_; +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BUFFERED_STREAM_HPP diff --git a/boost/asio/buffered_stream_fwd.hpp b/boost/asio/buffered_stream_fwd.hpp new file mode 100644 index 0000000..ceeac16 --- /dev/null +++ b/boost/asio/buffered_stream_fwd.hpp @@ -0,0 +1,27 @@ +// +// buffered_stream_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BUFFERED_STREAM_FWD_HPP +#define BOOST_ASIO_BUFFERED_STREAM_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +namespace boost { +namespace asio { + +template +class buffered_stream; + +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_BUFFERED_STREAM_FWD_HPP diff --git a/boost/asio/buffered_write_stream.hpp b/boost/asio/buffered_write_stream.hpp new file mode 100644 index 0000000..aab02b5 --- /dev/null +++ b/boost/asio/buffered_write_stream.hpp @@ -0,0 +1,234 @@ +// +// buffered_write_stream.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BUFFERED_WRITE_STREAM_HPP +#define BOOST_ASIO_BUFFERED_WRITE_STREAM_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +/// Adds buffering to the write-related operations of a stream. +/** + * The buffered_write_stream class template can be used to add buffering to the + * synchronous and asynchronous write operations of a stream. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Concepts: + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. + */ +template +class buffered_write_stream + : private noncopyable +{ +public: + /// The type of the next layer. + typedef typename remove_reference::type next_layer_type; + + /// The type of the lowest layer. + typedef typename next_layer_type::lowest_layer_type lowest_layer_type; + + /// The type of the executor associated with the object. + typedef typename lowest_layer_type::executor_type executor_type; + +#if defined(GENERATING_DOCUMENTATION) + /// The default buffer size. + static const std::size_t default_buffer_size = implementation_defined; +#else + BOOST_ASIO_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024); +#endif + + /// Construct, passing the specified argument to initialise the next layer. + template + explicit buffered_write_stream(Arg& a) + : next_layer_(a), + storage_(default_buffer_size) + { + } + + /// Construct, passing the specified argument to initialise the next layer. + template + buffered_write_stream(Arg& a, std::size_t buffer_size) + : next_layer_(a), + storage_(buffer_size) + { + } + + /// Get a reference to the next layer. + next_layer_type& next_layer() + { + return next_layer_; + } + + /// Get a reference to the lowest layer. + lowest_layer_type& lowest_layer() + { + return next_layer_.lowest_layer(); + } + + /// Get a const reference to the lowest layer. + const lowest_layer_type& lowest_layer() const + { + return next_layer_.lowest_layer(); + } + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return next_layer_.lowest_layer().get_executor(); + } + + /// Close the stream. + void close() + { + next_layer_.close(); + } + + /// Close the stream. + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) + { + next_layer_.close(ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Flush all data from the buffer to the next layer. Returns the number of + /// bytes written to the next layer on the last write operation. Throws an + /// exception on failure. + std::size_t flush(); + + /// Flush all data from the buffer to the next layer. Returns the number of + /// bytes written to the next layer on the last write operation, or 0 if an + /// error occurred. + std::size_t flush(boost::system::error_code& ec); + + /// Start an asynchronous flush. + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_flush(BOOST_ASIO_MOVE_ARG(WriteHandler) handler); + + /// Write the given data to the stream. Returns the number of bytes written. + /// Throws an exception on failure. + template + std::size_t write_some(const ConstBufferSequence& buffers); + + /// Write the given data to the stream. Returns the number of bytes written, + /// or 0 if an error occurred and the error handler did not throw. + template + std::size_t write_some(const ConstBufferSequence& buffers, + boost::system::error_code& ec); + + /// Start an asynchronous write. The data being written must be valid for the + /// lifetime of the asynchronous operation. + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_write_some(const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler); + + /// Read some data from the stream. Returns the number of bytes read. Throws + /// an exception on failure. + template + std::size_t read_some(const MutableBufferSequence& buffers) + { + return next_layer_.read_some(buffers); + } + + /// Read some data from the stream. Returns the number of bytes read or 0 if + /// an error occurred. + template + std::size_t read_some(const MutableBufferSequence& buffers, + boost::system::error_code& ec) + { + return next_layer_.read_some(buffers, ec); + } + + /// Start an asynchronous read. The buffer into which the data will be read + /// must be valid for the lifetime of the asynchronous operation. + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_read_some(const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + return next_layer_.async_read_some(buffers, + BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); + } + + /// Peek at the incoming data on the stream. Returns the number of bytes read. + /// Throws an exception on failure. + template + std::size_t peek(const MutableBufferSequence& buffers) + { + return next_layer_.peek(buffers); + } + + /// Peek at the incoming data on the stream. Returns the number of bytes read, + /// or 0 if an error occurred. + template + std::size_t peek(const MutableBufferSequence& buffers, + boost::system::error_code& ec) + { + return next_layer_.peek(buffers, ec); + } + + /// Determine the amount of data that may be read without blocking. + std::size_t in_avail() + { + return next_layer_.in_avail(); + } + + /// Determine the amount of data that may be read without blocking. + std::size_t in_avail(boost::system::error_code& ec) + { + return next_layer_.in_avail(ec); + } + +private: + /// Copy data into the internal buffer from the specified source buffer. + /// Returns the number of bytes copied. + template + std::size_t copy(const ConstBufferSequence& buffers); + + /// The next layer. + Stream next_layer_; + + // The data in the buffer. + detail::buffered_stream_storage storage_; +}; + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // BOOST_ASIO_BUFFERED_WRITE_STREAM_HPP diff --git a/boost/asio/buffered_write_stream_fwd.hpp b/boost/asio/buffered_write_stream_fwd.hpp new file mode 100644 index 0000000..eec5bc2 --- /dev/null +++ b/boost/asio/buffered_write_stream_fwd.hpp @@ -0,0 +1,27 @@ +// +// buffered_write_stream_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BUFFERED_WRITE_STREAM_FWD_HPP +#define BOOST_ASIO_BUFFERED_WRITE_STREAM_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +namespace boost { +namespace asio { + +template +class buffered_write_stream; + +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_BUFFERED_WRITE_STREAM_FWD_HPP diff --git a/boost/asio/buffers_iterator.hpp b/boost/asio/buffers_iterator.hpp new file mode 100644 index 0000000..316c144 --- /dev/null +++ b/boost/asio/buffers_iterator.hpp @@ -0,0 +1,523 @@ +// +// buffers_iterator.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_BUFFERS_ITERATOR_HPP +#define BOOST_ASIO_BUFFERS_ITERATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +namespace detail +{ + template + struct buffers_iterator_types_helper; + + template <> + struct buffers_iterator_types_helper + { + typedef const_buffer buffer_type; + template + struct byte_type + { + typedef typename add_const::type type; + }; + }; + + template <> + struct buffers_iterator_types_helper + { + typedef mutable_buffer buffer_type; + template + struct byte_type + { + typedef ByteType type; + }; + }; + + template + struct buffers_iterator_types + { + enum + { + is_mutable = is_convertible< + typename BufferSequence::value_type, + mutable_buffer>::value + }; + typedef buffers_iterator_types_helper helper; + typedef typename helper::buffer_type buffer_type; + typedef typename helper::template byte_type::type byte_type; + typedef typename BufferSequence::const_iterator const_iterator; + }; + + template + struct buffers_iterator_types + { + typedef mutable_buffer buffer_type; + typedef ByteType byte_type; + typedef const mutable_buffer* const_iterator; + }; + + template + struct buffers_iterator_types + { + typedef const_buffer buffer_type; + typedef typename add_const::type byte_type; + typedef const const_buffer* const_iterator; + }; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + + template + struct buffers_iterator_types + { + typedef mutable_buffer buffer_type; + typedef ByteType byte_type; + typedef const mutable_buffer* const_iterator; + }; + + template + struct buffers_iterator_types + { + typedef const_buffer buffer_type; + typedef typename add_const::type byte_type; + typedef const const_buffer* const_iterator; + }; + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) +} + +/// A random access iterator over the bytes in a buffer sequence. +template +class buffers_iterator +{ +private: + typedef typename detail::buffers_iterator_types< + BufferSequence, ByteType>::buffer_type buffer_type; + + typedef typename detail::buffers_iterator_types::const_iterator buffer_sequence_iterator_type; + +public: + /// The type used for the distance between two iterators. + typedef std::ptrdiff_t difference_type; + + /// The type of the value pointed to by the iterator. + typedef ByteType value_type; + +#if defined(GENERATING_DOCUMENTATION) + /// The type of the result of applying operator->() to the iterator. + /** + * If the buffer sequence stores buffer objects that are convertible to + * mutable_buffer, this is a pointer to a non-const ByteType. Otherwise, a + * pointer to a const ByteType. + */ + typedef const_or_non_const_ByteType* pointer; +#else // defined(GENERATING_DOCUMENTATION) + typedef typename detail::buffers_iterator_types< + BufferSequence, ByteType>::byte_type* pointer; +#endif // defined(GENERATING_DOCUMENTATION) + +#if defined(GENERATING_DOCUMENTATION) + /// The type of the result of applying operator*() to the iterator. + /** + * If the buffer sequence stores buffer objects that are convertible to + * mutable_buffer, this is a reference to a non-const ByteType. Otherwise, a + * reference to a const ByteType. + */ + typedef const_or_non_const_ByteType& reference; +#else // defined(GENERATING_DOCUMENTATION) + typedef typename detail::buffers_iterator_types< + BufferSequence, ByteType>::byte_type& reference; +#endif // defined(GENERATING_DOCUMENTATION) + + /// The iterator category. + typedef std::random_access_iterator_tag iterator_category; + + /// Default constructor. Creates an iterator in an undefined state. + buffers_iterator() + : current_buffer_(), + current_buffer_position_(0), + begin_(), + current_(), + end_(), + position_(0) + { + } + + /// Construct an iterator representing the beginning of the buffers' data. + static buffers_iterator begin(const BufferSequence& buffers) +#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3) + __attribute__ ((__noinline__)) +#endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3) + { + buffers_iterator new_iter; + new_iter.begin_ = boost::asio::buffer_sequence_begin(buffers); + new_iter.current_ = boost::asio::buffer_sequence_begin(buffers); + new_iter.end_ = boost::asio::buffer_sequence_end(buffers); + while (new_iter.current_ != new_iter.end_) + { + new_iter.current_buffer_ = *new_iter.current_; + if (new_iter.current_buffer_.size() > 0) + break; + ++new_iter.current_; + } + return new_iter; + } + + /// Construct an iterator representing the end of the buffers' data. + static buffers_iterator end(const BufferSequence& buffers) +#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3) + __attribute__ ((__noinline__)) +#endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3) + { + buffers_iterator new_iter; + new_iter.begin_ = boost::asio::buffer_sequence_begin(buffers); + new_iter.current_ = boost::asio::buffer_sequence_begin(buffers); + new_iter.end_ = boost::asio::buffer_sequence_end(buffers); + while (new_iter.current_ != new_iter.end_) + { + buffer_type buffer = *new_iter.current_; + new_iter.position_ += buffer.size(); + ++new_iter.current_; + } + return new_iter; + } + + /// Dereference an iterator. + reference operator*() const + { + return dereference(); + } + + /// Dereference an iterator. + pointer operator->() const + { + return &dereference(); + } + + /// Access an individual element. + reference operator[](std::ptrdiff_t difference) const + { + buffers_iterator tmp(*this); + tmp.advance(difference); + return *tmp; + } + + /// Increment operator (prefix). + buffers_iterator& operator++() + { + increment(); + return *this; + } + + /// Increment operator (postfix). + buffers_iterator operator++(int) + { + buffers_iterator tmp(*this); + ++*this; + return tmp; + } + + /// Decrement operator (prefix). + buffers_iterator& operator--() + { + decrement(); + return *this; + } + + /// Decrement operator (postfix). + buffers_iterator operator--(int) + { + buffers_iterator tmp(*this); + --*this; + return tmp; + } + + /// Addition operator. + buffers_iterator& operator+=(std::ptrdiff_t difference) + { + advance(difference); + return *this; + } + + /// Subtraction operator. + buffers_iterator& operator-=(std::ptrdiff_t difference) + { + advance(-difference); + return *this; + } + + /// Addition operator. + friend buffers_iterator operator+(const buffers_iterator& iter, + std::ptrdiff_t difference) + { + buffers_iterator tmp(iter); + tmp.advance(difference); + return tmp; + } + + /// Addition operator. + friend buffers_iterator operator+(std::ptrdiff_t difference, + const buffers_iterator& iter) + { + buffers_iterator tmp(iter); + tmp.advance(difference); + return tmp; + } + + /// Subtraction operator. + friend buffers_iterator operator-(const buffers_iterator& iter, + std::ptrdiff_t difference) + { + buffers_iterator tmp(iter); + tmp.advance(-difference); + return tmp; + } + + /// Subtraction operator. + friend std::ptrdiff_t operator-(const buffers_iterator& a, + const buffers_iterator& b) + { + return b.distance_to(a); + } + + /// Test two iterators for equality. + friend bool operator==(const buffers_iterator& a, const buffers_iterator& b) + { + return a.equal(b); + } + + /// Test two iterators for inequality. + friend bool operator!=(const buffers_iterator& a, const buffers_iterator& b) + { + return !a.equal(b); + } + + /// Compare two iterators. + friend bool operator<(const buffers_iterator& a, const buffers_iterator& b) + { + return a.distance_to(b) > 0; + } + + /// Compare two iterators. + friend bool operator<=(const buffers_iterator& a, const buffers_iterator& b) + { + return !(b < a); + } + + /// Compare two iterators. + friend bool operator>(const buffers_iterator& a, const buffers_iterator& b) + { + return b < a; + } + + /// Compare two iterators. + friend bool operator>=(const buffers_iterator& a, const buffers_iterator& b) + { + return !(a < b); + } + +private: + // Dereference the iterator. + reference dereference() const + { + return static_cast( + current_buffer_.data())[current_buffer_position_]; + } + + // Compare two iterators for equality. + bool equal(const buffers_iterator& other) const + { + return position_ == other.position_; + } + + // Increment the iterator. + void increment() + { + BOOST_ASIO_ASSERT(current_ != end_ && "iterator out of bounds"); + ++position_; + + // Check if the increment can be satisfied by the current buffer. + ++current_buffer_position_; + if (current_buffer_position_ != current_buffer_.size()) + return; + + // Find the next non-empty buffer. + ++current_; + current_buffer_position_ = 0; + while (current_ != end_) + { + current_buffer_ = *current_; + if (current_buffer_.size() > 0) + return; + ++current_; + } + } + + // Decrement the iterator. + void decrement() + { + BOOST_ASIO_ASSERT(position_ > 0 && "iterator out of bounds"); + --position_; + + // Check if the decrement can be satisfied by the current buffer. + if (current_buffer_position_ != 0) + { + --current_buffer_position_; + return; + } + + // Find the previous non-empty buffer. + buffer_sequence_iterator_type iter = current_; + while (iter != begin_) + { + --iter; + buffer_type buffer = *iter; + std::size_t buffer_size = buffer.size(); + if (buffer_size > 0) + { + current_ = iter; + current_buffer_ = buffer; + current_buffer_position_ = buffer_size - 1; + return; + } + } + } + + // Advance the iterator by the specified distance. + void advance(std::ptrdiff_t n) + { + if (n > 0) + { + BOOST_ASIO_ASSERT(current_ != end_ && "iterator out of bounds"); + for (;;) + { + std::ptrdiff_t current_buffer_balance + = current_buffer_.size() - current_buffer_position_; + + // Check if the advance can be satisfied by the current buffer. + if (current_buffer_balance > n) + { + position_ += n; + current_buffer_position_ += n; + return; + } + + // Update position. + n -= current_buffer_balance; + position_ += current_buffer_balance; + + // Move to next buffer. If it is empty then it will be skipped on the + // next iteration of this loop. + if (++current_ == end_) + { + BOOST_ASIO_ASSERT(n == 0 && "iterator out of bounds"); + current_buffer_ = buffer_type(); + current_buffer_position_ = 0; + return; + } + current_buffer_ = *current_; + current_buffer_position_ = 0; + } + } + else if (n < 0) + { + std::size_t abs_n = -n; + BOOST_ASIO_ASSERT(position_ >= abs_n && "iterator out of bounds"); + for (;;) + { + // Check if the advance can be satisfied by the current buffer. + if (current_buffer_position_ >= abs_n) + { + position_ -= abs_n; + current_buffer_position_ -= abs_n; + return; + } + + // Update position. + abs_n -= current_buffer_position_; + position_ -= current_buffer_position_; + + // Check if we've reached the beginning of the buffers. + if (current_ == begin_) + { + BOOST_ASIO_ASSERT(abs_n == 0 && "iterator out of bounds"); + current_buffer_position_ = 0; + return; + } + + // Find the previous non-empty buffer. + buffer_sequence_iterator_type iter = current_; + while (iter != begin_) + { + --iter; + buffer_type buffer = *iter; + std::size_t buffer_size = buffer.size(); + if (buffer_size > 0) + { + current_ = iter; + current_buffer_ = buffer; + current_buffer_position_ = buffer_size; + break; + } + } + } + } + } + + // Determine the distance between two iterators. + std::ptrdiff_t distance_to(const buffers_iterator& other) const + { + return other.position_ - position_; + } + + buffer_type current_buffer_; + std::size_t current_buffer_position_; + buffer_sequence_iterator_type begin_; + buffer_sequence_iterator_type current_; + buffer_sequence_iterator_type end_; + std::size_t position_; +}; + +/// Construct an iterator representing the beginning of the buffers' data. +template +inline buffers_iterator buffers_begin( + const BufferSequence& buffers) +{ + return buffers_iterator::begin(buffers); +} + +/// Construct an iterator representing the end of the buffers' data. +template +inline buffers_iterator buffers_end( + const BufferSequence& buffers) +{ + return buffers_iterator::end(buffers); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_BUFFERS_ITERATOR_HPP diff --git a/boost/asio/co_spawn.hpp b/boost/asio/co_spawn.hpp new file mode 100644 index 0000000..67d17e2 --- /dev/null +++ b/boost/asio/co_spawn.hpp @@ -0,0 +1,90 @@ +// +// co_spawn.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_CO_SPAWN_HPP +#define BOOST_ASIO_CO_SPAWN_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +struct awaitable_signature; + +template +struct awaitable_signature> +{ + typedef void type(std::exception_ptr, T); +}; + +template +struct awaitable_signature> +{ + typedef void type(std::exception_ptr); +}; + +} // namespace detail + +/// Spawn a new thread of execution. +/** + * The entry point function object @c f must have the signature: + * + * @code awaitable f(); @endcode + * + * where @c E is convertible from @c Executor. + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, + typename detail::awaitable_signature::type>::type) +co_spawn(const Executor& ex, F&& f, CompletionToken&& token, + typename enable_if< + is_executor::value + >::type* = 0); + +/// Spawn a new thread of execution. +/** + * The entry point function object @c f must have the signature: + * + * @code awaitable f(); @endcode + * + * where @c E is convertible from @c ExecutionContext::executor_type. + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, + typename detail::awaitable_signature::type>::type) +co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token, + typename enable_if< + is_convertible::value + >::type* = 0); + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_CO_SPAWN_HPP diff --git a/boost/asio/completion_condition.hpp b/boost/asio/completion_condition.hpp new file mode 100644 index 0000000..4d0337b --- /dev/null +++ b/boost/asio/completion_condition.hpp @@ -0,0 +1,220 @@ +// +// completion_condition.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_COMPLETION_CONDITION_HPP +#define BOOST_ASIO_COMPLETION_CONDITION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { + +namespace detail { + +// The default maximum number of bytes to transfer in a single operation. +enum default_max_transfer_size_t { default_max_transfer_size = 65536 }; + +// Adapt result of old-style completion conditions (which had a bool result +// where true indicated that the operation was complete). +inline std::size_t adapt_completion_condition_result(bool result) +{ + return result ? 0 : default_max_transfer_size; +} + +// Adapt result of current completion conditions (which have a size_t result +// where 0 means the operation is complete, and otherwise the result is the +// maximum number of bytes to transfer on the next underlying operation). +inline std::size_t adapt_completion_condition_result(std::size_t result) +{ + return result; +} + +class transfer_all_t +{ +public: + typedef std::size_t result_type; + + template + std::size_t operator()(const Error& err, std::size_t) + { + return !!err ? 0 : default_max_transfer_size; + } +}; + +class transfer_at_least_t +{ +public: + typedef std::size_t result_type; + + explicit transfer_at_least_t(std::size_t minimum) + : minimum_(minimum) + { + } + + template + std::size_t operator()(const Error& err, std::size_t bytes_transferred) + { + return (!!err || bytes_transferred >= minimum_) + ? 0 : default_max_transfer_size; + } + +private: + std::size_t minimum_; +}; + +class transfer_exactly_t +{ +public: + typedef std::size_t result_type; + + explicit transfer_exactly_t(std::size_t size) + : size_(size) + { + } + + template + std::size_t operator()(const Error& err, std::size_t bytes_transferred) + { + return (!!err || bytes_transferred >= size_) ? 0 : + (size_ - bytes_transferred < default_max_transfer_size + ? size_ - bytes_transferred : std::size_t(default_max_transfer_size)); + } + +private: + std::size_t size_; +}; + +} // namespace detail + +/** + * @defgroup completion_condition Completion Condition Function Objects + * + * Function objects used for determining when a read or write operation should + * complete. + */ +/*@{*/ + +/// Return a completion condition function object that indicates that a read or +/// write operation should continue until all of the data has been transferred, +/// or until an error occurs. +/** + * This function is used to create an object, of unspecified type, that meets + * CompletionCondition requirements. + * + * @par Example + * Reading until a buffer is full: + * @code + * boost::array buf; + * boost::system::error_code ec; + * std::size_t n = boost::asio::read( + * sock, boost::asio::buffer(buf), + * boost::asio::transfer_all(), ec); + * if (ec) + * { + * // An error occurred. + * } + * else + * { + * // n == 128 + * } + * @endcode + */ +#if defined(GENERATING_DOCUMENTATION) +unspecified transfer_all(); +#else +inline detail::transfer_all_t transfer_all() +{ + return detail::transfer_all_t(); +} +#endif + +/// Return a completion condition function object that indicates that a read or +/// write operation should continue until a minimum number of bytes has been +/// transferred, or until an error occurs. +/** + * This function is used to create an object, of unspecified type, that meets + * CompletionCondition requirements. + * + * @par Example + * Reading until a buffer is full or contains at least 64 bytes: + * @code + * boost::array buf; + * boost::system::error_code ec; + * std::size_t n = boost::asio::read( + * sock, boost::asio::buffer(buf), + * boost::asio::transfer_at_least(64), ec); + * if (ec) + * { + * // An error occurred. + * } + * else + * { + * // n >= 64 && n <= 128 + * } + * @endcode + */ +#if defined(GENERATING_DOCUMENTATION) +unspecified transfer_at_least(std::size_t minimum); +#else +inline detail::transfer_at_least_t transfer_at_least(std::size_t minimum) +{ + return detail::transfer_at_least_t(minimum); +} +#endif + +/// Return a completion condition function object that indicates that a read or +/// write operation should continue until an exact number of bytes has been +/// transferred, or until an error occurs. +/** + * This function is used to create an object, of unspecified type, that meets + * CompletionCondition requirements. + * + * @par Example + * Reading until a buffer is full or contains exactly 64 bytes: + * @code + * boost::array buf; + * boost::system::error_code ec; + * std::size_t n = boost::asio::read( + * sock, boost::asio::buffer(buf), + * boost::asio::transfer_exactly(64), ec); + * if (ec) + * { + * // An error occurred. + * } + * else + * { + * // n == 64 + * } + * @endcode + */ +#if defined(GENERATING_DOCUMENTATION) +unspecified transfer_exactly(std::size_t size); +#else +inline detail::transfer_exactly_t transfer_exactly(std::size_t size) +{ + return detail::transfer_exactly_t(size); +} +#endif + +/*@}*/ + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_COMPLETION_CONDITION_HPP diff --git a/boost/asio/compose.hpp b/boost/asio/compose.hpp new file mode 100644 index 0000000..b38e4fa --- /dev/null +++ b/boost/asio/compose.hpp @@ -0,0 +1,138 @@ +// +// compose.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_COMPOSE_HPP +#define BOOST_ASIO_COMPOSE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) \ + || defined(GENERATING_DOCUMENTATION) + +/// Launch an asynchronous operation with a stateful implementation. +/** + * The async_compose function simplifies the implementation of composed + * asynchronous operations automatically wrapping a stateful function object + * with a conforming intermediate completion handler. + * + * @param implementation A function object that contains the implementation of + * the composed asynchronous operation. The first argument to the function + * object is a non-const reference to the enclosing intermediate completion + * handler. The remaining arguments are any arguments that originate from the + * completion handlers of any asynchronous operations performed by the + * implementation. + + * @param token The completion token. + * + * @param io_objects_or_executors Zero or more I/O objects or I/O executors for + * which outstanding work must be maintained. + * + * @par Example: + * + * @code struct async_echo_implementation + * { + * tcp::socket& socket_; + * boost::asio::mutable_buffer buffer_; + * enum { starting, reading, writing } state_; + * + * template + * void operator()(Self& self, + * boost::system::error_code error = {}, + * std::size_t n = 0) + * { + * switch (state_) + * { + * case starting: + * state_ = reading; + * socket_.async_read_some( + * buffer_, std::move(self)); + * break; + * case reading: + * if (error) + * { + * self.complete(error, 0); + * } + * else + * { + * state_ = writing; + * boost::asio::async_write(socket_, buffer_, + * boost::asio::transfer_exactly(n), + * std::move(self)); + * } + * break; + * case writing: + * self.complete(error, n); + * break; + * } + * } + * }; + * + * template + * auto async_echo(tcp::socket& socket, + * boost::asio::mutable_buffer buffer, + * CompletionToken&& token) -> + * typename boost::asio::async_result< + * typename std::decay::type, + * void(boost::system::error_code, std::size_t)>::return_type + * { + * return boost::asio::async_compose( + * async_echo_implementation{socket, buffer, + * async_echo_implementation::starting}, + * token, socket); + * } @endcode + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature) +async_compose(BOOST_ASIO_MOVE_ARG(Implementation) implementation, + BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, + BOOST_ASIO_MOVE_ARG(IoObjectsOrExecutors)... io_objects_or_executors); + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature) +async_compose(BOOST_ASIO_MOVE_ARG(Implementation) implementation, + BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token); + +#define BOOST_ASIO_PRIVATE_ASYNC_COMPOSE_DEF(n) \ + template \ + BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature) \ + async_compose(BOOST_ASIO_MOVE_ARG(Implementation) implementation, \ + BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)); + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_ASYNC_COMPOSE_DEF) +#undef BOOST_ASIO_PRIVATE_ASYNC_COMPOSE_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // BOOST_ASIO_COMPOSE_HPP diff --git a/boost/asio/connect.hpp b/boost/asio/connect.hpp new file mode 100644 index 0000000..a500392 --- /dev/null +++ b/boost/asio/connect.hpp @@ -0,0 +1,1057 @@ +// +// connect.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_CONNECT_HPP +#define BOOST_ASIO_CONNECT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +namespace detail +{ + char (&has_iterator_helper(...))[2]; + + template + char has_iterator_helper(T*, typename T::iterator* = 0); + + template + struct has_iterator_typedef + { + enum { value = (sizeof((has_iterator_helper)((T*)(0))) == 1) }; + }; +} // namespace detail + +/// Type trait used to determine whether a type is an endpoint sequence that can +/// be used with with @c connect and @c async_connect. +template +struct is_endpoint_sequence +{ +#if defined(GENERATING_DOCUMENTATION) + /// The value member is true if the type may be used as an endpoint sequence. + static const bool value; +#else + enum + { + value = detail::has_iterator_typedef::value + }; +#endif +}; + +/** + * @defgroup connect boost::asio::connect + * + * @brief The @c connect function is a composed operation that establishes a + * socket connection by trying each endpoint in a sequence. + */ +/*@{*/ + +/// Establishes a socket connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param endpoints A sequence of endpoints. + * + * @returns The successfully connected endpoint. + * + * @throws boost::system::system_error Thrown on failure. If the sequence is + * empty, the associated @c error_code is boost::asio::error::not_found. + * Otherwise, contains the error from the last connection attempt. + * + * @par Example + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::socket s(my_context); + * boost::asio::connect(s, r.resolve(q)); @endcode + */ +template +typename Protocol::endpoint connect(basic_socket& s, + const EndpointSequence& endpoints, + typename enable_if::value>::type* = 0); + +/// Establishes a socket connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param endpoints A sequence of endpoints. + * + * @param ec Set to indicate what error occurred, if any. If the sequence is + * empty, set to boost::asio::error::not_found. Otherwise, contains the error + * from the last connection attempt. + * + * @returns On success, the successfully connected endpoint. Otherwise, a + * default-constructed endpoint. + * + * @par Example + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::socket s(my_context); + * boost::system::error_code ec; + * boost::asio::connect(s, r.resolve(q), ec); + * if (ec) + * { + * // An error occurred. + * } @endcode + */ +template +typename Protocol::endpoint connect(basic_socket& s, + const EndpointSequence& endpoints, boost::system::error_code& ec, + typename enable_if::value>::type* = 0); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +/// (Deprecated: Use range overload.) Establishes a socket connection by trying +/// each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @returns On success, an iterator denoting the successfully connected + * endpoint. Otherwise, the end iterator. + * + * @throws boost::system::system_error Thrown on failure. If the sequence is + * empty, the associated @c error_code is boost::asio::error::not_found. + * Otherwise, contains the error from the last connection attempt. + * + * @note This overload assumes that a default constructed object of type @c + * Iterator represents the end of the sequence. This is a valid assumption for + * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. + */ +template +Iterator connect(basic_socket& s, Iterator begin, + typename enable_if::value>::type* = 0); + +/// (Deprecated: Use range overload.) Establishes a socket connection by trying +/// each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param ec Set to indicate what error occurred, if any. If the sequence is + * empty, set to boost::asio::error::not_found. Otherwise, contains the error + * from the last connection attempt. + * + * @returns On success, an iterator denoting the successfully connected + * endpoint. Otherwise, the end iterator. + * + * @note This overload assumes that a default constructed object of type @c + * Iterator represents the end of the sequence. This is a valid assumption for + * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. + */ +template +Iterator connect(basic_socket& s, + Iterator begin, boost::system::error_code& ec, + typename enable_if::value>::type* = 0); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +/// Establishes a socket connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param end An iterator pointing to the end of a sequence of endpoints. + * + * @returns An iterator denoting the successfully connected endpoint. + * + * @throws boost::system::system_error Thrown on failure. If the sequence is + * empty, the associated @c error_code is boost::asio::error::not_found. + * Otherwise, contains the error from the last connection attempt. + * + * @par Example + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::resolver::results_type e = r.resolve(q); + * tcp::socket s(my_context); + * boost::asio::connect(s, e.begin(), e.end()); @endcode + */ +template +Iterator connect(basic_socket& s, + Iterator begin, Iterator end); + +/// Establishes a socket connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param end An iterator pointing to the end of a sequence of endpoints. + * + * @param ec Set to indicate what error occurred, if any. If the sequence is + * empty, set to boost::asio::error::not_found. Otherwise, contains the error + * from the last connection attempt. + * + * @returns On success, an iterator denoting the successfully connected + * endpoint. Otherwise, the end iterator. + * + * @par Example + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::resolver::results_type e = r.resolve(q); + * tcp::socket s(my_context); + * boost::system::error_code ec; + * boost::asio::connect(s, e.begin(), e.end(), ec); + * if (ec) + * { + * // An error occurred. + * } @endcode + */ +template +Iterator connect(basic_socket& s, + Iterator begin, Iterator end, boost::system::error_code& ec); + +/// Establishes a socket connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param endpoints A sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const boost::system::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @returns The successfully connected endpoint. + * + * @throws boost::system::system_error Thrown on failure. If the sequence is + * empty, the associated @c error_code is boost::asio::error::not_found. + * Otherwise, contains the error from the last connection attempt. + * + * @par Example + * The following connect condition function object can be used to output + * information about the individual connection attempts: + * @code struct my_connect_condition + * { + * bool operator()( + * const boost::system::error_code& ec, + * const::tcp::endpoint& next) + * { + * if (ec) std::cout << "Error: " << ec.message() << std::endl; + * std::cout << "Trying: " << next << std::endl; + * return true; + * } + * }; @endcode + * It would be used with the boost::asio::connect function as follows: + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::socket s(my_context); + * tcp::endpoint e = boost::asio::connect(s, + * r.resolve(q), my_connect_condition()); + * std::cout << "Connected to: " << e << std::endl; @endcode + */ +template +typename Protocol::endpoint connect(basic_socket& s, + const EndpointSequence& endpoints, ConnectCondition connect_condition, + typename enable_if::value>::type* = 0); + +/// Establishes a socket connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param endpoints A sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const boost::system::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @param ec Set to indicate what error occurred, if any. If the sequence is + * empty, set to boost::asio::error::not_found. Otherwise, contains the error + * from the last connection attempt. + * + * @returns On success, the successfully connected endpoint. Otherwise, a + * default-constructed endpoint. + * + * @par Example + * The following connect condition function object can be used to output + * information about the individual connection attempts: + * @code struct my_connect_condition + * { + * bool operator()( + * const boost::system::error_code& ec, + * const::tcp::endpoint& next) + * { + * if (ec) std::cout << "Error: " << ec.message() << std::endl; + * std::cout << "Trying: " << next << std::endl; + * return true; + * } + * }; @endcode + * It would be used with the boost::asio::connect function as follows: + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::socket s(my_context); + * boost::system::error_code ec; + * tcp::endpoint e = boost::asio::connect(s, + * r.resolve(q), my_connect_condition(), ec); + * if (ec) + * { + * // An error occurred. + * } + * else + * { + * std::cout << "Connected to: " << e << std::endl; + * } @endcode + */ +template +typename Protocol::endpoint connect(basic_socket& s, + const EndpointSequence& endpoints, ConnectCondition connect_condition, + boost::system::error_code& ec, + typename enable_if::value>::type* = 0); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +/// (Deprecated: Use range overload.) Establishes a socket connection by trying +/// each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const boost::system::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @returns On success, an iterator denoting the successfully connected + * endpoint. Otherwise, the end iterator. + * + * @throws boost::system::system_error Thrown on failure. If the sequence is + * empty, the associated @c error_code is boost::asio::error::not_found. + * Otherwise, contains the error from the last connection attempt. + * + * @note This overload assumes that a default constructed object of type @c + * Iterator represents the end of the sequence. This is a valid assumption for + * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. + */ +template +Iterator connect(basic_socket& s, + Iterator begin, ConnectCondition connect_condition, + typename enable_if::value>::type* = 0); + +/// (Deprecated: Use range overload.) Establishes a socket connection by trying +/// each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const boost::system::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @param ec Set to indicate what error occurred, if any. If the sequence is + * empty, set to boost::asio::error::not_found. Otherwise, contains the error + * from the last connection attempt. + * + * @returns On success, an iterator denoting the successfully connected + * endpoint. Otherwise, the end iterator. + * + * @note This overload assumes that a default constructed object of type @c + * Iterator represents the end of the sequence. This is a valid assumption for + * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. + */ +template +Iterator connect(basic_socket& s, Iterator begin, + ConnectCondition connect_condition, boost::system::error_code& ec, + typename enable_if::value>::type* = 0); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +/// Establishes a socket connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param end An iterator pointing to the end of a sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const boost::system::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @returns An iterator denoting the successfully connected endpoint. + * + * @throws boost::system::system_error Thrown on failure. If the sequence is + * empty, the associated @c error_code is boost::asio::error::not_found. + * Otherwise, contains the error from the last connection attempt. + * + * @par Example + * The following connect condition function object can be used to output + * information about the individual connection attempts: + * @code struct my_connect_condition + * { + * bool operator()( + * const boost::system::error_code& ec, + * const::tcp::endpoint& next) + * { + * if (ec) std::cout << "Error: " << ec.message() << std::endl; + * std::cout << "Trying: " << next << std::endl; + * return true; + * } + * }; @endcode + * It would be used with the boost::asio::connect function as follows: + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::resolver::results_type e = r.resolve(q); + * tcp::socket s(my_context); + * tcp::resolver::results_type::iterator i = boost::asio::connect( + * s, e.begin(), e.end(), my_connect_condition()); + * std::cout << "Connected to: " << i->endpoint() << std::endl; @endcode + */ +template +Iterator connect(basic_socket& s, Iterator begin, + Iterator end, ConnectCondition connect_condition); + +/// Establishes a socket connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c connect member + * function, once for each endpoint in the sequence, until a connection is + * successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param end An iterator pointing to the end of a sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const boost::system::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @param ec Set to indicate what error occurred, if any. If the sequence is + * empty, set to boost::asio::error::not_found. Otherwise, contains the error + * from the last connection attempt. + * + * @returns On success, an iterator denoting the successfully connected + * endpoint. Otherwise, the end iterator. + * + * @par Example + * The following connect condition function object can be used to output + * information about the individual connection attempts: + * @code struct my_connect_condition + * { + * bool operator()( + * const boost::system::error_code& ec, + * const::tcp::endpoint& next) + * { + * if (ec) std::cout << "Error: " << ec.message() << std::endl; + * std::cout << "Trying: " << next << std::endl; + * return true; + * } + * }; @endcode + * It would be used with the boost::asio::connect function as follows: + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::resolver::results_type e = r.resolve(q); + * tcp::socket s(my_context); + * boost::system::error_code ec; + * tcp::resolver::results_type::iterator i = boost::asio::connect( + * s, e.begin(), e.end(), my_connect_condition()); + * if (ec) + * { + * // An error occurred. + * } + * else + * { + * std::cout << "Connected to: " << i->endpoint() << std::endl; + * } @endcode + */ +template +Iterator connect(basic_socket& s, + Iterator begin, Iterator end, ConnectCondition connect_condition, + boost::system::error_code& ec); + +/*@}*/ + +/** + * @defgroup async_connect boost::asio::async_connect + * + * @brief The @c async_connect function is a composed asynchronous operation + * that establishes a socket connection by trying each endpoint in a sequence. + */ +/*@{*/ + +/// Asynchronously establishes a socket connection by trying each endpoint in a +/// sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c async_connect + * member function, once for each endpoint in the sequence, until a connection + * is successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param endpoints A sequence of endpoints. + * + * @param handler The handler to be called when the connect operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * // Result of operation. if the sequence is empty, set to + * // boost::asio::error::not_found. Otherwise, contains the + * // error from the last connection attempt. + * const boost::system::error_code& error, + * + * // On success, the successfully connected endpoint. + * // Otherwise, a default-constructed endpoint. + * const typename Protocol::endpoint& endpoint + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::socket s(my_context); + * + * // ... + * + * r.async_resolve(q, resolve_handler); + * + * // ... + * + * void resolve_handler( + * const boost::system::error_code& ec, + * tcp::resolver::results_type results) + * { + * if (!ec) + * { + * boost::asio::async_connect(s, results, connect_handler); + * } + * } + * + * // ... + * + * void connect_handler( + * const boost::system::error_code& ec, + * const tcp::endpoint& endpoint) + * { + * // ... + * } @endcode + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, + void (boost::system::error_code, typename Protocol::endpoint)) +async_connect(basic_socket& s, + const EndpointSequence& endpoints, + BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler, + typename enable_if::value>::type* = 0); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +/// (Deprecated: Use range overload.) Asynchronously establishes a socket +/// connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c async_connect + * member function, once for each endpoint in the sequence, until a connection + * is successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param handler The handler to be called when the connect operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * // Result of operation. if the sequence is empty, set to + * // boost::asio::error::not_found. Otherwise, contains the + * // error from the last connection attempt. + * const boost::system::error_code& error, + * + * // On success, an iterator denoting the successfully + * // connected endpoint. Otherwise, the end iterator. + * Iterator iterator + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note This overload assumes that a default constructed object of type @c + * Iterator represents the end of the sequence. This is a valid assumption for + * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, + void (boost::system::error_code, Iterator)) +async_connect(basic_socket& s, Iterator begin, + BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, + typename enable_if::value>::type* = 0); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +/// Asynchronously establishes a socket connection by trying each endpoint in a +/// sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c async_connect + * member function, once for each endpoint in the sequence, until a connection + * is successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param end An iterator pointing to the end of a sequence of endpoints. + * + * @param handler The handler to be called when the connect operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * // Result of operation. if the sequence is empty, set to + * // boost::asio::error::not_found. Otherwise, contains the + * // error from the last connection attempt. + * const boost::system::error_code& error, + * + * // On success, an iterator denoting the successfully + * // connected endpoint. Otherwise, the end iterator. + * Iterator iterator + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * @code std::vector endpoints = ...; + * tcp::socket s(my_context); + * boost::asio::async_connect(s, + * endpoints.begin(), endpoints.end(), + * connect_handler); + * + * // ... + * + * void connect_handler( + * const boost::system::error_code& ec, + * std::vector::iterator i) + * { + * // ... + * } @endcode + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, + void (boost::system::error_code, Iterator)) +async_connect(basic_socket& s, Iterator begin, Iterator end, + BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler); + +/// Asynchronously establishes a socket connection by trying each endpoint in a +/// sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c async_connect + * member function, once for each endpoint in the sequence, until a connection + * is successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param endpoints A sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const boost::system::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @param handler The handler to be called when the connect operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * // Result of operation. if the sequence is empty, set to + * // boost::asio::error::not_found. Otherwise, contains the + * // error from the last connection attempt. + * const boost::system::error_code& error, + * + * // On success, an iterator denoting the successfully + * // connected endpoint. Otherwise, the end iterator. + * Iterator iterator + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * The following connect condition function object can be used to output + * information about the individual connection attempts: + * @code struct my_connect_condition + * { + * bool operator()( + * const boost::system::error_code& ec, + * const::tcp::endpoint& next) + * { + * if (ec) std::cout << "Error: " << ec.message() << std::endl; + * std::cout << "Trying: " << next << std::endl; + * return true; + * } + * }; @endcode + * It would be used with the boost::asio::connect function as follows: + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::socket s(my_context); + * + * // ... + * + * r.async_resolve(q, resolve_handler); + * + * // ... + * + * void resolve_handler( + * const boost::system::error_code& ec, + * tcp::resolver::results_type results) + * { + * if (!ec) + * { + * boost::asio::async_connect(s, results, + * my_connect_condition(), + * connect_handler); + * } + * } + * + * // ... + * + * void connect_handler( + * const boost::system::error_code& ec, + * const tcp::endpoint& endpoint) + * { + * if (ec) + * { + * // An error occurred. + * } + * else + * { + * std::cout << "Connected to: " << endpoint << std::endl; + * } + * } @endcode + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, + void (boost::system::error_code, typename Protocol::endpoint)) +async_connect(basic_socket& s, + const EndpointSequence& endpoints, ConnectCondition connect_condition, + BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler, + typename enable_if::value>::type* = 0); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +/// (Deprecated: Use range overload.) Asynchronously establishes a socket +/// connection by trying each endpoint in a sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c async_connect + * member function, once for each endpoint in the sequence, until a connection + * is successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const boost::system::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @param handler The handler to be called when the connect operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * // Result of operation. if the sequence is empty, set to + * // boost::asio::error::not_found. Otherwise, contains the + * // error from the last connection attempt. + * const boost::system::error_code& error, + * + * // On success, an iterator denoting the successfully + * // connected endpoint. Otherwise, the end iterator. + * Iterator iterator + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note This overload assumes that a default constructed object of type @c + * Iterator represents the end of the sequence. This is a valid assumption for + * iterator types such as @c boost::asio::ip::tcp::resolver::iterator. + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, + void (boost::system::error_code, Iterator)) +async_connect(basic_socket& s, Iterator begin, + ConnectCondition connect_condition, + BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, + typename enable_if::value>::type* = 0); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +/// Asynchronously establishes a socket connection by trying each endpoint in a +/// sequence. +/** + * This function attempts to connect a socket to one of a sequence of + * endpoints. It does this by repeated calls to the socket's @c async_connect + * member function, once for each endpoint in the sequence, until a connection + * is successfully established. + * + * @param s The socket to be connected. If the socket is already open, it will + * be closed. + * + * @param begin An iterator pointing to the start of a sequence of endpoints. + * + * @param end An iterator pointing to the end of a sequence of endpoints. + * + * @param connect_condition A function object that is called prior to each + * connection attempt. The signature of the function object must be: + * @code bool connect_condition( + * const boost::system::error_code& ec, + * const typename Protocol::endpoint& next); @endcode + * The @c ec parameter contains the result from the most recent connect + * operation. Before the first connection attempt, @c ec is always set to + * indicate success. The @c next parameter is the next endpoint to be tried. + * The function object should return true if the next endpoint should be tried, + * and false if it should be skipped. + * + * @param handler The handler to be called when the connect operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * // Result of operation. if the sequence is empty, set to + * // boost::asio::error::not_found. Otherwise, contains the + * // error from the last connection attempt. + * const boost::system::error_code& error, + * + * // On success, an iterator denoting the successfully + * // connected endpoint. Otherwise, the end iterator. + * Iterator iterator + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * The following connect condition function object can be used to output + * information about the individual connection attempts: + * @code struct my_connect_condition + * { + * bool operator()( + * const boost::system::error_code& ec, + * const::tcp::endpoint& next) + * { + * if (ec) std::cout << "Error: " << ec.message() << std::endl; + * std::cout << "Trying: " << next << std::endl; + * return true; + * } + * }; @endcode + * It would be used with the boost::asio::connect function as follows: + * @code tcp::resolver r(my_context); + * tcp::resolver::query q("host", "service"); + * tcp::socket s(my_context); + * + * // ... + * + * r.async_resolve(q, resolve_handler); + * + * // ... + * + * void resolve_handler( + * const boost::system::error_code& ec, + * tcp::resolver::iterator i) + * { + * if (!ec) + * { + * tcp::resolver::iterator end; + * boost::asio::async_connect(s, i, end, + * my_connect_condition(), + * connect_handler); + * } + * } + * + * // ... + * + * void connect_handler( + * const boost::system::error_code& ec, + * tcp::resolver::iterator i) + * { + * if (ec) + * { + * // An error occurred. + * } + * else + * { + * std::cout << "Connected to: " << i->endpoint() << std::endl; + * } + * } @endcode + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, + void (boost::system::error_code, Iterator)) +async_connect(basic_socket& s, Iterator begin, + Iterator end, ConnectCondition connect_condition, + BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler); + +/*@}*/ + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif diff --git a/boost/asio/coroutine.hpp b/boost/asio/coroutine.hpp new file mode 100644 index 0000000..c519295 --- /dev/null +++ b/boost/asio/coroutine.hpp @@ -0,0 +1,330 @@ +// +// coroutine.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_COROUTINE_HPP +#define BOOST_ASIO_COROUTINE_HPP + +namespace boost { +namespace asio { +namespace detail { + +class coroutine_ref; + +} // namespace detail + +/// Provides support for implementing stackless coroutines. +/** + * The @c coroutine class may be used to implement stackless coroutines. The + * class itself is used to store the current state of the coroutine. + * + * Coroutines are copy-constructible and assignable, and the space overhead is + * a single int. They can be used as a base class: + * + * @code class session : coroutine + * { + * ... + * }; @endcode + * + * or as a data member: + * + * @code class session + * { + * ... + * coroutine coro_; + * }; @endcode + * + * or even bound in as a function argument using lambdas or @c bind(). The + * important thing is that as the application maintains a copy of the object + * for as long as the coroutine must be kept alive. + * + * @par Pseudo-keywords + * + * A coroutine is used in conjunction with certain "pseudo-keywords", which + * are implemented as macros. These macros are defined by a header file: + * + * @code #include @endcode + * + * and may conversely be undefined as follows: + * + * @code #include @endcode + * + * reenter + * + * The @c reenter macro is used to define the body of a coroutine. It takes a + * single argument: a pointer or reference to a coroutine object. For example, + * if the base class is a coroutine object you may write: + * + * @code reenter (this) + * { + * ... coroutine body ... + * } @endcode + * + * and if a data member or other variable you can write: + * + * @code reenter (coro_) + * { + * ... coroutine body ... + * } @endcode + * + * When @c reenter is executed at runtime, control jumps to the location of the + * last @c yield or @c fork. + * + * The coroutine body may also be a single statement, such as: + * + * @code reenter (this) for (;;) + * { + * ... + * } @endcode + * + * @b Limitation: The @c reenter macro is implemented using a switch. This + * means that you must take care when using local variables within the + * coroutine body. The local variable is not allowed in a position where + * reentering the coroutine could bypass the variable definition. + * + * yield statement + * + * This form of the @c yield keyword is often used with asynchronous operations: + * + * @code yield socket_->async_read_some(buffer(*buffer_), *this); @endcode + * + * This divides into four logical steps: + * + * @li @c yield saves the current state of the coroutine. + * @li The statement initiates the asynchronous operation. + * @li The resume point is defined immediately following the statement. + * @li Control is transferred to the end of the coroutine body. + * + * When the asynchronous operation completes, the function object is invoked + * and @c reenter causes control to transfer to the resume point. It is + * important to remember to carry the coroutine state forward with the + * asynchronous operation. In the above snippet, the current class is a + * function object object with a coroutine object as base class or data member. + * + * The statement may also be a compound statement, and this permits us to + * define local variables with limited scope: + * + * @code yield + * { + * mutable_buffers_1 b = buffer(*buffer_); + * socket_->async_read_some(b, *this); + * } @endcode + * + * yield return expression ; + * + * This form of @c yield is often used in generators or coroutine-based parsers. + * For example, the function object: + * + * @code struct interleave : coroutine + * { + * istream& is1; + * istream& is2; + * char operator()(char c) + * { + * reenter (this) for (;;) + * { + * yield return is1.get(); + * yield return is2.get(); + * } + * } + * }; @endcode + * + * defines a trivial coroutine that interleaves the characters from two input + * streams. + * + * This type of @c yield divides into three logical steps: + * + * @li @c yield saves the current state of the coroutine. + * @li The resume point is defined immediately following the semicolon. + * @li The value of the expression is returned from the function. + * + * yield ; + * + * This form of @c yield is equivalent to the following steps: + * + * @li @c yield saves the current state of the coroutine. + * @li The resume point is defined immediately following the semicolon. + * @li Control is transferred to the end of the coroutine body. + * + * This form might be applied when coroutines are used for cooperative + * threading and scheduling is explicitly managed. For example: + * + * @code struct task : coroutine + * { + * ... + * void operator()() + * { + * reenter (this) + * { + * while (... not finished ...) + * { + * ... do something ... + * yield; + * ... do some more ... + * yield; + * } + * } + * } + * ... + * }; + * ... + * task t1, t2; + * for (;;) + * { + * t1(); + * t2(); + * } @endcode + * + * yield break ; + * + * The final form of @c yield is used to explicitly terminate the coroutine. + * This form is comprised of two steps: + * + * @li @c yield sets the coroutine state to indicate termination. + * @li Control is transferred to the end of the coroutine body. + * + * Once terminated, calls to is_complete() return true and the coroutine cannot + * be reentered. + * + * Note that a coroutine may also be implicitly terminated if the coroutine + * body is exited without a yield, e.g. by return, throw or by running to the + * end of the body. + * + * fork statement + * + * The @c fork pseudo-keyword is used when "forking" a coroutine, i.e. splitting + * it into two (or more) copies. One use of @c fork is in a server, where a new + * coroutine is created to handle each client connection: + * + * @code reenter (this) + * { + * do + * { + * socket_.reset(new tcp::socket(my_context_)); + * yield acceptor->async_accept(*socket_, *this); + * fork server(*this)(); + * } while (is_parent()); + * ... client-specific handling follows ... + * } @endcode + * + * The logical steps involved in a @c fork are: + * + * @li @c fork saves the current state of the coroutine. + * @li The statement creates a copy of the coroutine and either executes it + * immediately or schedules it for later execution. + * @li The resume point is defined immediately following the semicolon. + * @li For the "parent", control immediately continues from the next line. + * + * The functions is_parent() and is_child() can be used to differentiate + * between parent and child. You would use these functions to alter subsequent + * control flow. + * + * Note that @c fork doesn't do the actual forking by itself. It is the + * application's responsibility to create a clone of the coroutine and call it. + * The clone can be called immediately, as above, or scheduled for delayed + * execution using something like boost::asio::post(). + * + * @par Alternate macro names + * + * If preferred, an application can use macro names that follow a more typical + * naming convention, rather than the pseudo-keywords. These are: + * + * @li @c BOOST_ASIO_CORO_REENTER instead of @c reenter + * @li @c BOOST_ASIO_CORO_YIELD instead of @c yield + * @li @c BOOST_ASIO_CORO_FORK instead of @c fork + */ +class coroutine +{ +public: + /// Constructs a coroutine in its initial state. + coroutine() : value_(0) {} + + /// Returns true if the coroutine is the child of a fork. + bool is_child() const { return value_ < 0; } + + /// Returns true if the coroutine is the parent of a fork. + bool is_parent() const { return !is_child(); } + + /// Returns true if the coroutine has reached its terminal state. + bool is_complete() const { return value_ == -1; } + +private: + friend class detail::coroutine_ref; + int value_; +}; + + +namespace detail { + +class coroutine_ref +{ +public: + coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {} + coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {} + ~coroutine_ref() { if (!modified_) value_ = -1; } + operator int() const { return value_; } + int& operator=(int v) { modified_ = true; return value_ = v; } +private: + void operator=(const coroutine_ref&); + int& value_; + bool modified_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#define BOOST_ASIO_CORO_REENTER(c) \ + switch (::boost::asio::detail::coroutine_ref _coro_value = c) \ + case -1: if (_coro_value) \ + { \ + goto terminate_coroutine; \ + terminate_coroutine: \ + _coro_value = -1; \ + goto bail_out_of_coroutine; \ + bail_out_of_coroutine: \ + break; \ + } \ + else /* fall-through */ case 0: + +#define BOOST_ASIO_CORO_YIELD_IMPL(n) \ + for (_coro_value = (n);;) \ + if (_coro_value == 0) \ + { \ + case (n): ; \ + break; \ + } \ + else \ + switch (_coro_value ? 0 : 1) \ + for (;;) \ + /* fall-through */ case -1: if (_coro_value) \ + goto terminate_coroutine; \ + else for (;;) \ + /* fall-through */ case 1: if (_coro_value) \ + goto bail_out_of_coroutine; \ + else /* fall-through */ case 0: + +#define BOOST_ASIO_CORO_FORK_IMPL(n) \ + for (_coro_value = -(n);; _coro_value = (n)) \ + if (_coro_value == (n)) \ + { \ + case -(n): ; \ + break; \ + } \ + else + +#if defined(_MSC_VER) +# define BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD_IMPL(__COUNTER__ + 1) +# define BOOST_ASIO_CORO_FORK BOOST_ASIO_CORO_FORK_IMPL(__COUNTER__ + 1) +#else // defined(_MSC_VER) +# define BOOST_ASIO_CORO_YIELD BOOST_ASIO_CORO_YIELD_IMPL(__LINE__) +# define BOOST_ASIO_CORO_FORK BOOST_ASIO_CORO_FORK_IMPL(__LINE__) +#endif // defined(_MSC_VER) + +#endif // BOOST_ASIO_COROUTINE_HPP diff --git a/boost/asio/deadline_timer.hpp b/boost/asio/deadline_timer.hpp new file mode 100644 index 0000000..1c061fc --- /dev/null +++ b/boost/asio/deadline_timer.hpp @@ -0,0 +1,40 @@ +// +// deadline_timer.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DEADLINE_TIMER_HPP +#define BOOST_ASIO_DEADLINE_TIMER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ + || defined(GENERATING_DOCUMENTATION) + +#include // Must come before posix_time. +#include + +#include + +namespace boost { +namespace asio { + +/// Typedef for the typical usage of timer. Uses a UTC clock. +typedef basic_deadline_timer deadline_timer; + +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_DEADLINE_TIMER_HPP diff --git a/boost/asio/defer.hpp b/boost/asio/defer.hpp new file mode 100644 index 0000000..319063a --- /dev/null +++ b/boost/asio/defer.hpp @@ -0,0 +1,119 @@ +// +// defer.hpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DEFER_HPP +#define BOOST_ASIO_DEFER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +/// Submits a completion token or function object for execution. +/** + * This function submits an object for execution using the object's associated + * executor. The function object is queued for execution, and is never called + * from the current thread prior to returning from defer(). + * + * The use of @c defer(), rather than @ref post(), indicates the caller's + * preference that the executor defer the queueing of the function object. This + * may allow the executor to optimise queueing for cases when the function + * object represents a continuation of the current call context. + * + * This function has the following effects: + * + * @li Constructs a function object handler of type @c Handler, initialized + * with handler(forward(token)). + * + * @li Constructs an object @c result of type async_result, + * initializing the object as result(handler). + * + * @li Obtains the handler's associated executor object @c ex by performing + * get_associated_executor(handler). + * + * @li Obtains the handler's associated allocator object @c alloc by performing + * get_associated_allocator(handler). + * + * @li Performs ex.defer(std::move(handler), alloc). + * + * @li Returns result.get(). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( + BOOST_ASIO_MOVE_ARG(CompletionToken) token); + +/// Submits a completion token or function object for execution. +/** + * This function submits an object for execution using the specified executor. + * The function object is queued for execution, and is never called from the + * current thread prior to returning from defer(). + * + * The use of @c defer(), rather than @ref post(), indicates the caller's + * preference that the executor defer the queueing of the function object. This + * may allow the executor to optimise queueing for cases when the function + * object represents a continuation of the current call context. + * + * This function has the following effects: + * + * @li Constructs a function object handler of type @c Handler, initialized + * with handler(forward(token)). + * + * @li Constructs an object @c result of type async_result, + * initializing the object as result(handler). + * + * @li Obtains the handler's associated executor object @c ex1 by performing + * get_associated_executor(handler). + * + * @li Creates a work object @c w by performing make_work(ex1). + * + * @li Obtains the handler's associated allocator object @c alloc by performing + * get_associated_allocator(handler). + * + * @li Constructs a function object @c f with a function call operator that + * performs ex1.dispatch(std::move(handler), alloc) followed by + * w.reset(). + * + * @li Performs Executor(ex).defer(std::move(f), alloc). + * + * @li Returns result.get(). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( + const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if::value>::type* = 0); + +/// Submits a completion token or function object for execution. +/** + * @returns defer(ctx.get_executor(), forward(token)). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( + ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if::value>::type* = 0); + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // BOOST_ASIO_DEFER_HPP diff --git a/boost/asio/detached.hpp b/boost/asio/detached.hpp new file mode 100644 index 0000000..54b6bd2 --- /dev/null +++ b/boost/asio/detached.hpp @@ -0,0 +1,64 @@ +// +// detached.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETACHED_HPP +#define BOOST_ASIO_DETACHED_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { + +/// Class used to specify that an asynchronous operation is detached. +/** + + * The detached_t class is used to indicate that an asynchronous operation is + * detached. That is, there is no completion handler waiting for the + * operation's result. A detached_t object may be passed as a handler to an + * asynchronous operation, typically using the special value + * @c boost::asio::detached. For example: + + * @code my_socket.async_send(my_buffer, boost::asio::detached); + * @endcode + */ +class detached_t +{ +public: + /// Constructor. + BOOST_ASIO_CONSTEXPR detached_t() + { + } +}; + +/// A special value, similar to std::nothrow. +/** + * See the documentation for boost::asio::detached_t for a usage example. + */ +#if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr detached_t detached; +#elif defined(BOOST_ASIO_MSVC) +__declspec(selectany) detached_t detached; +#endif + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // BOOST_ASIO_DETACHED_HPP diff --git a/boost/asio/detail/array.hpp b/boost/asio/detail/array.hpp new file mode 100644 index 0000000..6779e48 --- /dev/null +++ b/boost/asio/detail/array.hpp @@ -0,0 +1,40 @@ +// +// detail/array.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_ARRAY_HPP +#define BOOST_ASIO_DETAIL_ARRAY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) +# include +#else // defined(BOOST_ASIO_HAS_STD_ARRAY) +# include +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) +using std::array; +#else // defined(BOOST_ASIO_HAS_STD_ARRAY) +using boost::array; +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_ARRAY_HPP diff --git a/boost/asio/detail/array_fwd.hpp b/boost/asio/detail/array_fwd.hpp new file mode 100644 index 0000000..25a0c61 --- /dev/null +++ b/boost/asio/detail/array_fwd.hpp @@ -0,0 +1,34 @@ +// +// detail/array_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_ARRAY_FWD_HPP +#define BOOST_ASIO_DETAIL_ARRAY_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +namespace boost { + +template +class array; + +} // namespace boost + +// Standard library components can't be forward declared, so we'll have to +// include the array header. Fortunately, it's fairly lightweight and doesn't +// add significantly to the compile time. +#if defined(BOOST_ASIO_HAS_STD_ARRAY) +# include +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) + +#endif // BOOST_ASIO_DETAIL_ARRAY_FWD_HPP diff --git a/boost/asio/detail/assert.hpp b/boost/asio/detail/assert.hpp new file mode 100644 index 0000000..927dfce --- /dev/null +++ b/boost/asio/detail/assert.hpp @@ -0,0 +1,32 @@ +// +// detail/assert.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_ASSERT_HPP +#define BOOST_ASIO_DETAIL_ASSERT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_BOOST_ASSERT) +# include +#else // defined(BOOST_ASIO_HAS_BOOST_ASSERT) +# include +#endif // defined(BOOST_ASIO_HAS_BOOST_ASSERT) + +#if defined(BOOST_ASIO_HAS_BOOST_ASSERT) +# define BOOST_ASIO_ASSERT(expr) BOOST_ASSERT(expr) +#else // defined(BOOST_ASIO_HAS_BOOST_ASSERT) +# define BOOST_ASIO_ASSERT(expr) assert(expr) +#endif // defined(BOOST_ASIO_HAS_BOOST_ASSERT) + +#endif // BOOST_ASIO_DETAIL_ASSERT_HPP diff --git a/boost/asio/detail/atomic_count.hpp b/boost/asio/detail/atomic_count.hpp new file mode 100644 index 0000000..ba945a9 --- /dev/null +++ b/boost/asio/detail/atomic_count.hpp @@ -0,0 +1,47 @@ +// +// detail/atomic_count.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_ATOMIC_COUNT_HPP +#define BOOST_ASIO_DETAIL_ATOMIC_COUNT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_THREADS) +// Nothing to include. +#elif defined(BOOST_ASIO_HAS_STD_ATOMIC) +# include +#else // defined(BOOST_ASIO_HAS_STD_ATOMIC) +# include +#endif // defined(BOOST_ASIO_HAS_STD_ATOMIC) + +namespace boost { +namespace asio { +namespace detail { + +#if !defined(BOOST_ASIO_HAS_THREADS) +typedef long atomic_count; +inline void increment(atomic_count& a, long b) { a += b; } +#elif defined(BOOST_ASIO_HAS_STD_ATOMIC) +typedef std::atomic atomic_count; +inline void increment(atomic_count& a, long b) { a += b; } +#else // defined(BOOST_ASIO_HAS_STD_ATOMIC) +typedef boost::detail::atomic_count atomic_count; +inline void increment(atomic_count& a, long b) { while (b > 0) ++a, --b; } +#endif // defined(BOOST_ASIO_HAS_STD_ATOMIC) + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_ATOMIC_COUNT_HPP diff --git a/boost/asio/detail/base_from_completion_cond.hpp b/boost/asio/detail/base_from_completion_cond.hpp new file mode 100644 index 0000000..7904ead --- /dev/null +++ b/boost/asio/detail/base_from_completion_cond.hpp @@ -0,0 +1,71 @@ +// +// detail/base_from_completion_cond.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP +#define BOOST_ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class base_from_completion_cond +{ +protected: + explicit base_from_completion_cond(CompletionCondition& completion_condition) + : completion_condition_( + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)) + { + } + + std::size_t check_for_completion( + const boost::system::error_code& ec, + std::size_t total_transferred) + { + return detail::adapt_completion_condition_result( + completion_condition_(ec, total_transferred)); + } + +private: + CompletionCondition completion_condition_; +}; + +template <> +class base_from_completion_cond +{ +protected: + explicit base_from_completion_cond(transfer_all_t) + { + } + + static std::size_t check_for_completion( + const boost::system::error_code& ec, + std::size_t total_transferred) + { + return transfer_all_t()(ec, total_transferred); + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP diff --git a/boost/asio/detail/bind_handler.hpp b/boost/asio/detail/bind_handler.hpp new file mode 100644 index 0000000..ddeb58f --- /dev/null +++ b/boost/asio/detail/bind_handler.hpp @@ -0,0 +1,818 @@ +// +// detail/bind_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_BIND_HANDLER_HPP +#define BOOST_ASIO_DETAIL_BIND_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class binder1 +{ +public: + template + binder1(int, BOOST_ASIO_MOVE_ARG(T) handler, const Arg1& arg1) + : handler_(BOOST_ASIO_MOVE_CAST(T)(handler)), + arg1_(arg1) + { + } + + binder1(Handler& handler, const Arg1& arg1) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + binder1(const binder1& other) + : handler_(other.handler_), + arg1_(other.arg1_) + { + } + + binder1(binder1&& other) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()() + { + handler_(static_cast(arg1_)); + } + + void operator()() const + { + handler_(arg1_); + } + +//private: + Handler handler_; + Arg1 arg1_; +}; + +template +inline void* asio_handler_allocate(std::size_t size, + binder1* this_handler) +{ + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + binder1* this_handler) +{ + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template +inline bool asio_handler_is_continuation( + binder1* this_handler) +{ + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template +inline void asio_handler_invoke(Function& function, + binder1* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template +inline void asio_handler_invoke(const Function& function, + binder1* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template +inline binder1::type, Arg1> bind_handler( + BOOST_ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1) +{ + return binder1::type, Arg1>(0, + BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1); +} + +template +class binder2 +{ +public: + template + binder2(int, BOOST_ASIO_MOVE_ARG(T) handler, + const Arg1& arg1, const Arg2& arg2) + : handler_(BOOST_ASIO_MOVE_CAST(T)(handler)), + arg1_(arg1), + arg2_(arg2) + { + } + + binder2(Handler& handler, const Arg1& arg1, const Arg2& arg2) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1), + arg2_(arg2) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + binder2(const binder2& other) + : handler_(other.handler_), + arg1_(other.arg1_), + arg2_(other.arg2_) + { + } + + binder2(binder2&& other) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(BOOST_ASIO_MOVE_CAST(Arg2)(other.arg2_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()() + { + handler_(static_cast(arg1_), + static_cast(arg2_)); + } + + void operator()() const + { + handler_(arg1_, arg2_); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; +}; + +template +inline void* asio_handler_allocate(std::size_t size, + binder2* this_handler) +{ + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + binder2* this_handler) +{ + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template +inline bool asio_handler_is_continuation( + binder2* this_handler) +{ + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template +inline void asio_handler_invoke(Function& function, + binder2* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template +inline void asio_handler_invoke(const Function& function, + binder2* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template +inline binder2::type, Arg1, Arg2> bind_handler( + BOOST_ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2) +{ + return binder2::type, Arg1, Arg2>(0, + BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1, arg2); +} + +template +class binder3 +{ +public: + template + binder3(int, BOOST_ASIO_MOVE_ARG(T) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3) + : handler_(BOOST_ASIO_MOVE_CAST(T)(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3) + { + } + + binder3(Handler& handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + binder3(const binder3& other) + : handler_(other.handler_), + arg1_(other.arg1_), + arg2_(other.arg2_), + arg3_(other.arg3_) + { + } + + binder3(binder3&& other) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(BOOST_ASIO_MOVE_CAST(Arg2)(other.arg2_)), + arg3_(BOOST_ASIO_MOVE_CAST(Arg3)(other.arg3_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()() + { + handler_(static_cast(arg1_), + static_cast(arg2_), static_cast(arg3_)); + } + + void operator()() const + { + handler_(arg1_, arg2_, arg3_); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; + Arg3 arg3_; +}; + +template +inline void* asio_handler_allocate(std::size_t size, + binder3* this_handler) +{ + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + binder3* this_handler) +{ + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template +inline bool asio_handler_is_continuation( + binder3* this_handler) +{ + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template +inline void asio_handler_invoke(Function& function, + binder3* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template +inline void asio_handler_invoke(const Function& function, + binder3* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template +inline binder3::type, Arg1, Arg2, Arg3> bind_handler( + BOOST_ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2, + const Arg3& arg3) +{ + return binder3::type, Arg1, Arg2, Arg3>(0, + BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3); +} + +template +class binder4 +{ +public: + template + binder4(int, BOOST_ASIO_MOVE_ARG(T) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) + : handler_(BOOST_ASIO_MOVE_CAST(T)(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3), + arg4_(arg4) + { + } + + binder4(Handler& handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3), + arg4_(arg4) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + binder4(const binder4& other) + : handler_(other.handler_), + arg1_(other.arg1_), + arg2_(other.arg2_), + arg3_(other.arg3_), + arg4_(other.arg4_) + { + } + + binder4(binder4&& other) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(BOOST_ASIO_MOVE_CAST(Arg2)(other.arg2_)), + arg3_(BOOST_ASIO_MOVE_CAST(Arg3)(other.arg3_)), + arg4_(BOOST_ASIO_MOVE_CAST(Arg4)(other.arg4_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()() + { + handler_(static_cast(arg1_), + static_cast(arg2_), static_cast(arg3_), + static_cast(arg4_)); + } + + void operator()() const + { + handler_(arg1_, arg2_, arg3_, arg4_); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; + Arg3 arg3_; + Arg4 arg4_; +}; + +template +inline void* asio_handler_allocate(std::size_t size, + binder4* this_handler) +{ + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + binder4* this_handler) +{ + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template +inline bool asio_handler_is_continuation( + binder4* this_handler) +{ + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template +inline void asio_handler_invoke(Function& function, + binder4* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template +inline void asio_handler_invoke(const Function& function, + binder4* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template +inline binder4::type, Arg1, Arg2, Arg3, Arg4> +bind_handler(BOOST_ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4) +{ + return binder4::type, Arg1, Arg2, Arg3, Arg4>(0, + BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4); +} + +template +class binder5 +{ +public: + template + binder5(int, BOOST_ASIO_MOVE_ARG(T) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) + : handler_(BOOST_ASIO_MOVE_CAST(T)(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3), + arg4_(arg4), + arg5_(arg5) + { + } + + binder5(Handler& handler, const Arg1& arg1, const Arg2& arg2, + const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1), + arg2_(arg2), + arg3_(arg3), + arg4_(arg4), + arg5_(arg5) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + binder5(const binder5& other) + : handler_(other.handler_), + arg1_(other.arg1_), + arg2_(other.arg2_), + arg3_(other.arg3_), + arg4_(other.arg4_), + arg5_(other.arg5_) + { + } + + binder5(binder5&& other) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(BOOST_ASIO_MOVE_CAST(Arg2)(other.arg2_)), + arg3_(BOOST_ASIO_MOVE_CAST(Arg3)(other.arg3_)), + arg4_(BOOST_ASIO_MOVE_CAST(Arg4)(other.arg4_)), + arg5_(BOOST_ASIO_MOVE_CAST(Arg5)(other.arg5_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()() + { + handler_(static_cast(arg1_), + static_cast(arg2_), static_cast(arg3_), + static_cast(arg4_), static_cast(arg5_)); + } + + void operator()() const + { + handler_(arg1_, arg2_, arg3_, arg4_, arg5_); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; + Arg3 arg3_; + Arg4 arg4_; + Arg5 arg5_; +}; + +template +inline void* asio_handler_allocate(std::size_t size, + binder5* this_handler) +{ + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + binder5* this_handler) +{ + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template +inline bool asio_handler_is_continuation( + binder5* this_handler) +{ + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template +inline void asio_handler_invoke(Function& function, + binder5* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template +inline void asio_handler_invoke(const Function& function, + binder5* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template +inline binder5::type, Arg1, Arg2, Arg3, Arg4, Arg5> +bind_handler(BOOST_ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, + const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5) +{ + return binder5::type, Arg1, Arg2, Arg3, Arg4, Arg5>(0, + BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4, arg5); +} + +#if defined(BOOST_ASIO_HAS_MOVE) + +template +class move_binder1 +{ +public: + move_binder1(int, BOOST_ASIO_MOVE_ARG(Handler) handler, + BOOST_ASIO_MOVE_ARG(Arg1) arg1) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(arg1)) + { + } + + move_binder1(move_binder1&& other) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_)) + { + } + + void operator()() + { + handler_(BOOST_ASIO_MOVE_CAST(Arg1)(arg1_)); + } + +//private: + Handler handler_; + Arg1 arg1_; +}; + +template +inline void* asio_handler_allocate(std::size_t size, + move_binder1* this_handler) +{ + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + move_binder1* this_handler) +{ + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template +inline bool asio_handler_is_continuation( + move_binder1* this_handler) +{ + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template +inline void asio_handler_invoke(BOOST_ASIO_MOVE_ARG(Function) function, + move_binder1* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + BOOST_ASIO_MOVE_CAST(Function)(function), this_handler->handler_); +} + +template +class move_binder2 +{ +public: + move_binder2(int, BOOST_ASIO_MOVE_ARG(Handler) handler, + const Arg1& arg1, BOOST_ASIO_MOVE_ARG(Arg2) arg2) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + arg1_(arg1), + arg2_(BOOST_ASIO_MOVE_CAST(Arg2)(arg2)) + { + } + + move_binder2(move_binder2&& other) + : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)), + arg1_(BOOST_ASIO_MOVE_CAST(Arg1)(other.arg1_)), + arg2_(BOOST_ASIO_MOVE_CAST(Arg2)(other.arg2_)) + { + } + + void operator()() + { + handler_(static_cast(arg1_), + BOOST_ASIO_MOVE_CAST(Arg2)(arg2_)); + } + +//private: + Handler handler_; + Arg1 arg1_; + Arg2 arg2_; +}; + +template +inline void* asio_handler_allocate(std::size_t size, + move_binder2* this_handler) +{ + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + move_binder2* this_handler) +{ + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template +inline bool asio_handler_is_continuation( + move_binder2* this_handler) +{ + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template +inline void asio_handler_invoke(BOOST_ASIO_MOVE_ARG(Function) function, + move_binder2* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + BOOST_ASIO_MOVE_CAST(Function)(function), this_handler->handler_); +} + +#endif // defined(BOOST_ASIO_HAS_MOVE) + +} // namespace detail + +template +struct associated_allocator, Allocator> +{ + typedef typename associated_allocator::type type; + + static type get(const detail::binder1& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_allocator, Allocator> +{ + typedef typename associated_allocator::type type; + + static type get(const detail::binder2& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor, Executor> +{ + typedef typename associated_executor::type type; + + static type get(const detail::binder1& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +template +struct associated_executor, Executor> +{ + typedef typename associated_executor::type type; + + static type get(const detail::binder2& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#if defined(BOOST_ASIO_HAS_MOVE) + +template +struct associated_allocator, Allocator> +{ + typedef typename associated_allocator::type type; + + static type get(const detail::move_binder1& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_allocator< + detail::move_binder2, Allocator> +{ + typedef typename associated_allocator::type type; + + static type get(const detail::move_binder2& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor, Executor> +{ + typedef typename associated_executor::type type; + + static type get(const detail::move_binder1& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +template +struct associated_executor, Executor> +{ + typedef typename associated_executor::type type; + + static type get(const detail::move_binder2& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // defined(BOOST_ASIO_HAS_MOVE) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_BIND_HANDLER_HPP diff --git a/boost/asio/detail/buffer_resize_guard.hpp b/boost/asio/detail/buffer_resize_guard.hpp new file mode 100644 index 0000000..198e9c7 --- /dev/null +++ b/boost/asio/detail/buffer_resize_guard.hpp @@ -0,0 +1,68 @@ +// +// detail/buffer_resize_guard.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP +#define BOOST_ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Helper class to manage buffer resizing in an exception safe way. +template +class buffer_resize_guard +{ +public: + // Constructor. + buffer_resize_guard(Buffer& buffer) + : buffer_(buffer), + old_size_(buffer.size()) + { + } + + // Destructor rolls back the buffer resize unless commit was called. + ~buffer_resize_guard() + { + if (old_size_ != (std::numeric_limits::max)()) + { + buffer_.resize(old_size_); + } + } + + // Commit the resize transaction. + void commit() + { + old_size_ = (std::numeric_limits::max)(); + } + +private: + // The buffer being managed. + Buffer& buffer_; + + // The size of the buffer at the time the guard was constructed. + size_t old_size_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP diff --git a/boost/asio/detail/buffer_sequence_adapter.hpp b/boost/asio/detail/buffer_sequence_adapter.hpp new file mode 100644 index 0000000..f33d342 --- /dev/null +++ b/boost/asio/detail/buffer_sequence_adapter.hpp @@ -0,0 +1,546 @@ +// +// detail/buffer_sequence_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP +#define BOOST_ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class buffer_sequence_adapter_base +{ +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +public: + // The maximum number of buffers to support in a single operation. + enum { max_buffers = 1 }; + +protected: + typedef Windows::Storage::Streams::IBuffer^ native_buffer_type; + + BOOST_ASIO_DECL static void init_native_buffer( + native_buffer_type& buf, + const boost::asio::mutable_buffer& buffer); + + BOOST_ASIO_DECL static void init_native_buffer( + native_buffer_type& buf, + const boost::asio::const_buffer& buffer); +#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +public: + // The maximum number of buffers to support in a single operation. + enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; + +protected: + typedef WSABUF native_buffer_type; + + static void init_native_buffer(WSABUF& buf, + const boost::asio::mutable_buffer& buffer) + { + buf.buf = static_cast(buffer.data()); + buf.len = static_cast(buffer.size()); + } + + static void init_native_buffer(WSABUF& buf, + const boost::asio::const_buffer& buffer) + { + buf.buf = const_cast(static_cast(buffer.data())); + buf.len = static_cast(buffer.size()); + } +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +public: + // The maximum number of buffers to support in a single operation. + enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; + +protected: + typedef iovec native_buffer_type; + + static void init_iov_base(void*& base, void* addr) + { + base = addr; + } + + template + static void init_iov_base(T& base, void* addr) + { + base = static_cast(addr); + } + + static void init_native_buffer(iovec& iov, + const boost::asio::mutable_buffer& buffer) + { + init_iov_base(iov.iov_base, buffer.data()); + iov.iov_len = buffer.size(); + } + + static void init_native_buffer(iovec& iov, + const boost::asio::const_buffer& buffer) + { + init_iov_base(iov.iov_base, const_cast(buffer.data())); + iov.iov_len = buffer.size(); + } +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +}; + +// Helper class to translate buffers into the native buffer representation. +template +class buffer_sequence_adapter + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter(const Buffers& buffer_sequence) + : count_(0), total_buffer_size_(0) + { + buffer_sequence_adapter::init( + boost::asio::buffer_sequence_begin(buffer_sequence), + boost::asio::buffer_sequence_end(buffer_sequence)); + } + + native_buffer_type* buffers() + { + return buffers_; + } + + std::size_t count() const + { + return count_; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const Buffers& buffer_sequence) + { + return buffer_sequence_adapter::all_empty( + boost::asio::buffer_sequence_begin(buffer_sequence), + boost::asio::buffer_sequence_end(buffer_sequence)); + } + + static void validate(const Buffers& buffer_sequence) + { + buffer_sequence_adapter::validate( + boost::asio::buffer_sequence_begin(buffer_sequence), + boost::asio::buffer_sequence_end(buffer_sequence)); + } + + static Buffer first(const Buffers& buffer_sequence) + { + return buffer_sequence_adapter::first( + boost::asio::buffer_sequence_begin(buffer_sequence), + boost::asio::buffer_sequence_end(buffer_sequence)); + } + +private: + template + void init(Iterator begin, Iterator end) + { + Iterator iter = begin; + for (; iter != end && count_ < max_buffers; ++iter, ++count_) + { + Buffer buffer(*iter); + init_native_buffer(buffers_[count_], buffer); + total_buffer_size_ += buffer.size(); + } + } + + template + static bool all_empty(Iterator begin, Iterator end) + { + Iterator iter = begin; + std::size_t i = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + if (Buffer(*iter).size() > 0) + return false; + return true; + } + + template + static void validate(Iterator begin, Iterator end) + { + Iterator iter = begin; + for (; iter != end; ++iter) + { + Buffer buffer(*iter); + buffer.data(); + } + } + + template + static Buffer first(Iterator begin, Iterator end) + { + Iterator iter = begin; + for (; iter != end; ++iter) + { + Buffer buffer(*iter); + if (buffer.size() != 0) + return buffer; + } + return Buffer(); + } + + native_buffer_type buffers_[max_buffers]; + std::size_t count_; + std::size_t total_buffer_size_; +}; + +template +class buffer_sequence_adapter + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter( + const boost::asio::mutable_buffer& buffer_sequence) + { + init_native_buffer(buffer_, Buffer(buffer_sequence)); + total_buffer_size_ = buffer_sequence.size(); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const boost::asio::mutable_buffer& buffer_sequence) + { + return buffer_sequence.size() == 0; + } + + static void validate(const boost::asio::mutable_buffer& buffer_sequence) + { + buffer_sequence.data(); + } + + static Buffer first(const boost::asio::mutable_buffer& buffer_sequence) + { + return Buffer(buffer_sequence); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; +}; + +template +class buffer_sequence_adapter + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter( + const boost::asio::const_buffer& buffer_sequence) + { + init_native_buffer(buffer_, Buffer(buffer_sequence)); + total_buffer_size_ = buffer_sequence.size(); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const boost::asio::const_buffer& buffer_sequence) + { + return buffer_sequence.size() == 0; + } + + static void validate(const boost::asio::const_buffer& buffer_sequence) + { + buffer_sequence.data(); + } + + static Buffer first(const boost::asio::const_buffer& buffer_sequence) + { + return Buffer(buffer_sequence); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; +}; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + +template +class buffer_sequence_adapter + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter( + const boost::asio::mutable_buffers_1& buffer_sequence) + { + init_native_buffer(buffer_, Buffer(buffer_sequence)); + total_buffer_size_ = buffer_sequence.size(); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const boost::asio::mutable_buffers_1& buffer_sequence) + { + return buffer_sequence.size() == 0; + } + + static void validate(const boost::asio::mutable_buffers_1& buffer_sequence) + { + buffer_sequence.data(); + } + + static Buffer first(const boost::asio::mutable_buffers_1& buffer_sequence) + { + return Buffer(buffer_sequence); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; +}; + +template +class buffer_sequence_adapter + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter( + const boost::asio::const_buffers_1& buffer_sequence) + { + init_native_buffer(buffer_, Buffer(buffer_sequence)); + total_buffer_size_ = buffer_sequence.size(); + } + + native_buffer_type* buffers() + { + return &buffer_; + } + + std::size_t count() const + { + return 1; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const boost::asio::const_buffers_1& buffer_sequence) + { + return buffer_sequence.size() == 0; + } + + static void validate(const boost::asio::const_buffers_1& buffer_sequence) + { + buffer_sequence.data(); + } + + static Buffer first(const boost::asio::const_buffers_1& buffer_sequence) + { + return Buffer(buffer_sequence); + } + +private: + native_buffer_type buffer_; + std::size_t total_buffer_size_; +}; + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +template +class buffer_sequence_adapter > + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter( + const boost::array& buffer_sequence) + { + init_native_buffer(buffers_[0], Buffer(buffer_sequence[0])); + init_native_buffer(buffers_[1], Buffer(buffer_sequence[1])); + total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size(); + } + + native_buffer_type* buffers() + { + return buffers_; + } + + std::size_t count() const + { + return 2; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const boost::array& buffer_sequence) + { + return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0; + } + + static void validate(const boost::array& buffer_sequence) + { + buffer_sequence[0].data(); + buffer_sequence[1].data(); + } + + static Buffer first(const boost::array& buffer_sequence) + { + return Buffer(buffer_sequence[0].size() != 0 + ? buffer_sequence[0] : buffer_sequence[1]); + } + +private: + native_buffer_type buffers_[2]; + std::size_t total_buffer_size_; +}; + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) + +template +class buffer_sequence_adapter > + : buffer_sequence_adapter_base +{ +public: + explicit buffer_sequence_adapter( + const std::array& buffer_sequence) + { + init_native_buffer(buffers_[0], Buffer(buffer_sequence[0])); + init_native_buffer(buffers_[1], Buffer(buffer_sequence[1])); + total_buffer_size_ = buffer_sequence[0].size() + buffer_sequence[1].size(); + } + + native_buffer_type* buffers() + { + return buffers_; + } + + std::size_t count() const + { + return 2; + } + + std::size_t total_size() const + { + return total_buffer_size_; + } + + bool all_empty() const + { + return total_buffer_size_ == 0; + } + + static bool all_empty(const std::array& buffer_sequence) + { + return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0; + } + + static void validate(const std::array& buffer_sequence) + { + buffer_sequence[0].data(); + buffer_sequence[1].data(); + } + + static Buffer first(const std::array& buffer_sequence) + { + return Buffer(buffer_sequence[0].size() != 0 + ? buffer_sequence[0] : buffer_sequence[1]); + } + +private: + native_buffer_type buffers_[2]; + std::size_t total_buffer_size_; +}; + +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP diff --git a/boost/asio/detail/buffered_stream_storage.hpp b/boost/asio/detail/buffered_stream_storage.hpp new file mode 100644 index 0000000..2e060ce --- /dev/null +++ b/boost/asio/detail/buffered_stream_storage.hpp @@ -0,0 +1,128 @@ +// +// detail/buffered_stream_storage.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP +#define BOOST_ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class buffered_stream_storage +{ +public: + // The type of the bytes stored in the buffer. + typedef unsigned char byte_type; + + // The type used for offsets into the buffer. + typedef std::size_t size_type; + + // Constructor. + explicit buffered_stream_storage(std::size_t buffer_capacity) + : begin_offset_(0), + end_offset_(0), + buffer_(buffer_capacity) + { + } + + /// Clear the buffer. + void clear() + { + begin_offset_ = 0; + end_offset_ = 0; + } + + // Return a pointer to the beginning of the unread data. + mutable_buffer data() + { + return boost::asio::buffer(buffer_) + begin_offset_; + } + + // Return a pointer to the beginning of the unread data. + const_buffer data() const + { + return boost::asio::buffer(buffer_) + begin_offset_; + } + + // Is there no unread data in the buffer. + bool empty() const + { + return begin_offset_ == end_offset_; + } + + // Return the amount of unread data the is in the buffer. + size_type size() const + { + return end_offset_ - begin_offset_; + } + + // Resize the buffer to the specified length. + void resize(size_type length) + { + BOOST_ASIO_ASSERT(length <= capacity()); + if (begin_offset_ + length <= capacity()) + { + end_offset_ = begin_offset_ + length; + } + else + { + using namespace std; // For memmove. + memmove(&buffer_[0], &buffer_[0] + begin_offset_, size()); + end_offset_ = length; + begin_offset_ = 0; + } + } + + // Return the maximum size for data in the buffer. + size_type capacity() const + { + return buffer_.size(); + } + + // Consume multiple bytes from the beginning of the buffer. + void consume(size_type count) + { + BOOST_ASIO_ASSERT(begin_offset_ + count <= end_offset_); + begin_offset_ += count; + if (empty()) + clear(); + } + +private: + // The offset to the beginning of the unread data. + size_type begin_offset_; + + // The offset to the end of the unread data. + size_type end_offset_; + + // The data in the buffer. + std::vector buffer_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP diff --git a/boost/asio/detail/call_stack.hpp b/boost/asio/detail/call_stack.hpp new file mode 100644 index 0000000..eb63e54 --- /dev/null +++ b/boost/asio/detail/call_stack.hpp @@ -0,0 +1,127 @@ +// +// detail/call_stack.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_CALL_STACK_HPP +#define BOOST_ASIO_DETAIL_CALL_STACK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Helper class to determine whether or not the current thread is inside an +// invocation of io_context::run() for a specified io_context object. +template +class call_stack +{ +public: + // Context class automatically pushes the key/value pair on to the stack. + class context + : private noncopyable + { + public: + // Push the key on to the stack. + explicit context(Key* k) + : key_(k), + next_(call_stack::top_) + { + value_ = reinterpret_cast(this); + call_stack::top_ = this; + } + + // Push the key/value pair on to the stack. + context(Key* k, Value& v) + : key_(k), + value_(&v), + next_(call_stack::top_) + { + call_stack::top_ = this; + } + + // Pop the key/value pair from the stack. + ~context() + { + call_stack::top_ = next_; + } + + // Find the next context with the same key. + Value* next_by_key() const + { + context* elem = next_; + while (elem) + { + if (elem->key_ == key_) + return elem->value_; + elem = elem->next_; + } + return 0; + } + + private: + friend class call_stack; + + // The key associated with the context. + Key* key_; + + // The value associated with the context. + Value* value_; + + // The next element in the stack. + context* next_; + }; + + friend class context; + + // Determine whether the specified owner is on the stack. Returns address of + // key if present, 0 otherwise. + static Value* contains(Key* k) + { + context* elem = top_; + while (elem) + { + if (elem->key_ == k) + return elem->value_; + elem = elem->next_; + } + return 0; + } + + // Obtain the value at the top of the stack. + static Value* top() + { + context* elem = top_; + return elem ? elem->value_ : 0; + } + +private: + // The top of the stack of calls for the current thread. + static tss_ptr top_; +}; + +template +tss_ptr::context> +call_stack::top_; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_CALL_STACK_HPP diff --git a/boost/asio/detail/chrono.hpp b/boost/asio/detail/chrono.hpp new file mode 100644 index 0000000..d5a55ff --- /dev/null +++ b/boost/asio/detail/chrono.hpp @@ -0,0 +1,68 @@ +// +// detail/chrono.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_CHRONO_HPP +#define BOOST_ASIO_DETAIL_CHRONO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_STD_CHRONO) +# include +#elif defined(BOOST_ASIO_HAS_BOOST_CHRONO) +# include +#endif // defined(BOOST_ASIO_HAS_BOOST_CHRONO) + +namespace boost { +namespace asio { +namespace chrono { + +#if defined(BOOST_ASIO_HAS_STD_CHRONO) +using std::chrono::duration; +using std::chrono::time_point; +using std::chrono::duration_cast; +using std::chrono::nanoseconds; +using std::chrono::microseconds; +using std::chrono::milliseconds; +using std::chrono::seconds; +using std::chrono::minutes; +using std::chrono::hours; +using std::chrono::time_point_cast; +#if defined(BOOST_ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK) +typedef std::chrono::monotonic_clock steady_clock; +#else // defined(BOOST_ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK) +using std::chrono::steady_clock; +#endif // defined(BOOST_ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK) +using std::chrono::system_clock; +using std::chrono::high_resolution_clock; +#elif defined(BOOST_ASIO_HAS_BOOST_CHRONO) +using boost::chrono::duration; +using boost::chrono::time_point; +using boost::chrono::duration_cast; +using boost::chrono::nanoseconds; +using boost::chrono::microseconds; +using boost::chrono::milliseconds; +using boost::chrono::seconds; +using boost::chrono::minutes; +using boost::chrono::hours; +using boost::chrono::time_point_cast; +using boost::chrono::system_clock; +using boost::chrono::steady_clock; +using boost::chrono::high_resolution_clock; +#endif // defined(BOOST_ASIO_HAS_BOOST_CHRONO) + +} // namespace chrono +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_CHRONO_HPP diff --git a/boost/asio/detail/chrono_time_traits.hpp b/boost/asio/detail/chrono_time_traits.hpp new file mode 100644 index 0000000..85e3b8b --- /dev/null +++ b/boost/asio/detail/chrono_time_traits.hpp @@ -0,0 +1,192 @@ +// +// detail/chrono_time_traits.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP +#define BOOST_ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Helper template to compute the greatest common divisor. +template +struct gcd { enum { value = gcd::value }; }; + +template +struct gcd { enum { value = v1 }; }; + +// Adapts std::chrono clocks for use with a deadline timer. +template +struct chrono_time_traits +{ + // The clock type. + typedef Clock clock_type; + + // The duration type of the clock. + typedef typename clock_type::duration duration_type; + + // The time point type of the clock. + typedef typename clock_type::time_point time_type; + + // The period of the clock. + typedef typename duration_type::period period_type; + + // Get the current time. + static time_type now() + { + return clock_type::now(); + } + + // Add a duration to a time. + static time_type add(const time_type& t, const duration_type& d) + { + const time_type epoch; + if (t >= epoch) + { + if ((time_type::max)() - t < d) + return (time_type::max)(); + } + else // t < epoch + { + if (-(t - (time_type::min)()) > d) + return (time_type::min)(); + } + + return t + d; + } + + // Subtract one time from another. + static duration_type subtract(const time_type& t1, const time_type& t2) + { + const time_type epoch; + if (t1 >= epoch) + { + if (t2 >= epoch) + { + return t1 - t2; + } + else if (t2 == (time_type::min)()) + { + return (duration_type::max)(); + } + else if ((time_type::max)() - t1 < epoch - t2) + { + return (duration_type::max)(); + } + else + { + return t1 - t2; + } + } + else // t1 < epoch + { + if (t2 < epoch) + { + return t1 - t2; + } + else if (t1 == (time_type::min)()) + { + return (duration_type::min)(); + } + else if ((time_type::max)() - t2 < epoch - t1) + { + return (duration_type::min)(); + } + else + { + return -(t2 - t1); + } + } + } + + // Test whether one time is less than another. + static bool less_than(const time_type& t1, const time_type& t2) + { + return t1 < t2; + } + + // Implement just enough of the posix_time::time_duration interface to supply + // what the timer_queue requires. + class posix_time_duration + { + public: + explicit posix_time_duration(const duration_type& d) + : d_(d) + { + } + + int64_t ticks() const + { + return d_.count(); + } + + int64_t total_seconds() const + { + return duration_cast<1, 1>(); + } + + int64_t total_milliseconds() const + { + return duration_cast<1, 1000>(); + } + + int64_t total_microseconds() const + { + return duration_cast<1, 1000000>(); + } + + private: + template + int64_t duration_cast() const + { + const int64_t num1 = period_type::num / gcd::value; + const int64_t num2 = Num / gcd::value; + + const int64_t den1 = period_type::den / gcd::value; + const int64_t den2 = Den / gcd::value; + + const int64_t num = num1 * den2; + const int64_t den = num2 * den1; + + if (num == 1 && den == 1) + return ticks(); + else if (num != 1 && den == 1) + return ticks() * num; + else if (num == 1 && period_type::den != 1) + return ticks() / den; + else + return ticks() * num / den; + } + + duration_type d_; + }; + + // Convert to POSIX duration type. + static posix_time_duration to_posix_duration(const duration_type& d) + { + return posix_time_duration(WaitTraits::to_wait_duration(d)); + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP diff --git a/boost/asio/detail/completion_handler.hpp b/boost/asio/detail/completion_handler.hpp new file mode 100644 index 0000000..3cd1369 --- /dev/null +++ b/boost/asio/detail/completion_handler.hpp @@ -0,0 +1,85 @@ +// +// detail/completion_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_COMPLETION_HANDLER_HPP +#define BOOST_ASIO_DETAIL_COMPLETION_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class completion_handler : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(completion_handler); + + completion_handler(Handler& h) + : operation(&completion_handler::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(h)) + { + handler_work::start(handler_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + completion_handler* h(static_cast(base)); + ptr p = { boost::asio::detail::addressof(h->handler_), h, h }; + handler_work w(h->handler_); + + BOOST_ASIO_HANDLER_COMPLETION((*h)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + Handler handler(BOOST_ASIO_MOVE_CAST(Handler)(h->handler_)); + p.h = boost::asio::detail::addressof(handler); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN(()); + w.complete(handler, handler); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_COMPLETION_HANDLER_HPP diff --git a/boost/asio/detail/concurrency_hint.hpp b/boost/asio/detail/concurrency_hint.hpp new file mode 100644 index 0000000..99deb78 --- /dev/null +++ b/boost/asio/detail/concurrency_hint.hpp @@ -0,0 +1,94 @@ +// +// detail/concurrency_hint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_CONCURRENCY_HINT_HPP +#define BOOST_ASIO_DETAIL_CONCURRENCY_HINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +// The concurrency hint ID and mask are used to identify when a "well-known" +// concurrency hint value has been passed to the io_context. +#define BOOST_ASIO_CONCURRENCY_HINT_ID 0xA5100000u +#define BOOST_ASIO_CONCURRENCY_HINT_ID_MASK 0xFFFF0000u + +// If set, this bit indicates that the scheduler should perform locking. +#define BOOST_ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER 0x1u + +// If set, this bit indicates that the reactor should perform locking when +// managing descriptor registrations. +#define BOOST_ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION 0x2u + +// If set, this bit indicates that the reactor should perform locking for I/O. +#define BOOST_ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_IO 0x4u + +// Helper macro to determine if we have a special concurrency hint. +#define BOOST_ASIO_CONCURRENCY_HINT_IS_SPECIAL(hint) \ + ((static_cast(hint) \ + & BOOST_ASIO_CONCURRENCY_HINT_ID_MASK) \ + == BOOST_ASIO_CONCURRENCY_HINT_ID) + +// Helper macro to determine if locking is enabled for a given facility. +#define BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(facility, hint) \ + (((static_cast(hint) \ + & (BOOST_ASIO_CONCURRENCY_HINT_ID_MASK \ + | BOOST_ASIO_CONCURRENCY_HINT_LOCKING_ ## facility)) \ + ^ BOOST_ASIO_CONCURRENCY_HINT_ID) != 0) + +// This special concurrency hint disables locking in both the scheduler and +// reactor I/O. This hint has the following restrictions: +// +// - Care must be taken to ensure that all operations on the io_context and any +// of its associated I/O objects (such as sockets and timers) occur in only +// one thread at a time. +// +// - Asynchronous resolve operations fail with operation_not_supported. +// +// - If a signal_set is used with the io_context, signal_set objects cannot be +// used with any other io_context in the program. +#define BOOST_ASIO_CONCURRENCY_HINT_UNSAFE \ + static_cast(BOOST_ASIO_CONCURRENCY_HINT_ID) + +// This special concurrency hint disables locking in the reactor I/O. This hint +// has the following restrictions: +// +// - Care must be taken to ensure that run functions on the io_context, and all +// operations on the io_context's associated I/O objects (such as sockets and +// timers), occur in only one thread at a time. +#define BOOST_ASIO_CONCURRENCY_HINT_UNSAFE_IO \ + static_cast(BOOST_ASIO_CONCURRENCY_HINT_ID \ + | BOOST_ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \ + | BOOST_ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION) + +// The special concurrency hint provides full thread safety. +#define BOOST_ASIO_CONCURRENCY_HINT_SAFE \ + static_cast(BOOST_ASIO_CONCURRENCY_HINT_ID \ + | BOOST_ASIO_CONCURRENCY_HINT_LOCKING_SCHEDULER \ + | BOOST_ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_REGISTRATION \ + | BOOST_ASIO_CONCURRENCY_HINT_LOCKING_REACTOR_IO) + +// This #define may be overridden at compile time to specify a program-wide +// default concurrency hint, used by the zero-argument io_context constructor. +#if !defined(BOOST_ASIO_CONCURRENCY_HINT_DEFAULT) +# define BOOST_ASIO_CONCURRENCY_HINT_DEFAULT -1 +#endif // !defined(BOOST_ASIO_CONCURRENCY_HINT_DEFAULT) + +// This #define may be overridden at compile time to specify a program-wide +// concurrency hint, used by the one-argument io_context constructor when +// passed a value of 1. +#if !defined(BOOST_ASIO_CONCURRENCY_HINT_1) +# define BOOST_ASIO_CONCURRENCY_HINT_1 1 +#endif // !defined(BOOST_ASIO_CONCURRENCY_HINT_DEFAULT) + +#endif // BOOST_ASIO_DETAIL_CONCURRENCY_HINT_HPP diff --git a/boost/asio/detail/conditionally_enabled_event.hpp b/boost/asio/detail/conditionally_enabled_event.hpp new file mode 100644 index 0000000..2d5a45c --- /dev/null +++ b/boost/asio/detail/conditionally_enabled_event.hpp @@ -0,0 +1,114 @@ +// +// detail/conditionally_enabled_event.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP +#define BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Mutex adapter used to conditionally enable or disable locking. +class conditionally_enabled_event + : private noncopyable +{ +public: + // Constructor. + conditionally_enabled_event() + { + } + + // Destructor. + ~conditionally_enabled_event() + { + } + + // Signal the event. (Retained for backward compatibility.) + void signal(conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.signal(lock); + } + + // Signal all waiters. + void signal_all(conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.signal_all(lock); + } + + // Unlock the mutex and signal one waiter. + void unlock_and_signal_one( + conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.unlock_and_signal_one(lock); + } + + // If there's a waiter, unlock the mutex and signal it. + bool maybe_unlock_and_signal_one( + conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + return event_.maybe_unlock_and_signal_one(lock); + else + return false; + } + + // Reset the event. + void clear(conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.clear(lock); + } + + // Wait for the event to become signalled. + void wait(conditionally_enabled_mutex::scoped_lock& lock) + { + if (lock.mutex_.enabled_) + event_.wait(lock); + else + null_event().wait(lock); + } + + // Timed wait for the event to become signalled. + bool wait_for_usec( + conditionally_enabled_mutex::scoped_lock& lock, long usec) + { + if (lock.mutex_.enabled_) + return event_.wait_for_usec(lock, usec); + else + return null_event().wait_for_usec(lock, usec); + } + +private: + boost::asio::detail::event event_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP diff --git a/boost/asio/detail/conditionally_enabled_mutex.hpp b/boost/asio/detail/conditionally_enabled_mutex.hpp new file mode 100644 index 0000000..5d105e9 --- /dev/null +++ b/boost/asio/detail/conditionally_enabled_mutex.hpp @@ -0,0 +1,151 @@ +// +// detail/conditionally_enabled_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP +#define BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Mutex adapter used to conditionally enable or disable locking. +class conditionally_enabled_mutex + : private noncopyable +{ +public: + // Helper class to lock and unlock a mutex automatically. + class scoped_lock + : private noncopyable + { + public: + // Tag type used to distinguish constructors. + enum adopt_lock_t { adopt_lock }; + + // Constructor adopts a lock that is already held. + scoped_lock(conditionally_enabled_mutex& m, adopt_lock_t) + : mutex_(m), + locked_(m.enabled_) + { + } + + // Constructor acquires the lock. + explicit scoped_lock(conditionally_enabled_mutex& m) + : mutex_(m) + { + if (m.enabled_) + { + mutex_.mutex_.lock(); + locked_ = true; + } + else + locked_ = false; + } + + // Destructor releases the lock. + ~scoped_lock() + { + if (locked_) + mutex_.mutex_.unlock(); + } + + // Explicitly acquire the lock. + void lock() + { + if (mutex_.enabled_ && !locked_) + { + mutex_.mutex_.lock(); + locked_ = true; + } + } + + // Explicitly release the lock. + void unlock() + { + if (locked_) + { + mutex_.unlock(); + locked_ = false; + } + } + + // Test whether the lock is held. + bool locked() const + { + return locked_; + } + + // Get the underlying mutex. + boost::asio::detail::mutex& mutex() + { + return mutex_.mutex_; + } + + private: + friend class conditionally_enabled_event; + conditionally_enabled_mutex& mutex_; + bool locked_; + }; + + // Constructor. + explicit conditionally_enabled_mutex(bool enabled) + : enabled_(enabled) + { + } + + // Destructor. + ~conditionally_enabled_mutex() + { + } + + // Determine whether locking is enabled. + bool enabled() const + { + return enabled_; + } + + // Lock the mutex. + void lock() + { + if (enabled_) + mutex_.lock(); + } + + // Unlock the mutex. + void unlock() + { + if (enabled_) + mutex_.unlock(); + } + +private: + friend class scoped_lock; + friend class conditionally_enabled_event; + boost::asio::detail::mutex mutex_; + const bool enabled_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP diff --git a/boost/asio/detail/config.hpp b/boost/asio/detail/config.hpp new file mode 100644 index 0000000..683a2b1 --- /dev/null +++ b/boost/asio/detail/config.hpp @@ -0,0 +1,1442 @@ +// +// detail/config.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_CONFIG_HPP +#define BOOST_ASIO_DETAIL_CONFIG_HPP + +#if defined(BOOST_ASIO_STANDALONE) +# define BOOST_ASIO_DISABLE_BOOST_ARRAY 1 +# define BOOST_ASIO_DISABLE_BOOST_ASSERT 1 +# define BOOST_ASIO_DISABLE_BOOST_BIND 1 +# define BOOST_ASIO_DISABLE_BOOST_CHRONO 1 +# define BOOST_ASIO_DISABLE_BOOST_DATE_TIME 1 +# define BOOST_ASIO_DISABLE_BOOST_LIMITS 1 +# define BOOST_ASIO_DISABLE_BOOST_REGEX 1 +# define BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT 1 +# define BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION 1 +# define BOOST_ASIO_DISABLE_BOOST_WORKAROUND 1 +#else // defined(BOOST_ASIO_STANDALONE) +# include +# include +# define BOOST_ASIO_HAS_BOOST_CONFIG 1 +#endif // defined(BOOST_ASIO_STANDALONE) + +// Default to a header-only implementation. The user must specifically request +// separate compilation by defining either BOOST_ASIO_SEPARATE_COMPILATION or +// BOOST_ASIO_DYN_LINK (as a DLL/shared library implies separate compilation). +#if !defined(BOOST_ASIO_HEADER_ONLY) +# if !defined(BOOST_ASIO_SEPARATE_COMPILATION) +# if !defined(BOOST_ASIO_DYN_LINK) +# define BOOST_ASIO_HEADER_ONLY 1 +# endif // !defined(BOOST_ASIO_DYN_LINK) +# endif // !defined(BOOST_ASIO_SEPARATE_COMPILATION) +#endif // !defined(BOOST_ASIO_HEADER_ONLY) + +#if defined(BOOST_ASIO_HEADER_ONLY) +# define BOOST_ASIO_DECL inline +#else // defined(BOOST_ASIO_HEADER_ONLY) +# if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) +// We need to import/export our code only if the user has specifically asked +// for it by defining BOOST_ASIO_DYN_LINK. +# if defined(BOOST_ASIO_DYN_LINK) +// Export if this is our own source, otherwise import. +# if defined(BOOST_ASIO_SOURCE) +# define BOOST_ASIO_DECL __declspec(dllexport) +# else // defined(BOOST_ASIO_SOURCE) +# define BOOST_ASIO_DECL __declspec(dllimport) +# endif // defined(BOOST_ASIO_SOURCE) +# endif // defined(BOOST_ASIO_DYN_LINK) +# endif // defined(_MSC_VER) || defined(__BORLANDC__) || defined(__CODEGEARC__) +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +// If BOOST_ASIO_DECL isn't defined yet define it now. +#if !defined(BOOST_ASIO_DECL) +# define BOOST_ASIO_DECL +#endif // !defined(BOOST_ASIO_DECL) + +// Microsoft Visual C++ detection. +#if !defined(BOOST_ASIO_MSVC) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC) +# define BOOST_ASIO_MSVC BOOST_MSVC +# elif defined(_MSC_VER) && (defined(__INTELLISENSE__) \ + || (!defined(__MWERKS__) && !defined(__EDG_VERSION__))) +# define BOOST_ASIO_MSVC _MSC_VER +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_MSVC) +#endif // !defined(BOOST_ASIO_MSVC) + +// Clang / libc++ detection. +#if defined(__clang__) +# if (__cplusplus >= 201103) +# if __has_include(<__config>) +# include <__config> +# if defined(_LIBCPP_VERSION) +# define BOOST_ASIO_HAS_CLANG_LIBCXX 1 +# endif // defined(_LIBCPP_VERSION) +# endif // __has_include(<__config>) +# endif // (__cplusplus >= 201103) +#endif // defined(__clang__) + +// Android platform detection. +#if defined(__ANDROID__) +# include +#endif // defined(__ANDROID__) + +// Support move construction and assignment on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_MOVE) +# if !defined(BOOST_ASIO_DISABLE_MOVE) +# if defined(__clang__) +# if __has_feature(__cxx_rvalue_references__) +# define BOOST_ASIO_HAS_MOVE 1 +# endif // __has_feature(__cxx_rvalue_references__) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_MOVE 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_MOVE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# if defined(__INTEL_CXX11_MODE__) +# if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500) +# define BOOST_ASIO_HAS_MOVE 1 +# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500) +# if defined(__ICL) && (__ICL >= 1500) +# define BOOST_ASIO_HAS_MOVE 1 +# endif // defined(__ICL) && (__ICL >= 1500) +# endif // defined(__INTEL_CXX11_MODE__) +# endif // !defined(BOOST_ASIO_DISABLE_MOVE) +#endif // !defined(BOOST_ASIO_HAS_MOVE) + +// If BOOST_ASIO_MOVE_CAST isn't defined, and move support is available, define +// * BOOST_ASIO_MOVE_ARG, +// * BOOST_ASIO_NONDEDUCED_MOVE_ARG, and +// * BOOST_ASIO_MOVE_CAST +// to take advantage of rvalue references and perfect forwarding. +#if defined(BOOST_ASIO_HAS_MOVE) && !defined(BOOST_ASIO_MOVE_CAST) +# define BOOST_ASIO_MOVE_ARG(type) type&& +# define BOOST_ASIO_MOVE_ARG2(type1, type2) type1, type2&& +# define BOOST_ASIO_NONDEDUCED_MOVE_ARG(type) type& +# define BOOST_ASIO_MOVE_CAST(type) static_cast +# define BOOST_ASIO_MOVE_CAST2(type1, type2) static_cast +#endif // defined(BOOST_ASIO_HAS_MOVE) && !defined(BOOST_ASIO_MOVE_CAST) + +// If BOOST_ASIO_MOVE_CAST still isn't defined, default to a C++03-compatible +// implementation. Note that older g++ and MSVC versions don't like it when you +// pass a non-member function through a const reference, so for most compilers +// we'll play it safe and stick with the old approach of passing the handler by +// value. +#if !defined(BOOST_ASIO_MOVE_CAST) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) +# define BOOST_ASIO_MOVE_ARG(type) const type& +# else // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) +# define BOOST_ASIO_MOVE_ARG(type) type +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 1)) || (__GNUC__ > 4) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1400) +# define BOOST_ASIO_MOVE_ARG(type) const type& +# else // (_MSC_VER >= 1400) +# define BOOST_ASIO_MOVE_ARG(type) type +# endif // (_MSC_VER >= 1400) +# else +# define BOOST_ASIO_MOVE_ARG(type) type +# endif +# define BOOST_ASIO_NONDEDUCED_MOVE_ARG(type) const type& +# define BOOST_ASIO_MOVE_CAST(type) static_cast +# define BOOST_ASIO_MOVE_CAST2(type1, type2) static_cast +#endif // !defined(BOOST_ASIO_MOVE_CAST) + +// Support variadic templates on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +# if !defined(BOOST_ASIO_DISABLE_VARIADIC_TEMPLATES) +# if defined(__clang__) +# if __has_feature(__cxx_variadic_templates__) +# define BOOST_ASIO_HAS_VARIADIC_TEMPLATES 1 +# endif // __has_feature(__cxx_variadic_templates__) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_VARIADIC_TEMPLATES 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_HAS_VARIADIC_TEMPLATES 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_VARIADIC_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +// Support deleted functions on compilers known to allow it. +#if !defined(BOOST_ASIO_DELETED) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_DELETED = delete +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(__clang__) +# if __has_feature(__cxx_deleted_functions__) +# define BOOST_ASIO_DELETED = delete +# endif // __has_feature(__cxx_deleted_functions__) +# endif // defined(__clang__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_DELETED = delete +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# if !defined(BOOST_ASIO_DELETED) +# define BOOST_ASIO_DELETED +# endif // !defined(BOOST_ASIO_DELETED) +#endif // !defined(BOOST_ASIO_DELETED) + +// Support constexpr on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_CONSTEXPR) +# if !defined(BOOST_ASIO_DISABLE_CONSTEXPR) +# if defined(__clang__) +# if __has_feature(__cxx_constexpr__) +# define BOOST_ASIO_HAS_CONSTEXPR 1 +# endif // __has_feature(__cxx_constexr__) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_CONSTEXPR 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_HAS_CONSTEXPR 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_CONSTEXPR) +#endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) +#if !defined(BOOST_ASIO_CONSTEXPR) +# if defined(BOOST_ASIO_HAS_CONSTEXPR) +# define BOOST_ASIO_CONSTEXPR constexpr +# else // defined(BOOST_ASIO_HAS_CONSTEXPR) +# define BOOST_ASIO_CONSTEXPR +# endif // defined(BOOST_ASIO_HAS_CONSTEXPR) +#endif // !defined(BOOST_ASIO_CONSTEXPR) + +// Support noexcept on compilers known to allow it. +#if !defined(BOOST_ASIO_NOEXCEPT) +# if !defined(BOOST_ASIO_DISABLE_NOEXCEPT) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105300) +# define BOOST_ASIO_NOEXCEPT BOOST_NOEXCEPT +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW BOOST_NOEXCEPT_OR_NOTHROW +# elif defined(__clang__) +# if __has_feature(__cxx_noexcept__) +# define BOOST_ASIO_NOEXCEPT noexcept(true) +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) +# endif // __has_feature(__cxx_noexcept__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_NOEXCEPT noexcept(true) +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_NOEXCEPT noexcept(true) +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_NOEXCEPT) +# if !defined(BOOST_ASIO_NOEXCEPT) +# define BOOST_ASIO_NOEXCEPT +# endif // !defined(BOOST_ASIO_NOEXCEPT) +# if !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) +# define BOOST_ASIO_NOEXCEPT_OR_NOTHROW throw() +# endif // !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) +#endif // !defined(BOOST_ASIO_NOEXCEPT) + +// Support automatic type deduction on compilers known to support it. +#if !defined(BOOST_ASIO_HAS_DECLTYPE) +# if !defined(BOOST_ASIO_DISABLE_DECLTYPE) +# if defined(__clang__) +# if __has_feature(__cxx_decltype__) +# define BOOST_ASIO_HAS_DECLTYPE 1 +# endif // __has_feature(__cxx_decltype__) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_DECLTYPE 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1800) +# define BOOST_ASIO_HAS_DECLTYPE 1 +# endif // (_MSC_VER >= 1800) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_DECLTYPE) +#endif // !defined(BOOST_ASIO_HAS_DECLTYPE) + +// Support alias templates on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) +# if !defined(BOOST_ASIO_DISABLE_ALIAS_TEMPLATES) +# if defined(__clang__) +# if __has_feature(__cxx_alias_templates__) +# define BOOST_ASIO_HAS_ALIAS_TEMPLATES 1 +# endif // __has_feature(__cxx_alias_templates__) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_ALIAS_TEMPLATES 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_HAS_ALIAS_TEMPLATES 1 +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_ALIAS_TEMPLATES) +#endif // !defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) + +// Standard library support for system errors. +# if !defined(BOOST_ASIO_DISABLE_STD_SYSTEM_ERROR) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_SYSTEM_ERROR) + +// Compliant C++11 compilers put noexcept specifiers on error_category members. +#if !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105300) +# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT BOOST_NOEXCEPT +# elif defined(__clang__) +# if __has_feature(__cxx_noexcept__) +# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) +# endif // __has_feature(__cxx_noexcept__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1900) +# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) +# endif // (_MSC_VER >= 1900) +# endif // defined(BOOST_ASIO_MSVC) +# if !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT) +# define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT +# endif // !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT) +#endif // !defined(BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT) + +// Standard library support for arrays. +#if !defined(BOOST_ASIO_HAS_STD_ARRAY) +# if !defined(BOOST_ASIO_DISABLE_STD_ARRAY) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_ARRAY 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_ARRAY 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_ARRAY 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1600) +# define BOOST_ASIO_HAS_STD_ARRAY 1 +# endif // (_MSC_VER >= 1600) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ARRAY) +#endif // !defined(BOOST_ASIO_HAS_STD_ARRAY) + +// Standard library support for shared_ptr and weak_ptr. +#if !defined(BOOST_ASIO_HAS_STD_SHARED_PTR) +# if !defined(BOOST_ASIO_DISABLE_STD_SHARED_PTR) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_SHARED_PTR 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_SHARED_PTR 1 +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_SHARED_PTR 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1600) +# define BOOST_ASIO_HAS_STD_SHARED_PTR 1 +# endif // (_MSC_VER >= 1600) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_SHARED_PTR) +#endif // !defined(BOOST_ASIO_HAS_STD_SHARED_PTR) + +// Standard library support for allocator_arg_t. +#if !defined(BOOST_ASIO_HAS_STD_ALLOCATOR_ARG) +# if !defined(BOOST_ASIO_DISABLE_STD_ALLOCATOR_ARG) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1600) +# define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 +# endif // (_MSC_VER >= 1600) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ALLOCATOR_ARG) +#endif // !defined(BOOST_ASIO_HAS_STD_ALLOCATOR_ARG) + +// Standard library support for atomic operations. +#if !defined(BOOST_ASIO_HAS_STD_ATOMIC) +# if !defined(BOOST_ASIO_DISABLE_STD_ATOMIC) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_ATOMIC 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_ATOMIC 1 +# endif // __has_include() +# elif defined(__apple_build_version__) && defined(_LIBCPP_VERSION) +# if (__clang_major__ >= 10) +# if __has_include() +# define BOOST_ASIO_HAS_STD_ATOMIC 1 +# endif // __has_include() +# endif // (__clang_major__ >= 10) +# endif /// defined(__apple_build_version__) && defined(_LIBCPP_VERSION) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_ATOMIC 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_ATOMIC 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ATOMIC) +#endif // !defined(BOOST_ASIO_HAS_STD_ATOMIC) + +// Standard library support for chrono. Some standard libraries (such as the +// libstdc++ shipped with gcc 4.6) provide monotonic_clock as per early C++0x +// drafts, rather than the eventually standardised name of steady_clock. +#if !defined(BOOST_ASIO_HAS_STD_CHRONO) +# if !defined(BOOST_ASIO_DISABLE_STD_CHRONO) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_CHRONO 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_CHRONO 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_CHRONO 1 +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) +# define BOOST_ASIO_HAS_STD_CHRONO_MONOTONIC_CLOCK 1 +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ == 6)) +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_CHRONO 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_CHRONO) +#endif // !defined(BOOST_ASIO_HAS_STD_CHRONO) + +// Boost support for chrono. +#if !defined(BOOST_ASIO_HAS_BOOST_CHRONO) +# if !defined(BOOST_ASIO_DISABLE_BOOST_CHRONO) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700) +# define BOOST_ASIO_HAS_BOOST_CHRONO 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 104700) +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_CHRONO) +#endif // !defined(BOOST_ASIO_HAS_BOOST_CHRONO) + +// Some form of chrono library is available. +#if !defined(BOOST_ASIO_HAS_CHRONO) +# if defined(BOOST_ASIO_HAS_STD_CHRONO) \ + || defined(BOOST_ASIO_HAS_BOOST_CHRONO) +# define BOOST_ASIO_HAS_CHRONO 1 +# endif // defined(BOOST_ASIO_HAS_STD_CHRONO) + // || defined(BOOST_ASIO_HAS_BOOST_CHRONO) +#endif // !defined(BOOST_ASIO_HAS_CHRONO) + +// Boost support for the DateTime library. +#if !defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +# if !defined(BOOST_ASIO_DISABLE_BOOST_DATE_TIME) +# define BOOST_ASIO_HAS_BOOST_DATE_TIME 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_DATE_TIME) +#endif // !defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +// Standard library support for addressof. +#if !defined(BOOST_ASIO_HAS_STD_ADDRESSOF) +# if !defined(BOOST_ASIO_DISABLE_STD_ADDRESSOF) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_ADDRESSOF 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_ADDRESSOF 1 +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_ADDRESSOF 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_ADDRESSOF 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_ADDRESSOF) +#endif // !defined(BOOST_ASIO_HAS_STD_ADDRESSOF) + +// Standard library support for the function class. +#if !defined(BOOST_ASIO_HAS_STD_FUNCTION) +# if !defined(BOOST_ASIO_DISABLE_STD_FUNCTION) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_FUNCTION 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_STD_FUNCTION 1 +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_FUNCTION 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_FUNCTION 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_FUNCTION) +#endif // !defined(BOOST_ASIO_HAS_STD_FUNCTION) + +// Standard library support for type traits. +#if !defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) +# if !defined(BOOST_ASIO_DISABLE_STD_TYPE_TRAITS) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_TYPE_TRAITS) +#endif // !defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) + +// Standard library support for the nullptr_t type. +#if !defined(BOOST_ASIO_HAS_NULLPTR) +# if !defined(BOOST_ASIO_DISABLE_NULLPTR) +# if defined(__clang__) +# if __has_feature(__cxx_nullptr__) +# define BOOST_ASIO_HAS_NULLPTR 1 +# endif // __has_feature(__cxx_rvalue_references__) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_NULLPTR 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_NULLPTR 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_NULLPTR) +#endif // !defined(BOOST_ASIO_HAS_NULLPTR) + +// Standard library support for the C++11 allocator additions. +#if !defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS) +# if !defined(BOOST_ASIO_DISABLE_CXX11_ALLOCATORS) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 +# endif // (__cplusplus >= 201103) +# elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1800) +# define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 +# endif // (_MSC_VER >= 1800) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_CXX11_ALLOCATORS) +#endif // !defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS) + +// Standard library support for the cstdint header. +#if !defined(BOOST_ASIO_HAS_CSTDINT) +# if !defined(BOOST_ASIO_DISABLE_CSTDINT) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_CSTDINT 1 +# elif (__cplusplus >= 201103) +# define BOOST_ASIO_HAS_CSTDINT 1 +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_CSTDINT 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_CSTDINT 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_CSTDINT) +#endif // !defined(BOOST_ASIO_HAS_CSTDINT) + +// Standard library support for the thread class. +#if !defined(BOOST_ASIO_HAS_STD_THREAD) +# if !defined(BOOST_ASIO_DISABLE_STD_THREAD) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_THREAD 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_THREAD 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_THREAD 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_THREAD 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_THREAD) +#endif // !defined(BOOST_ASIO_HAS_STD_THREAD) + +// Standard library support for the mutex and condition variable classes. +#if !defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) +# if !defined(BOOST_ASIO_DISABLE_STD_MUTEX_AND_CONDVAR) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_MUTEX_AND_CONDVAR) +#endif // !defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +// Standard library support for the call_once function. +#if !defined(BOOST_ASIO_HAS_STD_CALL_ONCE) +# if !defined(BOOST_ASIO_DISABLE_STD_CALL_ONCE) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_CALL_ONCE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_CALL_ONCE) +#endif // !defined(BOOST_ASIO_HAS_STD_CALL_ONCE) + +// Standard library support for futures. +#if !defined(BOOST_ASIO_HAS_STD_FUTURE) +# if !defined(BOOST_ASIO_DISABLE_STD_FUTURE) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_FUTURE 1 +# elif (__cplusplus >= 201103) +# if __has_include() +# define BOOST_ASIO_HAS_STD_FUTURE 1 +# endif // __has_include() +# endif // (__cplusplus >= 201103) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_FUTURE 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_FUTURE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_FUTURE) +#endif // !defined(BOOST_ASIO_HAS_STD_FUTURE) + +// Standard library support for std::string_view. +#if !defined(BOOST_ASIO_HAS_STD_STRING_VIEW) +# if !defined(BOOST_ASIO_DISABLE_STD_STRING_VIEW) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201402) +# if __has_include() +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201402) +# else // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) +# endif // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# elif defined(__GNUC__) +# if (__GNUC__ >= 7) +# if (__cplusplus >= 201703) +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // (__cplusplus >= 201703) +# endif // (__GNUC__ >= 7) +# elif defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) +# define BOOST_ASIO_HAS_STD_STRING_VIEW 1 +# endif // (_MSC_VER >= 1910 && _MSVC_LANG >= 201703) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_STRING_VIEW) +#endif // !defined(BOOST_ASIO_HAS_STD_STRING_VIEW) + +// Standard library support for std::experimental::string_view. +#if !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# if !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW) +# if defined(__clang__) +# if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (_LIBCPP_VERSION < 7000) +# if (__cplusplus >= 201402) +# if __has_include() +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201402) +# endif // (_LIBCPP_VERSION < 7000) +# else // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if (__cplusplus >= 201402) +# if __has_include() +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // __has_include() +# endif // (__cplusplus >= 201402) +# endif // // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# endif // defined(__clang__) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# if (__cplusplus >= 201402) +# define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 +# endif // (__cplusplus >= 201402) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# endif // !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_STRING_VIEW) +#endif // !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + +// Standard library has a string_view that we can use. +#if !defined(BOOST_ASIO_HAS_STRING_VIEW) +# if !defined(BOOST_ASIO_DISABLE_STRING_VIEW) +# if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) +# define BOOST_ASIO_HAS_STRING_VIEW 1 +# elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# define BOOST_ASIO_HAS_STRING_VIEW 1 +# endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# endif // !defined(BOOST_ASIO_DISABLE_STRING_VIEW) +#endif // !defined(BOOST_ASIO_HAS_STRING_VIEW) + +// Standard library support for iostream move construction and assignment. +#if !defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE) +# if !defined(BOOST_ASIO_DISABLE_STD_IOSTREAM_MOVE) +# if defined(__GNUC__) +# if (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_HAS_STD_IOSTREAM_MOVE 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_STD_IOSTREAM_MOVE 1 +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_IOSTREAM_MOVE) +#endif // !defined(BOOST_ASIO_HAS_STD_IOSTREAM_MOVE) + +// Standard library has invoke_result (which supersedes result_of). +#if !defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT) +# if !defined(BOOST_ASIO_DISABLE_STD_INVOKE_RESULT) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1911 && _MSVC_LANG >= 201703) +# define BOOST_ASIO_HAS_STD_INVOKE_RESULT 1 +# endif // (_MSC_VER >= 1911 && _MSVC_LANG >= 201703) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_STD_INVOKE_RESULT) +#endif // !defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT) + +// Windows App target. Windows but with a limited API. +#if !defined(BOOST_ASIO_WINDOWS_APP) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) +# include +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \ + && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define BOOST_ASIO_WINDOWS_APP 1 +# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) +#endif // !defined(BOOST_ASIO_WINDOWS_APP) + +// Legacy WinRT target. Windows App is preferred. +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) +# if !defined(BOOST_ASIO_WINDOWS_APP) +# if defined(__cplusplus_winrt) +# include +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \ + && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define BOOST_ASIO_WINDOWS_RUNTIME 1 +# endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) + // && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# endif // defined(__cplusplus_winrt) +# endif // !defined(BOOST_ASIO_WINDOWS_APP) +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +// Windows target. Excludes WinRT but includes Windows App targets. +#if !defined(BOOST_ASIO_WINDOWS) +# if !defined(BOOST_ASIO_WINDOWS_RUNTIME) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS) +# define BOOST_ASIO_WINDOWS 1 +# elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) +# define BOOST_ASIO_WINDOWS 1 +# elif defined(BOOST_ASIO_WINDOWS_APP) +# define BOOST_ASIO_WINDOWS 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_WINDOWS) +# endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) +#endif // !defined(BOOST_ASIO_WINDOWS) + +// Windows: target OS version. +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) || defined(__BORLANDC__) +# pragma message( \ + "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ + "- add -D_WIN32_WINNT=0x0601 to the compiler command line; or\n"\ + "- add _WIN32_WINNT=0x0601 to your project's Preprocessor Definitions.\n"\ + "Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target).") +# else // defined(_MSC_VER) || defined(__BORLANDC__) +# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. +# warning For example, add -D_WIN32_WINNT=0x0601 to the compiler command line. +# warning Assuming _WIN32_WINNT=0x0601 (i.e. Windows 7 target). +# endif // defined(_MSC_VER) || defined(__BORLANDC__) +# define _WIN32_WINNT 0x0601 +# endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) +# if defined(_MSC_VER) +# if defined(_WIN32) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(_WIN32) && !defined(WIN32) +# endif // defined(_MSC_VER) +# if defined(__BORLANDC__) +# if defined(__WIN32__) && !defined(WIN32) +# if !defined(_WINSOCK2API_) +# define WIN32 // Needed for correct types in winsock2.h +# else // !defined(_WINSOCK2API_) +# error Please define the macro WIN32 in your compiler options +# endif // !defined(_WINSOCK2API_) +# endif // defined(__WIN32__) && !defined(WIN32) +# endif // defined(__BORLANDC__) +# if defined(__CYGWIN__) +# if !defined(__USE_W32_SOCKETS) +# error You must add -D__USE_W32_SOCKETS to your compiler options. +# endif // !defined(__USE_W32_SOCKETS) +# endif // defined(__CYGWIN__) +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: minimise header inclusion. +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) +# if !defined(WIN32_LEAN_AND_MEAN) +# define WIN32_LEAN_AND_MEAN +# endif // !defined(WIN32_LEAN_AND_MEAN) +# endif // !defined(BOOST_ASIO_NO_WIN32_LEAN_AND_MEAN) +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: suppress definition of "min" and "max" macros. +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(BOOST_ASIO_NO_NOMINMAX) +# if !defined(NOMINMAX) +# define NOMINMAX 1 +# endif // !defined(NOMINMAX) +# endif // !defined(BOOST_ASIO_NO_NOMINMAX) +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +// Windows: IO Completion Ports. +#if !defined(BOOST_ASIO_HAS_IOCP) +# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +# if !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# if !defined(BOOST_ASIO_DISABLE_IOCP) +# define BOOST_ASIO_HAS_IOCP 1 +# endif // !defined(BOOST_ASIO_DISABLE_IOCP) +# endif // !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_HAS_IOCP) + +// On POSIX (and POSIX-like) platforms we need to include unistd.h in order to +// get access to the various platform feature macros, e.g. to be able to test +// for threads support. +#if !defined(BOOST_ASIO_HAS_UNISTD_H) +# if !defined(BOOST_ASIO_HAS_BOOST_CONFIG) +# if defined(unix) \ + || defined(__unix) \ + || defined(_XOPEN_SOURCE) \ + || defined(_POSIX_SOURCE) \ + || (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) \ + || defined(__linux__) \ + || defined(__HAIKU__) +# define BOOST_ASIO_HAS_UNISTD_H 1 +# endif +# endif // !defined(BOOST_ASIO_HAS_BOOST_CONFIG) +#endif // !defined(BOOST_ASIO_HAS_UNISTD_H) +#if defined(BOOST_ASIO_HAS_UNISTD_H) +# include +#endif // defined(BOOST_ASIO_HAS_UNISTD_H) + +// Linux: epoll, eventfd and timerfd. +#if defined(__linux__) +# include +# if !defined(BOOST_ASIO_HAS_EPOLL) +# if !defined(BOOST_ASIO_DISABLE_EPOLL) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# define BOOST_ASIO_HAS_EPOLL 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +# endif // !defined(BOOST_ASIO_DISABLE_EPOLL) +# endif // !defined(BOOST_ASIO_HAS_EPOLL) +# if !defined(BOOST_ASIO_HAS_EVENTFD) +# if !defined(BOOST_ASIO_DISABLE_EVENTFD) +# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# define BOOST_ASIO_HAS_EVENTFD 1 +# endif // LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +# endif // !defined(BOOST_ASIO_DISABLE_EVENTFD) +# endif // !defined(BOOST_ASIO_HAS_EVENTFD) +# if !defined(BOOST_ASIO_HAS_TIMERFD) +# if defined(BOOST_ASIO_HAS_EPOLL) +# if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# define BOOST_ASIO_HAS_TIMERFD 1 +# endif // (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +# endif // defined(BOOST_ASIO_HAS_EPOLL) +# endif // !defined(BOOST_ASIO_HAS_TIMERFD) +#endif // defined(__linux__) + +// Mac OS X, FreeBSD, NetBSD, OpenBSD: kqueue. +#if (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) \ + || defined(__NetBSD__) \ + || defined(__OpenBSD__) +# if !defined(BOOST_ASIO_HAS_KQUEUE) +# if !defined(BOOST_ASIO_DISABLE_KQUEUE) +# define BOOST_ASIO_HAS_KQUEUE 1 +# endif // !defined(BOOST_ASIO_DISABLE_KQUEUE) +# endif // !defined(BOOST_ASIO_HAS_KQUEUE) +#endif // (defined(__MACH__) && defined(__APPLE__)) + // || defined(__FreeBSD__) + // || defined(__NetBSD__) + // || defined(__OpenBSD__) + +// Solaris: /dev/poll. +#if defined(__sun) +# if !defined(BOOST_ASIO_HAS_DEV_POLL) +# if !defined(BOOST_ASIO_DISABLE_DEV_POLL) +# define BOOST_ASIO_HAS_DEV_POLL 1 +# endif // !defined(BOOST_ASIO_DISABLE_DEV_POLL) +# endif // !defined(BOOST_ASIO_HAS_DEV_POLL) +#endif // defined(__sun) + +// Serial ports. +#if !defined(BOOST_ASIO_HAS_SERIAL_PORT) +# if defined(BOOST_ASIO_HAS_IOCP) \ + || !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# if !defined(__SYMBIAN32__) +# if !defined(BOOST_ASIO_DISABLE_SERIAL_PORT) +# define BOOST_ASIO_HAS_SERIAL_PORT 1 +# endif // !defined(BOOST_ASIO_DISABLE_SERIAL_PORT) +# endif // !defined(__SYMBIAN32__) +# endif // defined(BOOST_ASIO_HAS_IOCP) + // || !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_HAS_SERIAL_PORT) + +// Windows: stream handles. +#if !defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) + +// Windows: random access handles. +#if !defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) + +// Windows: object handles. +#if !defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_OBJECT_HANDLE) +# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# define BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE 1 +# endif // !defined(UNDER_CE) && !defined(BOOST_ASIO_WINDOWS_APP) +# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_OBJECT_HANDLE) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) + +// Windows: OVERLAPPED wrapper. +#if !defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) +# if !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) +# if defined(BOOST_ASIO_HAS_IOCP) +# define BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR 1 +# endif // defined(BOOST_ASIO_HAS_IOCP) +# endif // !defined(BOOST_ASIO_DISABLE_WINDOWS_OVERLAPPED_PTR) +#endif // !defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) + +// POSIX: stream-oriented file descriptors. +#if !defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) +# if !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +# if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# define BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1 +# endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +# endif // !defined(BOOST_ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +#endif // !defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + +// UNIX domain sockets. +#if !defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) +# if !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) +# if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# define BOOST_ASIO_HAS_LOCAL_SOCKETS 1 +# endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +# endif // !defined(BOOST_ASIO_DISABLE_LOCAL_SOCKETS) +#endif // !defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +// Can use sigaction() instead of signal(). +#if !defined(BOOST_ASIO_HAS_SIGACTION) +# if !defined(BOOST_ASIO_DISABLE_SIGACTION) +# if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +# define BOOST_ASIO_HAS_SIGACTION 1 +# endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +# endif // !defined(BOOST_ASIO_DISABLE_SIGACTION) +#endif // !defined(BOOST_ASIO_HAS_SIGACTION) + +// Can use signal(). +#if !defined(BOOST_ASIO_HAS_SIGNAL) +# if !defined(BOOST_ASIO_DISABLE_SIGNAL) +# if !defined(UNDER_CE) +# define BOOST_ASIO_HAS_SIGNAL 1 +# endif // !defined(UNDER_CE) +# endif // !defined(BOOST_ASIO_DISABLE_SIGNAL) +#endif // !defined(BOOST_ASIO_HAS_SIGNAL) + +// Can use getaddrinfo() and getnameinfo(). +#if !defined(BOOST_ASIO_HAS_GETADDRINFO) +# if !defined(BOOST_ASIO_DISABLE_GETADDRINFO) +# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# elif defined(UNDER_CE) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // defined(UNDER_CE) +# elif defined(__MACH__) && defined(__APPLE__) +# if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) +# else // defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +# else // defined(__MACH__) && defined(__APPLE__) +# define BOOST_ASIO_HAS_GETADDRINFO 1 +# endif // defined(__MACH__) && defined(__APPLE__) +# endif // !defined(BOOST_ASIO_DISABLE_GETADDRINFO) +#endif // !defined(BOOST_ASIO_HAS_GETADDRINFO) + +// Whether standard iostreams are disabled. +#if !defined(BOOST_ASIO_NO_IOSTREAM) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_IOSTREAM) +# define BOOST_ASIO_NO_IOSTREAM 1 +# endif // !defined(BOOST_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +// Whether exception handling is disabled. +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_EXCEPTIONS) +# define BOOST_ASIO_NO_EXCEPTIONS 1 +# endif // !defined(BOOST_NO_EXCEPTIONS) +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) + +// Whether the typeid operator is supported. +#if !defined(BOOST_ASIO_NO_TYPEID) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_NO_TYPEID) +# define BOOST_ASIO_NO_TYPEID 1 +# endif // !defined(BOOST_NO_TYPEID) +#endif // !defined(BOOST_ASIO_NO_TYPEID) + +// Threads. +#if !defined(BOOST_ASIO_HAS_THREADS) +# if !defined(BOOST_ASIO_DISABLE_THREADS) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(__GNUC__) && !defined(__MINGW32__) \ + && !defined(linux) && !defined(__linux) && !defined(__linux__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_MT) || defined(__MT__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_REENTRANT) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(__APPLE__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(__HAIKU__) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) +# define BOOST_ASIO_HAS_THREADS 1 +# elif defined(_PTHREADS) +# define BOOST_ASIO_HAS_THREADS 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_THREADS) +# endif // !defined(BOOST_ASIO_DISABLE_THREADS) +#endif // !defined(BOOST_ASIO_HAS_THREADS) + +// POSIX threads. +#if !defined(BOOST_ASIO_HAS_PTHREADS) +# if defined(BOOST_ASIO_HAS_THREADS) +# if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS) +# define BOOST_ASIO_HAS_PTHREADS 1 +# elif defined(_POSIX_THREADS) && (_POSIX_THREADS + 0 >= 0) +# define BOOST_ASIO_HAS_PTHREADS 1 +# elif defined(__HAIKU__) +# define BOOST_ASIO_HAS_PTHREADS 1 +# endif // defined(BOOST_ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS) +# endif // defined(BOOST_ASIO_HAS_THREADS) +#endif // !defined(BOOST_ASIO_HAS_PTHREADS) + +// Helper to prevent macro expansion. +#define BOOST_ASIO_PREVENT_MACRO_SUBSTITUTION + +// Helper to define in-class constants. +#if !defined(BOOST_ASIO_STATIC_CONSTANT) +# if !defined(BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT) +# define BOOST_ASIO_STATIC_CONSTANT(type, assignment) \ + BOOST_STATIC_CONSTANT(type, assignment) +# else // !defined(BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT) +# define BOOST_ASIO_STATIC_CONSTANT(type, assignment) \ + static const type assignment +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_STATIC_CONSTANT) +#endif // !defined(BOOST_ASIO_STATIC_CONSTANT) + +// Boost array library. +#if !defined(BOOST_ASIO_HAS_BOOST_ARRAY) +# if !defined(BOOST_ASIO_DISABLE_BOOST_ARRAY) +# define BOOST_ASIO_HAS_BOOST_ARRAY 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_ARRAY) +#endif // !defined(BOOST_ASIO_HAS_BOOST_ARRAY) + +// Boost assert macro. +#if !defined(BOOST_ASIO_HAS_BOOST_ASSERT) +# if !defined(BOOST_ASIO_DISABLE_BOOST_ASSERT) +# define BOOST_ASIO_HAS_BOOST_ASSERT 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_ASSERT) +#endif // !defined(BOOST_ASIO_HAS_BOOST_ASSERT) + +// Boost limits header. +#if !defined(BOOST_ASIO_HAS_BOOST_LIMITS) +# if !defined(BOOST_ASIO_DISABLE_BOOST_LIMITS) +# define BOOST_ASIO_HAS_BOOST_LIMITS 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_LIMITS) +#endif // !defined(BOOST_ASIO_HAS_BOOST_LIMITS) + +// Boost throw_exception function. +#if !defined(BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION) +# if !defined(BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION) +# define BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_THROW_EXCEPTION) +#endif // !defined(BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION) + +// Boost regex library. +#if !defined(BOOST_ASIO_HAS_BOOST_REGEX) +# if !defined(BOOST_ASIO_DISABLE_BOOST_REGEX) +# define BOOST_ASIO_HAS_BOOST_REGEX 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_REGEX) +#endif // !defined(BOOST_ASIO_HAS_BOOST_REGEX) + +// Boost bind function. +#if !defined(BOOST_ASIO_HAS_BOOST_BIND) +# if !defined(BOOST_ASIO_DISABLE_BOOST_BIND) +# define BOOST_ASIO_HAS_BOOST_BIND 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_BIND) +#endif // !defined(BOOST_ASIO_HAS_BOOST_BIND) + +// Boost's BOOST_WORKAROUND macro. +#if !defined(BOOST_ASIO_HAS_BOOST_WORKAROUND) +# if !defined(BOOST_ASIO_DISABLE_BOOST_WORKAROUND) +# define BOOST_ASIO_HAS_BOOST_WORKAROUND 1 +# endif // !defined(BOOST_ASIO_DISABLE_BOOST_WORKAROUND) +#endif // !defined(BOOST_ASIO_HAS_BOOST_WORKAROUND) + +// Microsoft Visual C++'s secure C runtime library. +#if !defined(BOOST_ASIO_HAS_SECURE_RTL) +# if !defined(BOOST_ASIO_DISABLE_SECURE_RTL) +# if defined(BOOST_ASIO_MSVC) \ + && (BOOST_ASIO_MSVC >= 1400) \ + && !defined(UNDER_CE) +# define BOOST_ASIO_HAS_SECURE_RTL 1 +# endif // defined(BOOST_ASIO_MSVC) + // && (BOOST_ASIO_MSVC >= 1400) + // && !defined(UNDER_CE) +# endif // !defined(BOOST_ASIO_DISABLE_SECURE_RTL) +#endif // !defined(BOOST_ASIO_HAS_SECURE_RTL) + +// Handler hooking. Disabled for ancient Borland C++ and gcc compilers. +#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) +# if !defined(BOOST_ASIO_DISABLE_HANDLER_HOOKS) +# if defined(__GNUC__) +# if (__GNUC__ >= 3) +# define BOOST_ASIO_HAS_HANDLER_HOOKS 1 +# endif // (__GNUC__ >= 3) +# elif !defined(__BORLANDC__) +# define BOOST_ASIO_HAS_HANDLER_HOOKS 1 +# endif // !defined(__BORLANDC__) +# endif // !defined(BOOST_ASIO_DISABLE_HANDLER_HOOKS) +#endif // !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) + +// Support for the __thread keyword extension. +#if !defined(BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION) +# if defined(__linux__) +# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) +# if !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !(defined(__clang__) && defined(__ANDROID__)) +# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define BOOST_ASIO_THREAD_KEYWORD __thread +# elif defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) +# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) + // && !(defined(__clang__) && defined(__ANDROID__)) +# endif // ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3) +# endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# endif // defined(__linux__) +# if defined(BOOST_ASIO_MSVC) && defined(BOOST_ASIO_WINDOWS_RUNTIME) +# if (_MSC_VER >= 1700) +# define BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION 1 +# define BOOST_ASIO_THREAD_KEYWORD __declspec(thread) +# endif // (_MSC_VER >= 1700) +# endif // defined(BOOST_ASIO_MSVC) && defined(BOOST_ASIO_WINDOWS_RUNTIME) +#endif // !defined(BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION) +#if !defined(BOOST_ASIO_THREAD_KEYWORD) +# define BOOST_ASIO_THREAD_KEYWORD __thread +#endif // !defined(BOOST_ASIO_THREAD_KEYWORD) + +// Support for POSIX ssize_t typedef. +#if !defined(BOOST_ASIO_DISABLE_SSIZE_T) +# if defined(__linux__) \ + || (defined(__MACH__) && defined(__APPLE__)) +# define BOOST_ASIO_HAS_SSIZE_T 1 +# endif // defined(__linux__) + // || (defined(__MACH__) && defined(__APPLE__)) +#endif // !defined(BOOST_ASIO_DISABLE_SSIZE_T) + +// Helper macros to manage transition away from error_code return values. +#if defined(BOOST_ASIO_NO_DEPRECATED) +# define BOOST_ASIO_SYNC_OP_VOID void +# define BOOST_ASIO_SYNC_OP_VOID_RETURN(e) return +#else // defined(BOOST_ASIO_NO_DEPRECATED) +# define BOOST_ASIO_SYNC_OP_VOID boost::system::error_code +# define BOOST_ASIO_SYNC_OP_VOID_RETURN(e) return e +#endif // defined(BOOST_ASIO_NO_DEPRECATED) + +// Newer gcc, clang need special treatment to suppress unused typedef warnings. +#if defined(__clang__) +# if defined(__apple_build_version__) +# if (__clang_major__ >= 7) +# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // (__clang_major__ >= 7) +# elif ((__clang_major__ == 3) && (__clang_minor__ >= 6)) \ + || (__clang_major__ > 3) +# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // ((__clang_major__ == 3) && (__clang_minor__ >= 6)) + // || (__clang_major__ > 3) +#elif defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +# define BOOST_ASIO_UNUSED_TYPEDEF __attribute__((__unused__)) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) +#endif // defined(__GNUC__) +#if !defined(BOOST_ASIO_UNUSED_TYPEDEF) +# define BOOST_ASIO_UNUSED_TYPEDEF +#endif // !defined(BOOST_ASIO_UNUSED_TYPEDEF) + +// Some versions of gcc generate spurious warnings about unused variables. +#if defined(__GNUC__) +# if (__GNUC__ >= 4) +# define BOOST_ASIO_UNUSED_VARIABLE __attribute__((__unused__)) +# endif // (__GNUC__ >= 4) +#endif // defined(__GNUC__) +#if !defined(BOOST_ASIO_UNUSED_VARIABLE) +# define BOOST_ASIO_UNUSED_VARIABLE +#endif // !defined(BOOST_ASIO_UNUSED_VARIABLE) + +// Support co_await on compilers known to allow it. +#if !defined(BOOST_ASIO_HAS_CO_AWAIT) +# if !defined(BOOST_ASIO_DISABLE_CO_AWAIT) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_FULL_VER >= 190023506) +# if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // defined(_RESUMABLE_FUNCTIONS_SUPPORTED) +# endif // (_MSC_FULL_VER >= 190023506) +# endif // defined(BOOST_ASIO_MSVC) +# endif // !defined(BOOST_ASIO_DISABLE_CO_AWAIT) +# if defined(__clang__) +# if (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# if __has_include() +# define BOOST_ASIO_HAS_CO_AWAIT 1 +# endif // __has_include() +# endif // (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) +# endif // defined(__clang__) +#endif // !defined(BOOST_ASIO_HAS_CO_AWAIT) + +#endif // BOOST_ASIO_DETAIL_CONFIG_HPP diff --git a/boost/asio/detail/consuming_buffers.hpp b/boost/asio/detail/consuming_buffers.hpp new file mode 100644 index 0000000..f8226a4 --- /dev/null +++ b/boost/asio/detail/consuming_buffers.hpp @@ -0,0 +1,416 @@ +// +// detail/consuming_buffers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP +#define BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Helper template to determine the maximum number of prepared buffers. +template +struct prepared_buffers_max +{ + enum { value = buffer_sequence_adapter_base::max_buffers }; +}; + +template +struct prepared_buffers_max > +{ + enum { value = N }; +}; + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) + +template +struct prepared_buffers_max > +{ + enum { value = N }; +}; + +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) + +// A buffer sequence used to represent a subsequence of the buffers. +template +struct prepared_buffers +{ + typedef Buffer value_type; + typedef const Buffer* const_iterator; + + enum { max_buffers = MaxBuffers < 16 ? MaxBuffers : 16 }; + + prepared_buffers() : count(0) {} + const_iterator begin() const { return elems; } + const_iterator end() const { return elems + count; } + + Buffer elems[max_buffers]; + std::size_t count; +}; + +// A proxy for a sub-range in a list of buffers. +template +class consuming_buffers +{ +public: + typedef prepared_buffers::value> + prepared_buffers_type; + + // Construct to represent the entire list of buffers. + explicit consuming_buffers(const Buffers& buffers) + : buffers_(buffers), + total_consumed_(0), + next_elem_(0), + next_elem_offset_(0) + { + using boost::asio::buffer_size; + total_size_ = buffer_size(buffers); + } + + // Determine if we are at the end of the buffers. + bool empty() const + { + return total_consumed_ >= total_size_; + } + + // Get the buffer for a single transfer, with a size. + prepared_buffers_type prepare(std::size_t max_size) + { + prepared_buffers_type result; + + Buffer_Iterator next = boost::asio::buffer_sequence_begin(buffers_); + Buffer_Iterator end = boost::asio::buffer_sequence_end(buffers_); + + std::advance(next, next_elem_); + std::size_t elem_offset = next_elem_offset_; + while (next != end && max_size > 0 && (result.count) < result.max_buffers) + { + Buffer next_buf = Buffer(*next) + elem_offset; + result.elems[result.count] = boost::asio::buffer(next_buf, max_size); + max_size -= result.elems[result.count].size(); + elem_offset = 0; + if (result.elems[result.count].size() > 0) + ++result.count; + ++next; + } + + return result; + } + + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) + { + total_consumed_ += size; + + Buffer_Iterator next = boost::asio::buffer_sequence_begin(buffers_); + Buffer_Iterator end = boost::asio::buffer_sequence_end(buffers_); + + std::advance(next, next_elem_); + while (next != end && size > 0) + { + Buffer next_buf = Buffer(*next) + next_elem_offset_; + if (size < next_buf.size()) + { + next_elem_offset_ += size; + size = 0; + } + else + { + size -= next_buf.size(); + next_elem_offset_ = 0; + ++next_elem_; + ++next; + } + } + } + + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const + { + return total_consumed_; + } + +private: + Buffers buffers_; + std::size_t total_size_; + std::size_t total_consumed_; + std::size_t next_elem_; + std::size_t next_elem_offset_; +}; + +// Base class of all consuming_buffers specialisations for single buffers. +template +class consuming_single_buffer +{ +public: + // Construct to represent the entire list of buffers. + template + explicit consuming_single_buffer(const Buffer1& buffer) + : buffer_(buffer), + total_consumed_(0) + { + } + + // Determine if we are at the end of the buffers. + bool empty() const + { + return total_consumed_ >= buffer_.size(); + } + + // Get the buffer for a single transfer, with a size. + Buffer prepare(std::size_t max_size) + { + return boost::asio::buffer(buffer_ + total_consumed_, max_size); + } + + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) + { + total_consumed_ += size; + } + + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const + { + return total_consumed_; + } + +private: + Buffer buffer_; + std::size_t total_consumed_; +}; + +template <> +class consuming_buffers + : public consuming_single_buffer +{ +public: + explicit consuming_buffers(const mutable_buffer& buffer) + : consuming_single_buffer(buffer) + { + } +}; + +template <> +class consuming_buffers + : public consuming_single_buffer +{ +public: + explicit consuming_buffers(const mutable_buffer& buffer) + : consuming_single_buffer(buffer) + { + } +}; + +template <> +class consuming_buffers + : public consuming_single_buffer +{ +public: + explicit consuming_buffers(const const_buffer& buffer) + : consuming_single_buffer(buffer) + { + } +}; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + +template <> +class consuming_buffers + : public consuming_single_buffer +{ +public: + explicit consuming_buffers(const mutable_buffers_1& buffer) + : consuming_single_buffer(buffer) + { + } +}; + +template <> +class consuming_buffers + : public consuming_single_buffer +{ +public: + explicit consuming_buffers(const mutable_buffers_1& buffer) + : consuming_single_buffer(buffer) + { + } +}; + +template <> +class consuming_buffers + : public consuming_single_buffer +{ +public: + explicit consuming_buffers(const const_buffers_1& buffer) + : consuming_single_buffer(buffer) + { + } +}; + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +template +class consuming_buffers, + typename boost::array::const_iterator> +{ +public: + // Construct to represent the entire list of buffers. + explicit consuming_buffers(const boost::array& buffers) + : buffers_(buffers), + total_consumed_(0) + { + } + + // Determine if we are at the end of the buffers. + bool empty() const + { + return total_consumed_ >= + Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size(); + } + + // Get the buffer for a single transfer, with a size. + boost::array prepare(std::size_t max_size) + { + boost::array result = {{ + Buffer(buffers_[0]), Buffer(buffers_[1]) }}; + std::size_t buffer0_size = result[0].size(); + result[0] = boost::asio::buffer(result[0] + total_consumed_, max_size); + result[1] = boost::asio::buffer( + result[1] + (total_consumed_ < buffer0_size + ? 0 : total_consumed_ - buffer0_size), + max_size - result[0].size()); + return result; + } + + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) + { + total_consumed_ += size; + } + + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const + { + return total_consumed_; + } + +private: + boost::array buffers_; + std::size_t total_consumed_; +}; + +#if defined(BOOST_ASIO_HAS_STD_ARRAY) + +template +class consuming_buffers, + typename std::array::const_iterator> +{ +public: + // Construct to represent the entire list of buffers. + explicit consuming_buffers(const std::array& buffers) + : buffers_(buffers), + total_consumed_(0) + { + } + + // Determine if we are at the end of the buffers. + bool empty() const + { + return total_consumed_ >= + Buffer(buffers_[0]).size() + Buffer(buffers_[1]).size(); + } + + // Get the buffer for a single transfer, with a size. + std::array prepare(std::size_t max_size) + { + std::array result = {{ + Buffer(buffers_[0]), Buffer(buffers_[1]) }}; + std::size_t buffer0_size = result[0].size(); + result[0] = boost::asio::buffer(result[0] + total_consumed_, max_size); + result[1] = boost::asio::buffer( + result[1] + (total_consumed_ < buffer0_size + ? 0 : total_consumed_ - buffer0_size), + max_size - result[0].size()); + return result; + } + + // Consume the specified number of bytes from the buffers. + void consume(std::size_t size) + { + total_consumed_ += size; + } + + // Get the total number of bytes consumed from the buffers. + std::size_t total_consumed() const + { + return total_consumed_; + } + +private: + std::array buffers_; + std::size_t total_consumed_; +}; + +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) + +// Specialisation for null_buffers to ensure that the null_buffers type is +// always passed through to the underlying read or write operation. +template +class consuming_buffers + : public boost::asio::null_buffers +{ +public: + consuming_buffers(const null_buffers&) + { + // No-op. + } + + bool empty() + { + return false; + } + + null_buffers prepare(std::size_t) + { + return null_buffers(); + } + + void consume(std::size_t) + { + // No-op. + } + + std::size_t total_consumed() const + { + return 0; + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP diff --git a/boost/asio/detail/cstddef.hpp b/boost/asio/detail/cstddef.hpp new file mode 100644 index 0000000..b77d9aa --- /dev/null +++ b/boost/asio/detail/cstddef.hpp @@ -0,0 +1,33 @@ +// +// detail/cstddef.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_CSTDDEF_HPP +#define BOOST_ASIO_DETAIL_CSTDDEF_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +namespace boost { +namespace asio { + +#if defined(BOOST_ASIO_HAS_NULLPTR) +using std::nullptr_t; +#else // defined(BOOST_ASIO_HAS_NULLPTR) +struct nullptr_t {}; +#endif // defined(BOOST_ASIO_HAS_NULLPTR) + +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_CSTDDEF_HPP diff --git a/boost/asio/detail/cstdint.hpp b/boost/asio/detail/cstdint.hpp new file mode 100644 index 0000000..b916f78 --- /dev/null +++ b/boost/asio/detail/cstdint.hpp @@ -0,0 +1,62 @@ +// +// detail/cstdint.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_CSTDINT_HPP +#define BOOST_ASIO_DETAIL_CSTDINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_CSTDINT) +# include +#else // defined(BOOST_ASIO_HAS_CSTDINT) +# include +#endif // defined(BOOST_ASIO_HAS_CSTDINT) + +namespace boost { +namespace asio { + +#if defined(BOOST_ASIO_HAS_CSTDINT) +using std::int16_t; +using std::int_least16_t; +using std::uint16_t; +using std::uint_least16_t; +using std::int32_t; +using std::int_least32_t; +using std::uint32_t; +using std::uint_least32_t; +using std::int64_t; +using std::int_least64_t; +using std::uint64_t; +using std::uint_least64_t; +using std::uintmax_t; +#else // defined(BOOST_ASIO_HAS_CSTDINT) +using boost::int16_t; +using boost::int_least16_t; +using boost::uint16_t; +using boost::uint_least16_t; +using boost::int32_t; +using boost::int_least32_t; +using boost::uint32_t; +using boost::uint_least32_t; +using boost::int64_t; +using boost::int_least64_t; +using boost::uint64_t; +using boost::uint_least64_t; +using boost::uintmax_t; +#endif // defined(BOOST_ASIO_HAS_CSTDINT) + +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_CSTDINT_HPP diff --git a/boost/asio/detail/date_time_fwd.hpp b/boost/asio/detail/date_time_fwd.hpp new file mode 100644 index 0000000..c917be4 --- /dev/null +++ b/boost/asio/detail/date_time_fwd.hpp @@ -0,0 +1,34 @@ +// +// detail/date_time_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_DATE_TIME_FWD_HPP +#define BOOST_ASIO_DETAIL_DATE_TIME_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +namespace boost { +namespace date_time { + +template +class base_time; + +} // namespace date_time +namespace posix_time { + +class ptime; + +} // namespace posix_time +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_DATE_TIME_FWD_HPP diff --git a/boost/asio/detail/deadline_timer_service.hpp b/boost/asio/detail/deadline_timer_service.hpp new file mode 100644 index 0000000..8732990 --- /dev/null +++ b/boost/asio/detail/deadline_timer_service.hpp @@ -0,0 +1,282 @@ +// +// detail/deadline_timer_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP +#define BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +# include +# include +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class deadline_timer_service + : public execution_context_service_base > +{ +public: + // The time type. + typedef typename Time_Traits::time_type time_type; + + // The duration type. + typedef typename Time_Traits::duration_type duration_type; + + // The implementation type of the timer. This type is dependent on the + // underlying implementation of the timer service. + struct implementation_type + : private boost::asio::detail::noncopyable + { + time_type expiry; + bool might_have_pending_waits; + typename timer_queue::per_timer_data timer_data; + }; + + // Constructor. + deadline_timer_service(execution_context& context) + : execution_context_service_base< + deadline_timer_service >(context), + scheduler_(boost::asio::use_service(context)) + { + scheduler_.init_task(); + scheduler_.add_timer_queue(timer_queue_); + } + + // Destructor. + ~deadline_timer_service() + { + scheduler_.remove_timer_queue(timer_queue_); + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + } + + // Construct a new timer implementation. + void construct(implementation_type& impl) + { + impl.expiry = time_type(); + impl.might_have_pending_waits = false; + } + + // Destroy a timer implementation. + void destroy(implementation_type& impl) + { + boost::system::error_code ec; + cancel(impl, ec); + } + + // Move-construct a new serial port implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + scheduler_.move_timer(timer_queue_, impl.timer_data, other_impl.timer_data); + + impl.expiry = other_impl.expiry; + other_impl.expiry = time_type(); + + impl.might_have_pending_waits = other_impl.might_have_pending_waits; + other_impl.might_have_pending_waits = false; + } + + // Move-assign from another serial port implementation. + void move_assign(implementation_type& impl, + deadline_timer_service& other_service, + implementation_type& other_impl) + { + if (this != &other_service) + if (impl.might_have_pending_waits) + scheduler_.cancel_timer(timer_queue_, impl.timer_data); + + other_service.scheduler_.move_timer(other_service.timer_queue_, + impl.timer_data, other_impl.timer_data); + + impl.expiry = other_impl.expiry; + other_impl.expiry = time_type(); + + impl.might_have_pending_waits = other_impl.might_have_pending_waits; + other_impl.might_have_pending_waits = false; + } + + // Cancel any asynchronous wait operations associated with the timer. + std::size_t cancel(implementation_type& impl, boost::system::error_code& ec) + { + if (!impl.might_have_pending_waits) + { + ec = boost::system::error_code(); + return 0; + } + + BOOST_ASIO_HANDLER_OPERATION((scheduler_.context(), + "deadline_timer", &impl, 0, "cancel")); + + std::size_t count = scheduler_.cancel_timer(timer_queue_, impl.timer_data); + impl.might_have_pending_waits = false; + ec = boost::system::error_code(); + return count; + } + + // Cancels one asynchronous wait operation associated with the timer. + std::size_t cancel_one(implementation_type& impl, + boost::system::error_code& ec) + { + if (!impl.might_have_pending_waits) + { + ec = boost::system::error_code(); + return 0; + } + + BOOST_ASIO_HANDLER_OPERATION((scheduler_.context(), + "deadline_timer", &impl, 0, "cancel_one")); + + std::size_t count = scheduler_.cancel_timer( + timer_queue_, impl.timer_data, 1); + if (count == 0) + impl.might_have_pending_waits = false; + ec = boost::system::error_code(); + return count; + } + + // Get the expiry time for the timer as an absolute time. + time_type expiry(const implementation_type& impl) const + { + return impl.expiry; + } + + // Get the expiry time for the timer as an absolute time. + time_type expires_at(const implementation_type& impl) const + { + return impl.expiry; + } + + // Get the expiry time for the timer relative to now. + duration_type expires_from_now(const implementation_type& impl) const + { + return Time_Traits::subtract(this->expiry(impl), Time_Traits::now()); + } + + // Set the expiry time for the timer as an absolute time. + std::size_t expires_at(implementation_type& impl, + const time_type& expiry_time, boost::system::error_code& ec) + { + std::size_t count = cancel(impl, ec); + impl.expiry = expiry_time; + ec = boost::system::error_code(); + return count; + } + + // Set the expiry time for the timer relative to now. + std::size_t expires_after(implementation_type& impl, + const duration_type& expiry_time, boost::system::error_code& ec) + { + return expires_at(impl, + Time_Traits::add(Time_Traits::now(), expiry_time), ec); + } + + // Set the expiry time for the timer relative to now. + std::size_t expires_from_now(implementation_type& impl, + const duration_type& expiry_time, boost::system::error_code& ec) + { + return expires_at(impl, + Time_Traits::add(Time_Traits::now(), expiry_time), ec); + } + + // Perform a blocking wait on the timer. + void wait(implementation_type& impl, boost::system::error_code& ec) + { + time_type now = Time_Traits::now(); + ec = boost::system::error_code(); + while (Time_Traits::less_than(now, impl.expiry) && !ec) + { + this->do_wait(Time_Traits::to_posix_duration( + Time_Traits::subtract(impl.expiry, now)), ec); + now = Time_Traits::now(); + } + } + + // Start an asynchronous wait on the timer. + template + void async_wait(implementation_type& impl, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef wait_handler op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_ex); + + impl.might_have_pending_waits = true; + + BOOST_ASIO_HANDLER_CREATION((scheduler_.context(), + *p.p, "deadline_timer", &impl, 0, "async_wait")); + + scheduler_.schedule_timer(timer_queue_, impl.expiry, impl.timer_data, p.p); + p.v = p.p = 0; + } + +private: + // Helper function to wait given a duration type. The duration type should + // either be of type boost::posix_time::time_duration, or implement the + // required subset of its interface. + template + void do_wait(const Duration& timeout, boost::system::error_code& ec) + { +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + std::this_thread::sleep_for( + std::chrono::seconds(timeout.total_seconds()) + + std::chrono::microseconds(timeout.total_microseconds())); + ec = boost::system::error_code(); +#else // defined(BOOST_ASIO_WINDOWS_RUNTIME) + ::timeval tv; + tv.tv_sec = timeout.total_seconds(); + tv.tv_usec = timeout.total_microseconds() % 1000000; + socket_ops::select(0, 0, 0, 0, &tv, ec); +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + } + + // The queue of timers. + timer_queue timer_queue_; + + // The object that schedules and executes timers. Usually a reactor. + timer_scheduler& scheduler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP diff --git a/boost/asio/detail/dependent_type.hpp b/boost/asio/detail/dependent_type.hpp new file mode 100644 index 0000000..53aef3f --- /dev/null +++ b/boost/asio/detail/dependent_type.hpp @@ -0,0 +1,38 @@ +// +// detail/dependent_type.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_DEPENDENT_TYPE_HPP +#define BOOST_ASIO_DETAIL_DEPENDENT_TYPE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +struct dependent_type +{ + typedef T type; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_DEPENDENT_TYPE_HPP diff --git a/boost/asio/detail/descriptor_ops.hpp b/boost/asio/detail/descriptor_ops.hpp new file mode 100644 index 0000000..bfb0824 --- /dev/null +++ b/boost/asio/detail/descriptor_ops.hpp @@ -0,0 +1,123 @@ +// +// detail/descriptor_ops.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_DESCRIPTOR_OPS_HPP +#define BOOST_ASIO_DETAIL_DESCRIPTOR_OPS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { +namespace descriptor_ops { + +// Descriptor state bits. +enum +{ + // The user wants a non-blocking descriptor. + user_set_non_blocking = 1, + + // The descriptor has been set non-blocking. + internal_non_blocking = 2, + + // Helper "state" used to determine whether the descriptor is non-blocking. + non_blocking = user_set_non_blocking | internal_non_blocking, + + // The descriptor may have been dup()-ed. + possible_dup = 4 +}; + +typedef unsigned char state_type; + +template +inline ReturnType error_wrapper(ReturnType return_value, + boost::system::error_code& ec) +{ + ec = boost::system::error_code(errno, + boost::asio::error::get_system_category()); + return return_value; +} + +BOOST_ASIO_DECL int open(const char* path, int flags, + boost::system::error_code& ec); + +BOOST_ASIO_DECL int close(int d, state_type& state, + boost::system::error_code& ec); + +BOOST_ASIO_DECL bool set_user_non_blocking(int d, + state_type& state, bool value, boost::system::error_code& ec); + +BOOST_ASIO_DECL bool set_internal_non_blocking(int d, + state_type& state, bool value, boost::system::error_code& ec); + +typedef iovec buf; + +BOOST_ASIO_DECL std::size_t sync_read(int d, state_type state, buf* bufs, + std::size_t count, bool all_empty, boost::system::error_code& ec); + +BOOST_ASIO_DECL bool non_blocking_read(int d, buf* bufs, std::size_t count, + boost::system::error_code& ec, std::size_t& bytes_transferred); + +BOOST_ASIO_DECL std::size_t sync_write(int d, state_type state, + const buf* bufs, std::size_t count, bool all_empty, + boost::system::error_code& ec); + +BOOST_ASIO_DECL bool non_blocking_write(int d, + const buf* bufs, std::size_t count, + boost::system::error_code& ec, std::size_t& bytes_transferred); + +BOOST_ASIO_DECL int ioctl(int d, state_type& state, long cmd, + ioctl_arg_type* arg, boost::system::error_code& ec); + +BOOST_ASIO_DECL int fcntl(int d, int cmd, boost::system::error_code& ec); + +BOOST_ASIO_DECL int fcntl(int d, int cmd, + long arg, boost::system::error_code& ec); + +BOOST_ASIO_DECL int poll_read(int d, + state_type state, boost::system::error_code& ec); + +BOOST_ASIO_DECL int poll_write(int d, + state_type state, boost::system::error_code& ec); + +BOOST_ASIO_DECL int poll_error(int d, + state_type state, boost::system::error_code& ec); + +} // namespace descriptor_ops +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_DESCRIPTOR_OPS_HPP diff --git a/boost/asio/detail/descriptor_read_op.hpp b/boost/asio/detail/descriptor_read_op.hpp new file mode 100644 index 0000000..3ced62b --- /dev/null +++ b/boost/asio/detail/descriptor_read_op.hpp @@ -0,0 +1,132 @@ +// +// detail/descriptor_read_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP +#define BOOST_ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class descriptor_read_op_base : public reactor_op +{ +public: + descriptor_read_op_base(int descriptor, + const MutableBufferSequence& buffers, func_type complete_func) + : reactor_op(&descriptor_read_op_base::do_perform, complete_func), + descriptor_(descriptor), + buffers_(buffers) + { + } + + static status do_perform(reactor_op* base) + { + descriptor_read_op_base* o(static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + status result = descriptor_ops::non_blocking_read(o->descriptor_, + bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_) + ? done : not_done; + + BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_read", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + int descriptor_; + MutableBufferSequence buffers_; +}; + +template +class descriptor_read_op + : public descriptor_read_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(descriptor_read_op); + + descriptor_read_op(int descriptor, const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + : descriptor_read_op_base( + descriptor, buffers, &descriptor_read_op::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + descriptor_read_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP diff --git a/boost/asio/detail/descriptor_write_op.hpp b/boost/asio/detail/descriptor_write_op.hpp new file mode 100644 index 0000000..d1eea52 --- /dev/null +++ b/boost/asio/detail/descriptor_write_op.hpp @@ -0,0 +1,132 @@ +// +// detail/descriptor_write_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP +#define BOOST_ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class descriptor_write_op_base : public reactor_op +{ +public: + descriptor_write_op_base(int descriptor, + const ConstBufferSequence& buffers, func_type complete_func) + : reactor_op(&descriptor_write_op_base::do_perform, complete_func), + descriptor_(descriptor), + buffers_(buffers) + { + } + + static status do_perform(reactor_op* base) + { + descriptor_write_op_base* o(static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + status result = descriptor_ops::non_blocking_write(o->descriptor_, + bufs.buffers(), bufs.count(), o->ec_, o->bytes_transferred_) + ? done : not_done; + + BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_write", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + int descriptor_; + ConstBufferSequence buffers_; +}; + +template +class descriptor_write_op + : public descriptor_write_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(descriptor_write_op); + + descriptor_write_op(int descriptor, const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + : descriptor_write_op_base( + descriptor, buffers, &descriptor_write_op::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + descriptor_write_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP diff --git a/boost/asio/detail/dev_poll_reactor.hpp b/boost/asio/detail/dev_poll_reactor.hpp new file mode 100644 index 0000000..63a0c30 --- /dev/null +++ b/boost/asio/detail/dev_poll_reactor.hpp @@ -0,0 +1,220 @@ +// +// detail/dev_poll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_DEV_POLL_REACTOR_HPP +#define BOOST_ASIO_DETAIL_DEV_POLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_DEV_POLL) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class dev_poll_reactor + : public execution_context_service_base +{ +public: + enum op_types { read_op = 0, write_op = 1, + connect_op = 1, except_op = 2, max_ops = 3 }; + + // Per-descriptor data. + struct per_descriptor_data + { + }; + + // Constructor. + BOOST_ASIO_DECL dev_poll_reactor(boost::asio::execution_context& ctx); + + // Destructor. + BOOST_ASIO_DECL ~dev_poll_reactor(); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown(); + + // Recreate internal descriptors following a fork. + BOOST_ASIO_DECL void notify_fork( + boost::asio::execution_context::fork_event fork_ev); + + // Initialise the task. + BOOST_ASIO_DECL void init_task(); + + // Register a socket with the reactor. Returns 0 on success, system error + // code on failure. + BOOST_ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&); + + // Register a descriptor with an associated single operation. Returns 0 on + // success, system error code on failure. + BOOST_ASIO_DECL int register_internal_descriptor( + int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op); + + // Move descriptor registration from one descriptor_data object to another. + BOOST_ASIO_DECL void move_descriptor(socket_type descriptor, + per_descriptor_data& target_descriptor_data, + per_descriptor_data& source_descriptor_data); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op, bool is_continuation) + { + scheduler_.post_immediate_completion(op, is_continuation); + } + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor, + per_descriptor_data&, reactor_op* op, + bool is_continuation, bool allow_speculative); + + // Cancel all operations associated with the given descriptor. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + BOOST_ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&); + + // Cancel any operations that are running against the descriptor and remove + // its registration from the reactor. The reactor resources associated with + // the descriptor must be released by calling cleanup_descriptor_data. + BOOST_ASIO_DECL void deregister_descriptor(socket_type descriptor, + per_descriptor_data&, bool closing); + + // Remove the descriptor's registration from the reactor. The reactor + // resources associated with the descriptor must be released by calling + // cleanup_descriptor_data. + BOOST_ASIO_DECL void deregister_internal_descriptor( + socket_type descriptor, per_descriptor_data&); + + // Perform any post-deregistration cleanup tasks associated with the + // descriptor data. + BOOST_ASIO_DECL void cleanup_descriptor_data(per_descriptor_data&); + + // Add a new timer queue to the reactor. + template + void add_timer_queue(timer_queue& queue); + + // Remove a timer queue from the reactor. + template + void remove_timer_queue(timer_queue& queue); + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template + void schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op); + + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. + template + std::size_t cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled = (std::numeric_limits::max)()); + + // Move the timer operations associated with the given timer. + template + void move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& target, + typename timer_queue::per_timer_data& source); + + // Run /dev/poll once until interrupted or events are ready to be dispatched. + BOOST_ASIO_DECL void run(long usec, op_queue& ops); + + // Interrupt the select loop. + BOOST_ASIO_DECL void interrupt(); + +private: + // Create the /dev/poll file descriptor. Throws an exception if the descriptor + // cannot be created. + BOOST_ASIO_DECL static int do_dev_poll_create(); + + // Helper function to add a new timer queue. + BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // Get the timeout value for the /dev/poll DP_POLL operation. The timeout + // value is returned as a number of milliseconds. A return value of -1 + // indicates that the poll should block indefinitely. + BOOST_ASIO_DECL int get_timeout(int msec); + + // Cancel all operations associated with the given descriptor. The do_cancel + // function of the handler objects will be invoked. This function does not + // acquire the dev_poll_reactor's mutex. + BOOST_ASIO_DECL void cancel_ops_unlocked(socket_type descriptor, + const boost::system::error_code& ec); + + // Add a pending event entry for the given descriptor. + BOOST_ASIO_DECL ::pollfd& add_pending_event_change(int descriptor); + + // The scheduler implementation used to post completions. + scheduler& scheduler_; + + // Mutex to protect access to internal data. + boost::asio::detail::mutex mutex_; + + // The /dev/poll file descriptor. + int dev_poll_fd_; + + // Vector of /dev/poll events waiting to be written to the descriptor. + std::vector< ::pollfd> pending_event_changes_; + + // Hash map to associate a descriptor with a pending event change index. + hash_map pending_event_change_index_; + + // The interrupter is used to break a blocking DP_POLL operation. + select_interrupter interrupter_; + + // The queues of read, write and except operations. + reactor_op_queue op_queue_[max_ops]; + + // The timer queues. + timer_queue_set timer_queues_; + + // Whether the service has been shut down. + bool shutdown_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_DEV_POLL) + +#endif // BOOST_ASIO_DETAIL_DEV_POLL_REACTOR_HPP diff --git a/boost/asio/detail/epoll_reactor.hpp b/boost/asio/detail/epoll_reactor.hpp new file mode 100644 index 0000000..c361978 --- /dev/null +++ b/boost/asio/detail/epoll_reactor.hpp @@ -0,0 +1,268 @@ +// +// detail/epoll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_EPOLL_REACTOR_HPP +#define BOOST_ASIO_DETAIL_EPOLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_EPOLL) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_TIMERFD) +# include +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + +#include + +namespace boost { +namespace asio { +namespace detail { + +class epoll_reactor + : public execution_context_service_base +{ +private: + // The mutex type used by this reactor. + typedef conditionally_enabled_mutex mutex; + +public: + enum op_types { read_op = 0, write_op = 1, + connect_op = 1, except_op = 2, max_ops = 3 }; + + // Per-descriptor queues. + class descriptor_state : operation + { + friend class epoll_reactor; + friend class object_pool_access; + + descriptor_state* next_; + descriptor_state* prev_; + + mutex mutex_; + epoll_reactor* reactor_; + int descriptor_; + uint32_t registered_events_; + op_queue op_queue_[max_ops]; + bool try_speculative_[max_ops]; + bool shutdown_; + + BOOST_ASIO_DECL descriptor_state(bool locking); + void set_ready_events(uint32_t events) { task_result_ = events; } + void add_ready_events(uint32_t events) { task_result_ |= events; } + BOOST_ASIO_DECL operation* perform_io(uint32_t events); + BOOST_ASIO_DECL static void do_complete( + void* owner, operation* base, + const boost::system::error_code& ec, std::size_t bytes_transferred); + }; + + // Per-descriptor data. + typedef descriptor_state* per_descriptor_data; + + // Constructor. + BOOST_ASIO_DECL epoll_reactor(boost::asio::execution_context& ctx); + + // Destructor. + BOOST_ASIO_DECL ~epoll_reactor(); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown(); + + // Recreate internal descriptors following a fork. + BOOST_ASIO_DECL void notify_fork( + boost::asio::execution_context::fork_event fork_ev); + + // Initialise the task. + BOOST_ASIO_DECL void init_task(); + + // Register a socket with the reactor. Returns 0 on success, system error + // code on failure. + BOOST_ASIO_DECL int register_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data); + + // Register a descriptor with an associated single operation. Returns 0 on + // success, system error code on failure. + BOOST_ASIO_DECL int register_internal_descriptor( + int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op); + + // Move descriptor registration from one descriptor_data object to another. + BOOST_ASIO_DECL void move_descriptor(socket_type descriptor, + per_descriptor_data& target_descriptor_data, + per_descriptor_data& source_descriptor_data); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op, bool is_continuation) + { + scheduler_.post_immediate_completion(op, is_continuation); + } + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative); + + // Cancel all operations associated with the given descriptor. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + BOOST_ASIO_DECL void cancel_ops(socket_type descriptor, + per_descriptor_data& descriptor_data); + + // Cancel any operations that are running against the descriptor and remove + // its registration from the reactor. The reactor resources associated with + // the descriptor must be released by calling cleanup_descriptor_data. + BOOST_ASIO_DECL void deregister_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data, bool closing); + + // Remove the descriptor's registration from the reactor. The reactor + // resources associated with the descriptor must be released by calling + // cleanup_descriptor_data. + BOOST_ASIO_DECL void deregister_internal_descriptor( + socket_type descriptor, per_descriptor_data& descriptor_data); + + // Perform any post-deregistration cleanup tasks associated with the + // descriptor data. + BOOST_ASIO_DECL void cleanup_descriptor_data( + per_descriptor_data& descriptor_data); + + // Add a new timer queue to the reactor. + template + void add_timer_queue(timer_queue& timer_queue); + + // Remove a timer queue from the reactor. + template + void remove_timer_queue(timer_queue& timer_queue); + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template + void schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op); + + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. + template + std::size_t cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled = (std::numeric_limits::max)()); + + // Move the timer operations associated with the given timer. + template + void move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& target, + typename timer_queue::per_timer_data& source); + + // Run epoll once until interrupted or events are ready to be dispatched. + BOOST_ASIO_DECL void run(long usec, op_queue& ops); + + // Interrupt the select loop. + BOOST_ASIO_DECL void interrupt(); + +private: + // The hint to pass to epoll_create to size its data structures. + enum { epoll_size = 20000 }; + + // Create the epoll file descriptor. Throws an exception if the descriptor + // cannot be created. + BOOST_ASIO_DECL static int do_epoll_create(); + + // Create the timerfd file descriptor. Does not throw. + BOOST_ASIO_DECL static int do_timerfd_create(); + + // Allocate a new descriptor state object. + BOOST_ASIO_DECL descriptor_state* allocate_descriptor_state(); + + // Free an existing descriptor state object. + BOOST_ASIO_DECL void free_descriptor_state(descriptor_state* s); + + // Helper function to add a new timer queue. + BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // Called to recalculate and update the timeout. + BOOST_ASIO_DECL void update_timeout(); + + // Get the timeout value for the epoll_wait call. The timeout value is + // returned as a number of milliseconds. A return value of -1 indicates + // that epoll_wait should block indefinitely. + BOOST_ASIO_DECL int get_timeout(int msec); + +#if defined(BOOST_ASIO_HAS_TIMERFD) + // Get the timeout value for the timer descriptor. The return value is the + // flag argument to be used when calling timerfd_settime. + BOOST_ASIO_DECL int get_timeout(itimerspec& ts); +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + + // The scheduler implementation used to post completions. + scheduler& scheduler_; + + // Mutex to protect access to internal data. + mutex mutex_; + + // The interrupter is used to break a blocking epoll_wait call. + select_interrupter interrupter_; + + // The epoll file descriptor. + int epoll_fd_; + + // The timer file descriptor. + int timer_fd_; + + // The timer queues. + timer_queue_set timer_queues_; + + // Whether the service has been shut down. + bool shutdown_; + + // Mutex to protect access to the registered descriptors. + mutex registered_descriptors_mutex_; + + // Keep track of all registered descriptors. + object_pool registered_descriptors_; + + // Helper class to do post-perform_io cleanup. + struct perform_io_cleanup_on_block_exit; + friend struct perform_io_cleanup_on_block_exit; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_EPOLL) + +#endif // BOOST_ASIO_DETAIL_EPOLL_REACTOR_HPP diff --git a/boost/asio/detail/event.hpp b/boost/asio/detail/event.hpp new file mode 100644 index 0000000..b55a204 --- /dev/null +++ b/boost/asio/detail/event.hpp @@ -0,0 +1,50 @@ +// +// detail/event.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_EVENT_HPP +#define BOOST_ASIO_DETAIL_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_THREADS) +# include +#elif defined(BOOST_ASIO_WINDOWS) +# include +#elif defined(BOOST_ASIO_HAS_PTHREADS) +# include +#elif defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) +# include +#else +# error Only Windows, POSIX and std::condition_variable are supported! +#endif + +namespace boost { +namespace asio { +namespace detail { + +#if !defined(BOOST_ASIO_HAS_THREADS) +typedef null_event event; +#elif defined(BOOST_ASIO_WINDOWS) +typedef win_event event; +#elif defined(BOOST_ASIO_HAS_PTHREADS) +typedef posix_event event; +#elif defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) +typedef std_event event; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_EVENT_HPP diff --git a/boost/asio/detail/eventfd_select_interrupter.hpp b/boost/asio/detail/eventfd_select_interrupter.hpp new file mode 100644 index 0000000..0bcbcb9 --- /dev/null +++ b/boost/asio/detail/eventfd_select_interrupter.hpp @@ -0,0 +1,85 @@ +// +// detail/eventfd_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP +#define BOOST_ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_EVENTFD) + +#include + +namespace boost { +namespace asio { +namespace detail { + +class eventfd_select_interrupter +{ +public: + // Constructor. + BOOST_ASIO_DECL eventfd_select_interrupter(); + + // Destructor. + BOOST_ASIO_DECL ~eventfd_select_interrupter(); + + // Recreate the interrupter's descriptors. Used after a fork. + BOOST_ASIO_DECL void recreate(); + + // Interrupt the select call. + BOOST_ASIO_DECL void interrupt(); + + // Reset the select interrupt. Returns true if the call was interrupted. + BOOST_ASIO_DECL bool reset(); + + // Get the read descriptor to be passed to select. + int read_descriptor() const + { + return read_descriptor_; + } + +private: + // Open the descriptors. Throws on error. + BOOST_ASIO_DECL void open_descriptors(); + + // Close the descriptors. + BOOST_ASIO_DECL void close_descriptors(); + + // The read end of a connection used to interrupt the select call. This file + // descriptor is passed to select such that when it is time to stop, a single + // 64bit value will be written on the other end of the connection and this + // descriptor will become readable. + int read_descriptor_; + + // The write end of a connection used to interrupt the select call. A single + // 64bit non-zero value may be written to this to wake up the select which is + // waiting for the other end to become readable. This descriptor will only + // differ from the read descriptor when a pipe is used. + int write_descriptor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_EVENTFD) + +#endif // BOOST_ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP diff --git a/boost/asio/detail/executor_function.hpp b/boost/asio/detail/executor_function.hpp new file mode 100644 index 0000000..2b8fb40 --- /dev/null +++ b/boost/asio/detail/executor_function.hpp @@ -0,0 +1,106 @@ +// +// detail/executor_function.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_EXECUTOR_FUNCTION_HPP +#define BOOST_ASIO_DETAIL_EXECUTOR_FUNCTION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class executor_function_base +{ +public: + void complete() + { + func_(this, true); + } + + void destroy() + { + func_(this, false); + } + +protected: + typedef void (*func_type)(executor_function_base*, bool); + + executor_function_base(func_type func) + : func_(func) + { + } + + // Prevents deletion through this type. + ~executor_function_base() + { + } + +private: + func_type func_; +}; + +template +class executor_function : public executor_function_base +{ +public: + BOOST_ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR( + thread_info_base::executor_function_tag, executor_function); + + template + executor_function(BOOST_ASIO_MOVE_ARG(F) f, const Alloc& allocator) + : executor_function_base(&executor_function::do_complete), + function_(BOOST_ASIO_MOVE_CAST(F)(f)), + allocator_(allocator) + { + } + + static void do_complete(executor_function_base* base, bool call) + { + // Take ownership of the function object. + executor_function* o(static_cast(base)); + Alloc allocator(o->allocator_); + ptr p = { detail::addressof(allocator), o, o }; + + // Make a copy of the function so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the function may be the true owner of the memory + // associated with the function. Consequently, a local copy of the function + // is required to ensure that any owning sub-object remains valid until + // after we have deallocated the memory here. + Function function(BOOST_ASIO_MOVE_CAST(Function)(o->function_)); + p.reset(); + + // Make the upcall if required. + if (call) + { + function(); + } + } + +private: + Function function_; + Alloc allocator_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_EXECUTOR_FUNCTION_HPP diff --git a/boost/asio/detail/executor_op.hpp b/boost/asio/detail/executor_op.hpp new file mode 100644 index 0000000..b258120 --- /dev/null +++ b/boost/asio/detail/executor_op.hpp @@ -0,0 +1,86 @@ +// +// detail/executor_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_EXECUTOR_OP_HPP +#define BOOST_ASIO_DETAIL_EXECUTOR_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class executor_op : public Operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(executor_op); + + template + executor_op(BOOST_ASIO_MOVE_ARG(H) h, const Alloc& allocator) + : Operation(&executor_op::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(H)(h)), + allocator_(allocator) + { + } + + static void do_complete(void* owner, Operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + executor_op* o(static_cast(base)); + Alloc allocator(o->allocator_); + ptr p = { detail::addressof(allocator), o, o }; + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + Handler handler(BOOST_ASIO_MOVE_CAST(Handler)(o->handler_)); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN(()); + boost_asio_handler_invoke_helpers::invoke(handler, handler); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + Alloc allocator_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_EXECUTOR_OP_HPP diff --git a/boost/asio/detail/fd_set_adapter.hpp b/boost/asio/detail/fd_set_adapter.hpp new file mode 100644 index 0000000..d502910 --- /dev/null +++ b/boost/asio/detail/fd_set_adapter.hpp @@ -0,0 +1,41 @@ +// +// detail/fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_FD_SET_ADAPTER_HPP +#define BOOST_ASIO_DETAIL_FD_SET_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +typedef win_fd_set_adapter fd_set_adapter; +#else +typedef posix_fd_set_adapter fd_set_adapter; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#endif // BOOST_ASIO_DETAIL_FD_SET_ADAPTER_HPP diff --git a/boost/asio/detail/fenced_block.hpp b/boost/asio/detail/fenced_block.hpp new file mode 100644 index 0000000..479db6d --- /dev/null +++ b/boost/asio/detail/fenced_block.hpp @@ -0,0 +1,82 @@ +// +// detail/fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_THREADS) \ + || defined(BOOST_ASIO_DISABLE_FENCED_BLOCK) +# include +#elif defined(BOOST_ASIO_HAS_STD_ATOMIC) +# include +#elif defined(__MACH__) && defined(__APPLE__) +# include +#elif defined(__sun) +# include +#elif defined(__GNUC__) && defined(__arm__) \ + && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) +# include +#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) +# include +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +# include +#elif defined(__GNUC__) \ + && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ + && !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) +# include +#elif defined(BOOST_ASIO_WINDOWS) && !defined(UNDER_CE) +# include +#else +# include +#endif + +namespace boost { +namespace asio { +namespace detail { + +#if !defined(BOOST_ASIO_HAS_THREADS) \ + || defined(BOOST_ASIO_DISABLE_FENCED_BLOCK) +typedef null_fenced_block fenced_block; +#elif defined(BOOST_ASIO_HAS_STD_ATOMIC) +typedef std_fenced_block fenced_block; +#elif defined(__MACH__) && defined(__APPLE__) +typedef macos_fenced_block fenced_block; +#elif defined(__sun) +typedef solaris_fenced_block fenced_block; +#elif defined(__GNUC__) && defined(__arm__) \ + && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) +typedef gcc_arm_fenced_block fenced_block; +#elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) +typedef gcc_hppa_fenced_block fenced_block; +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) +typedef gcc_x86_fenced_block fenced_block; +#elif defined(__GNUC__) \ + && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ + && !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) +typedef gcc_sync_fenced_block fenced_block; +#elif defined(BOOST_ASIO_WINDOWS) && !defined(UNDER_CE) +typedef win_fenced_block fenced_block; +#else +typedef null_fenced_block fenced_block; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_FENCED_BLOCK_HPP diff --git a/boost/asio/detail/functional.hpp b/boost/asio/detail/functional.hpp new file mode 100644 index 0000000..73f06ec --- /dev/null +++ b/boost/asio/detail/functional.hpp @@ -0,0 +1,40 @@ +// +// detail/functional.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_FUNCTIONAL_HPP +#define BOOST_ASIO_DETAIL_FUNCTIONAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +#if !defined(BOOST_ASIO_HAS_STD_FUNCTION) +# include +#endif // !defined(BOOST_ASIO_HAS_STD_FUNCTION) + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_HAS_STD_FUNCTION) +using std::function; +#else // defined(BOOST_ASIO_HAS_STD_FUNCTION) +using boost::function; +#endif // defined(BOOST_ASIO_HAS_STD_FUNCTION) + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_FUNCTIONAL_HPP diff --git a/boost/asio/detail/future.hpp b/boost/asio/detail/future.hpp new file mode 100644 index 0000000..67a0c1b --- /dev/null +++ b/boost/asio/detail/future.hpp @@ -0,0 +1,33 @@ +// +// detail/future.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_FUTURE_HPP +#define BOOST_ASIO_DETAIL_FUTURE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#if defined(BOOST_ASIO_HAS_STD_FUTURE) +# include +// Even though the future header is available, libstdc++ may not implement the +// std::future class itself. However, we need to have already included the +// future header to reliably test for _GLIBCXX_HAS_GTHREADS. +# if defined(__GNUC__) && !defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# if defined(_GLIBCXX_HAS_GTHREADS) +# define BOOST_ASIO_HAS_STD_FUTURE_CLASS 1 +# endif // defined(_GLIBCXX_HAS_GTHREADS) +# else // defined(__GNUC__) && !defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +# define BOOST_ASIO_HAS_STD_FUTURE_CLASS 1 +# endif // defined(__GNUC__) && !defined(BOOST_ASIO_HAS_CLANG_LIBCXX) +#endif // defined(BOOST_ASIO_HAS_STD_FUTURE) + +#endif // BOOST_ASIO_DETAIL_FUTURE_HPP diff --git a/boost/asio/detail/gcc_arm_fenced_block.hpp b/boost/asio/detail/gcc_arm_fenced_block.hpp new file mode 100644 index 0000000..4051657 --- /dev/null +++ b/boost/asio/detail/gcc_arm_fenced_block.hpp @@ -0,0 +1,93 @@ +// +// detail/gcc_arm_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(__GNUC__) && defined(__arm__) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class gcc_arm_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit gcc_arm_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit gcc_arm_fenced_block(full_t) + { + barrier(); + } + + // Destructor. + ~gcc_arm_fenced_block() + { + barrier(); + } + +private: + static void barrier() + { +#if defined(__ARM_ARCH_4__) \ + || defined(__ARM_ARCH_4T__) \ + || defined(__ARM_ARCH_5__) \ + || defined(__ARM_ARCH_5E__) \ + || defined(__ARM_ARCH_5T__) \ + || defined(__ARM_ARCH_5TE__) \ + || defined(__ARM_ARCH_5TEJ__) \ + || defined(__ARM_ARCH_6__) \ + || defined(__ARM_ARCH_6J__) \ + || defined(__ARM_ARCH_6K__) \ + || defined(__ARM_ARCH_6Z__) \ + || defined(__ARM_ARCH_6ZK__) \ + || defined(__ARM_ARCH_6T2__) +# if defined(__thumb__) + // This is just a placeholder and almost certainly not sufficient. + __asm__ __volatile__ ("" : : : "memory"); +# else // defined(__thumb__) + int a = 0, b = 0; + __asm__ __volatile__ ("swp %0, %1, [%2]" + : "=&r"(a) : "r"(1), "r"(&b) : "memory", "cc"); +# endif // defined(__thumb__) +#else + // ARMv7 and later. + __asm__ __volatile__ ("dmb" : : : "memory"); +#endif + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(__GNUC__) && defined(__arm__) + +#endif // BOOST_ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP diff --git a/boost/asio/detail/gcc_hppa_fenced_block.hpp b/boost/asio/detail/gcc_hppa_fenced_block.hpp new file mode 100644 index 0000000..a3061c0 --- /dev/null +++ b/boost/asio/detail/gcc_hppa_fenced_block.hpp @@ -0,0 +1,70 @@ +// +// detail/gcc_hppa_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class gcc_hppa_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit gcc_hppa_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit gcc_hppa_fenced_block(full_t) + { + barrier(); + } + + // Destructor. + ~gcc_hppa_fenced_block() + { + barrier(); + } + +private: + static void barrier() + { + // This is just a placeholder and almost certainly not sufficient. + __asm__ __volatile__ ("" : : : "memory"); + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) + +#endif // BOOST_ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP diff --git a/boost/asio/detail/gcc_sync_fenced_block.hpp b/boost/asio/detail/gcc_sync_fenced_block.hpp new file mode 100644 index 0000000..a167c52 --- /dev/null +++ b/boost/asio/detail/gcc_sync_fenced_block.hpp @@ -0,0 +1,67 @@ +// +// detail/gcc_sync_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(__GNUC__) \ + && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ + && !defined(__INTEL_COMPILER) && !defined(__ICL) \ + && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class gcc_sync_fenced_block + : private noncopyable +{ +public: + enum half_or_full_t { half, full }; + + // Constructor. + explicit gcc_sync_fenced_block(half_or_full_t) + : value_(0) + { + __sync_lock_test_and_set(&value_, 1); + } + + // Destructor. + ~gcc_sync_fenced_block() + { + __sync_lock_release(&value_); + } + +private: + int value_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(__GNUC__) + // && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) + // && !defined(__INTEL_COMPILER) && !defined(__ICL) + // && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) + +#endif // BOOST_ASIO_DETAIL_GCC_SYNC_FENCED_BLOCK_HPP diff --git a/boost/asio/detail/gcc_x86_fenced_block.hpp b/boost/asio/detail/gcc_x86_fenced_block.hpp new file mode 100644 index 0000000..5d5e4ee --- /dev/null +++ b/boost/asio/detail/gcc_x86_fenced_block.hpp @@ -0,0 +1,101 @@ +// +// detail/gcc_x86_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class gcc_x86_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit gcc_x86_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit gcc_x86_fenced_block(full_t) + { + lbarrier(); + } + + // Destructor. + ~gcc_x86_fenced_block() + { + sbarrier(); + } + +private: + static int barrier() + { + int r = 0, m = 1; + __asm__ __volatile__ ( + "xchgl %0, %1" : + "=r"(r), "=m"(m) : + "0"(1), "m"(m) : + "memory", "cc"); + return r; + } + + static void lbarrier() + { +#if defined(__SSE2__) +# if (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) + __builtin_ia32_lfence(); +# else // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) + __asm__ __volatile__ ("lfence" ::: "memory"); +# endif // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) +#else // defined(__SSE2__) + barrier(); +#endif // defined(__SSE2__) + } + + static void sbarrier() + { +#if defined(__SSE2__) +# if (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) + __builtin_ia32_sfence(); +# else // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) + __asm__ __volatile__ ("sfence" ::: "memory"); +# endif // (__GNUC__ >= 4) && !defined(__INTEL_COMPILER) && !defined(__ICL) +#else // defined(__SSE2__) + barrier(); +#endif // defined(__SSE2__) + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +#endif // BOOST_ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP diff --git a/boost/asio/detail/global.hpp b/boost/asio/detail/global.hpp new file mode 100644 index 0000000..383ceb8 --- /dev/null +++ b/boost/asio/detail/global.hpp @@ -0,0 +1,54 @@ +// +// detail/global.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_GLOBAL_HPP +#define BOOST_ASIO_DETAIL_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_THREADS) +# include +#elif defined(BOOST_ASIO_WINDOWS) +# include +#elif defined(BOOST_ASIO_HAS_PTHREADS) +# include +#elif defined(BOOST_ASIO_HAS_STD_CALL_ONCE) +# include +#else +# error Only Windows, POSIX and std::call_once are supported! +#endif + +namespace boost { +namespace asio { +namespace detail { + +template +inline T& global() +{ +#if !defined(BOOST_ASIO_HAS_THREADS) + return null_global(); +#elif defined(BOOST_ASIO_WINDOWS) + return win_global(); +#elif defined(BOOST_ASIO_HAS_PTHREADS) + return posix_global(); +#elif defined(BOOST_ASIO_HAS_STD_CALL_ONCE) + return std_global(); +#endif +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_GLOBAL_HPP diff --git a/boost/asio/detail/handler_alloc_helpers.hpp b/boost/asio/detail/handler_alloc_helpers.hpp new file mode 100644 index 0000000..85b825d --- /dev/null +++ b/boost/asio/detail/handler_alloc_helpers.hpp @@ -0,0 +1,244 @@ +// +// detail/handler_alloc_helpers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP +#define BOOST_ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +// Calls to asio_handler_allocate and asio_handler_deallocate must be made from +// a namespace that does not contain any overloads of these functions. The +// boost_asio_handler_alloc_helpers namespace is defined here for that purpose. +namespace boost_asio_handler_alloc_helpers { + +template +inline void* allocate(std::size_t s, Handler& h) +{ +#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) + return ::operator new(s); +#else + using boost::asio::asio_handler_allocate; + return asio_handler_allocate(s, boost::asio::detail::addressof(h)); +#endif +} + +template +inline void deallocate(void* p, std::size_t s, Handler& h) +{ +#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) + ::operator delete(p); +#else + using boost::asio::asio_handler_deallocate; + asio_handler_deallocate(p, s, boost::asio::detail::addressof(h)); +#endif +} + +} // namespace boost_asio_handler_alloc_helpers + +namespace boost { +namespace asio { +namespace detail { + +template +class hook_allocator +{ +public: + typedef T value_type; + + template + struct rebind + { + typedef hook_allocator other; + }; + + explicit hook_allocator(Handler& h) + : handler_(h) + { + } + + template + hook_allocator(const hook_allocator& a) + : handler_(a.handler_) + { + } + + T* allocate(std::size_t n) + { + return static_cast( + boost_asio_handler_alloc_helpers::allocate(sizeof(T) * n, handler_)); + } + + void deallocate(T* p, std::size_t n) + { + boost_asio_handler_alloc_helpers::deallocate(p, sizeof(T) * n, handler_); + } + +//private: + Handler& handler_; +}; + +template +class hook_allocator +{ +public: + typedef void value_type; + + template + struct rebind + { + typedef hook_allocator other; + }; + + explicit hook_allocator(Handler& h) + : handler_(h) + { + } + + template + hook_allocator(const hook_allocator& a) + : handler_(a.handler_) + { + } + +//private: + Handler& handler_; +}; + +template +struct get_hook_allocator +{ + typedef Allocator type; + + static type get(Handler&, const Allocator& a) + { + return a; + } +}; + +template +struct get_hook_allocator > +{ + typedef hook_allocator type; + + static type get(Handler& handler, const std::allocator&) + { + return type(handler); + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#define BOOST_ASIO_DEFINE_HANDLER_PTR(op) \ + struct ptr \ + { \ + Handler* h; \ + op* v; \ + op* p; \ + ~ptr() \ + { \ + reset(); \ + } \ + static op* allocate(Handler& handler) \ + { \ + typedef typename ::boost::asio::associated_allocator< \ + Handler>::type associated_allocator_type; \ + typedef typename ::boost::asio::detail::get_hook_allocator< \ + Handler, associated_allocator_type>::type hook_allocator_type; \ + BOOST_ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \ + ::boost::asio::detail::get_hook_allocator< \ + Handler, associated_allocator_type>::get( \ + handler, ::boost::asio::get_associated_allocator(handler))); \ + return a.allocate(1); \ + } \ + void reset() \ + { \ + if (p) \ + { \ + p->~op(); \ + p = 0; \ + } \ + if (v) \ + { \ + typedef typename ::boost::asio::associated_allocator< \ + Handler>::type associated_allocator_type; \ + typedef typename ::boost::asio::detail::get_hook_allocator< \ + Handler, associated_allocator_type>::type hook_allocator_type; \ + BOOST_ASIO_REBIND_ALLOC(hook_allocator_type, op) a( \ + ::boost::asio::detail::get_hook_allocator< \ + Handler, associated_allocator_type>::get( \ + *h, ::boost::asio::get_associated_allocator(*h))); \ + a.deallocate(static_cast(v), 1); \ + v = 0; \ + } \ + } \ + } \ + /**/ + +#define BOOST_ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR(purpose, op) \ + struct ptr \ + { \ + const Alloc* a; \ + void* v; \ + op* p; \ + ~ptr() \ + { \ + reset(); \ + } \ + static op* allocate(const Alloc& a) \ + { \ + typedef typename ::boost::asio::detail::get_recycling_allocator< \ + Alloc, purpose>::type recycling_allocator_type; \ + BOOST_ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \ + ::boost::asio::detail::get_recycling_allocator< \ + Alloc, purpose>::get(a)); \ + return a1.allocate(1); \ + } \ + void reset() \ + { \ + if (p) \ + { \ + p->~op(); \ + p = 0; \ + } \ + if (v) \ + { \ + typedef typename ::boost::asio::detail::get_recycling_allocator< \ + Alloc, purpose>::type recycling_allocator_type; \ + BOOST_ASIO_REBIND_ALLOC(recycling_allocator_type, op) a1( \ + ::boost::asio::detail::get_recycling_allocator< \ + Alloc, purpose>::get(*a)); \ + a1.deallocate(static_cast(v), 1); \ + v = 0; \ + } \ + } \ + } \ + /**/ + +#define BOOST_ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(op) \ + BOOST_ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR( \ + ::boost::asio::detail::thread_info_base::default_tag, op ) \ + /**/ + +#include + +#endif // BOOST_ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP diff --git a/boost/asio/detail/handler_cont_helpers.hpp b/boost/asio/detail/handler_cont_helpers.hpp new file mode 100644 index 0000000..204097e --- /dev/null +++ b/boost/asio/detail/handler_cont_helpers.hpp @@ -0,0 +1,45 @@ +// +// detail/handler_cont_helpers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_HANDLER_CONT_HELPERS_HPP +#define BOOST_ASIO_DETAIL_HANDLER_CONT_HELPERS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +// Calls to asio_handler_is_continuation must be made from a namespace that +// does not contain overloads of this function. This namespace is defined here +// for that purpose. +namespace boost_asio_handler_cont_helpers { + +template +inline bool is_continuation(Context& context) +{ +#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) + return false; +#else + using boost::asio::asio_handler_is_continuation; + return asio_handler_is_continuation( + boost::asio::detail::addressof(context)); +#endif +} + +} // namespace boost_asio_handler_cont_helpers + +#include + +#endif // BOOST_ASIO_DETAIL_HANDLER_CONT_HELPERS_HPP diff --git a/boost/asio/detail/handler_invoke_helpers.hpp b/boost/asio/detail/handler_invoke_helpers.hpp new file mode 100644 index 0000000..e453b02 --- /dev/null +++ b/boost/asio/detail/handler_invoke_helpers.hpp @@ -0,0 +1,57 @@ +// +// detail/handler_invoke_helpers.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP +#define BOOST_ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +// Calls to asio_handler_invoke must be made from a namespace that does not +// contain overloads of this function. The boost_asio_handler_invoke_helpers +// namespace is defined here for that purpose. +namespace boost_asio_handler_invoke_helpers { + +template +inline void invoke(Function& function, Context& context) +{ +#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) + Function tmp(function); + tmp(); +#else + using boost::asio::asio_handler_invoke; + asio_handler_invoke(function, boost::asio::detail::addressof(context)); +#endif +} + +template +inline void invoke(const Function& function, Context& context) +{ +#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) + Function tmp(function); + tmp(); +#else + using boost::asio::asio_handler_invoke; + asio_handler_invoke(function, boost::asio::detail::addressof(context)); +#endif +} + +} // namespace boost_asio_handler_invoke_helpers + +#include + +#endif // BOOST_ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP diff --git a/boost/asio/detail/handler_tracking.hpp b/boost/asio/detail/handler_tracking.hpp new file mode 100644 index 0000000..35eff02 --- /dev/null +++ b/boost/asio/detail/handler_tracking.hpp @@ -0,0 +1,242 @@ +// +// detail/handler_tracking.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_HANDLER_TRACKING_HPP +#define BOOST_ASIO_DETAIL_HANDLER_TRACKING_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +namespace boost { +namespace asio { + +class execution_context; + +} // namespace asio +} // namespace boost + +#if defined(BOOST_ASIO_CUSTOM_HANDLER_TRACKING) +# include BOOST_ASIO_CUSTOM_HANDLER_TRACKING +#elif defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) +# include +# include +# include +# include +#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + +#include + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_CUSTOM_HANDLER_TRACKING) + +// The user-specified header must define the following macros: +// - BOOST_ASIO_INHERIT_TRACKED_HANDLER +// - BOOST_ASIO_ALSO_INHERIT_TRACKED_HANDLER +// - BOOST_ASIO_HANDLER_TRACKING_INIT +// - BOOST_ASIO_HANDLER_CREATION(args) +// - BOOST_ASIO_HANDLER_COMPLETION(args) +// - BOOST_ASIO_HANDLER_INVOCATION_BEGIN(args) +// - BOOST_ASIO_HANDLER_INVOCATION_END +// - BOOST_ASIO_HANDLER_OPERATION(args) +// - BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(args) +// - BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(args) +// - BOOST_ASIO_HANDLER_REACTOR_READ_EVENT +// - BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT +// - BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT +// - BOOST_ASIO_HANDLER_REACTOR_EVENTS(args) +// - BOOST_ASIO_HANDLER_REACTOR_OPERATION(args) + +# if !defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) +# define BOOST_ASIO_ENABLE_HANDLER_TRACKING 1 +# endif /// !defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + +#elif defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + +class handler_tracking +{ +public: + class completion; + + // Base class for objects containing tracked handlers. + class tracked_handler + { + private: + // Only the handler_tracking class will have access to the id. + friend class handler_tracking; + friend class completion; + uint64_t id_; + + protected: + // Constructor initialises with no id. + tracked_handler() : id_(0) {} + + // Prevent deletion through this type. + ~tracked_handler() {} + }; + + // Initialise the tracking system. + BOOST_ASIO_DECL static void init(); + + // Record the creation of a tracked handler. + BOOST_ASIO_DECL static void creation( + execution_context& context, tracked_handler& h, + const char* object_type, void* object, + uintmax_t native_handle, const char* op_name); + + class completion + { + public: + // Constructor records that handler is to be invoked with no arguments. + BOOST_ASIO_DECL explicit completion(const tracked_handler& h); + + // Destructor records only when an exception is thrown from the handler, or + // if the memory is being freed without the handler having been invoked. + BOOST_ASIO_DECL ~completion(); + + // Records that handler is to be invoked with no arguments. + BOOST_ASIO_DECL void invocation_begin(); + + // Records that handler is to be invoked with one arguments. + BOOST_ASIO_DECL void invocation_begin(const boost::system::error_code& ec); + + // Constructor records that handler is to be invoked with two arguments. + BOOST_ASIO_DECL void invocation_begin( + const boost::system::error_code& ec, std::size_t bytes_transferred); + + // Constructor records that handler is to be invoked with two arguments. + BOOST_ASIO_DECL void invocation_begin( + const boost::system::error_code& ec, int signal_number); + + // Constructor records that handler is to be invoked with two arguments. + BOOST_ASIO_DECL void invocation_begin( + const boost::system::error_code& ec, const char* arg); + + // Record that handler invocation has ended. + BOOST_ASIO_DECL void invocation_end(); + + private: + friend class handler_tracking; + uint64_t id_; + bool invoked_; + completion* next_; + }; + + // Record an operation that is not directly associated with a handler. + BOOST_ASIO_DECL static void operation(execution_context& context, + const char* object_type, void* object, + uintmax_t native_handle, const char* op_name); + + // Record that a descriptor has been registered with the reactor. + BOOST_ASIO_DECL static void reactor_registration(execution_context& context, + uintmax_t native_handle, uintmax_t registration); + + // Record that a descriptor has been deregistered from the reactor. + BOOST_ASIO_DECL static void reactor_deregistration(execution_context& context, + uintmax_t native_handle, uintmax_t registration); + + // Record a reactor-based operation that is associated with a handler. + BOOST_ASIO_DECL static void reactor_events(execution_context& context, + uintmax_t registration, unsigned events); + + // Record a reactor-based operation that is associated with a handler. + BOOST_ASIO_DECL static void reactor_operation( + const tracked_handler& h, const char* op_name, + const boost::system::error_code& ec); + + // Record a reactor-based operation that is associated with a handler. + BOOST_ASIO_DECL static void reactor_operation( + const tracked_handler& h, const char* op_name, + const boost::system::error_code& ec, std::size_t bytes_transferred); + + // Write a line of output. + BOOST_ASIO_DECL static void write_line(const char* format, ...); + +private: + struct tracking_state; + BOOST_ASIO_DECL static tracking_state* get_state(); +}; + +# define BOOST_ASIO_INHERIT_TRACKED_HANDLER \ + : public boost::asio::detail::handler_tracking::tracked_handler + +# define BOOST_ASIO_ALSO_INHERIT_TRACKED_HANDLER \ + , public boost::asio::detail::handler_tracking::tracked_handler + +# define BOOST_ASIO_HANDLER_TRACKING_INIT \ + boost::asio::detail::handler_tracking::init() + +# define BOOST_ASIO_HANDLER_CREATION(args) \ + boost::asio::detail::handler_tracking::creation args + +# define BOOST_ASIO_HANDLER_COMPLETION(args) \ + boost::asio::detail::handler_tracking::completion tracked_completion args + +# define BOOST_ASIO_HANDLER_INVOCATION_BEGIN(args) \ + tracked_completion.invocation_begin args + +# define BOOST_ASIO_HANDLER_INVOCATION_END \ + tracked_completion.invocation_end() + +# define BOOST_ASIO_HANDLER_OPERATION(args) \ + boost::asio::detail::handler_tracking::operation args + +# define BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(args) \ + boost::asio::detail::handler_tracking::reactor_registration args + +# define BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(args) \ + boost::asio::detail::handler_tracking::reactor_deregistration args + +# define BOOST_ASIO_HANDLER_REACTOR_READ_EVENT 1 +# define BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT 2 +# define BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT 4 + +# define BOOST_ASIO_HANDLER_REACTOR_EVENTS(args) \ + boost::asio::detail::handler_tracking::reactor_events args + +# define BOOST_ASIO_HANDLER_REACTOR_OPERATION(args) \ + boost::asio::detail::handler_tracking::reactor_operation args + +#else // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + +# define BOOST_ASIO_INHERIT_TRACKED_HANDLER +# define BOOST_ASIO_ALSO_INHERIT_TRACKED_HANDLER +# define BOOST_ASIO_HANDLER_TRACKING_INIT (void)0 +# define BOOST_ASIO_HANDLER_CREATION(args) (void)0 +# define BOOST_ASIO_HANDLER_COMPLETION(args) (void)0 +# define BOOST_ASIO_HANDLER_INVOCATION_BEGIN(args) (void)0 +# define BOOST_ASIO_HANDLER_INVOCATION_END (void)0 +# define BOOST_ASIO_HANDLER_OPERATION(args) (void)0 +# define BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(args) (void)0 +# define BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(args) (void)0 +# define BOOST_ASIO_HANDLER_REACTOR_READ_EVENT 0 +# define BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT 0 +# define BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT 0 +# define BOOST_ASIO_HANDLER_REACTOR_EVENTS(args) (void)0 +# define BOOST_ASIO_HANDLER_REACTOR_OPERATION(args) (void)0 + +#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_DETAIL_HANDLER_TRACKING_HPP diff --git a/boost/asio/detail/handler_type_requirements.hpp b/boost/asio/detail/handler_type_requirements.hpp new file mode 100644 index 0000000..cf57d67 --- /dev/null +++ b/boost/asio/detail/handler_type_requirements.hpp @@ -0,0 +1,558 @@ +// +// detail/handler_type_requirements.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP +#define BOOST_ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +// Older versions of gcc have difficulty compiling the sizeof expressions where +// we test the handler type requirements. We'll disable checking of handler type +// requirements for those compilers, but otherwise enable it by default. +#if !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS) +# if !defined(__GNUC__) || (__GNUC__ >= 4) +# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS 1 +# endif // !defined(__GNUC__) || (__GNUC__ >= 4) +#endif // !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS) + +// With C++0x we can use a combination of enhanced SFINAE and static_assert to +// generate better template error messages. As this technique is not yet widely +// portable, we'll only enable it for tested compilers. +#if !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT) +# if defined(__GNUC__) +# if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# if defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1 +# endif // defined(__GXX_EXPERIMENTAL_CXX0X__) +# endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 5)) || (__GNUC__ > 4) +# endif // defined(__GNUC__) +# if defined(BOOST_ASIO_MSVC) +# if (_MSC_VER >= 1600) +# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1 +# endif // (_MSC_VER >= 1600) +# endif // defined(BOOST_ASIO_MSVC) +# if defined(__clang__) +# if __has_feature(__cxx_static_assert__) +# define BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT 1 +# endif // __has_feature(cxx_static_assert) +# endif // defined(__clang__) +#endif // !defined(BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS) + +#if defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS) +# include +#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS) + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS) + +# if defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT) + +template +auto zero_arg_copyable_handler_test(Handler h, void*) + -> decltype( + sizeof(Handler(static_cast(h))), + ((h)()), + char(0)); + +template +char (&zero_arg_copyable_handler_test(Handler, ...))[2]; + +template +auto one_arg_handler_test(Handler h, Arg1* a1) + -> decltype( + sizeof(Handler(BOOST_ASIO_MOVE_CAST(Handler)(h))), + ((h)(*a1)), + char(0)); + +template +char (&one_arg_handler_test(Handler h, ...))[2]; + +template +auto two_arg_handler_test(Handler h, Arg1* a1, Arg2* a2) + -> decltype( + sizeof(Handler(BOOST_ASIO_MOVE_CAST(Handler)(h))), + ((h)(*a1, *a2)), + char(0)); + +template +char (&two_arg_handler_test(Handler, ...))[2]; + +template +auto two_arg_move_handler_test(Handler h, Arg1* a1, Arg2* a2) + -> decltype( + sizeof(Handler(BOOST_ASIO_MOVE_CAST(Handler)(h))), + ((h)(*a1, BOOST_ASIO_MOVE_CAST(Arg2)(*a2))), + char(0)); + +template +char (&two_arg_move_handler_test(Handler, ...))[2]; + +# define BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg) \ + static_assert(expr, msg); + +# else // defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT) + +# define BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT(expr, msg) + +# endif // defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS_ASSERT) + +template T& lvref(); +template T& lvref(T); +template const T& clvref(); +template const T& clvref(T); +#if defined(BOOST_ASIO_HAS_MOVE) +template T rvref(); +template T rvref(T); +#else // defined(BOOST_ASIO_HAS_MOVE) +template const T& rvref(); +template const T& rvref(T); +#endif // defined(BOOST_ASIO_HAS_MOVE) +template char argbyv(T); + +template +struct handler_type_requirements +{ +}; + +#define BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \ + void()) asio_true_handler_type; \ + \ + BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(boost::asio::detail::zero_arg_copyable_handler_test( \ + boost::asio::detail::clvref< \ + asio_true_handler_type>(), 0)) == 1, \ + "CompletionHandler type requirements not met") \ + \ + typedef boost::asio::detail::handler_type_requirements< \ + sizeof( \ + boost::asio::detail::argbyv( \ + boost::asio::detail::clvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + boost::asio::detail::lvref< \ + asio_true_handler_type>()(), \ + char(0))> BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_READ_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \ + void(boost::system::error_code, std::size_t)) \ + asio_true_handler_type; \ + \ + BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(boost::asio::detail::two_arg_handler_test( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0), \ + static_cast(0))) == 1, \ + "ReadHandler type requirements not met") \ + \ + typedef boost::asio::detail::handler_type_requirements< \ + sizeof( \ + boost::asio::detail::argbyv( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + boost::asio::detail::lvref< \ + asio_true_handler_type>()( \ + boost::asio::detail::lvref(), \ + boost::asio::detail::lvref()), \ + char(0))> BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_WRITE_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \ + void(boost::system::error_code, std::size_t)) \ + asio_true_handler_type; \ + \ + BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(boost::asio::detail::two_arg_handler_test( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0), \ + static_cast(0))) == 1, \ + "WriteHandler type requirements not met") \ + \ + typedef boost::asio::detail::handler_type_requirements< \ + sizeof( \ + boost::asio::detail::argbyv( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + boost::asio::detail::lvref< \ + asio_true_handler_type>()( \ + boost::asio::detail::lvref(), \ + boost::asio::detail::lvref()), \ + char(0))> BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_ACCEPT_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \ + void(boost::system::error_code)) \ + asio_true_handler_type; \ + \ + BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(boost::asio::detail::one_arg_handler_test( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0))) == 1, \ + "AcceptHandler type requirements not met") \ + \ + typedef boost::asio::detail::handler_type_requirements< \ + sizeof( \ + boost::asio::detail::argbyv( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + boost::asio::detail::lvref< \ + asio_true_handler_type>()( \ + boost::asio::detail::lvref()), \ + char(0))> BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_MOVE_ACCEPT_HANDLER_CHECK( \ + handler_type, handler, socket_type) \ + \ + typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \ + void(boost::system::error_code, socket_type)) \ + asio_true_handler_type; \ + \ + BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(boost::asio::detail::two_arg_move_handler_test( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0), \ + static_cast(0))) == 1, \ + "MoveAcceptHandler type requirements not met") \ + \ + typedef boost::asio::detail::handler_type_requirements< \ + sizeof( \ + boost::asio::detail::argbyv( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + boost::asio::detail::lvref< \ + asio_true_handler_type>()( \ + boost::asio::detail::lvref(), \ + boost::asio::detail::rvref()), \ + char(0))> BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_CONNECT_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \ + void(boost::system::error_code)) \ + asio_true_handler_type; \ + \ + BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(boost::asio::detail::one_arg_handler_test( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0))) == 1, \ + "ConnectHandler type requirements not met") \ + \ + typedef boost::asio::detail::handler_type_requirements< \ + sizeof( \ + boost::asio::detail::argbyv( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + boost::asio::detail::lvref< \ + asio_true_handler_type>()( \ + boost::asio::detail::lvref()), \ + char(0))> BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK( \ + handler_type, handler, endpoint_type) \ + \ + typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \ + void(boost::system::error_code, endpoint_type)) \ + asio_true_handler_type; \ + \ + BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(boost::asio::detail::two_arg_handler_test( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0), \ + static_cast(0))) == 1, \ + "RangeConnectHandler type requirements not met") \ + \ + typedef boost::asio::detail::handler_type_requirements< \ + sizeof( \ + boost::asio::detail::argbyv( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + boost::asio::detail::lvref< \ + asio_true_handler_type>()( \ + boost::asio::detail::lvref(), \ + boost::asio::detail::lvref()), \ + char(0))> BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \ + handler_type, handler, iter_type) \ + \ + typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \ + void(boost::system::error_code, iter_type)) \ + asio_true_handler_type; \ + \ + BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(boost::asio::detail::two_arg_handler_test( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0), \ + static_cast(0))) == 1, \ + "IteratorConnectHandler type requirements not met") \ + \ + typedef boost::asio::detail::handler_type_requirements< \ + sizeof( \ + boost::asio::detail::argbyv( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + boost::asio::detail::lvref< \ + asio_true_handler_type>()( \ + boost::asio::detail::lvref(), \ + boost::asio::detail::lvref()), \ + char(0))> BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_RESOLVE_HANDLER_CHECK( \ + handler_type, handler, range_type) \ + \ + typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \ + void(boost::system::error_code, range_type)) \ + asio_true_handler_type; \ + \ + BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(boost::asio::detail::two_arg_handler_test( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0), \ + static_cast(0))) == 1, \ + "ResolveHandler type requirements not met") \ + \ + typedef boost::asio::detail::handler_type_requirements< \ + sizeof( \ + boost::asio::detail::argbyv( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + boost::asio::detail::lvref< \ + asio_true_handler_type>()( \ + boost::asio::detail::lvref(), \ + boost::asio::detail::lvref()), \ + char(0))> BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_WAIT_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \ + void(boost::system::error_code)) \ + asio_true_handler_type; \ + \ + BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(boost::asio::detail::one_arg_handler_test( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0))) == 1, \ + "WaitHandler type requirements not met") \ + \ + typedef boost::asio::detail::handler_type_requirements< \ + sizeof( \ + boost::asio::detail::argbyv( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + boost::asio::detail::lvref< \ + asio_true_handler_type>()( \ + boost::asio::detail::lvref()), \ + char(0))> BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_SIGNAL_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \ + void(boost::system::error_code, int)) \ + asio_true_handler_type; \ + \ + BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(boost::asio::detail::two_arg_handler_test( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0), \ + static_cast(0))) == 1, \ + "SignalHandler type requirements not met") \ + \ + typedef boost::asio::detail::handler_type_requirements< \ + sizeof( \ + boost::asio::detail::argbyv( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + boost::asio::detail::lvref< \ + asio_true_handler_type>()( \ + boost::asio::detail::lvref(), \ + boost::asio::detail::lvref()), \ + char(0))> BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_HANDSHAKE_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \ + void(boost::system::error_code)) \ + asio_true_handler_type; \ + \ + BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(boost::asio::detail::one_arg_handler_test( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0))) == 1, \ + "HandshakeHandler type requirements not met") \ + \ + typedef boost::asio::detail::handler_type_requirements< \ + sizeof( \ + boost::asio::detail::argbyv( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + boost::asio::detail::lvref< \ + asio_true_handler_type>()( \ + boost::asio::detail::lvref()), \ + char(0))> BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \ + void(boost::system::error_code, std::size_t)) \ + asio_true_handler_type; \ + \ + BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(boost::asio::detail::two_arg_handler_test( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0), \ + static_cast(0))) == 1, \ + "BufferedHandshakeHandler type requirements not met") \ + \ + typedef boost::asio::detail::handler_type_requirements< \ + sizeof( \ + boost::asio::detail::argbyv( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + boost::asio::detail::lvref< \ + asio_true_handler_type>()( \ + boost::asio::detail::lvref(), \ + boost::asio::detail::lvref()), \ + char(0))> BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_SHUTDOWN_HANDLER_CHECK( \ + handler_type, handler) \ + \ + typedef BOOST_ASIO_HANDLER_TYPE(handler_type, \ + void(boost::system::error_code)) \ + asio_true_handler_type; \ + \ + BOOST_ASIO_HANDLER_TYPE_REQUIREMENTS_ASSERT( \ + sizeof(boost::asio::detail::one_arg_handler_test( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>(), \ + static_cast(0))) == 1, \ + "ShutdownHandler type requirements not met") \ + \ + typedef boost::asio::detail::handler_type_requirements< \ + sizeof( \ + boost::asio::detail::argbyv( \ + boost::asio::detail::rvref< \ + asio_true_handler_type>())) + \ + sizeof( \ + boost::asio::detail::lvref< \ + asio_true_handler_type>()( \ + boost::asio::detail::lvref()), \ + char(0))> BOOST_ASIO_UNUSED_TYPEDEF + +#else // !defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS) + +#define BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_READ_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_WRITE_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_ACCEPT_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_MOVE_ACCEPT_HANDLER_CHECK( \ + handler_type, handler, socket_type) \ + typedef int BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_CONNECT_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK( \ + handler_type, handler, iter_type) \ + typedef int BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( \ + handler_type, handler, iter_type) \ + typedef int BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_RESOLVE_HANDLER_CHECK( \ + handler_type, handler, iter_type) \ + typedef int BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_WAIT_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_SIGNAL_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_HANDSHAKE_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int BOOST_ASIO_UNUSED_TYPEDEF + +#define BOOST_ASIO_SHUTDOWN_HANDLER_CHECK( \ + handler_type, handler) \ + typedef int BOOST_ASIO_UNUSED_TYPEDEF + +#endif // !defined(BOOST_ASIO_ENABLE_HANDLER_TYPE_REQUIREMENTS) + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_HANDLER_TYPE_REQUIREMENTS_HPP diff --git a/boost/asio/detail/handler_work.hpp b/boost/asio/detail/handler_work.hpp new file mode 100644 index 0000000..06da376 --- /dev/null +++ b/boost/asio/detail/handler_work.hpp @@ -0,0 +1,115 @@ +// +// detail/handler_work.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_HANDLER_WORK_HPP +#define BOOST_ASIO_DETAIL_HANDLER_WORK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// A helper class template to allow completion handlers to be dispatched +// through either the new executors framework or the old invocaton hook. The +// primary template uses the new executors framework. +template ::type> +class handler_work +{ +public: + explicit handler_work(Handler& handler) BOOST_ASIO_NOEXCEPT + : io_executor_(), + executor_(boost::asio::get_associated_executor(handler, io_executor_)) + { + } + + handler_work(Handler& handler, const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT + : io_executor_(io_ex), + executor_(boost::asio::get_associated_executor(handler, io_executor_)) + { + } + + static void start(Handler& handler) BOOST_ASIO_NOEXCEPT + { + HandlerExecutor ex(boost::asio::get_associated_executor(handler)); + ex.on_work_started(); + } + + static void start(Handler& handler, + const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT + { + HandlerExecutor ex(boost::asio::get_associated_executor(handler, io_ex)); + ex.on_work_started(); + io_ex.on_work_started(); + } + + ~handler_work() + { + io_executor_.on_work_finished(); + executor_.on_work_finished(); + } + + template + void complete(Function& function, Handler& handler) + { + executor_.dispatch(BOOST_ASIO_MOVE_CAST(Function)(function), + boost::asio::get_associated_allocator(handler)); + } + +private: + // Disallow copying and assignment. + handler_work(const handler_work&); + handler_work& operator=(const handler_work&); + + IoExecutor io_executor_; + HandlerExecutor executor_; +}; + +// This specialisation dispatches a handler through the old invocation hook. +// The specialisation is not strictly required for correctness, as the +// system_executor will dispatch through the hook anyway. However, by doing +// this we avoid an extra copy of the handler. +template +class handler_work +{ +public: + explicit handler_work(Handler&) BOOST_ASIO_NOEXCEPT {} + static void start(Handler&) BOOST_ASIO_NOEXCEPT {} + ~handler_work() {} + + template + void complete(Function& function, Handler& handler) + { + boost_asio_handler_invoke_helpers::invoke(function, handler); + } + +private: + // Disallow copying and assignment. + handler_work(const handler_work&); + handler_work& operator=(const handler_work&); +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_HANDLER_WORK_HPP diff --git a/boost/asio/detail/hash_map.hpp b/boost/asio/detail/hash_map.hpp new file mode 100644 index 0000000..ac80abd --- /dev/null +++ b/boost/asio/detail/hash_map.hpp @@ -0,0 +1,333 @@ +// +// detail/hash_map.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_HASH_MAP_HPP +#define BOOST_ASIO_DETAIL_HASH_MAP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# include +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +#include + +namespace boost { +namespace asio { +namespace detail { + +inline std::size_t calculate_hash_value(int i) +{ + return static_cast(i); +} + +inline std::size_t calculate_hash_value(void* p) +{ + return reinterpret_cast(p) + + (reinterpret_cast(p) >> 3); +} + +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +inline std::size_t calculate_hash_value(SOCKET s) +{ + return static_cast(s); +} +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +// Note: assumes K and V are POD types. +template +class hash_map + : private noncopyable +{ +public: + // The type of a value in the map. + typedef std::pair value_type; + + // The type of a non-const iterator over the hash map. + typedef typename std::list::iterator iterator; + + // The type of a const iterator over the hash map. + typedef typename std::list::const_iterator const_iterator; + + // Constructor. + hash_map() + : size_(0), + buckets_(0), + num_buckets_(0) + { + } + + // Destructor. + ~hash_map() + { + delete[] buckets_; + } + + // Get an iterator for the beginning of the map. + iterator begin() + { + return values_.begin(); + } + + // Get an iterator for the beginning of the map. + const_iterator begin() const + { + return values_.begin(); + } + + // Get an iterator for the end of the map. + iterator end() + { + return values_.end(); + } + + // Get an iterator for the end of the map. + const_iterator end() const + { + return values_.end(); + } + + // Check whether the map is empty. + bool empty() const + { + return values_.empty(); + } + + // Find an entry in the map. + iterator find(const K& k) + { + if (num_buckets_) + { + size_t bucket = calculate_hash_value(k) % num_buckets_; + iterator it = buckets_[bucket].first; + if (it == values_.end()) + return values_.end(); + iterator end_it = buckets_[bucket].last; + ++end_it; + while (it != end_it) + { + if (it->first == k) + return it; + ++it; + } + } + return values_.end(); + } + + // Find an entry in the map. + const_iterator find(const K& k) const + { + if (num_buckets_) + { + size_t bucket = calculate_hash_value(k) % num_buckets_; + const_iterator it = buckets_[bucket].first; + if (it == values_.end()) + return it; + const_iterator end_it = buckets_[bucket].last; + ++end_it; + while (it != end_it) + { + if (it->first == k) + return it; + ++it; + } + } + return values_.end(); + } + + // Insert a new entry into the map. + std::pair insert(const value_type& v) + { + if (size_ + 1 >= num_buckets_) + rehash(hash_size(size_ + 1)); + size_t bucket = calculate_hash_value(v.first) % num_buckets_; + iterator it = buckets_[bucket].first; + if (it == values_.end()) + { + buckets_[bucket].first = buckets_[bucket].last = + values_insert(values_.end(), v); + ++size_; + return std::pair(buckets_[bucket].last, true); + } + iterator end_it = buckets_[bucket].last; + ++end_it; + while (it != end_it) + { + if (it->first == v.first) + return std::pair(it, false); + ++it; + } + buckets_[bucket].last = values_insert(end_it, v); + ++size_; + return std::pair(buckets_[bucket].last, true); + } + + // Erase an entry from the map. + void erase(iterator it) + { + BOOST_ASIO_ASSERT(it != values_.end()); + BOOST_ASIO_ASSERT(num_buckets_ != 0); + + size_t bucket = calculate_hash_value(it->first) % num_buckets_; + bool is_first = (it == buckets_[bucket].first); + bool is_last = (it == buckets_[bucket].last); + if (is_first && is_last) + buckets_[bucket].first = buckets_[bucket].last = values_.end(); + else if (is_first) + ++buckets_[bucket].first; + else if (is_last) + --buckets_[bucket].last; + + values_erase(it); + --size_; + } + + // Erase a key from the map. + void erase(const K& k) + { + iterator it = find(k); + if (it != values_.end()) + erase(it); + } + + // Remove all entries from the map. + void clear() + { + // Clear the values. + values_.clear(); + size_ = 0; + + // Initialise all buckets to empty. + iterator end_it = values_.end(); + for (size_t i = 0; i < num_buckets_; ++i) + buckets_[i].first = buckets_[i].last = end_it; + } + +private: + // Calculate the hash size for the specified number of elements. + static std::size_t hash_size(std::size_t num_elems) + { + static std::size_t sizes[] = + { +#if defined(BOOST_ASIO_HASH_MAP_BUCKETS) + BOOST_ASIO_HASH_MAP_BUCKETS +#else // BOOST_ASIO_HASH_MAP_BUCKETS + 3, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, + 49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, + 12582917, 25165843 +#endif // BOOST_ASIO_HASH_MAP_BUCKETS + }; + const std::size_t nth_size = sizeof(sizes) / sizeof(std::size_t) - 1; + for (std::size_t i = 0; i < nth_size; ++i) + if (num_elems < sizes[i]) + return sizes[i]; + return sizes[nth_size]; + } + + // Re-initialise the hash from the values already contained in the list. + void rehash(std::size_t num_buckets) + { + if (num_buckets == num_buckets_) + return; + BOOST_ASIO_ASSERT(num_buckets != 0); + + iterator end_iter = values_.end(); + + // Update number of buckets and initialise all buckets to empty. + bucket_type* tmp = new bucket_type[num_buckets]; + delete[] buckets_; + buckets_ = tmp; + num_buckets_ = num_buckets; + for (std::size_t i = 0; i < num_buckets_; ++i) + buckets_[i].first = buckets_[i].last = end_iter; + + // Put all values back into the hash. + iterator iter = values_.begin(); + while (iter != end_iter) + { + std::size_t bucket = calculate_hash_value(iter->first) % num_buckets_; + if (buckets_[bucket].last == end_iter) + { + buckets_[bucket].first = buckets_[bucket].last = iter++; + } + else if (++buckets_[bucket].last == iter) + { + ++iter; + } + else + { + values_.splice(buckets_[bucket].last, values_, iter++); + --buckets_[bucket].last; + } + } + } + + // Insert an element into the values list by splicing from the spares list, + // if a spare is available, and otherwise by inserting a new element. + iterator values_insert(iterator it, const value_type& v) + { + if (spares_.empty()) + { + return values_.insert(it, v); + } + else + { + spares_.front() = v; + values_.splice(it, spares_, spares_.begin()); + return --it; + } + } + + // Erase an element from the values list by splicing it to the spares list. + void values_erase(iterator it) + { + *it = value_type(); + spares_.splice(spares_.begin(), values_, it); + } + + // The number of elements in the hash. + std::size_t size_; + + // The list of all values in the hash map. + std::list values_; + + // The list of spare nodes waiting to be recycled. Assumes that POD types only + // are stored in the hash map. + std::list spares_; + + // The type for a bucket in the hash table. + struct bucket_type + { + iterator first; + iterator last; + }; + + // The buckets in the hash. + bucket_type* buckets_; + + // The number of buckets in the hash. + std::size_t num_buckets_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_HASH_MAP_HPP diff --git a/boost/asio/detail/impl/buffer_sequence_adapter.ipp b/boost/asio/detail/impl/buffer_sequence_adapter.ipp new file mode 100644 index 0000000..b3fb59c --- /dev/null +++ b/boost/asio/detail/impl/buffer_sequence_adapter.ipp @@ -0,0 +1,120 @@ +// +// detail/impl/buffer_sequence_adapter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_BUFFER_SEQUENCE_ADAPTER_IPP +#define BOOST_ASIO_DETAIL_IMPL_BUFFER_SEQUENCE_ADAPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class winrt_buffer_impl : + public Microsoft::WRL::RuntimeClass< + Microsoft::WRL::RuntimeClassFlags< + Microsoft::WRL::RuntimeClassType::WinRtClassicComMix>, + ABI::Windows::Storage::Streams::IBuffer, + Windows::Storage::Streams::IBufferByteAccess> +{ +public: + explicit winrt_buffer_impl(const boost::asio::const_buffer& b) + { + bytes_ = const_cast(static_cast(b.data())); + length_ = b.size(); + capacity_ = b.size(); + } + + explicit winrt_buffer_impl(const boost::asio::mutable_buffer& b) + { + bytes_ = static_cast(b.data()); + length_ = 0; + capacity_ = b.size(); + } + + ~winrt_buffer_impl() + { + } + + STDMETHODIMP Buffer(byte** value) + { + *value = bytes_; + return S_OK; + } + + STDMETHODIMP get_Capacity(UINT32* value) + { + *value = capacity_; + return S_OK; + } + + STDMETHODIMP get_Length(UINT32 *value) + { + *value = length_; + return S_OK; + } + + STDMETHODIMP put_Length(UINT32 value) + { + if (value > capacity_) + return E_INVALIDARG; + length_ = value; + return S_OK; + } + +private: + byte* bytes_; + UINT32 length_; + UINT32 capacity_; +}; + +void buffer_sequence_adapter_base::init_native_buffer( + buffer_sequence_adapter_base::native_buffer_type& buf, + const boost::asio::mutable_buffer& buffer) +{ + std::memset(&buf, 0, sizeof(native_buffer_type)); + Microsoft::WRL::ComPtr insp + = Microsoft::WRL::Make(buffer); + buf = reinterpret_cast(insp.Get()); +} + +void buffer_sequence_adapter_base::init_native_buffer( + buffer_sequence_adapter_base::native_buffer_type& buf, + const boost::asio::const_buffer& buffer) +{ + std::memset(&buf, 0, sizeof(native_buffer_type)); + Microsoft::WRL::ComPtr insp + = Microsoft::WRL::Make(buffer); + Platform::Object^ buf_obj = reinterpret_cast(insp.Get()); + buf = reinterpret_cast(insp.Get()); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#endif // BOOST_ASIO_DETAIL_IMPL_BUFFER_SEQUENCE_ADAPTER_IPP diff --git a/boost/asio/detail/impl/descriptor_ops.ipp b/boost/asio/detail/impl/descriptor_ops.ipp new file mode 100644 index 0000000..1a26e6d --- /dev/null +++ b/boost/asio/detail/impl/descriptor_ops.ipp @@ -0,0 +1,476 @@ +// +// detail/impl/descriptor_ops.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP +#define BOOST_ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + +#include + +namespace boost { +namespace asio { +namespace detail { +namespace descriptor_ops { + +int open(const char* path, int flags, boost::system::error_code& ec) +{ + errno = 0; + int result = error_wrapper(::open(path, flags), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +} + +int close(int d, state_type& state, boost::system::error_code& ec) +{ + int result = 0; + if (d != -1) + { + errno = 0; + result = error_wrapper(::close(d), ec); + + if (result != 0 + && (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again)) + { + // According to UNIX Network Programming Vol. 1, it is possible for + // close() to fail with EWOULDBLOCK under certain circumstances. What + // isn't clear is the state of the descriptor after this error. The one + // current OS where this behaviour is seen, Windows, says that the socket + // remains open. Therefore we'll put the descriptor back into blocking + // mode and have another attempt at closing it. +#if defined(__SYMBIAN32__) + int flags = ::fcntl(d, F_GETFL, 0); + if (flags >= 0) + ::fcntl(d, F_SETFL, flags & ~O_NONBLOCK); +#else // defined(__SYMBIAN32__) + ioctl_arg_type arg = 0; + ::ioctl(d, FIONBIO, &arg); +#endif // defined(__SYMBIAN32__) + state &= ~non_blocking; + + errno = 0; + result = error_wrapper(::close(d), ec); + } + } + + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +bool set_user_non_blocking(int d, state_type& state, + bool value, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return false; + } + + errno = 0; +#if defined(__SYMBIAN32__) + int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec); + if (result >= 0) + { + errno = 0; + int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); + result = error_wrapper(::fcntl(d, F_SETFL, flag), ec); + } +#else // defined(__SYMBIAN32__) + ioctl_arg_type arg = (value ? 1 : 0); + int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec); +#endif // defined(__SYMBIAN32__) + + if (result >= 0) + { + ec = boost::system::error_code(); + if (value) + state |= user_set_non_blocking; + else + { + // Clearing the user-set non-blocking mode always overrides any + // internally-set non-blocking flag. Any subsequent asynchronous + // operations will need to re-enable non-blocking I/O. + state &= ~(user_set_non_blocking | internal_non_blocking); + } + return true; + } + + return false; +} + +bool set_internal_non_blocking(int d, state_type& state, + bool value, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return false; + } + + if (!value && (state & user_set_non_blocking)) + { + // It does not make sense to clear the internal non-blocking flag if the + // user still wants non-blocking behaviour. Return an error and let the + // caller figure out whether to update the user-set non-blocking flag. + ec = boost::asio::error::invalid_argument; + return false; + } + + errno = 0; +#if defined(__SYMBIAN32__) + int result = error_wrapper(::fcntl(d, F_GETFL, 0), ec); + if (result >= 0) + { + errno = 0; + int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); + result = error_wrapper(::fcntl(d, F_SETFL, flag), ec); + } +#else // defined(__SYMBIAN32__) + ioctl_arg_type arg = (value ? 1 : 0); + int result = error_wrapper(::ioctl(d, FIONBIO, &arg), ec); +#endif // defined(__SYMBIAN32__) + + if (result >= 0) + { + ec = boost::system::error_code(); + if (value) + state |= internal_non_blocking; + else + state &= ~internal_non_blocking; + return true; + } + + return false; +} + +std::size_t sync_read(int d, state_type state, buf* bufs, + std::size_t count, bool all_empty, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (all_empty) + { + ec = boost::system::error_code(); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + errno = 0; + signed_size_type bytes = error_wrapper(::readv( + d, bufs, static_cast(count)), ec); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if (bytes == 0) + { + ec = boost::asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_read(d, 0, ec) < 0) + return 0; + } +} + +bool non_blocking_read(int d, buf* bufs, std::size_t count, + boost::system::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + errno = 0; + signed_size_type bytes = error_wrapper(::readv( + d, bufs, static_cast(count)), ec); + + // Check for end of stream. + if (bytes == 0) + { + ec = boost::asio::error::eof; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes > 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +std::size_t sync_write(int d, state_type state, const buf* bufs, + std::size_t count, bool all_empty, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a stream is a no-op. + if (all_empty) + { + ec = boost::system::error_code(); + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + errno = 0; + signed_size_type bytes = error_wrapper(::writev( + d, bufs, static_cast(count)), ec); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_write(d, 0, ec) < 0) + return 0; + } +} + +bool non_blocking_write(int d, const buf* bufs, std::size_t count, + boost::system::error_code& ec, std::size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + errno = 0; + signed_size_type bytes = error_wrapper(::writev( + d, bufs, static_cast(count)), ec); + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +int ioctl(int d, state_type& state, long cmd, + ioctl_arg_type* arg, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return -1; + } + + errno = 0; + int result = error_wrapper(::ioctl(d, cmd, arg), ec); + + if (result >= 0) + { + ec = boost::system::error_code(); + + // When updating the non-blocking mode we always perform the ioctl syscall, + // even if the flags would otherwise indicate that the descriptor is + // already in the correct state. This ensures that the underlying + // descriptor is put into the state that has been requested by the user. If + // the ioctl syscall was successful then we need to update the flags to + // match. + if (cmd == static_cast(FIONBIO)) + { + if (*arg) + { + state |= user_set_non_blocking; + } + else + { + // Clearing the non-blocking mode always overrides any internally-set + // non-blocking flag. Any subsequent asynchronous operations will need + // to re-enable non-blocking I/O. + state &= ~(user_set_non_blocking | internal_non_blocking); + } + } + } + + return result; +} + +int fcntl(int d, int cmd, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return -1; + } + + errno = 0; + int result = error_wrapper(::fcntl(d, cmd), ec); + if (result != -1) + ec = boost::system::error_code(); + return result; +} + +int fcntl(int d, int cmd, long arg, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return -1; + } + + errno = 0; + int result = error_wrapper(::fcntl(d, cmd, arg), ec); + if (result != -1) + ec = boost::system::error_code(); + return result; +} + +int poll_read(int d, state_type state, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return -1; + } + + pollfd fds; + fds.fd = d; + fds.events = POLLIN; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : -1; + errno = 0; + int result = error_wrapper(::poll(&fds, 1, timeout), ec); + if (result == 0) + ec = (state & user_set_non_blocking) + ? boost::asio::error::would_block : boost::system::error_code(); + else if (result > 0) + ec = boost::system::error_code(); + return result; +} + +int poll_write(int d, state_type state, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return -1; + } + + pollfd fds; + fds.fd = d; + fds.events = POLLOUT; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : -1; + errno = 0; + int result = error_wrapper(::poll(&fds, 1, timeout), ec); + if (result == 0) + ec = (state & user_set_non_blocking) + ? boost::asio::error::would_block : boost::system::error_code(); + else if (result > 0) + ec = boost::system::error_code(); + return result; +} + +int poll_error(int d, state_type state, boost::system::error_code& ec) +{ + if (d == -1) + { + ec = boost::asio::error::bad_descriptor; + return -1; + } + + pollfd fds; + fds.fd = d; + fds.events = POLLPRI | POLLERR | POLLHUP; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : -1; + errno = 0; + int result = error_wrapper(::poll(&fds, 1, timeout), ec); + if (result == 0) + ec = (state & user_set_non_blocking) + ? boost::asio::error::would_block : boost::system::error_code(); + else if (result > 0) + ec = boost::system::error_code(); + return result; +} + +} // namespace descriptor_ops +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP diff --git a/boost/asio/detail/impl/dev_poll_reactor.hpp b/boost/asio/detail/impl/dev_poll_reactor.hpp new file mode 100644 index 0000000..87dd20a --- /dev/null +++ b/boost/asio/detail/impl/dev_poll_reactor.hpp @@ -0,0 +1,93 @@ +// +// detail/impl/dev_poll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP +#define BOOST_ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_DEV_POLL) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +void dev_poll_reactor::add_timer_queue(timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +template +void dev_poll_reactor::remove_timer_queue(timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void dev_poll_reactor::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + scheduler_.post_immediate_completion(op, false); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + scheduler_.work_started(); + if (earliest) + interrupter_.interrupt(); +} + +template +std::size_t dev_poll_reactor::cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + lock.unlock(); + scheduler_.post_deferred_completions(ops); + return n; +} + +template +void dev_poll_reactor::move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& target, + typename timer_queue::per_timer_data& source) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + queue.cancel_timer(target, ops); + queue.move_timer(target, source); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_DEV_POLL) + +#endif // BOOST_ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP diff --git a/boost/asio/detail/impl/dev_poll_reactor.ipp b/boost/asio/detail/impl/dev_poll_reactor.ipp new file mode 100644 index 0000000..807741d --- /dev/null +++ b/boost/asio/detail/impl/dev_poll_reactor.ipp @@ -0,0 +1,448 @@ +// +// detail/impl/dev_poll_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP +#define BOOST_ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_DEV_POLL) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +dev_poll_reactor::dev_poll_reactor(boost::asio::execution_context& ctx) + : boost::asio::detail::execution_context_service_base(ctx), + scheduler_(use_service(ctx)), + mutex_(), + dev_poll_fd_(do_dev_poll_create()), + interrupter_(), + shutdown_(false) +{ + // Add the interrupter's descriptor to /dev/poll. + ::pollfd ev = { 0, 0, 0 }; + ev.fd = interrupter_.read_descriptor(); + ev.events = POLLIN | POLLERR; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); +} + +dev_poll_reactor::~dev_poll_reactor() +{ + shutdown(); + ::close(dev_poll_fd_); +} + +void dev_poll_reactor::shutdown() +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + op_queue ops; + + for (int i = 0; i < max_ops; ++i) + op_queue_[i].get_all_operations(ops); + + timer_queues_.get_all_timers(ops); + + scheduler_.abandon_operations(ops); +} + +void dev_poll_reactor::notify_fork( + boost::asio::execution_context::fork_event fork_ev) +{ + if (fork_ev == boost::asio::execution_context::fork_child) + { + detail::mutex::scoped_lock lock(mutex_); + + if (dev_poll_fd_ != -1) + ::close(dev_poll_fd_); + dev_poll_fd_ = -1; + dev_poll_fd_ = do_dev_poll_create(); + + interrupter_.recreate(); + + // Add the interrupter's descriptor to /dev/poll. + ::pollfd ev = { 0, 0, 0 }; + ev.fd = interrupter_.read_descriptor(); + ev.events = POLLIN | POLLERR; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); + + // Re-register all descriptors with /dev/poll. The changes will be written + // to the /dev/poll descriptor the next time the reactor is run. + for (int i = 0; i < max_ops; ++i) + { + reactor_op_queue::iterator iter = op_queue_[i].begin(); + reactor_op_queue::iterator end = op_queue_[i].end(); + for (; iter != end; ++iter) + { + ::pollfd& pending_ev = add_pending_event_change(iter->first); + pending_ev.events |= POLLERR | POLLHUP; + switch (i) + { + case read_op: pending_ev.events |= POLLIN; break; + case write_op: pending_ev.events |= POLLOUT; break; + case except_op: pending_ev.events |= POLLPRI; break; + default: break; + } + } + } + interrupter_.interrupt(); + } +} + +void dev_poll_reactor::init_task() +{ + scheduler_.init_task(); +} + +int dev_poll_reactor::register_descriptor(socket_type, per_descriptor_data&) +{ + return 0; +} + +int dev_poll_reactor::register_internal_descriptor(int op_type, + socket_type descriptor, per_descriptor_data&, reactor_op* op) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + op_queue_[op_type].enqueue_operation(descriptor, op); + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLERR | POLLHUP; + switch (op_type) + { + case read_op: ev.events |= POLLIN; break; + case write_op: ev.events |= POLLOUT; break; + case except_op: ev.events |= POLLPRI; break; + default: break; + } + interrupter_.interrupt(); + + return 0; +} + +void dev_poll_reactor::move_descriptor(socket_type, + dev_poll_reactor::per_descriptor_data&, + dev_poll_reactor::per_descriptor_data&) +{ +} + +void dev_poll_reactor::start_op(int op_type, socket_type descriptor, + dev_poll_reactor::per_descriptor_data&, reactor_op* op, + bool is_continuation, bool allow_speculative) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + post_immediate_completion(op, is_continuation); + return; + } + + if (allow_speculative) + { + if (op_type != read_op || !op_queue_[except_op].has_operation(descriptor)) + { + if (!op_queue_[op_type].has_operation(descriptor)) + { + if (op->perform()) + { + lock.unlock(); + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + } + } + } + + bool first = op_queue_[op_type].enqueue_operation(descriptor, op); + scheduler_.work_started(); + if (first) + { + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLERR | POLLHUP; + if (op_type == read_op + || op_queue_[read_op].has_operation(descriptor)) + ev.events |= POLLIN; + if (op_type == write_op + || op_queue_[write_op].has_operation(descriptor)) + ev.events |= POLLOUT; + if (op_type == except_op + || op_queue_[except_op].has_operation(descriptor)) + ev.events |= POLLPRI; + interrupter_.interrupt(); + } +} + +void dev_poll_reactor::cancel_ops(socket_type descriptor, + dev_poll_reactor::per_descriptor_data&) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); +} + +void dev_poll_reactor::deregister_descriptor(socket_type descriptor, + dev_poll_reactor::per_descriptor_data&, bool) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // Remove the descriptor from /dev/poll. + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLREMOVE; + interrupter_.interrupt(); + + // Cancel any outstanding operations associated with the descriptor. + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); +} + +void dev_poll_reactor::deregister_internal_descriptor( + socket_type descriptor, dev_poll_reactor::per_descriptor_data&) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // Remove the descriptor from /dev/poll. Since this function is only called + // during a fork, we can apply the change immediately. + ::pollfd ev = { 0, 0, 0 }; + ev.fd = descriptor; + ev.events = POLLREMOVE; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); + + // Destroy all operations associated with the descriptor. + op_queue ops; + boost::system::error_code ec; + for (int i = 0; i < max_ops; ++i) + op_queue_[i].cancel_operations(descriptor, ops, ec); +} + +void dev_poll_reactor::cleanup_descriptor_data( + dev_poll_reactor::per_descriptor_data&) +{ +} + +void dev_poll_reactor::run(long usec, op_queue& ops) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // We can return immediately if there's no work to do and the reactor is + // not supposed to block. + if (usec == 0 && op_queue_[read_op].empty() && op_queue_[write_op].empty() + && op_queue_[except_op].empty() && timer_queues_.all_empty()) + return; + + // Write the pending event registration changes to the /dev/poll descriptor. + std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size(); + if (events_size > 0) + { + errno = 0; + int result = ::write(dev_poll_fd_, + &pending_event_changes_[0], events_size); + if (result != static_cast(events_size)) + { + boost::system::error_code ec = boost::system::error_code( + errno, boost::asio::error::get_system_category()); + for (std::size_t i = 0; i < pending_event_changes_.size(); ++i) + { + int descriptor = pending_event_changes_[i].fd; + for (int j = 0; j < max_ops; ++j) + op_queue_[j].cancel_operations(descriptor, ops, ec); + } + } + pending_event_changes_.clear(); + pending_event_change_index_.clear(); + } + + // Calculate timeout. + int timeout; + if (usec == 0) + timeout = 0; + else + { + timeout = (usec < 0) ? -1 : ((usec - 1) / 1000 + 1); + timeout = get_timeout(timeout); + } + lock.unlock(); + + // Block on the /dev/poll descriptor. + ::pollfd events[128] = { { 0, 0, 0 } }; + ::dvpoll dp = { 0, 0, 0 }; + dp.dp_fds = events; + dp.dp_nfds = 128; + dp.dp_timeout = timeout; + int num_events = ::ioctl(dev_poll_fd_, DP_POLL, &dp); + + lock.lock(); + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + int descriptor = events[i].fd; + if (descriptor == interrupter_.read_descriptor()) + { + interrupter_.reset(); + } + else + { + bool more_reads = false; + bool more_writes = false; + bool more_except = false; + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + if (events[i].events & (POLLPRI | POLLERR | POLLHUP)) + more_except = + op_queue_[except_op].perform_operations(descriptor, ops); + else + more_except = op_queue_[except_op].has_operation(descriptor); + + if (events[i].events & (POLLIN | POLLERR | POLLHUP)) + more_reads = op_queue_[read_op].perform_operations(descriptor, ops); + else + more_reads = op_queue_[read_op].has_operation(descriptor); + + if (events[i].events & (POLLOUT | POLLERR | POLLHUP)) + more_writes = op_queue_[write_op].perform_operations(descriptor, ops); + else + more_writes = op_queue_[write_op].has_operation(descriptor); + + if ((events[i].events & (POLLERR | POLLHUP)) != 0 + && !more_except && !more_reads && !more_writes) + { + // If we have an event and no operations associated with the + // descriptor then we need to delete the descriptor from /dev/poll. + // The poll operation can produce POLLHUP or POLLERR events when there + // is no operation pending, so if we do not remove the descriptor we + // can end up in a tight polling loop. + ::pollfd ev = { 0, 0, 0 }; + ev.fd = descriptor; + ev.events = POLLREMOVE; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); + } + else + { + ::pollfd ev = { 0, 0, 0 }; + ev.fd = descriptor; + ev.events = POLLERR | POLLHUP; + if (more_reads) + ev.events |= POLLIN; + if (more_writes) + ev.events |= POLLOUT; + if (more_except) + ev.events |= POLLPRI; + ev.revents = 0; + int result = ::write(dev_poll_fd_, &ev, sizeof(ev)); + if (result != sizeof(ev)) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + for (int j = 0; j < max_ops; ++j) + op_queue_[j].cancel_operations(descriptor, ops, ec); + } + } + } + } + timer_queues_.get_ready_timers(ops); +} + +void dev_poll_reactor::interrupt() +{ + interrupter_.interrupt(); +} + +int dev_poll_reactor::do_dev_poll_create() +{ + int fd = ::open("/dev/poll", O_RDWR); + if (fd == -1) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "/dev/poll"); + } + return fd; +} + +void dev_poll_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void dev_poll_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +int dev_poll_reactor::get_timeout(int msec) +{ + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + const int max_msec = 5 * 60 * 1000; + return timer_queues_.wait_duration_msec( + (msec < 0 || max_msec < msec) ? max_msec : msec); +} + +void dev_poll_reactor::cancel_ops_unlocked(socket_type descriptor, + const boost::system::error_code& ec) +{ + bool need_interrupt = false; + op_queue ops; + for (int i = 0; i < max_ops; ++i) + need_interrupt = op_queue_[i].cancel_operations( + descriptor, ops, ec) || need_interrupt; + scheduler_.post_deferred_completions(ops); + if (need_interrupt) + interrupter_.interrupt(); +} + +::pollfd& dev_poll_reactor::add_pending_event_change(int descriptor) +{ + hash_map::iterator iter + = pending_event_change_index_.find(descriptor); + if (iter == pending_event_change_index_.end()) + { + std::size_t index = pending_event_changes_.size(); + pending_event_changes_.reserve(pending_event_changes_.size() + 1); + pending_event_change_index_.insert(std::make_pair(descriptor, index)); + pending_event_changes_.push_back(::pollfd()); + pending_event_changes_[index].fd = descriptor; + pending_event_changes_[index].revents = 0; + return pending_event_changes_[index]; + } + else + { + return pending_event_changes_[iter->second]; + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_DEV_POLL) + +#endif // BOOST_ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP diff --git a/boost/asio/detail/impl/epoll_reactor.hpp b/boost/asio/detail/impl/epoll_reactor.hpp new file mode 100644 index 0000000..15968a3 --- /dev/null +++ b/boost/asio/detail/impl/epoll_reactor.hpp @@ -0,0 +1,91 @@ +// +// detail/impl/epoll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP +#define BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if defined(BOOST_ASIO_HAS_EPOLL) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +void epoll_reactor::add_timer_queue(timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +template +void epoll_reactor::remove_timer_queue(timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void epoll_reactor::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op) +{ + mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + scheduler_.post_immediate_completion(op, false); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + scheduler_.work_started(); + if (earliest) + update_timeout(); +} + +template +std::size_t epoll_reactor::cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled) +{ + mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + lock.unlock(); + scheduler_.post_deferred_completions(ops); + return n; +} + +template +void epoll_reactor::move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& target, + typename timer_queue::per_timer_data& source) +{ + mutex::scoped_lock lock(mutex_); + op_queue ops; + queue.cancel_timer(target, ops); + queue.move_timer(target, source); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_EPOLL) + +#endif // BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP diff --git a/boost/asio/detail/impl/epoll_reactor.ipp b/boost/asio/detail/impl/epoll_reactor.ipp new file mode 100644 index 0000000..b1e1b39 --- /dev/null +++ b/boost/asio/detail/impl/epoll_reactor.ipp @@ -0,0 +1,789 @@ +// +// detail/impl/epoll_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP +#define BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_EPOLL) + +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_TIMERFD) +# include +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + +#include + +namespace boost { +namespace asio { +namespace detail { + +epoll_reactor::epoll_reactor(boost::asio::execution_context& ctx) + : execution_context_service_base(ctx), + scheduler_(use_service(ctx)), + mutex_(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_REGISTRATION, scheduler_.concurrency_hint())), + interrupter_(), + epoll_fd_(do_epoll_create()), + timer_fd_(do_timerfd_create()), + shutdown_(false), + registered_descriptors_mutex_(mutex_.enabled()) +{ + // Add the interrupter's descriptor to epoll. + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLET; + ev.data.ptr = &interrupter_; + epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev); + interrupter_.interrupt(); + + // Add the timer descriptor to epoll. + if (timer_fd_ != -1) + { + ev.events = EPOLLIN | EPOLLERR; + ev.data.ptr = &timer_fd_; + epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev); + } +} + +epoll_reactor::~epoll_reactor() +{ + if (epoll_fd_ != -1) + close(epoll_fd_); + if (timer_fd_ != -1) + close(timer_fd_); +} + +void epoll_reactor::shutdown() +{ + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + op_queue ops; + + while (descriptor_state* state = registered_descriptors_.first()) + { + for (int i = 0; i < max_ops; ++i) + ops.push(state->op_queue_[i]); + state->shutdown_ = true; + registered_descriptors_.free(state); + } + + timer_queues_.get_all_timers(ops); + + scheduler_.abandon_operations(ops); +} + +void epoll_reactor::notify_fork( + boost::asio::execution_context::fork_event fork_ev) +{ + if (fork_ev == boost::asio::execution_context::fork_child) + { + if (epoll_fd_ != -1) + ::close(epoll_fd_); + epoll_fd_ = -1; + epoll_fd_ = do_epoll_create(); + + if (timer_fd_ != -1) + ::close(timer_fd_); + timer_fd_ = -1; + timer_fd_ = do_timerfd_create(); + + interrupter_.recreate(); + + // Add the interrupter's descriptor to epoll. + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLET; + ev.data.ptr = &interrupter_; + epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev); + interrupter_.interrupt(); + + // Add the timer descriptor to epoll. + if (timer_fd_ != -1) + { + ev.events = EPOLLIN | EPOLLERR; + ev.data.ptr = &timer_fd_; + epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev); + } + + update_timeout(); + + // Re-register all descriptors with epoll. + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + for (descriptor_state* state = registered_descriptors_.first(); + state != 0; state = state->next_) + { + ev.events = state->registered_events_; + ev.data.ptr = state; + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, state->descriptor_, &ev); + if (result != 0) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "epoll re-registration"); + } + } + } +} + +void epoll_reactor::init_task() +{ + scheduler_.init_task(); +} + +int epoll_reactor::register_descriptor(socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data) +{ + descriptor_data = allocate_descriptor_state(); + + BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(( + context(), static_cast(descriptor), + reinterpret_cast(descriptor_data))); + + { + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + descriptor_data->reactor_ = this; + descriptor_data->descriptor_ = descriptor; + descriptor_data->shutdown_ = false; + for (int i = 0; i < max_ops; ++i) + descriptor_data->try_speculative_[i] = true; + } + + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLPRI | EPOLLET; + descriptor_data->registered_events_ = ev.events; + ev.data.ptr = descriptor_data; + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); + if (result != 0) + { + if (errno == EPERM) + { + // This file descriptor type is not supported by epoll. However, if it is + // a regular file then operations on it will not block. We will allow + // this descriptor to be used and fail later if an operation on it would + // otherwise require a trip through the reactor. + descriptor_data->registered_events_ = 0; + return 0; + } + return errno; + } + + return 0; +} + +int epoll_reactor::register_internal_descriptor( + int op_type, socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op) +{ + descriptor_data = allocate_descriptor_state(); + + BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(( + context(), static_cast(descriptor), + reinterpret_cast(descriptor_data))); + + { + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + descriptor_data->reactor_ = this; + descriptor_data->descriptor_ = descriptor; + descriptor_data->shutdown_ = false; + descriptor_data->op_queue_[op_type].push(op); + for (int i = 0; i < max_ops; ++i) + descriptor_data->try_speculative_[i] = true; + } + + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLPRI | EPOLLET; + descriptor_data->registered_events_ = ev.events; + ev.data.ptr = descriptor_data; + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); + if (result != 0) + return errno; + + return 0; +} + +void epoll_reactor::move_descriptor(socket_type, + epoll_reactor::per_descriptor_data& target_descriptor_data, + epoll_reactor::per_descriptor_data& source_descriptor_data) +{ + target_descriptor_data = source_descriptor_data; + source_descriptor_data = 0; +} + +void epoll_reactor::start_op(int op_type, socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative) +{ + if (!descriptor_data) + { + op->ec_ = boost::asio::error::bad_descriptor; + post_immediate_completion(op, is_continuation); + return; + } + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (descriptor_data->shutdown_) + { + post_immediate_completion(op, is_continuation); + return; + } + + if (descriptor_data->op_queue_[op_type].empty()) + { + if (allow_speculative + && (op_type != read_op + || descriptor_data->op_queue_[except_op].empty())) + { + if (descriptor_data->try_speculative_[op_type]) + { + if (reactor_op::status status = op->perform()) + { + if (status == reactor_op::done_and_exhausted) + if (descriptor_data->registered_events_ != 0) + descriptor_data->try_speculative_[op_type] = false; + descriptor_lock.unlock(); + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + } + + if (descriptor_data->registered_events_ == 0) + { + op->ec_ = boost::asio::error::operation_not_supported; + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + + if (op_type == write_op) + { + if ((descriptor_data->registered_events_ & EPOLLOUT) == 0) + { + epoll_event ev = { 0, { 0 } }; + ev.events = descriptor_data->registered_events_ | EPOLLOUT; + ev.data.ptr = descriptor_data; + if (epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev) == 0) + { + descriptor_data->registered_events_ |= ev.events; + } + else + { + op->ec_ = boost::system::error_code(errno, + boost::asio::error::get_system_category()); + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + } + } + } + else if (descriptor_data->registered_events_ == 0) + { + op->ec_ = boost::asio::error::operation_not_supported; + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + else + { + if (op_type == write_op) + { + descriptor_data->registered_events_ |= EPOLLOUT; + } + + epoll_event ev = { 0, { 0 } }; + ev.events = descriptor_data->registered_events_; + ev.data.ptr = descriptor_data; + epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); + } + } + + descriptor_data->op_queue_[op_type].push(op); + scheduler_.work_started(); +} + +void epoll_reactor::cancel_ops(socket_type, + epoll_reactor::per_descriptor_data& descriptor_data) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_lock.unlock(); + + scheduler_.post_deferred_completions(ops); +} + +void epoll_reactor::deregister_descriptor(socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data, bool closing) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (!descriptor_data->shutdown_) + { + if (closing) + { + // The descriptor will be automatically removed from the epoll set when + // it is closed. + } + else if (descriptor_data->registered_events_ != 0) + { + epoll_event ev = { 0, { 0 } }; + epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev); + } + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_data->descriptor_ = -1; + descriptor_data->shutdown_ = true; + + descriptor_lock.unlock(); + + BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(( + context(), static_cast(descriptor), + reinterpret_cast(descriptor_data))); + + scheduler_.post_deferred_completions(ops); + + // Leave descriptor_data set so that it will be freed by the subsequent + // call to cleanup_descriptor_data. + } + else + { + // We are shutting down, so prevent cleanup_descriptor_data from freeing + // the descriptor_data object and let the destructor free it instead. + descriptor_data = 0; + } +} + +void epoll_reactor::deregister_internal_descriptor(socket_type descriptor, + epoll_reactor::per_descriptor_data& descriptor_data) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (!descriptor_data->shutdown_) + { + epoll_event ev = { 0, { 0 } }; + epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev); + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + ops.push(descriptor_data->op_queue_[i]); + + descriptor_data->descriptor_ = -1; + descriptor_data->shutdown_ = true; + + descriptor_lock.unlock(); + + BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(( + context(), static_cast(descriptor), + reinterpret_cast(descriptor_data))); + + // Leave descriptor_data set so that it will be freed by the subsequent + // call to cleanup_descriptor_data. + } + else + { + // We are shutting down, so prevent cleanup_descriptor_data from freeing + // the descriptor_data object and let the destructor free it instead. + descriptor_data = 0; + } +} + +void epoll_reactor::cleanup_descriptor_data( + per_descriptor_data& descriptor_data) +{ + if (descriptor_data) + { + free_descriptor_state(descriptor_data); + descriptor_data = 0; + } +} + +void epoll_reactor::run(long usec, op_queue& ops) +{ + // This code relies on the fact that the scheduler queues the reactor task + // behind all descriptor operations generated by this function. This means, + // that by the time we reach this point, any previously returned descriptor + // operations have already been dequeued. Therefore it is now safe for us to + // reuse and return them for the scheduler to queue again. + + // Calculate timeout. Check the timer queues only if timerfd is not in use. + int timeout; + if (usec == 0) + timeout = 0; + else + { + timeout = (usec < 0) ? -1 : ((usec - 1) / 1000 + 1); + if (timer_fd_ == -1) + { + mutex::scoped_lock lock(mutex_); + timeout = get_timeout(timeout); + } + } + + // Block on the epoll descriptor. + epoll_event events[128]; + int num_events = epoll_wait(epoll_fd_, events, 128, timeout); + +#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + // Trace the waiting events. + for (int i = 0; i < num_events; ++i) + { + void* ptr = events[i].data.ptr; + if (ptr == &interrupter_) + { + // Ignore. + } +# if defined(BOOST_ASIO_HAS_TIMERFD) + else if (ptr == &timer_fd_) + { + // Ignore. + } +# endif // defined(BOOST_ASIO_HAS_TIMERFD) + else + { + unsigned event_mask = 0; + if ((events[i].events & EPOLLIN) != 0) + event_mask |= BOOST_ASIO_HANDLER_REACTOR_READ_EVENT; + if ((events[i].events & EPOLLOUT)) + event_mask |= BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT; + if ((events[i].events & (EPOLLERR | EPOLLHUP)) != 0) + event_mask |= BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT; + BOOST_ASIO_HANDLER_REACTOR_EVENTS((context(), + reinterpret_cast(ptr), event_mask)); + } + } +#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + +#if defined(BOOST_ASIO_HAS_TIMERFD) + bool check_timers = (timer_fd_ == -1); +#else // defined(BOOST_ASIO_HAS_TIMERFD) + bool check_timers = true; +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + void* ptr = events[i].data.ptr; + if (ptr == &interrupter_) + { + // No need to reset the interrupter since we're leaving the descriptor + // in a ready-to-read state and relying on edge-triggered notifications + // to make it so that we only get woken up when the descriptor's epoll + // registration is updated. + +#if defined(BOOST_ASIO_HAS_TIMERFD) + if (timer_fd_ == -1) + check_timers = true; +#else // defined(BOOST_ASIO_HAS_TIMERFD) + check_timers = true; +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + } +#if defined(BOOST_ASIO_HAS_TIMERFD) + else if (ptr == &timer_fd_) + { + check_timers = true; + } +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + else + { + // The descriptor operation doesn't count as work in and of itself, so we + // don't call work_started() here. This still allows the scheduler to + // stop if the only remaining operations are descriptor operations. + descriptor_state* descriptor_data = static_cast(ptr); + if (!ops.is_enqueued(descriptor_data)) + { + descriptor_data->set_ready_events(events[i].events); + ops.push(descriptor_data); + } + else + { + descriptor_data->add_ready_events(events[i].events); + } + } + } + + if (check_timers) + { + mutex::scoped_lock common_lock(mutex_); + timer_queues_.get_ready_timers(ops); + +#if defined(BOOST_ASIO_HAS_TIMERFD) + if (timer_fd_ != -1) + { + itimerspec new_timeout; + itimerspec old_timeout; + int flags = get_timeout(new_timeout); + timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); + } +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + } +} + +void epoll_reactor::interrupt() +{ + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLIN | EPOLLERR | EPOLLET; + ev.data.ptr = &interrupter_; + epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev); +} + +int epoll_reactor::do_epoll_create() +{ +#if defined(EPOLL_CLOEXEC) + int fd = epoll_create1(EPOLL_CLOEXEC); +#else // defined(EPOLL_CLOEXEC) + int fd = -1; + errno = EINVAL; +#endif // defined(EPOLL_CLOEXEC) + + if (fd == -1 && (errno == EINVAL || errno == ENOSYS)) + { + fd = epoll_create(epoll_size); + if (fd != -1) + ::fcntl(fd, F_SETFD, FD_CLOEXEC); + } + + if (fd == -1) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "epoll"); + } + + return fd; +} + +int epoll_reactor::do_timerfd_create() +{ +#if defined(BOOST_ASIO_HAS_TIMERFD) +# if defined(TFD_CLOEXEC) + int fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); +# else // defined(TFD_CLOEXEC) + int fd = -1; + errno = EINVAL; +# endif // defined(TFD_CLOEXEC) + + if (fd == -1 && errno == EINVAL) + { + fd = timerfd_create(CLOCK_MONOTONIC, 0); + if (fd != -1) + ::fcntl(fd, F_SETFD, FD_CLOEXEC); + } + + return fd; +#else // defined(BOOST_ASIO_HAS_TIMERFD) + return -1; +#endif // defined(BOOST_ASIO_HAS_TIMERFD) +} + +epoll_reactor::descriptor_state* epoll_reactor::allocate_descriptor_state() +{ + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + return registered_descriptors_.alloc(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_IO, scheduler_.concurrency_hint())); +} + +void epoll_reactor::free_descriptor_state(epoll_reactor::descriptor_state* s) +{ + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + registered_descriptors_.free(s); +} + +void epoll_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void epoll_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +void epoll_reactor::update_timeout() +{ +#if defined(BOOST_ASIO_HAS_TIMERFD) + if (timer_fd_ != -1) + { + itimerspec new_timeout; + itimerspec old_timeout; + int flags = get_timeout(new_timeout); + timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); + return; + } +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + interrupt(); +} + +int epoll_reactor::get_timeout(int msec) +{ + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + const int max_msec = 5 * 60 * 1000; + return timer_queues_.wait_duration_msec( + (msec < 0 || max_msec < msec) ? max_msec : msec); +} + +#if defined(BOOST_ASIO_HAS_TIMERFD) +int epoll_reactor::get_timeout(itimerspec& ts) +{ + ts.it_interval.tv_sec = 0; + ts.it_interval.tv_nsec = 0; + + long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); + ts.it_value.tv_sec = usec / 1000000; + ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1; + + return usec ? 0 : TFD_TIMER_ABSTIME; +} +#endif // defined(BOOST_ASIO_HAS_TIMERFD) + +struct epoll_reactor::perform_io_cleanup_on_block_exit +{ + explicit perform_io_cleanup_on_block_exit(epoll_reactor* r) + : reactor_(r), first_op_(0) + { + } + + ~perform_io_cleanup_on_block_exit() + { + if (first_op_) + { + // Post the remaining completed operations for invocation. + if (!ops_.empty()) + reactor_->scheduler_.post_deferred_completions(ops_); + + // A user-initiated operation has completed, but there's no need to + // explicitly call work_finished() here. Instead, we'll take advantage of + // the fact that the scheduler will call work_finished() once we return. + } + else + { + // No user-initiated operations have completed, so we need to compensate + // for the work_finished() call that the scheduler will make once this + // operation returns. + reactor_->scheduler_.compensating_work_started(); + } + } + + epoll_reactor* reactor_; + op_queue ops_; + operation* first_op_; +}; + +epoll_reactor::descriptor_state::descriptor_state(bool locking) + : operation(&epoll_reactor::descriptor_state::do_complete), + mutex_(locking) +{ +} + +operation* epoll_reactor::descriptor_state::perform_io(uint32_t events) +{ + mutex_.lock(); + perform_io_cleanup_on_block_exit io_cleanup(reactor_); + mutex::scoped_lock descriptor_lock(mutex_, mutex::scoped_lock::adopt_lock); + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI }; + for (int j = max_ops - 1; j >= 0; --j) + { + if (events & (flag[j] | EPOLLERR | EPOLLHUP)) + { + try_speculative_[j] = true; + while (reactor_op* op = op_queue_[j].front()) + { + if (reactor_op::status status = op->perform()) + { + op_queue_[j].pop(); + io_cleanup.ops_.push(op); + if (status == reactor_op::done_and_exhausted) + { + try_speculative_[j] = false; + break; + } + } + else + break; + } + } + } + + // The first operation will be returned for completion now. The others will + // be posted for later by the io_cleanup object's destructor. + io_cleanup.first_op_ = io_cleanup.ops_.front(); + io_cleanup.ops_.pop(); + return io_cleanup.first_op_; +} + +void epoll_reactor::descriptor_state::do_complete( + void* owner, operation* base, + const boost::system::error_code& ec, std::size_t bytes_transferred) +{ + if (owner) + { + descriptor_state* descriptor_data = static_cast(base); + uint32_t events = static_cast(bytes_transferred); + if (operation* op = descriptor_data->perform_io(events)) + { + op->complete(owner, ec, 0); + } + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_EPOLL) + +#endif // BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP diff --git a/boost/asio/detail/impl/eventfd_select_interrupter.ipp b/boost/asio/detail/impl/eventfd_select_interrupter.ipp new file mode 100644 index 0000000..38d4b2a --- /dev/null +++ b/boost/asio/detail/impl/eventfd_select_interrupter.ipp @@ -0,0 +1,167 @@ +// +// detail/impl/eventfd_select_interrupter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Roelof Naude (roelof.naude at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP +#define BOOST_ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_EVENTFD) + +#include +#include +#include +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +# include +#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +# include +#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +eventfd_select_interrupter::eventfd_select_interrupter() +{ + open_descriptors(); +} + +void eventfd_select_interrupter::open_descriptors() +{ +#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + write_descriptor_ = read_descriptor_ = syscall(__NR_eventfd, 0); + if (read_descriptor_ != -1) + { + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC); + } +#else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 +# if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK) + write_descriptor_ = read_descriptor_ = + ::eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); +# else // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK) + errno = EINVAL; + write_descriptor_ = read_descriptor_ = -1; +# endif // defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK) + if (read_descriptor_ == -1 && errno == EINVAL) + { + write_descriptor_ = read_descriptor_ = ::eventfd(0, 0); + if (read_descriptor_ != -1) + { + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC); + } + } +#endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 + + if (read_descriptor_ == -1) + { + int pipe_fds[2]; + if (pipe(pipe_fds) == 0) + { + read_descriptor_ = pipe_fds[0]; + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC); + write_descriptor_ = pipe_fds[1]; + ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); + ::fcntl(write_descriptor_, F_SETFD, FD_CLOEXEC); + } + else + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "eventfd_select_interrupter"); + } + } +} + +eventfd_select_interrupter::~eventfd_select_interrupter() +{ + close_descriptors(); +} + +void eventfd_select_interrupter::close_descriptors() +{ + if (write_descriptor_ != -1 && write_descriptor_ != read_descriptor_) + ::close(write_descriptor_); + if (read_descriptor_ != -1) + ::close(read_descriptor_); +} + +void eventfd_select_interrupter::recreate() +{ + close_descriptors(); + + write_descriptor_ = -1; + read_descriptor_ = -1; + + open_descriptors(); +} + +void eventfd_select_interrupter::interrupt() +{ + uint64_t counter(1UL); + int result = ::write(write_descriptor_, &counter, sizeof(uint64_t)); + (void)result; +} + +bool eventfd_select_interrupter::reset() +{ + if (write_descriptor_ == read_descriptor_) + { + for (;;) + { + // Only perform one read. The kernel maintains an atomic counter. + uint64_t counter(0); + errno = 0; + int bytes_read = ::read(read_descriptor_, &counter, sizeof(uint64_t)); + if (bytes_read < 0 && errno == EINTR) + continue; + bool was_interrupted = (bytes_read > 0); + return was_interrupted; + } + } + else + { + for (;;) + { + // Clear all data from the pipe. + char data[1024]; + int bytes_read = ::read(read_descriptor_, data, sizeof(data)); + if (bytes_read < 0 && errno == EINTR) + continue; + bool was_interrupted = (bytes_read > 0); + while (bytes_read == sizeof(data)) + bytes_read = ::read(read_descriptor_, data, sizeof(data)); + return was_interrupted; + } + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_EVENTFD) + +#endif // BOOST_ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP diff --git a/boost/asio/detail/impl/handler_tracking.ipp b/boost/asio/detail/impl/handler_tracking.ipp new file mode 100644 index 0000000..c873a50 --- /dev/null +++ b/boost/asio/detail/impl/handler_tracking.ipp @@ -0,0 +1,360 @@ +// +// detail/impl/handler_tracking.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP +#define BOOST_ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_CUSTOM_HANDLER_TRACKING) + +// The handler tracking implementation is provided by the user-specified header. + +#elif defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) +# include +#elif defined(BOOST_ASIO_HAS_CHRONO) +# include +# include +# include +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +# include +#elif !defined(BOOST_ASIO_WINDOWS) +# include +#endif // !defined(BOOST_ASIO_WINDOWS) + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct handler_tracking_timestamp +{ + uint64_t seconds; + uint64_t microseconds; + + handler_tracking_timestamp() + { +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); + boost::posix_time::time_duration now = + boost::posix_time::microsec_clock::universal_time() - epoch; +#elif defined(BOOST_ASIO_HAS_CHRONO) + typedef chrono_time_traits > traits_helper; + traits_helper::posix_time_duration now( + chrono::system_clock::now().time_since_epoch()); +#endif + seconds = static_cast(now.total_seconds()); + microseconds = static_cast(now.total_microseconds() % 1000000); + } +}; + +struct handler_tracking::tracking_state +{ + static_mutex mutex_; + uint64_t next_id_; + tss_ptr* current_completion_; +}; + +handler_tracking::tracking_state* handler_tracking::get_state() +{ + static tracking_state state = { BOOST_ASIO_STATIC_MUTEX_INIT, 1, 0 }; + return &state; +} + +void handler_tracking::init() +{ + static tracking_state* state = get_state(); + + state->mutex_.init(); + + static_mutex::scoped_lock lock(state->mutex_); + if (state->current_completion_ == 0) + state->current_completion_ = new tss_ptr; +} + +void handler_tracking::creation(execution_context&, + handler_tracking::tracked_handler& h, + const char* object_type, void* object, + uintmax_t /*native_handle*/, const char* op_name) +{ + static tracking_state* state = get_state(); + + static_mutex::scoped_lock lock(state->mutex_); + h.id_ = state->next_id_++; + lock.unlock(); + + handler_tracking_timestamp timestamp; + + uint64_t current_id = 0; + if (completion* current_completion = *state->current_completion_) + current_id = current_completion->id_; + + write_line( +#if defined(BOOST_ASIO_WINDOWS) + "@asio|%I64u.%06I64u|%I64u*%I64u|%.20s@%p.%.50s\n", +#else // defined(BOOST_ASIO_WINDOWS) + "@asio|%llu.%06llu|%llu*%llu|%.20s@%p.%.50s\n", +#endif // defined(BOOST_ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + current_id, h.id_, object_type, object, op_name); +} + +handler_tracking::completion::completion( + const handler_tracking::tracked_handler& h) + : id_(h.id_), + invoked_(false), + next_(*get_state()->current_completion_) +{ + *get_state()->current_completion_ = this; +} + +handler_tracking::completion::~completion() +{ + if (id_) + { + handler_tracking_timestamp timestamp; + + write_line( +#if defined(BOOST_ASIO_WINDOWS) + "@asio|%I64u.%06I64u|%c%I64u|\n", +#else // defined(BOOST_ASIO_WINDOWS) + "@asio|%llu.%06llu|%c%llu|\n", +#endif // defined(BOOST_ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + invoked_ ? '!' : '~', id_); + } + + *get_state()->current_completion_ = next_; +} + +void handler_tracking::completion::invocation_begin() +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(BOOST_ASIO_WINDOWS) + "@asio|%I64u.%06I64u|>%I64u|\n", +#else // defined(BOOST_ASIO_WINDOWS) + "@asio|%llu.%06llu|>%llu|\n", +#endif // defined(BOOST_ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, id_); + + invoked_ = true; +} + +void handler_tracking::completion::invocation_begin( + const boost::system::error_code& ec) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(BOOST_ASIO_WINDOWS) + "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d\n", +#else // defined(BOOST_ASIO_WINDOWS) + "@asio|%llu.%06llu|>%llu|ec=%.20s:%d\n", +#endif // defined(BOOST_ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + id_, ec.category().name(), ec.value()); + + invoked_ = true; +} + +void handler_tracking::completion::invocation_begin( + const boost::system::error_code& ec, std::size_t bytes_transferred) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(BOOST_ASIO_WINDOWS) + "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,bytes_transferred=%I64u\n", +#else // defined(BOOST_ASIO_WINDOWS) + "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,bytes_transferred=%llu\n", +#endif // defined(BOOST_ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + id_, ec.category().name(), ec.value(), + static_cast(bytes_transferred)); + + invoked_ = true; +} + +void handler_tracking::completion::invocation_begin( + const boost::system::error_code& ec, int signal_number) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(BOOST_ASIO_WINDOWS) + "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,signal_number=%d\n", +#else // defined(BOOST_ASIO_WINDOWS) + "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,signal_number=%d\n", +#endif // defined(BOOST_ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + id_, ec.category().name(), ec.value(), signal_number); + + invoked_ = true; +} + +void handler_tracking::completion::invocation_begin( + const boost::system::error_code& ec, const char* arg) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(BOOST_ASIO_WINDOWS) + "@asio|%I64u.%06I64u|>%I64u|ec=%.20s:%d,%.50s\n", +#else // defined(BOOST_ASIO_WINDOWS) + "@asio|%llu.%06llu|>%llu|ec=%.20s:%d,%.50s\n", +#endif // defined(BOOST_ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + id_, ec.category().name(), ec.value(), arg); + + invoked_ = true; +} + +void handler_tracking::completion::invocation_end() +{ + if (id_) + { + handler_tracking_timestamp timestamp; + + write_line( +#if defined(BOOST_ASIO_WINDOWS) + "@asio|%I64u.%06I64u|<%I64u|\n", +#else // defined(BOOST_ASIO_WINDOWS) + "@asio|%llu.%06llu|<%llu|\n", +#endif // defined(BOOST_ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, id_); + + id_ = 0; + } +} + +void handler_tracking::operation(execution_context&, + const char* object_type, void* object, + uintmax_t /*native_handle*/, const char* op_name) +{ + static tracking_state* state = get_state(); + + handler_tracking_timestamp timestamp; + + unsigned long long current_id = 0; + if (completion* current_completion = *state->current_completion_) + current_id = current_completion->id_; + + write_line( +#if defined(BOOST_ASIO_WINDOWS) + "@asio|%I64u.%06I64u|%I64u|%.20s@%p.%.50s\n", +#else // defined(BOOST_ASIO_WINDOWS) + "@asio|%llu.%06llu|%llu|%.20s@%p.%.50s\n", +#endif // defined(BOOST_ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + current_id, object_type, object, op_name); +} + +void handler_tracking::reactor_registration(execution_context& /*context*/, + uintmax_t /*native_handle*/, uintmax_t /*registration*/) +{ +} + +void handler_tracking::reactor_deregistration(execution_context& /*context*/, + uintmax_t /*native_handle*/, uintmax_t /*registration*/) +{ +} + +void handler_tracking::reactor_events(execution_context& /*context*/, + uintmax_t /*native_handle*/, unsigned /*events*/) +{ +} + +void handler_tracking::reactor_operation( + const tracked_handler& h, const char* op_name, + const boost::system::error_code& ec) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(BOOST_ASIO_WINDOWS) + "@asio|%I64u.%06I64u|.%I64u|%s,ec=%.20s:%d\n", +#else // defined(BOOST_ASIO_WINDOWS) + "@asio|%llu.%06llu|.%llu|%s,ec=%.20s:%d\n", +#endif // defined(BOOST_ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + h.id_, op_name, ec.category().name(), ec.value()); +} + +void handler_tracking::reactor_operation( + const tracked_handler& h, const char* op_name, + const boost::system::error_code& ec, std::size_t bytes_transferred) +{ + handler_tracking_timestamp timestamp; + + write_line( +#if defined(BOOST_ASIO_WINDOWS) + "@asio|%I64u.%06I64u|.%I64u|%s,ec=%.20s:%d,bytes_transferred=%I64u\n", +#else // defined(BOOST_ASIO_WINDOWS) + "@asio|%llu.%06llu|.%llu|%s,ec=%.20s:%d,bytes_transferred=%llu\n", +#endif // defined(BOOST_ASIO_WINDOWS) + timestamp.seconds, timestamp.microseconds, + h.id_, op_name, ec.category().name(), ec.value(), + static_cast(bytes_transferred)); +} + +void handler_tracking::write_line(const char* format, ...) +{ + using namespace std; // For sprintf (or equivalent). + + va_list args; + va_start(args, format); + + char line[256] = ""; +#if defined(BOOST_ASIO_HAS_SECURE_RTL) + int length = vsprintf_s(line, sizeof(line), format, args); +#else // defined(BOOST_ASIO_HAS_SECURE_RTL) + int length = vsprintf(line, format, args); +#endif // defined(BOOST_ASIO_HAS_SECURE_RTL) + + va_end(args); + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + wchar_t wline[256] = L""; + mbstowcs_s(0, wline, sizeof(wline) / sizeof(wchar_t), line, length); + ::OutputDebugStringW(wline); +#elif defined(BOOST_ASIO_WINDOWS) + HANDLE stderr_handle = ::GetStdHandle(STD_ERROR_HANDLE); + DWORD bytes_written = 0; + ::WriteFile(stderr_handle, line, length, &bytes_written, 0); +#else // defined(BOOST_ASIO_WINDOWS) + ::write(STDERR_FILENO, line, length); +#endif // defined(BOOST_ASIO_WINDOWS) +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + +#endif // BOOST_ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP diff --git a/boost/asio/detail/impl/kqueue_reactor.hpp b/boost/asio/detail/impl/kqueue_reactor.hpp new file mode 100644 index 0000000..f4dd174 --- /dev/null +++ b/boost/asio/detail/impl/kqueue_reactor.hpp @@ -0,0 +1,95 @@ +// +// detail/impl/kqueue_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP +#define BOOST_ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_KQUEUE) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +void kqueue_reactor::add_timer_queue(timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +// Remove a timer queue from the reactor. +template +void kqueue_reactor::remove_timer_queue(timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void kqueue_reactor::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op) +{ + mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + scheduler_.post_immediate_completion(op, false); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + scheduler_.work_started(); + if (earliest) + interrupt(); +} + +template +std::size_t kqueue_reactor::cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled) +{ + mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + lock.unlock(); + scheduler_.post_deferred_completions(ops); + return n; +} + +template +void kqueue_reactor::move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& target, + typename timer_queue::per_timer_data& source) +{ + mutex::scoped_lock lock(mutex_); + op_queue ops; + queue.cancel_timer(target, ops); + queue.move_timer(target, source); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_KQUEUE) + +#endif // BOOST_ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP diff --git a/boost/asio/detail/impl/kqueue_reactor.ipp b/boost/asio/detail/impl/kqueue_reactor.ipp new file mode 100644 index 0000000..02475aa --- /dev/null +++ b/boost/asio/detail/impl/kqueue_reactor.ipp @@ -0,0 +1,568 @@ +// +// detail/impl/kqueue_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP +#define BOOST_ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_KQUEUE) + +#include +#include +#include +#include + +#include + +#if defined(__NetBSD__) +# define BOOST_ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \ + EV_SET(ev, ident, filt, flags, fflags, data, \ + reinterpret_cast(static_cast(udata))) +#else +# define BOOST_ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \ + EV_SET(ev, ident, filt, flags, fflags, data, udata) +#endif + +namespace boost { +namespace asio { +namespace detail { + +kqueue_reactor::kqueue_reactor(boost::asio::execution_context& ctx) + : execution_context_service_base(ctx), + scheduler_(use_service(ctx)), + mutex_(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_REGISTRATION, scheduler_.concurrency_hint())), + kqueue_fd_(do_kqueue_create()), + interrupter_(), + shutdown_(false), + registered_descriptors_mutex_(mutex_.enabled()) +{ + struct kevent events[1]; + BOOST_ASIO_KQUEUE_EV_SET(&events[0], interrupter_.read_descriptor(), + EVFILT_READ, EV_ADD, 0, 0, &interrupter_); + if (::kevent(kqueue_fd_, events, 1, 0, 0, 0) == -1) + { + boost::system::error_code error(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(error); + } +} + +kqueue_reactor::~kqueue_reactor() +{ + close(kqueue_fd_); +} + +void kqueue_reactor::shutdown() +{ + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + lock.unlock(); + + op_queue ops; + + while (descriptor_state* state = registered_descriptors_.first()) + { + for (int i = 0; i < max_ops; ++i) + ops.push(state->op_queue_[i]); + state->shutdown_ = true; + registered_descriptors_.free(state); + } + + timer_queues_.get_all_timers(ops); + + scheduler_.abandon_operations(ops); +} + +void kqueue_reactor::notify_fork( + boost::asio::execution_context::fork_event fork_ev) +{ + if (fork_ev == boost::asio::execution_context::fork_child) + { + // The kqueue descriptor is automatically closed in the child. + kqueue_fd_ = -1; + kqueue_fd_ = do_kqueue_create(); + + interrupter_.recreate(); + + struct kevent events[2]; + BOOST_ASIO_KQUEUE_EV_SET(&events[0], interrupter_.read_descriptor(), + EVFILT_READ, EV_ADD, 0, 0, &interrupter_); + if (::kevent(kqueue_fd_, events, 1, 0, 0, 0) == -1) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "kqueue interrupter registration"); + } + + // Re-register all descriptors with kqueue. + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + for (descriptor_state* state = registered_descriptors_.first(); + state != 0; state = state->next_) + { + if (state->num_kevents_ > 0) + { + BOOST_ASIO_KQUEUE_EV_SET(&events[0], state->descriptor_, + EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, state); + BOOST_ASIO_KQUEUE_EV_SET(&events[1], state->descriptor_, + EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, state); + if (::kevent(kqueue_fd_, events, state->num_kevents_, 0, 0, 0) == -1) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "kqueue re-registration"); + } + } + } + } +} + +void kqueue_reactor::init_task() +{ + scheduler_.init_task(); +} + +int kqueue_reactor::register_descriptor(socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data) +{ + descriptor_data = allocate_descriptor_state(); + + BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(( + context(), static_cast(descriptor), + reinterpret_cast(descriptor_data))); + + mutex::scoped_lock lock(descriptor_data->mutex_); + + descriptor_data->descriptor_ = descriptor; + descriptor_data->num_kevents_ = 0; + descriptor_data->shutdown_ = false; + + return 0; +} + +int kqueue_reactor::register_internal_descriptor( + int op_type, socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data, reactor_op* op) +{ + descriptor_data = allocate_descriptor_state(); + + BOOST_ASIO_HANDLER_REACTOR_REGISTRATION(( + context(), static_cast(descriptor), + reinterpret_cast(descriptor_data))); + + mutex::scoped_lock lock(descriptor_data->mutex_); + + descriptor_data->descriptor_ = descriptor; + descriptor_data->num_kevents_ = 1; + descriptor_data->shutdown_ = false; + descriptor_data->op_queue_[op_type].push(op); + + struct kevent events[1]; + BOOST_ASIO_KQUEUE_EV_SET(&events[0], descriptor, EVFILT_READ, + EV_ADD | EV_CLEAR, 0, 0, descriptor_data); + if (::kevent(kqueue_fd_, events, 1, 0, 0, 0) == -1) + return errno; + + return 0; +} + +void kqueue_reactor::move_descriptor(socket_type, + kqueue_reactor::per_descriptor_data& target_descriptor_data, + kqueue_reactor::per_descriptor_data& source_descriptor_data) +{ + target_descriptor_data = source_descriptor_data; + source_descriptor_data = 0; +} + +void kqueue_reactor::start_op(int op_type, socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative) +{ + if (!descriptor_data) + { + op->ec_ = boost::asio::error::bad_descriptor; + post_immediate_completion(op, is_continuation); + return; + } + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (descriptor_data->shutdown_) + { + post_immediate_completion(op, is_continuation); + return; + } + + if (descriptor_data->op_queue_[op_type].empty()) + { + static const int num_kevents[max_ops] = { 1, 2, 1 }; + + if (allow_speculative + && (op_type != read_op + || descriptor_data->op_queue_[except_op].empty())) + { + if (op->perform()) + { + descriptor_lock.unlock(); + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + + if (descriptor_data->num_kevents_ < num_kevents[op_type]) + { + struct kevent events[2]; + BOOST_ASIO_KQUEUE_EV_SET(&events[0], descriptor, EVFILT_READ, + EV_ADD | EV_CLEAR, 0, 0, descriptor_data); + BOOST_ASIO_KQUEUE_EV_SET(&events[1], descriptor, EVFILT_WRITE, + EV_ADD | EV_CLEAR, 0, 0, descriptor_data); + if (::kevent(kqueue_fd_, events, num_kevents[op_type], 0, 0, 0) != -1) + { + descriptor_data->num_kevents_ = num_kevents[op_type]; + } + else + { + op->ec_ = boost::system::error_code(errno, + boost::asio::error::get_system_category()); + scheduler_.post_immediate_completion(op, is_continuation); + return; + } + } + } + else + { + if (descriptor_data->num_kevents_ < num_kevents[op_type]) + descriptor_data->num_kevents_ = num_kevents[op_type]; + + struct kevent events[2]; + BOOST_ASIO_KQUEUE_EV_SET(&events[0], descriptor, EVFILT_READ, + EV_ADD | EV_CLEAR, 0, 0, descriptor_data); + BOOST_ASIO_KQUEUE_EV_SET(&events[1], descriptor, EVFILT_WRITE, + EV_ADD | EV_CLEAR, 0, 0, descriptor_data); + ::kevent(kqueue_fd_, events, descriptor_data->num_kevents_, 0, 0, 0); + } + } + + descriptor_data->op_queue_[op_type].push(op); + scheduler_.work_started(); +} + +void kqueue_reactor::cancel_ops(socket_type, + kqueue_reactor::per_descriptor_data& descriptor_data) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_lock.unlock(); + + scheduler_.post_deferred_completions(ops); +} + +void kqueue_reactor::deregister_descriptor(socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data, bool closing) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (!descriptor_data->shutdown_) + { + if (closing) + { + // The descriptor will be automatically removed from the kqueue when it + // is closed. + } + else + { + struct kevent events[2]; + BOOST_ASIO_KQUEUE_EV_SET(&events[0], descriptor, + EVFILT_READ, EV_DELETE, 0, 0, 0); + BOOST_ASIO_KQUEUE_EV_SET(&events[1], descriptor, + EVFILT_WRITE, EV_DELETE, 0, 0, 0); + ::kevent(kqueue_fd_, events, descriptor_data->num_kevents_, 0, 0, 0); + } + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + { + while (reactor_op* op = descriptor_data->op_queue_[i].front()) + { + op->ec_ = boost::asio::error::operation_aborted; + descriptor_data->op_queue_[i].pop(); + ops.push(op); + } + } + + descriptor_data->descriptor_ = -1; + descriptor_data->shutdown_ = true; + + descriptor_lock.unlock(); + + BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(( + context(), static_cast(descriptor), + reinterpret_cast(descriptor_data))); + + scheduler_.post_deferred_completions(ops); + + // Leave descriptor_data set so that it will be freed by the subsequent + // call to cleanup_descriptor_data. + } + else + { + // We are shutting down, so prevent cleanup_descriptor_data from freeing + // the descriptor_data object and let the destructor free it instead. + descriptor_data = 0; + } +} + +void kqueue_reactor::deregister_internal_descriptor(socket_type descriptor, + kqueue_reactor::per_descriptor_data& descriptor_data) +{ + if (!descriptor_data) + return; + + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (!descriptor_data->shutdown_) + { + struct kevent events[2]; + BOOST_ASIO_KQUEUE_EV_SET(&events[0], descriptor, + EVFILT_READ, EV_DELETE, 0, 0, 0); + BOOST_ASIO_KQUEUE_EV_SET(&events[1], descriptor, + EVFILT_WRITE, EV_DELETE, 0, 0, 0); + ::kevent(kqueue_fd_, events, descriptor_data->num_kevents_, 0, 0, 0); + + op_queue ops; + for (int i = 0; i < max_ops; ++i) + ops.push(descriptor_data->op_queue_[i]); + + descriptor_data->descriptor_ = -1; + descriptor_data->shutdown_ = true; + + descriptor_lock.unlock(); + + BOOST_ASIO_HANDLER_REACTOR_DEREGISTRATION(( + context(), static_cast(descriptor), + reinterpret_cast(descriptor_data))); + + // Leave descriptor_data set so that it will be freed by the subsequent + // call to cleanup_descriptor_data. + } + else + { + // We are shutting down, so prevent cleanup_descriptor_data from freeing + // the descriptor_data object and let the destructor free it instead. + descriptor_data = 0; + } +} + +void kqueue_reactor::cleanup_descriptor_data( + per_descriptor_data& descriptor_data) +{ + if (descriptor_data) + { + free_descriptor_state(descriptor_data); + descriptor_data = 0; + } +} + +void kqueue_reactor::run(long usec, op_queue& ops) +{ + mutex::scoped_lock lock(mutex_); + + // Determine how long to block while waiting for events. + timespec timeout_buf = { 0, 0 }; + timespec* timeout = usec ? get_timeout(usec, timeout_buf) : &timeout_buf; + + lock.unlock(); + + // Block on the kqueue descriptor. + struct kevent events[128]; + int num_events = kevent(kqueue_fd_, 0, 0, events, 128, timeout); + +#if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + // Trace the waiting events. + for (int i = 0; i < num_events; ++i) + { + void* ptr = reinterpret_cast(events[i].udata); + if (ptr != &interrupter_) + { + unsigned event_mask = 0; + switch (events[i].filter) + { + case EVFILT_READ: + event_mask |= BOOST_ASIO_HANDLER_REACTOR_READ_EVENT; + break; + case EVFILT_WRITE: + event_mask |= BOOST_ASIO_HANDLER_REACTOR_WRITE_EVENT; + break; + } + if ((events[i].flags & (EV_ERROR | EV_OOBAND)) != 0) + event_mask |= BOOST_ASIO_HANDLER_REACTOR_ERROR_EVENT; + BOOST_ASIO_HANDLER_REACTOR_EVENTS((context(), + reinterpret_cast(ptr), event_mask)); + } + } +#endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) + + // Dispatch the waiting events. + for (int i = 0; i < num_events; ++i) + { + void* ptr = reinterpret_cast(events[i].udata); + if (ptr == &interrupter_) + { + interrupter_.reset(); + } + else + { + descriptor_state* descriptor_data = static_cast(ptr); + mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); + + if (events[i].filter == EVFILT_WRITE + && descriptor_data->num_kevents_ == 2 + && descriptor_data->op_queue_[write_op].empty()) + { + // Some descriptor types, like serial ports, don't seem to support + // EV_CLEAR with EVFILT_WRITE. Since we have no pending write + // operations we'll remove the EVFILT_WRITE registration here so that + // we don't end up in a tight spin. + struct kevent delete_events[1]; + BOOST_ASIO_KQUEUE_EV_SET(&delete_events[0], + descriptor_data->descriptor_, EVFILT_WRITE, EV_DELETE, 0, 0, 0); + ::kevent(kqueue_fd_, delete_events, 1, 0, 0, 0); + descriptor_data->num_kevents_ = 1; + } + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. +#if defined(__NetBSD__) + static const unsigned int filter[max_ops] = +#else + static const int filter[max_ops] = +#endif + { EVFILT_READ, EVFILT_WRITE, EVFILT_READ }; + for (int j = max_ops - 1; j >= 0; --j) + { + if (events[i].filter == filter[j]) + { + if (j != except_op || events[i].flags & EV_OOBAND) + { + while (reactor_op* op = descriptor_data->op_queue_[j].front()) + { + if (events[i].flags & EV_ERROR) + { + op->ec_ = boost::system::error_code( + static_cast(events[i].data), + boost::asio::error::get_system_category()); + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + if (op->perform()) + { + descriptor_data->op_queue_[j].pop(); + ops.push(op); + } + else + break; + } + } + } + } + } + } + + lock.lock(); + timer_queues_.get_ready_timers(ops); +} + +void kqueue_reactor::interrupt() +{ + interrupter_.interrupt(); +} + +int kqueue_reactor::do_kqueue_create() +{ + int fd = ::kqueue(); + if (fd == -1) + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "kqueue"); + } + return fd; +} + +kqueue_reactor::descriptor_state* kqueue_reactor::allocate_descriptor_state() +{ + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + return registered_descriptors_.alloc(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_IO, scheduler_.concurrency_hint())); +} + +void kqueue_reactor::free_descriptor_state(kqueue_reactor::descriptor_state* s) +{ + mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); + registered_descriptors_.free(s); +} + +void kqueue_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void kqueue_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +timespec* kqueue_reactor::get_timeout(long usec, timespec& ts) +{ + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + const long max_usec = 5 * 60 * 1000 * 1000; + usec = timer_queues_.wait_duration_usec( + (usec < 0 || max_usec < usec) ? max_usec : usec); + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + return &ts; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#undef BOOST_ASIO_KQUEUE_EV_SET + +#include + +#endif // defined(BOOST_ASIO_HAS_KQUEUE) + +#endif // BOOST_ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP diff --git a/boost/asio/detail/impl/null_event.ipp b/boost/asio/detail/impl/null_event.ipp new file mode 100644 index 0000000..b756841 --- /dev/null +++ b/boost/asio/detail/impl/null_event.ipp @@ -0,0 +1,76 @@ +// +// detail/impl/null_event.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_NULL_EVENT_IPP +#define BOOST_ASIO_DETAIL_IMPL_NULL_EVENT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +# include +#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# include +#else +# include +# if defined(__hpux) +# include +# endif +# if !defined(__hpux) || defined(__SELECT) +# include +# endif +#endif + +#include + +namespace boost { +namespace asio { +namespace detail { + +void null_event::do_wait() +{ +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + std::this_thread::sleep_until((std::chrono::steady_clock::time_point::max)()); +#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + ::Sleep(INFINITE); +#else + ::pause(); +#endif +} + +void null_event::do_wait_for_usec(long usec) +{ +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + std::this_thread::sleep_for(std::chrono::microseconds(usec)); +#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + ::Sleep(usec / 1000); +#elif defined(__hpux) && defined(__SELECT) + timespec ts; + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + ::pselect(0, 0, 0, 0, &ts, 0); +#else + timeval tv; + tv.tv_sec = usec / 1000000; + tv.tv_usec = usec % 1000000; + ::select(0, 0, 0, 0, &tv); +#endif +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_NULL_EVENT_IPP diff --git a/boost/asio/detail/impl/pipe_select_interrupter.ipp b/boost/asio/detail/impl/pipe_select_interrupter.ipp new file mode 100644 index 0000000..f7bb785 --- /dev/null +++ b/boost/asio/detail/impl/pipe_select_interrupter.ipp @@ -0,0 +1,126 @@ +// +// detail/impl/pipe_select_interrupter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP +#define BOOST_ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) +#if !defined(BOOST_ASIO_WINDOWS) +#if !defined(__CYGWIN__) +#if !defined(__SYMBIAN32__) +#if !defined(BOOST_ASIO_HAS_EVENTFD) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +pipe_select_interrupter::pipe_select_interrupter() +{ + open_descriptors(); +} + +void pipe_select_interrupter::open_descriptors() +{ + int pipe_fds[2]; + if (pipe(pipe_fds) == 0) + { + read_descriptor_ = pipe_fds[0]; + ::fcntl(read_descriptor_, F_SETFL, O_NONBLOCK); + write_descriptor_ = pipe_fds[1]; + ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); + +#if defined(FD_CLOEXEC) + ::fcntl(read_descriptor_, F_SETFD, FD_CLOEXEC); + ::fcntl(write_descriptor_, F_SETFD, FD_CLOEXEC); +#endif // defined(FD_CLOEXEC) + } + else + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "pipe_select_interrupter"); + } +} + +pipe_select_interrupter::~pipe_select_interrupter() +{ + close_descriptors(); +} + +void pipe_select_interrupter::close_descriptors() +{ + if (read_descriptor_ != -1) + ::close(read_descriptor_); + if (write_descriptor_ != -1) + ::close(write_descriptor_); +} + +void pipe_select_interrupter::recreate() +{ + close_descriptors(); + + write_descriptor_ = -1; + read_descriptor_ = -1; + + open_descriptors(); +} + +void pipe_select_interrupter::interrupt() +{ + char byte = 0; + signed_size_type result = ::write(write_descriptor_, &byte, 1); + (void)result; +} + +bool pipe_select_interrupter::reset() +{ + for (;;) + { + char data[1024]; + signed_size_type bytes_read = ::read(read_descriptor_, data, sizeof(data)); + if (bytes_read < 0 && errno == EINTR) + continue; + bool was_interrupted = (bytes_read > 0); + while (bytes_read == sizeof(data)) + bytes_read = ::read(read_descriptor_, data, sizeof(data)); + return was_interrupted; + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_HAS_EVENTFD) +#endif // !defined(__SYMBIAN32__) +#endif // !defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_WINDOWS) +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#endif // BOOST_ASIO_DETAIL_IMPL_PIPE_SELECT_INTERRUPTER_IPP diff --git a/boost/asio/detail/impl/posix_event.ipp b/boost/asio/detail/impl/posix_event.ipp new file mode 100644 index 0000000..1c6d885 --- /dev/null +++ b/boost/asio/detail/impl/posix_event.ipp @@ -0,0 +1,61 @@ +// +// detail/impl/posix_event.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_POSIX_EVENT_IPP +#define BOOST_ASIO_DETAIL_IMPL_POSIX_EVENT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_PTHREADS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +posix_event::posix_event() + : state_(0) +{ +#if (defined(__MACH__) && defined(__APPLE__)) \ + || (defined(__ANDROID__) && (__ANDROID_API__ < 21)) + int error = ::pthread_cond_init(&cond_, 0); +#else // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21)) + ::pthread_condattr_t attr; + ::pthread_condattr_init(&attr); + int error = ::pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + if (error == 0) + error = ::pthread_cond_init(&cond_, &attr); +#endif // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21)) + + boost::system::error_code ec(error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "event"); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_PTHREADS) + +#endif // BOOST_ASIO_DETAIL_IMPL_POSIX_EVENT_IPP diff --git a/boost/asio/detail/impl/posix_mutex.ipp b/boost/asio/detail/impl/posix_mutex.ipp new file mode 100644 index 0000000..fc86d43 --- /dev/null +++ b/boost/asio/detail/impl/posix_mutex.ipp @@ -0,0 +1,48 @@ +// +// detail/impl/posix_mutex.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP +#define BOOST_ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_PTHREADS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +posix_mutex::posix_mutex() +{ + int error = ::pthread_mutex_init(&mutex_, 0); + boost::system::error_code ec(error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "mutex"); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_PTHREADS) + +#endif // BOOST_ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP diff --git a/boost/asio/detail/impl/posix_thread.ipp b/boost/asio/detail/impl/posix_thread.ipp new file mode 100644 index 0000000..d01922c --- /dev/null +++ b/boost/asio/detail/impl/posix_thread.ipp @@ -0,0 +1,86 @@ +// +// detail/impl/posix_thread.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_POSIX_THREAD_IPP +#define BOOST_ASIO_DETAIL_IMPL_POSIX_THREAD_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_PTHREADS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +posix_thread::~posix_thread() +{ + if (!joined_) + ::pthread_detach(thread_); +} + +void posix_thread::join() +{ + if (!joined_) + { + ::pthread_join(thread_, 0); + joined_ = true; + } +} + +std::size_t posix_thread::hardware_concurrency() +{ +#if defined(_SC_NPROCESSORS_ONLN) + long result = sysconf(_SC_NPROCESSORS_ONLN); + if (result > 0) + return result; +#endif // defined(_SC_NPROCESSORS_ONLN) + return 0; +} + +void posix_thread::start_thread(func_base* arg) +{ + int error = ::pthread_create(&thread_, 0, + boost_asio_detail_posix_thread_function, arg); + if (error != 0) + { + delete arg; + boost::system::error_code ec(error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "thread"); + } +} + +void* boost_asio_detail_posix_thread_function(void* arg) +{ + posix_thread::auto_func_base_ptr func = { + static_cast(arg) }; + func.ptr->run(); + return 0; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_PTHREADS) + +#endif // BOOST_ASIO_DETAIL_IMPL_POSIX_THREAD_IPP diff --git a/boost/asio/detail/impl/posix_tss_ptr.ipp b/boost/asio/detail/impl/posix_tss_ptr.ipp new file mode 100644 index 0000000..623dc67 --- /dev/null +++ b/boost/asio/detail/impl/posix_tss_ptr.ipp @@ -0,0 +1,48 @@ +// +// detail/impl/posix_tss_ptr.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP +#define BOOST_ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_PTHREADS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +void posix_tss_ptr_create(pthread_key_t& key) +{ + int error = ::pthread_key_create(&key, 0); + boost::system::error_code ec(error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "tss"); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_PTHREADS) + +#endif // BOOST_ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP diff --git a/boost/asio/detail/impl/reactive_descriptor_service.ipp b/boost/asio/detail/impl/reactive_descriptor_service.ipp new file mode 100644 index 0000000..0611a95 --- /dev/null +++ b/boost/asio/detail/impl/reactive_descriptor_service.ipp @@ -0,0 +1,224 @@ +// +// detail/impl/reactive_descriptor_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +reactive_descriptor_service::reactive_descriptor_service( + execution_context& context) + : execution_context_service_base(context), + reactor_(boost::asio::use_service(context)) +{ + reactor_.init_task(); +} + +void reactive_descriptor_service::shutdown() +{ +} + +void reactive_descriptor_service::construct( + reactive_descriptor_service::implementation_type& impl) +{ + impl.descriptor_ = -1; + impl.state_ = 0; +} + +void reactive_descriptor_service::move_construct( + reactive_descriptor_service::implementation_type& impl, + reactive_descriptor_service::implementation_type& other_impl) +{ + impl.descriptor_ = other_impl.descriptor_; + other_impl.descriptor_ = -1; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + reactor_.move_descriptor(impl.descriptor_, + impl.reactor_data_, other_impl.reactor_data_); +} + +void reactive_descriptor_service::move_assign( + reactive_descriptor_service::implementation_type& impl, + reactive_descriptor_service& other_service, + reactive_descriptor_service::implementation_type& other_impl) +{ + destroy(impl); + + impl.descriptor_ = other_impl.descriptor_; + other_impl.descriptor_ = -1; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + other_service.reactor_.move_descriptor(impl.descriptor_, + impl.reactor_data_, other_impl.reactor_data_); +} + +void reactive_descriptor_service::destroy( + reactive_descriptor_service::implementation_type& impl) +{ + if (is_open(impl)) + { + BOOST_ASIO_HANDLER_OPERATION((reactor_.context(), + "descriptor", &impl, impl.descriptor_, "close")); + + reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_, + (impl.state_ & descriptor_ops::possible_dup) == 0); + + boost::system::error_code ignored_ec; + descriptor_ops::close(impl.descriptor_, impl.state_, ignored_ec); + + reactor_.cleanup_descriptor_data(impl.reactor_data_); + } +} + +boost::system::error_code reactive_descriptor_service::assign( + reactive_descriptor_service::implementation_type& impl, + const native_handle_type& native_descriptor, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + if (int err = reactor_.register_descriptor( + native_descriptor, impl.reactor_data_)) + { + ec = boost::system::error_code(err, + boost::asio::error::get_system_category()); + return ec; + } + + impl.descriptor_ = native_descriptor; + impl.state_ = descriptor_ops::possible_dup; + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code reactive_descriptor_service::close( + reactive_descriptor_service::implementation_type& impl, + boost::system::error_code& ec) +{ + if (is_open(impl)) + { + BOOST_ASIO_HANDLER_OPERATION((reactor_.context(), + "descriptor", &impl, impl.descriptor_, "close")); + + reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_, + (impl.state_ & descriptor_ops::possible_dup) == 0); + + descriptor_ops::close(impl.descriptor_, impl.state_, ec); + + reactor_.cleanup_descriptor_data(impl.reactor_data_); + } + else + { + ec = boost::system::error_code(); + } + + // The descriptor is closed by the OS even if close() returns an error. + // + // (Actually, POSIX says the state of the descriptor is unspecified. On + // Linux the descriptor is apparently closed anyway; e.g. see + // http://lkml.org/lkml/2005/9/10/129 + // We'll just have to assume that other OSes follow the same behaviour.) + construct(impl); + + return ec; +} + +reactive_descriptor_service::native_handle_type +reactive_descriptor_service::release( + reactive_descriptor_service::implementation_type& impl) +{ + native_handle_type descriptor = impl.descriptor_; + + if (is_open(impl)) + { + BOOST_ASIO_HANDLER_OPERATION((reactor_.context(), + "descriptor", &impl, impl.descriptor_, "release")); + + reactor_.deregister_descriptor(impl.descriptor_, impl.reactor_data_, false); + reactor_.cleanup_descriptor_data(impl.reactor_data_); + construct(impl); + } + + return descriptor; +} + +boost::system::error_code reactive_descriptor_service::cancel( + reactive_descriptor_service::implementation_type& impl, + boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + + BOOST_ASIO_HANDLER_OPERATION((reactor_.context(), + "descriptor", &impl, impl.descriptor_, "cancel")); + + reactor_.cancel_ops(impl.descriptor_, impl.reactor_data_); + ec = boost::system::error_code(); + return ec; +} + +void reactive_descriptor_service::start_op( + reactive_descriptor_service::implementation_type& impl, + int op_type, reactor_op* op, bool is_continuation, + bool is_non_blocking, bool noop) +{ + if (!noop) + { + if ((impl.state_ & descriptor_ops::non_blocking) || + descriptor_ops::set_internal_non_blocking( + impl.descriptor_, impl.state_, true, op->ec_)) + { + reactor_.start_op(op_type, impl.descriptor_, + impl.reactor_data_, op, is_continuation, is_non_blocking); + return; + } + } + + reactor_.post_immediate_completion(op, is_continuation); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP diff --git a/boost/asio/detail/impl/reactive_serial_port_service.ipp b/boost/asio/detail/impl/reactive_serial_port_service.ipp new file mode 100644 index 0000000..6254660 --- /dev/null +++ b/boost/asio/detail/impl/reactive_serial_port_service.ipp @@ -0,0 +1,154 @@ +// +// detail/impl/reactive_serial_port_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_SERIAL_PORT) +#if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +reactive_serial_port_service::reactive_serial_port_service( + execution_context& context) + : execution_context_service_base(context), + descriptor_service_(context) +{ +} + +void reactive_serial_port_service::shutdown() +{ + descriptor_service_.shutdown(); +} + +boost::system::error_code reactive_serial_port_service::open( + reactive_serial_port_service::implementation_type& impl, + const std::string& device, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + descriptor_ops::state_type state = 0; + int fd = descriptor_ops::open(device.c_str(), + O_RDWR | O_NONBLOCK | O_NOCTTY, ec); + if (fd < 0) + return ec; + + int s = descriptor_ops::fcntl(fd, F_GETFL, ec); + if (s >= 0) + s = descriptor_ops::fcntl(fd, F_SETFL, s | O_NONBLOCK, ec); + if (s < 0) + { + boost::system::error_code ignored_ec; + descriptor_ops::close(fd, state, ignored_ec); + return ec; + } + + // Set up default serial port options. + termios ios; + errno = 0; + s = descriptor_ops::error_wrapper(::tcgetattr(fd, &ios), ec); + if (s >= 0) + { +#if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) + ::cfmakeraw(&ios); +#else + ios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK + | ISTRIP | INLCR | IGNCR | ICRNL | IXON); + ios.c_oflag &= ~OPOST; + ios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); + ios.c_cflag &= ~(CSIZE | PARENB); + ios.c_cflag |= CS8; +#endif + ios.c_iflag |= IGNPAR; + ios.c_cflag |= CREAD | CLOCAL; + errno = 0; + s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec); + } + if (s < 0) + { + boost::system::error_code ignored_ec; + descriptor_ops::close(fd, state, ignored_ec); + return ec; + } + + // We're done. Take ownership of the serial port descriptor. + if (descriptor_service_.assign(impl, fd, ec)) + { + boost::system::error_code ignored_ec; + descriptor_ops::close(fd, state, ignored_ec); + } + + return ec; +} + +boost::system::error_code reactive_serial_port_service::do_set_option( + reactive_serial_port_service::implementation_type& impl, + reactive_serial_port_service::store_function_type store, + const void* option, boost::system::error_code& ec) +{ + termios ios; + errno = 0; + descriptor_ops::error_wrapper(::tcgetattr( + descriptor_service_.native_handle(impl), &ios), ec); + if (ec) + return ec; + + if (store(option, ios, ec)) + return ec; + + errno = 0; + descriptor_ops::error_wrapper(::tcsetattr( + descriptor_service_.native_handle(impl), TCSANOW, &ios), ec); + return ec; +} + +boost::system::error_code reactive_serial_port_service::do_get_option( + const reactive_serial_port_service::implementation_type& impl, + reactive_serial_port_service::load_function_type load, + void* option, boost::system::error_code& ec) const +{ + termios ios; + errno = 0; + descriptor_ops::error_wrapper(::tcgetattr( + descriptor_service_.native_handle(impl), &ios), ec); + if (ec) + return ec; + + return load(option, ios, ec); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) +#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) + +#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP diff --git a/boost/asio/detail/impl/reactive_socket_service_base.ipp b/boost/asio/detail/impl/reactive_socket_service_base.ipp new file mode 100644 index 0000000..5ae4b64 --- /dev/null +++ b/boost/asio/detail/impl/reactive_socket_service_base.ipp @@ -0,0 +1,301 @@ +// +// detail/reactive_socket_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP +#define BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_IOCP) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +reactive_socket_service_base::reactive_socket_service_base( + execution_context& context) + : reactor_(use_service(context)) +{ + reactor_.init_task(); +} + +void reactive_socket_service_base::base_shutdown() +{ +} + +void reactive_socket_service_base::construct( + reactive_socket_service_base::base_implementation_type& impl) +{ + impl.socket_ = invalid_socket; + impl.state_ = 0; +} + +void reactive_socket_service_base::base_move_construct( + reactive_socket_service_base::base_implementation_type& impl, + reactive_socket_service_base::base_implementation_type& other_impl) +{ + impl.socket_ = other_impl.socket_; + other_impl.socket_ = invalid_socket; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + reactor_.move_descriptor(impl.socket_, + impl.reactor_data_, other_impl.reactor_data_); +} + +void reactive_socket_service_base::base_move_assign( + reactive_socket_service_base::base_implementation_type& impl, + reactive_socket_service_base& other_service, + reactive_socket_service_base::base_implementation_type& other_impl) +{ + destroy(impl); + + impl.socket_ = other_impl.socket_; + other_impl.socket_ = invalid_socket; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + other_service.reactor_.move_descriptor(impl.socket_, + impl.reactor_data_, other_impl.reactor_data_); +} + +void reactive_socket_service_base::destroy( + reactive_socket_service_base::base_implementation_type& impl) +{ + if (impl.socket_ != invalid_socket) + { + BOOST_ASIO_HANDLER_OPERATION((reactor_.context(), + "socket", &impl, impl.socket_, "close")); + + reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, + (impl.state_ & socket_ops::possible_dup) == 0); + + boost::system::error_code ignored_ec; + socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); + + reactor_.cleanup_descriptor_data(impl.reactor_data_); + } +} + +boost::system::error_code reactive_socket_service_base::close( + reactive_socket_service_base::base_implementation_type& impl, + boost::system::error_code& ec) +{ + if (is_open(impl)) + { + BOOST_ASIO_HANDLER_OPERATION((reactor_.context(), + "socket", &impl, impl.socket_, "close")); + + reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, + (impl.state_ & socket_ops::possible_dup) == 0); + + socket_ops::close(impl.socket_, impl.state_, false, ec); + + reactor_.cleanup_descriptor_data(impl.reactor_data_); + } + else + { + ec = boost::system::error_code(); + } + + // The descriptor is closed by the OS even if close() returns an error. + // + // (Actually, POSIX says the state of the descriptor is unspecified. On + // Linux the descriptor is apparently closed anyway; e.g. see + // http://lkml.org/lkml/2005/9/10/129 + // We'll just have to assume that other OSes follow the same behaviour. The + // known exception is when Windows's closesocket() function fails with + // WSAEWOULDBLOCK, but this case is handled inside socket_ops::close(). + construct(impl); + + return ec; +} + +socket_type reactive_socket_service_base::release( + reactive_socket_service_base::base_implementation_type& impl, + boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return invalid_socket; + } + + BOOST_ASIO_HANDLER_OPERATION((reactor_.context(), + "socket", &impl, impl.socket_, "release")); + + reactor_.deregister_descriptor(impl.socket_, impl.reactor_data_, false); + reactor_.cleanup_descriptor_data(impl.reactor_data_); + socket_type sock = impl.socket_; + construct(impl); + ec = boost::system::error_code(); + return sock; +} + +boost::system::error_code reactive_socket_service_base::cancel( + reactive_socket_service_base::base_implementation_type& impl, + boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + + BOOST_ASIO_HANDLER_OPERATION((reactor_.context(), + "socket", &impl, impl.socket_, "cancel")); + + reactor_.cancel_ops(impl.socket_, impl.reactor_data_); + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code reactive_socket_service_base::do_open( + reactive_socket_service_base::base_implementation_type& impl, + int af, int type, int protocol, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + socket_holder sock(socket_ops::socket(af, type, protocol, ec)); + if (sock.get() == invalid_socket) + return ec; + + if (int err = reactor_.register_descriptor(sock.get(), impl.reactor_data_)) + { + ec = boost::system::error_code(err, + boost::asio::error::get_system_category()); + return ec; + } + + impl.socket_ = sock.release(); + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code reactive_socket_service_base::do_assign( + reactive_socket_service_base::base_implementation_type& impl, int type, + const reactive_socket_service_base::native_handle_type& native_socket, + boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + if (int err = reactor_.register_descriptor( + native_socket, impl.reactor_data_)) + { + ec = boost::system::error_code(err, + boost::asio::error::get_system_category()); + return ec; + } + + impl.socket_ = native_socket; + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + impl.state_ |= socket_ops::possible_dup; + ec = boost::system::error_code(); + return ec; +} + +void reactive_socket_service_base::start_op( + reactive_socket_service_base::base_implementation_type& impl, + int op_type, reactor_op* op, bool is_continuation, + bool is_non_blocking, bool noop) +{ + if (!noop) + { + if ((impl.state_ & socket_ops::non_blocking) + || socket_ops::set_internal_non_blocking( + impl.socket_, impl.state_, true, op->ec_)) + { + reactor_.start_op(op_type, impl.socket_, + impl.reactor_data_, op, is_continuation, is_non_blocking); + return; + } + } + + reactor_.post_immediate_completion(op, is_continuation); +} + +void reactive_socket_service_base::start_accept_op( + reactive_socket_service_base::base_implementation_type& impl, + reactor_op* op, bool is_continuation, bool peer_is_open) +{ + if (!peer_is_open) + start_op(impl, reactor::read_op, op, is_continuation, true, false); + else + { + op->ec_ = boost::asio::error::already_open; + reactor_.post_immediate_completion(op, is_continuation); + } +} + +void reactive_socket_service_base::start_connect_op( + reactive_socket_service_base::base_implementation_type& impl, + reactor_op* op, bool is_continuation, + const socket_addr_type* addr, size_t addrlen) +{ + if ((impl.state_ & socket_ops::non_blocking) + || socket_ops::set_internal_non_blocking( + impl.socket_, impl.state_, true, op->ec_)) + { + if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0) + { + if (op->ec_ == boost::asio::error::in_progress + || op->ec_ == boost::asio::error::would_block) + { + op->ec_ = boost::system::error_code(); + reactor_.start_op(reactor::connect_op, impl.socket_, + impl.reactor_data_, op, is_continuation, false); + return; + } + } + } + + reactor_.post_immediate_completion(op, is_continuation); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_HAS_IOCP) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP diff --git a/boost/asio/detail/impl/resolver_service_base.ipp b/boost/asio/detail/impl/resolver_service_base.ipp new file mode 100644 index 0000000..64b92a8 --- /dev/null +++ b/boost/asio/detail/impl/resolver_service_base.ipp @@ -0,0 +1,162 @@ +// +// detail/impl/resolver_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP +#define BOOST_ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class resolver_service_base::work_scheduler_runner +{ +public: + work_scheduler_runner(scheduler_impl& work_scheduler) + : work_scheduler_(work_scheduler) + { + } + + void operator()() + { + boost::system::error_code ec; + work_scheduler_.run(ec); + } + +private: + scheduler_impl& work_scheduler_; +}; + +resolver_service_base::resolver_service_base(execution_context& context) + : scheduler_(boost::asio::use_service(context)), + work_scheduler_(new scheduler_impl(context, -1, false)), + work_thread_(0) +{ + work_scheduler_->work_started(); +} + +resolver_service_base::~resolver_service_base() +{ + base_shutdown(); +} + +void resolver_service_base::base_shutdown() +{ + if (work_scheduler_.get()) + { + work_scheduler_->work_finished(); + work_scheduler_->stop(); + if (work_thread_.get()) + { + work_thread_->join(); + work_thread_.reset(); + } + work_scheduler_.reset(); + } +} + +void resolver_service_base::base_notify_fork( + execution_context::fork_event fork_ev) +{ + if (work_thread_.get()) + { + if (fork_ev == execution_context::fork_prepare) + { + work_scheduler_->stop(); + work_thread_->join(); + work_thread_.reset(); + } + else + { + work_scheduler_->restart(); + work_thread_.reset(new boost::asio::detail::thread( + work_scheduler_runner(*work_scheduler_))); + } + } +} + +void resolver_service_base::construct( + resolver_service_base::implementation_type& impl) +{ + impl.reset(static_cast(0), socket_ops::noop_deleter()); +} + +void resolver_service_base::destroy( + resolver_service_base::implementation_type& impl) +{ + BOOST_ASIO_HANDLER_OPERATION((scheduler_.context(), + "resolver", &impl, 0, "cancel")); + + impl.reset(); +} + +void resolver_service_base::move_construct(implementation_type& impl, + implementation_type& other_impl) +{ + impl = BOOST_ASIO_MOVE_CAST(implementation_type)(other_impl); +} + +void resolver_service_base::move_assign(implementation_type& impl, + resolver_service_base&, implementation_type& other_impl) +{ + destroy(impl); + impl = BOOST_ASIO_MOVE_CAST(implementation_type)(other_impl); +} + +void resolver_service_base::cancel( + resolver_service_base::implementation_type& impl) +{ + BOOST_ASIO_HANDLER_OPERATION((scheduler_.context(), + "resolver", &impl, 0, "cancel")); + + impl.reset(static_cast(0), socket_ops::noop_deleter()); +} + +void resolver_service_base::start_resolve_op(resolve_op* op) +{ + if (BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER, + scheduler_.concurrency_hint())) + { + start_work_thread(); + scheduler_.work_started(); + work_scheduler_->post_immediate_completion(op, false); + } + else + { + op->ec_ = boost::asio::error::operation_not_supported; + scheduler_.post_immediate_completion(op, false); + } +} + +void resolver_service_base::start_work_thread() +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (!work_thread_.get()) + { + work_thread_.reset(new boost::asio::detail::thread( + work_scheduler_runner(*work_scheduler_))); + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP diff --git a/boost/asio/detail/impl/scheduler.ipp b/boost/asio/detail/impl/scheduler.ipp new file mode 100644 index 0000000..4ef5c86 --- /dev/null +++ b/boost/asio/detail/impl/scheduler.ipp @@ -0,0 +1,619 @@ +// +// detail/impl/scheduler.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_SCHEDULER_IPP +#define BOOST_ASIO_DETAIL_IMPL_SCHEDULER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class scheduler::thread_function +{ +public: + explicit thread_function(scheduler* s) + : this_(s) + { + } + + void operator()() + { + boost::system::error_code ec; + this_->run(ec); + } + +private: + scheduler* this_; +}; + +struct scheduler::task_cleanup +{ + ~task_cleanup() + { + if (this_thread_->private_outstanding_work > 0) + { + boost::asio::detail::increment( + scheduler_->outstanding_work_, + this_thread_->private_outstanding_work); + } + this_thread_->private_outstanding_work = 0; + + // Enqueue the completed operations and reinsert the task at the end of + // the operation queue. + lock_->lock(); + scheduler_->task_interrupted_ = true; + scheduler_->op_queue_.push(this_thread_->private_op_queue); + scheduler_->op_queue_.push(&scheduler_->task_operation_); + } + + scheduler* scheduler_; + mutex::scoped_lock* lock_; + thread_info* this_thread_; +}; + +struct scheduler::work_cleanup +{ + ~work_cleanup() + { + if (this_thread_->private_outstanding_work > 1) + { + boost::asio::detail::increment( + scheduler_->outstanding_work_, + this_thread_->private_outstanding_work - 1); + } + else if (this_thread_->private_outstanding_work < 1) + { + scheduler_->work_finished(); + } + this_thread_->private_outstanding_work = 0; + +#if defined(BOOST_ASIO_HAS_THREADS) + if (!this_thread_->private_op_queue.empty()) + { + lock_->lock(); + scheduler_->op_queue_.push(this_thread_->private_op_queue); + } +#endif // defined(BOOST_ASIO_HAS_THREADS) + } + + scheduler* scheduler_; + mutex::scoped_lock* lock_; + thread_info* this_thread_; +}; + +scheduler::scheduler(boost::asio::execution_context& ctx, + int concurrency_hint, bool own_thread) + : boost::asio::detail::execution_context_service_base(ctx), + one_thread_(concurrency_hint == 1 + || !BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING( + SCHEDULER, concurrency_hint) + || !BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING( + REACTOR_IO, concurrency_hint)), + mutex_(BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING( + SCHEDULER, concurrency_hint)), + task_(0), + task_interrupted_(true), + outstanding_work_(0), + stopped_(false), + shutdown_(false), + concurrency_hint_(concurrency_hint), + thread_(0) +{ + BOOST_ASIO_HANDLER_TRACKING_INIT; + + if (own_thread) + { + ++outstanding_work_; + boost::asio::detail::signal_blocker sb; + thread_ = new boost::asio::detail::thread(thread_function(this)); + } +} + +scheduler::~scheduler() +{ + if (thread_) + { + thread_->join(); + delete thread_; + } +} + +void scheduler::shutdown() +{ + mutex::scoped_lock lock(mutex_); + shutdown_ = true; + if (thread_) + stop_all_threads(lock); + lock.unlock(); + + // Join thread to ensure task operation is returned to queue. + if (thread_) + { + thread_->join(); + delete thread_; + thread_ = 0; + } + + // Destroy handler objects. + while (!op_queue_.empty()) + { + operation* o = op_queue_.front(); + op_queue_.pop(); + if (o != &task_operation_) + o->destroy(); + } + + // Reset to initial state. + task_ = 0; +} + +void scheduler::init_task() +{ + mutex::scoped_lock lock(mutex_); + if (!shutdown_ && !task_) + { + task_ = &use_service(this->context()); + op_queue_.push(&task_operation_); + wake_one_thread_and_unlock(lock); + } +} + +std::size_t scheduler::run(boost::system::error_code& ec) +{ + ec = boost::system::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + thread_info this_thread; + this_thread.private_outstanding_work = 0; + thread_call_stack::context ctx(this, this_thread); + + mutex::scoped_lock lock(mutex_); + + std::size_t n = 0; + for (; do_run_one(lock, this_thread, ec); lock.lock()) + if (n != (std::numeric_limits::max)()) + ++n; + return n; +} + +std::size_t scheduler::run_one(boost::system::error_code& ec) +{ + ec = boost::system::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + thread_info this_thread; + this_thread.private_outstanding_work = 0; + thread_call_stack::context ctx(this, this_thread); + + mutex::scoped_lock lock(mutex_); + + return do_run_one(lock, this_thread, ec); +} + +std::size_t scheduler::wait_one(long usec, boost::system::error_code& ec) +{ + ec = boost::system::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + thread_info this_thread; + this_thread.private_outstanding_work = 0; + thread_call_stack::context ctx(this, this_thread); + + mutex::scoped_lock lock(mutex_); + + return do_wait_one(lock, this_thread, usec, ec); +} + +std::size_t scheduler::poll(boost::system::error_code& ec) +{ + ec = boost::system::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + thread_info this_thread; + this_thread.private_outstanding_work = 0; + thread_call_stack::context ctx(this, this_thread); + + mutex::scoped_lock lock(mutex_); + +#if defined(BOOST_ASIO_HAS_THREADS) + // We want to support nested calls to poll() and poll_one(), so any handlers + // that are already on a thread-private queue need to be put on to the main + // queue now. + if (one_thread_) + if (thread_info* outer_info = static_cast(ctx.next_by_key())) + op_queue_.push(outer_info->private_op_queue); +#endif // defined(BOOST_ASIO_HAS_THREADS) + + std::size_t n = 0; + for (; do_poll_one(lock, this_thread, ec); lock.lock()) + if (n != (std::numeric_limits::max)()) + ++n; + return n; +} + +std::size_t scheduler::poll_one(boost::system::error_code& ec) +{ + ec = boost::system::error_code(); + if (outstanding_work_ == 0) + { + stop(); + return 0; + } + + thread_info this_thread; + this_thread.private_outstanding_work = 0; + thread_call_stack::context ctx(this, this_thread); + + mutex::scoped_lock lock(mutex_); + +#if defined(BOOST_ASIO_HAS_THREADS) + // We want to support nested calls to poll() and poll_one(), so any handlers + // that are already on a thread-private queue need to be put on to the main + // queue now. + if (one_thread_) + if (thread_info* outer_info = static_cast(ctx.next_by_key())) + op_queue_.push(outer_info->private_op_queue); +#endif // defined(BOOST_ASIO_HAS_THREADS) + + return do_poll_one(lock, this_thread, ec); +} + +void scheduler::stop() +{ + mutex::scoped_lock lock(mutex_); + stop_all_threads(lock); +} + +bool scheduler::stopped() const +{ + mutex::scoped_lock lock(mutex_); + return stopped_; +} + +void scheduler::restart() +{ + mutex::scoped_lock lock(mutex_); + stopped_ = false; +} + +void scheduler::compensating_work_started() +{ + thread_info_base* this_thread = thread_call_stack::contains(this); + ++static_cast(this_thread)->private_outstanding_work; +} + +void scheduler::post_immediate_completion( + scheduler::operation* op, bool is_continuation) +{ +#if defined(BOOST_ASIO_HAS_THREADS) + if (one_thread_ || is_continuation) + { + if (thread_info_base* this_thread = thread_call_stack::contains(this)) + { + ++static_cast(this_thread)->private_outstanding_work; + static_cast(this_thread)->private_op_queue.push(op); + return; + } + } +#else // defined(BOOST_ASIO_HAS_THREADS) + (void)is_continuation; +#endif // defined(BOOST_ASIO_HAS_THREADS) + + work_started(); + mutex::scoped_lock lock(mutex_); + op_queue_.push(op); + wake_one_thread_and_unlock(lock); +} + +void scheduler::post_deferred_completion(scheduler::operation* op) +{ +#if defined(BOOST_ASIO_HAS_THREADS) + if (one_thread_) + { + if (thread_info_base* this_thread = thread_call_stack::contains(this)) + { + static_cast(this_thread)->private_op_queue.push(op); + return; + } + } +#endif // defined(BOOST_ASIO_HAS_THREADS) + + mutex::scoped_lock lock(mutex_); + op_queue_.push(op); + wake_one_thread_and_unlock(lock); +} + +void scheduler::post_deferred_completions( + op_queue& ops) +{ + if (!ops.empty()) + { +#if defined(BOOST_ASIO_HAS_THREADS) + if (one_thread_) + { + if (thread_info_base* this_thread = thread_call_stack::contains(this)) + { + static_cast(this_thread)->private_op_queue.push(ops); + return; + } + } +#endif // defined(BOOST_ASIO_HAS_THREADS) + + mutex::scoped_lock lock(mutex_); + op_queue_.push(ops); + wake_one_thread_and_unlock(lock); + } +} + +void scheduler::do_dispatch( + scheduler::operation* op) +{ + work_started(); + mutex::scoped_lock lock(mutex_); + op_queue_.push(op); + wake_one_thread_and_unlock(lock); +} + +void scheduler::abandon_operations( + op_queue& ops) +{ + op_queue ops2; + ops2.push(ops); +} + +std::size_t scheduler::do_run_one(mutex::scoped_lock& lock, + scheduler::thread_info& this_thread, + const boost::system::error_code& ec) +{ + while (!stopped_) + { + if (!op_queue_.empty()) + { + // Prepare to execute first handler from queue. + operation* o = op_queue_.front(); + op_queue_.pop(); + bool more_handlers = (!op_queue_.empty()); + + if (o == &task_operation_) + { + task_interrupted_ = more_handlers; + + if (more_handlers && !one_thread_) + wakeup_event_.unlock_and_signal_one(lock); + else + lock.unlock(); + + task_cleanup on_exit = { this, &lock, &this_thread }; + (void)on_exit; + + // Run the task. May throw an exception. Only block if the operation + // queue is empty and we're not polling, otherwise we want to return + // as soon as possible. + task_->run(more_handlers ? 0 : -1, this_thread.private_op_queue); + } + else + { + std::size_t task_result = o->task_result_; + + if (more_handlers && !one_thread_) + wake_one_thread_and_unlock(lock); + else + lock.unlock(); + + // Ensure the count of outstanding work is decremented on block exit. + work_cleanup on_exit = { this, &lock, &this_thread }; + (void)on_exit; + + // Complete the operation. May throw an exception. Deletes the object. + o->complete(this, ec, task_result); + + return 1; + } + } + else + { + wakeup_event_.clear(lock); + wakeup_event_.wait(lock); + } + } + + return 0; +} + +std::size_t scheduler::do_wait_one(mutex::scoped_lock& lock, + scheduler::thread_info& this_thread, long usec, + const boost::system::error_code& ec) +{ + if (stopped_) + return 0; + + operation* o = op_queue_.front(); + if (o == 0) + { + wakeup_event_.clear(lock); + wakeup_event_.wait_for_usec(lock, usec); + usec = 0; // Wait at most once. + o = op_queue_.front(); + } + + if (o == &task_operation_) + { + op_queue_.pop(); + bool more_handlers = (!op_queue_.empty()); + + task_interrupted_ = more_handlers; + + if (more_handlers && !one_thread_) + wakeup_event_.unlock_and_signal_one(lock); + else + lock.unlock(); + + { + task_cleanup on_exit = { this, &lock, &this_thread }; + (void)on_exit; + + // Run the task. May throw an exception. Only block if the operation + // queue is empty and we're not polling, otherwise we want to return + // as soon as possible. + task_->run(more_handlers ? 0 : usec, this_thread.private_op_queue); + } + + o = op_queue_.front(); + if (o == &task_operation_) + { + if (!one_thread_) + wakeup_event_.maybe_unlock_and_signal_one(lock); + return 0; + } + } + + if (o == 0) + return 0; + + op_queue_.pop(); + bool more_handlers = (!op_queue_.empty()); + + std::size_t task_result = o->task_result_; + + if (more_handlers && !one_thread_) + wake_one_thread_and_unlock(lock); + else + lock.unlock(); + + // Ensure the count of outstanding work is decremented on block exit. + work_cleanup on_exit = { this, &lock, &this_thread }; + (void)on_exit; + + // Complete the operation. May throw an exception. Deletes the object. + o->complete(this, ec, task_result); + + return 1; +} + +std::size_t scheduler::do_poll_one(mutex::scoped_lock& lock, + scheduler::thread_info& this_thread, + const boost::system::error_code& ec) +{ + if (stopped_) + return 0; + + operation* o = op_queue_.front(); + if (o == &task_operation_) + { + op_queue_.pop(); + lock.unlock(); + + { + task_cleanup c = { this, &lock, &this_thread }; + (void)c; + + // Run the task. May throw an exception. Only block if the operation + // queue is empty and we're not polling, otherwise we want to return + // as soon as possible. + task_->run(0, this_thread.private_op_queue); + } + + o = op_queue_.front(); + if (o == &task_operation_) + { + wakeup_event_.maybe_unlock_and_signal_one(lock); + return 0; + } + } + + if (o == 0) + return 0; + + op_queue_.pop(); + bool more_handlers = (!op_queue_.empty()); + + std::size_t task_result = o->task_result_; + + if (more_handlers && !one_thread_) + wake_one_thread_and_unlock(lock); + else + lock.unlock(); + + // Ensure the count of outstanding work is decremented on block exit. + work_cleanup on_exit = { this, &lock, &this_thread }; + (void)on_exit; + + // Complete the operation. May throw an exception. Deletes the object. + o->complete(this, ec, task_result); + + return 1; +} + +void scheduler::stop_all_threads( + mutex::scoped_lock& lock) +{ + stopped_ = true; + wakeup_event_.signal_all(lock); + + if (!task_interrupted_ && task_) + { + task_interrupted_ = true; + task_->interrupt(); + } +} + +void scheduler::wake_one_thread_and_unlock( + mutex::scoped_lock& lock) +{ + if (!wakeup_event_.maybe_unlock_and_signal_one(lock)) + { + if (!task_interrupted_ && task_) + { + task_interrupted_ = true; + task_->interrupt(); + } + lock.unlock(); + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_SCHEDULER_IPP diff --git a/boost/asio/detail/impl/select_reactor.hpp b/boost/asio/detail/impl/select_reactor.hpp new file mode 100644 index 0000000..c741492 --- /dev/null +++ b/boost/asio/detail/impl/select_reactor.hpp @@ -0,0 +1,102 @@ +// +// detail/impl/select_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP +#define BOOST_ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) \ + || (!defined(BOOST_ASIO_HAS_DEV_POLL) \ + && !defined(BOOST_ASIO_HAS_EPOLL) \ + && !defined(BOOST_ASIO_HAS_KQUEUE) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME)) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +void select_reactor::add_timer_queue(timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +// Remove a timer queue from the reactor. +template +void select_reactor::remove_timer_queue(timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void select_reactor::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + scheduler_.post_immediate_completion(op, false); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + scheduler_.work_started(); + if (earliest) + interrupter_.interrupt(); +} + +template +std::size_t select_reactor::cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + lock.unlock(); + scheduler_.post_deferred_completions(ops); + return n; +} + +template +void select_reactor::move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& target, + typename timer_queue::per_timer_data& source) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + queue.cancel_timer(target, ops); + queue.move_timer(target, source); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + // || (!defined(BOOST_ASIO_HAS_DEV_POLL) + // && !defined(BOOST_ASIO_HAS_EPOLL) + // && !defined(BOOST_ASIO_HAS_KQUEUE) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)) + +#endif // BOOST_ASIO_DETAIL_IMPL_SELECT_REACTOR_HPP diff --git a/boost/asio/detail/impl/select_reactor.ipp b/boost/asio/detail/impl/select_reactor.ipp new file mode 100644 index 0000000..34d3d9f --- /dev/null +++ b/boost/asio/detail/impl/select_reactor.ipp @@ -0,0 +1,335 @@ +// +// detail/impl/select_reactor.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP +#define BOOST_ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) \ + || (!defined(BOOST_ASIO_HAS_DEV_POLL) \ + && !defined(BOOST_ASIO_HAS_EPOLL) \ + && !defined(BOOST_ASIO_HAS_KQUEUE) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME)) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_HAS_IOCP) +class select_reactor::thread_function +{ +public: + explicit thread_function(select_reactor* r) + : this_(r) + { + } + + void operator()() + { + this_->run_thread(); + } + +private: + select_reactor* this_; +}; +#endif // defined(BOOST_ASIO_HAS_IOCP) + +select_reactor::select_reactor(boost::asio::execution_context& ctx) + : execution_context_service_base(ctx), + scheduler_(use_service(ctx)), + mutex_(), + interrupter_(), +#if defined(BOOST_ASIO_HAS_IOCP) + stop_thread_(false), + thread_(0), +#endif // defined(BOOST_ASIO_HAS_IOCP) + shutdown_(false) +{ +#if defined(BOOST_ASIO_HAS_IOCP) + boost::asio::detail::signal_blocker sb; + thread_ = new boost::asio::detail::thread(thread_function(this)); +#endif // defined(BOOST_ASIO_HAS_IOCP) +} + +select_reactor::~select_reactor() +{ + shutdown(); +} + +void select_reactor::shutdown() +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; +#if defined(BOOST_ASIO_HAS_IOCP) + stop_thread_ = true; +#endif // defined(BOOST_ASIO_HAS_IOCP) + lock.unlock(); + +#if defined(BOOST_ASIO_HAS_IOCP) + if (thread_) + { + interrupter_.interrupt(); + thread_->join(); + delete thread_; + thread_ = 0; + } +#endif // defined(BOOST_ASIO_HAS_IOCP) + + op_queue ops; + + for (int i = 0; i < max_ops; ++i) + op_queue_[i].get_all_operations(ops); + + timer_queues_.get_all_timers(ops); + + scheduler_.abandon_operations(ops); +} + +void select_reactor::notify_fork( + boost::asio::execution_context::fork_event fork_ev) +{ + if (fork_ev == boost::asio::execution_context::fork_child) + interrupter_.recreate(); +} + +void select_reactor::init_task() +{ + scheduler_.init_task(); +} + +int select_reactor::register_descriptor(socket_type, + select_reactor::per_descriptor_data&) +{ + return 0; +} + +int select_reactor::register_internal_descriptor( + int op_type, socket_type descriptor, + select_reactor::per_descriptor_data&, reactor_op* op) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + op_queue_[op_type].enqueue_operation(descriptor, op); + interrupter_.interrupt(); + + return 0; +} + +void select_reactor::move_descriptor(socket_type, + select_reactor::per_descriptor_data&, + select_reactor::per_descriptor_data&) +{ +} + +void select_reactor::start_op(int op_type, socket_type descriptor, + select_reactor::per_descriptor_data&, reactor_op* op, + bool is_continuation, bool) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + post_immediate_completion(op, is_continuation); + return; + } + + bool first = op_queue_[op_type].enqueue_operation(descriptor, op); + scheduler_.work_started(); + if (first) + interrupter_.interrupt(); +} + +void select_reactor::cancel_ops(socket_type descriptor, + select_reactor::per_descriptor_data&) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); +} + +void select_reactor::deregister_descriptor(socket_type descriptor, + select_reactor::per_descriptor_data&, bool) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor, boost::asio::error::operation_aborted); +} + +void select_reactor::deregister_internal_descriptor( + socket_type descriptor, select_reactor::per_descriptor_data&) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + for (int i = 0; i < max_ops; ++i) + op_queue_[i].cancel_operations(descriptor, ops); +} + +void select_reactor::cleanup_descriptor_data( + select_reactor::per_descriptor_data&) +{ +} + +void select_reactor::run(long usec, op_queue& ops) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + +#if defined(BOOST_ASIO_HAS_IOCP) + // Check if the thread is supposed to stop. + if (stop_thread_) + return; +#endif // defined(BOOST_ASIO_HAS_IOCP) + + // Set up the descriptor sets. + for (int i = 0; i < max_select_ops; ++i) + fd_sets_[i].reset(); + fd_sets_[read_op].set(interrupter_.read_descriptor()); + socket_type max_fd = 0; + bool have_work_to_do = !timer_queues_.all_empty(); + for (int i = 0; i < max_select_ops; ++i) + { + have_work_to_do = have_work_to_do || !op_queue_[i].empty(); + fd_sets_[i].set(op_queue_[i], ops); + if (fd_sets_[i].max_descriptor() > max_fd) + max_fd = fd_sets_[i].max_descriptor(); + } + +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + // Connection operations on Windows use both except and write fd_sets. + have_work_to_do = have_work_to_do || !op_queue_[connect_op].empty(); + fd_sets_[write_op].set(op_queue_[connect_op], ops); + if (fd_sets_[write_op].max_descriptor() > max_fd) + max_fd = fd_sets_[write_op].max_descriptor(); + fd_sets_[except_op].set(op_queue_[connect_op], ops); + if (fd_sets_[except_op].max_descriptor() > max_fd) + max_fd = fd_sets_[except_op].max_descriptor(); +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + + // We can return immediately if there's no work to do and the reactor is + // not supposed to block. + if (!usec && !have_work_to_do) + return; + + // Determine how long to block while waiting for events. + timeval tv_buf = { 0, 0 }; + timeval* tv = usec ? get_timeout(usec, tv_buf) : &tv_buf; + + lock.unlock(); + + // Block on the select call until descriptors become ready. + boost::system::error_code ec; + int retval = socket_ops::select(static_cast(max_fd + 1), + fd_sets_[read_op], fd_sets_[write_op], fd_sets_[except_op], tv, ec); + + // Reset the interrupter. + if (retval > 0 && fd_sets_[read_op].is_set(interrupter_.read_descriptor())) + { + interrupter_.reset(); + --retval; + } + + lock.lock(); + + // Dispatch all ready operations. + if (retval > 0) + { +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + // Connection operations on Windows use both except and write fd_sets. + fd_sets_[except_op].perform(op_queue_[connect_op], ops); + fd_sets_[write_op].perform(op_queue_[connect_op], ops); +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + for (int i = max_select_ops - 1; i >= 0; --i) + fd_sets_[i].perform(op_queue_[i], ops); + } + timer_queues_.get_ready_timers(ops); +} + +void select_reactor::interrupt() +{ + interrupter_.interrupt(); +} + +#if defined(BOOST_ASIO_HAS_IOCP) +void select_reactor::run_thread() +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + while (!stop_thread_) + { + lock.unlock(); + op_queue ops; + run(true, ops); + scheduler_.post_deferred_completions(ops); + lock.lock(); + } +} +#endif // defined(BOOST_ASIO_HAS_IOCP) + +void select_reactor::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void select_reactor::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +timeval* select_reactor::get_timeout(long usec, timeval& tv) +{ + // By default we will wait no longer than 5 minutes. This will ensure that + // any changes to the system clock are detected after no longer than this. + const long max_usec = 5 * 60 * 1000 * 1000; + usec = timer_queues_.wait_duration_usec( + (usec < 0 || max_usec < usec) ? max_usec : usec); + tv.tv_sec = usec / 1000000; + tv.tv_usec = usec % 1000000; + return &tv; +} + +void select_reactor::cancel_ops_unlocked(socket_type descriptor, + const boost::system::error_code& ec) +{ + bool need_interrupt = false; + op_queue ops; + for (int i = 0; i < max_ops; ++i) + need_interrupt = op_queue_[i].cancel_operations( + descriptor, ops, ec) || need_interrupt; + scheduler_.post_deferred_completions(ops); + if (need_interrupt) + interrupter_.interrupt(); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + // || (!defined(BOOST_ASIO_HAS_DEV_POLL) + // && !defined(BOOST_ASIO_HAS_EPOLL) + // && !defined(BOOST_ASIO_HAS_KQUEUE)) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)) + +#endif // BOOST_ASIO_DETAIL_IMPL_SELECT_REACTOR_IPP diff --git a/boost/asio/detail/impl/service_registry.hpp b/boost/asio/detail/impl/service_registry.hpp new file mode 100644 index 0000000..e18473c --- /dev/null +++ b/boost/asio/detail/impl/service_registry.hpp @@ -0,0 +1,96 @@ +// +// detail/impl/service_registry.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP +#define BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +Service& service_registry::use_service() +{ + execution_context::service::key key; + init_key(key, 0); + factory_type factory = &service_registry::create; + return *static_cast(do_use_service(key, factory, &owner_)); +} + +template +Service& service_registry::use_service(io_context& owner) +{ + execution_context::service::key key; + init_key(key, 0); + factory_type factory = &service_registry::create; + return *static_cast(do_use_service(key, factory, &owner)); +} + +template +void service_registry::add_service(Service* new_service) +{ + execution_context::service::key key; + init_key(key, 0); + return do_add_service(key, new_service); +} + +template +bool service_registry::has_service() const +{ + execution_context::service::key key; + init_key(key, 0); + return do_has_service(key); +} + +template +inline void service_registry::init_key( + execution_context::service::key& key, ...) +{ + init_key_from_id(key, Service::id); +} + +#if !defined(BOOST_ASIO_NO_TYPEID) +template +void service_registry::init_key(execution_context::service::key& key, + typename enable_if< + is_base_of::value>::type*) +{ + key.type_info_ = &typeid(typeid_wrapper); + key.id_ = 0; +} + +template +void service_registry::init_key_from_id(execution_context::service::key& key, + const service_id& /*id*/) +{ + key.type_info_ = &typeid(typeid_wrapper); + key.id_ = 0; +} +#endif // !defined(BOOST_ASIO_NO_TYPEID) + +template +execution_context::service* service_registry::create(void* owner) +{ + return new Service(*static_cast(owner)); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP diff --git a/boost/asio/detail/impl/service_registry.ipp b/boost/asio/detail/impl/service_registry.ipp new file mode 100644 index 0000000..da920fb --- /dev/null +++ b/boost/asio/detail/impl/service_registry.ipp @@ -0,0 +1,199 @@ +// +// detail/impl/service_registry.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP +#define BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +service_registry::service_registry(execution_context& owner) + : owner_(owner), + first_service_(0) +{ +} + +service_registry::~service_registry() +{ +} + +void service_registry::shutdown_services() +{ + execution_context::service* service = first_service_; + while (service) + { + service->shutdown(); + service = service->next_; + } +} + +void service_registry::destroy_services() +{ + while (first_service_) + { + execution_context::service* next_service = first_service_->next_; + destroy(first_service_); + first_service_ = next_service; + } +} + +void service_registry::notify_fork(execution_context::fork_event fork_ev) +{ + // Make a copy of all of the services while holding the lock. We don't want + // to hold the lock while calling into each service, as it may try to call + // back into this class. + std::vector services; + { + boost::asio::detail::mutex::scoped_lock lock(mutex_); + execution_context::service* service = first_service_; + while (service) + { + services.push_back(service); + service = service->next_; + } + } + + // If processing the fork_prepare event, we want to go in reverse order of + // service registration, which happens to be the existing order of the + // services in the vector. For the other events we want to go in the other + // direction. + std::size_t num_services = services.size(); + if (fork_ev == execution_context::fork_prepare) + for (std::size_t i = 0; i < num_services; ++i) + services[i]->notify_fork(fork_ev); + else + for (std::size_t i = num_services; i > 0; --i) + services[i - 1]->notify_fork(fork_ev); +} + +void service_registry::init_key_from_id(execution_context::service::key& key, + const execution_context::id& id) +{ + key.type_info_ = 0; + key.id_ = &id; +} + +bool service_registry::keys_match( + const execution_context::service::key& key1, + const execution_context::service::key& key2) +{ + if (key1.id_ && key2.id_) + if (key1.id_ == key2.id_) + return true; + if (key1.type_info_ && key2.type_info_) + if (*key1.type_info_ == *key2.type_info_) + return true; + return false; +} + +void service_registry::destroy(execution_context::service* service) +{ + delete service; +} + +execution_context::service* service_registry::do_use_service( + const execution_context::service::key& key, + factory_type factory, void* owner) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // First see if there is an existing service object with the given key. + execution_context::service* service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + return service; + service = service->next_; + } + + // Create a new service object. The service registry's mutex is not locked + // at this time to allow for nested calls into this function from the new + // service's constructor. + lock.unlock(); + auto_service_ptr new_service = { factory(owner) }; + new_service.ptr_->key_ = key; + lock.lock(); + + // Check that nobody else created another service object of the same type + // while the lock was released. + service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + return service; + service = service->next_; + } + + // Service was successfully initialised, pass ownership to registry. + new_service.ptr_->next_ = first_service_; + first_service_ = new_service.ptr_; + new_service.ptr_ = 0; + return first_service_; +} + +void service_registry::do_add_service( + const execution_context::service::key& key, + execution_context::service* new_service) +{ + if (&owner_ != &new_service->context()) + boost::asio::detail::throw_exception(invalid_service_owner()); + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // Check if there is an existing service object with the given key. + execution_context::service* service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + boost::asio::detail::throw_exception(service_already_exists()); + service = service->next_; + } + + // Take ownership of the service object. + new_service->key_ = key; + new_service->next_ = first_service_; + first_service_ = new_service; +} + +bool service_registry::do_has_service( + const execution_context::service::key& key) const +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + execution_context::service* service = first_service_; + while (service) + { + if (keys_match(service->key_, key)) + return true; + service = service->next_; + } + + return false; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP diff --git a/boost/asio/detail/impl/signal_set_service.ipp b/boost/asio/detail/impl/signal_set_service.ipp new file mode 100644 index 0000000..5e23702 --- /dev/null +++ b/boost/asio/detail/impl/signal_set_service.ipp @@ -0,0 +1,669 @@ +// +// detail/impl/signal_set_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct signal_state +{ + // Mutex used for protecting global state. + static_mutex mutex_; + + // The read end of the pipe used for signal notifications. + int read_descriptor_; + + // The write end of the pipe used for signal notifications. + int write_descriptor_; + + // Whether the signal state has been prepared for a fork. + bool fork_prepared_; + + // The head of a linked list of all signal_set_service instances. + class signal_set_service* service_list_; + + // A count of the number of objects that are registered for each signal. + std::size_t registration_count_[max_signal_number]; +}; + +signal_state* get_signal_state() +{ + static signal_state state = { + BOOST_ASIO_STATIC_MUTEX_INIT, -1, -1, false, 0, { 0 } }; + return &state; +} + +void boost_asio_signal_handler(int signal_number) +{ +#if defined(BOOST_ASIO_WINDOWS) \ + || defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + || defined(__CYGWIN__) + signal_set_service::deliver_signal(signal_number); +#else // defined(BOOST_ASIO_WINDOWS) + // || defined(BOOST_ASIO_WINDOWS_RUNTIME) + // || defined(__CYGWIN__) + int saved_errno = errno; + signal_state* state = get_signal_state(); + signed_size_type result = ::write(state->write_descriptor_, + &signal_number, sizeof(signal_number)); + (void)result; + errno = saved_errno; +#endif // defined(BOOST_ASIO_WINDOWS) + // || defined(BOOST_ASIO_WINDOWS_RUNTIME) + // || defined(__CYGWIN__) + +#if defined(BOOST_ASIO_HAS_SIGNAL) && !defined(BOOST_ASIO_HAS_SIGACTION) + ::signal(signal_number, boost_asio_signal_handler); +#endif // defined(BOOST_ASIO_HAS_SIGNAL) && !defined(BOOST_ASIO_HAS_SIGACTION) +} + +#if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) +class signal_set_service::pipe_read_op : public reactor_op +{ +public: + pipe_read_op() + : reactor_op(&pipe_read_op::do_perform, pipe_read_op::do_complete) + { + } + + static status do_perform(reactor_op*) + { + signal_state* state = get_signal_state(); + + int fd = state->read_descriptor_; + int signal_number = 0; + while (::read(fd, &signal_number, sizeof(int)) == sizeof(int)) + if (signal_number >= 0 && signal_number < max_signal_number) + signal_set_service::deliver_signal(signal_number); + + return not_done; + } + + static void do_complete(void* /*owner*/, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + pipe_read_op* o(static_cast(base)); + delete o; + } +}; +#endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + +signal_set_service::signal_set_service(execution_context& context) + : execution_context_service_base(context), + scheduler_(boost::asio::use_service(context)), +#if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + reactor_(boost::asio::use_service(context)), +#endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + next_(0), + prev_(0) +{ + get_signal_state()->mutex_.init(); + +#if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + reactor_.init_task(); +#endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + + for (int i = 0; i < max_signal_number; ++i) + registrations_[i] = 0; + + add_service(this); +} + +signal_set_service::~signal_set_service() +{ + remove_service(this); +} + +void signal_set_service::shutdown() +{ + remove_service(this); + + op_queue ops; + + for (int i = 0; i < max_signal_number; ++i) + { + registration* reg = registrations_[i]; + while (reg) + { + ops.push(*reg->queue_); + reg = reg->next_in_table_; + } + } + + scheduler_.abandon_operations(ops); +} + +void signal_set_service::notify_fork(execution_context::fork_event fork_ev) +{ +#if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + switch (fork_ev) + { + case execution_context::fork_prepare: + { + int read_descriptor = state->read_descriptor_; + state->fork_prepared_ = true; + lock.unlock(); + reactor_.deregister_internal_descriptor(read_descriptor, reactor_data_); + reactor_.cleanup_descriptor_data(reactor_data_); + } + break; + case execution_context::fork_parent: + if (state->fork_prepared_) + { + int read_descriptor = state->read_descriptor_; + state->fork_prepared_ = false; + lock.unlock(); + reactor_.register_internal_descriptor(reactor::read_op, + read_descriptor, reactor_data_, new pipe_read_op); + } + break; + case execution_context::fork_child: + if (state->fork_prepared_) + { + boost::asio::detail::signal_blocker blocker; + close_descriptors(); + open_descriptors(); + int read_descriptor = state->read_descriptor_; + state->fork_prepared_ = false; + lock.unlock(); + reactor_.register_internal_descriptor(reactor::read_op, + read_descriptor, reactor_data_, new pipe_read_op); + } + break; + default: + break; + } +#else // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + (void)fork_ev; +#endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +} + +void signal_set_service::construct( + signal_set_service::implementation_type& impl) +{ + impl.signals_ = 0; +} + +void signal_set_service::destroy( + signal_set_service::implementation_type& impl) +{ + boost::system::error_code ignored_ec; + clear(impl, ignored_ec); + cancel(impl, ignored_ec); +} + +boost::system::error_code signal_set_service::add( + signal_set_service::implementation_type& impl, + int signal_number, boost::system::error_code& ec) +{ + // Check that the signal number is valid. + if (signal_number < 0 || signal_number >= max_signal_number) + { + ec = boost::asio::error::invalid_argument; + return ec; + } + + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + // Find the appropriate place to insert the registration. + registration** insertion_point = &impl.signals_; + registration* next = impl.signals_; + while (next && next->signal_number_ < signal_number) + { + insertion_point = &next->next_in_set_; + next = next->next_in_set_; + } + + // Only do something if the signal is not already registered. + if (next == 0 || next->signal_number_ != signal_number) + { + registration* new_registration = new registration; + +#if defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION) + // Register for the signal if we're the first. + if (state->registration_count_[signal_number] == 0) + { +# if defined(BOOST_ASIO_HAS_SIGACTION) + using namespace std; // For memset. + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = boost_asio_signal_handler; + sigfillset(&sa.sa_mask); + if (::sigaction(signal_number, &sa, 0) == -1) +# else // defined(BOOST_ASIO_HAS_SIGACTION) + if (::signal(signal_number, boost_asio_signal_handler) == SIG_ERR) +# endif // defined(BOOST_ASIO_HAS_SIGACTION) + { +# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + ec = boost::asio::error::invalid_argument; +# else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + ec = boost::system::error_code(errno, + boost::asio::error::get_system_category()); +# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + delete new_registration; + return ec; + } + } +#endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION) + + // Record the new registration in the set. + new_registration->signal_number_ = signal_number; + new_registration->queue_ = &impl.queue_; + new_registration->next_in_set_ = next; + *insertion_point = new_registration; + + // Insert registration into the registration table. + new_registration->next_in_table_ = registrations_[signal_number]; + if (registrations_[signal_number]) + registrations_[signal_number]->prev_in_table_ = new_registration; + registrations_[signal_number] = new_registration; + + ++state->registration_count_[signal_number]; + } + + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code signal_set_service::remove( + signal_set_service::implementation_type& impl, + int signal_number, boost::system::error_code& ec) +{ + // Check that the signal number is valid. + if (signal_number < 0 || signal_number >= max_signal_number) + { + ec = boost::asio::error::invalid_argument; + return ec; + } + + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + // Find the signal number in the list of registrations. + registration** deletion_point = &impl.signals_; + registration* reg = impl.signals_; + while (reg && reg->signal_number_ < signal_number) + { + deletion_point = ®->next_in_set_; + reg = reg->next_in_set_; + } + + if (reg != 0 && reg->signal_number_ == signal_number) + { +#if defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION) + // Set signal handler back to the default if we're the last. + if (state->registration_count_[signal_number] == 1) + { +# if defined(BOOST_ASIO_HAS_SIGACTION) + using namespace std; // For memset. + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + if (::sigaction(signal_number, &sa, 0) == -1) +# else // defined(BOOST_ASIO_HAS_SIGACTION) + if (::signal(signal_number, SIG_DFL) == SIG_ERR) +# endif // defined(BOOST_ASIO_HAS_SIGACTION) + { +# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + ec = boost::asio::error::invalid_argument; +# else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + ec = boost::system::error_code(errno, + boost::asio::error::get_system_category()); +# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + return ec; + } + } +#endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION) + + // Remove the registration from the set. + *deletion_point = reg->next_in_set_; + + // Remove the registration from the registration table. + if (registrations_[signal_number] == reg) + registrations_[signal_number] = reg->next_in_table_; + if (reg->prev_in_table_) + reg->prev_in_table_->next_in_table_ = reg->next_in_table_; + if (reg->next_in_table_) + reg->next_in_table_->prev_in_table_ = reg->prev_in_table_; + + --state->registration_count_[signal_number]; + + delete reg; + } + + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code signal_set_service::clear( + signal_set_service::implementation_type& impl, + boost::system::error_code& ec) +{ + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + while (registration* reg = impl.signals_) + { +#if defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION) + // Set signal handler back to the default if we're the last. + if (state->registration_count_[reg->signal_number_] == 1) + { +# if defined(BOOST_ASIO_HAS_SIGACTION) + using namespace std; // For memset. + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + if (::sigaction(reg->signal_number_, &sa, 0) == -1) +# else // defined(BOOST_ASIO_HAS_SIGACTION) + if (::signal(reg->signal_number_, SIG_DFL) == SIG_ERR) +# endif // defined(BOOST_ASIO_HAS_SIGACTION) + { +# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + ec = boost::asio::error::invalid_argument; +# else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + ec = boost::system::error_code(errno, + boost::asio::error::get_system_category()); +# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + return ec; + } + } +#endif // defined(BOOST_ASIO_HAS_SIGNAL) || defined(BOOST_ASIO_HAS_SIGACTION) + + // Remove the registration from the registration table. + if (registrations_[reg->signal_number_] == reg) + registrations_[reg->signal_number_] = reg->next_in_table_; + if (reg->prev_in_table_) + reg->prev_in_table_->next_in_table_ = reg->next_in_table_; + if (reg->next_in_table_) + reg->next_in_table_->prev_in_table_ = reg->prev_in_table_; + + --state->registration_count_[reg->signal_number_]; + + impl.signals_ = reg->next_in_set_; + delete reg; + } + + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code signal_set_service::cancel( + signal_set_service::implementation_type& impl, + boost::system::error_code& ec) +{ + BOOST_ASIO_HANDLER_OPERATION((scheduler_.context(), + "signal_set", &impl, 0, "cancel")); + + op_queue ops; + { + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + while (signal_op* op = impl.queue_.front()) + { + op->ec_ = boost::asio::error::operation_aborted; + impl.queue_.pop(); + ops.push(op); + } + } + + scheduler_.post_deferred_completions(ops); + + ec = boost::system::error_code(); + return ec; +} + +void signal_set_service::deliver_signal(int signal_number) +{ + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + signal_set_service* service = state->service_list_; + while (service) + { + op_queue ops; + + registration* reg = service->registrations_[signal_number]; + while (reg) + { + if (reg->queue_->empty()) + { + ++reg->undelivered_; + } + else + { + while (signal_op* op = reg->queue_->front()) + { + op->signal_number_ = signal_number; + reg->queue_->pop(); + ops.push(op); + } + } + + reg = reg->next_in_table_; + } + + service->scheduler_.post_deferred_completions(ops); + + service = service->next_; + } +} + +void signal_set_service::add_service(signal_set_service* service) +{ + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + +#if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + // If this is the first service to be created, open a new pipe. + if (state->service_list_ == 0) + open_descriptors(); +#endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + + // If a scheduler_ object is thread-unsafe then it must be the only + // scheduler used to create signal_set objects. + if (state->service_list_ != 0) + { + if (!BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER, + service->scheduler_.concurrency_hint()) + || !BOOST_ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER, + state->service_list_->scheduler_.concurrency_hint())) + { + std::logic_error ex( + "Thread-unsafe execution context objects require " + "exclusive access to signal handling."); + boost::asio::detail::throw_exception(ex); + } + } + + // Insert service into linked list of all services. + service->next_ = state->service_list_; + service->prev_ = 0; + if (state->service_list_) + state->service_list_->prev_ = service; + state->service_list_ = service; + +#if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + // Register for pipe readiness notifications. + int read_descriptor = state->read_descriptor_; + lock.unlock(); + service->reactor_.register_internal_descriptor(reactor::read_op, + read_descriptor, service->reactor_data_, new pipe_read_op); +#endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +} + +void signal_set_service::remove_service(signal_set_service* service) +{ + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + if (service->next_ || service->prev_ || state->service_list_ == service) + { +#if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + // Disable the pipe readiness notifications. + int read_descriptor = state->read_descriptor_; + lock.unlock(); + service->reactor_.deregister_internal_descriptor( + read_descriptor, service->reactor_data_); + service->reactor_.cleanup_descriptor_data(service->reactor_data_); + lock.lock(); +#endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + + // Remove service from linked list of all services. + if (state->service_list_ == service) + state->service_list_ = service->next_; + if (service->prev_) + service->prev_->next_ = service->next_; + if (service->next_) + service->next_->prev_= service->prev_; + service->next_ = 0; + service->prev_ = 0; + +#if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + // If this is the last service to be removed, close the pipe. + if (state->service_list_ == 0) + close_descriptors(); +#endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + } +} + +void signal_set_service::open_descriptors() +{ +#if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + signal_state* state = get_signal_state(); + + int pipe_fds[2]; + if (::pipe(pipe_fds) == 0) + { + state->read_descriptor_ = pipe_fds[0]; + ::fcntl(state->read_descriptor_, F_SETFL, O_NONBLOCK); + + state->write_descriptor_ = pipe_fds[1]; + ::fcntl(state->write_descriptor_, F_SETFL, O_NONBLOCK); + +#if defined(FD_CLOEXEC) + ::fcntl(state->read_descriptor_, F_SETFD, FD_CLOEXEC); + ::fcntl(state->write_descriptor_, F_SETFD, FD_CLOEXEC); +#endif // defined(FD_CLOEXEC) + } + else + { + boost::system::error_code ec(errno, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "signal_set_service pipe"); + } +#endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +} + +void signal_set_service::close_descriptors() +{ +#if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + signal_state* state = get_signal_state(); + + if (state->read_descriptor_ != -1) + ::close(state->read_descriptor_); + state->read_descriptor_ = -1; + + if (state->write_descriptor_ != -1) + ::close(state->write_descriptor_); + state->write_descriptor_ = -1; +#endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) +} + +void signal_set_service::start_wait_op( + signal_set_service::implementation_type& impl, signal_op* op) +{ + scheduler_.work_started(); + + signal_state* state = get_signal_state(); + static_mutex::scoped_lock lock(state->mutex_); + + registration* reg = impl.signals_; + while (reg) + { + if (reg->undelivered_ > 0) + { + --reg->undelivered_; + op->signal_number_ = reg->signal_number_; + scheduler_.post_deferred_completion(op); + return; + } + + reg = reg->next_in_set_; + } + + impl.queue_.push(op); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP diff --git a/boost/asio/detail/impl/socket_ops.ipp b/boost/asio/detail/impl/socket_ops.ipp new file mode 100644 index 0000000..7d7c31f --- /dev/null +++ b/boost/asio/detail/impl/socket_ops.ipp @@ -0,0 +1,3574 @@ +// +// detail/impl/socket_ops.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SOCKET_OPS_IPP +#define BOOST_ASIO_DETAIL_SOCKET_OPS_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +# include +# include +# include +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) \ + || defined(__MACH__) && defined(__APPLE__) +# if defined(BOOST_ASIO_HAS_PTHREADS) +# include +# endif // defined(BOOST_ASIO_HAS_PTHREADS) +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + // || defined(__MACH__) && defined(__APPLE__) + +#include + +namespace boost { +namespace asio { +namespace detail { +namespace socket_ops { + +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +struct msghdr { int msg_namelen; }; +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +#if defined(__hpux) +// HP-UX doesn't declare these functions extern "C", so they are declared again +// here to avoid linker errors about undefined symbols. +extern "C" char* if_indextoname(unsigned int, char*); +extern "C" unsigned int if_nametoindex(const char*); +#endif // defined(__hpux) + +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +inline void clear_last_error() +{ +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + WSASetLastError(0); +#else + errno = 0; +#endif +} + +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +template +inline ReturnType error_wrapper(ReturnType return_value, + boost::system::error_code& ec) +{ +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + ec = boost::system::error_code(WSAGetLastError(), + boost::asio::error::get_system_category()); +#else + ec = boost::system::error_code(errno, + boost::asio::error::get_system_category()); +#endif + return return_value; +} + +template +inline socket_type call_accept(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; + socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0); + if (addrlen) + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +socket_type accept(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return invalid_socket; + } + + clear_last_error(); + + socket_type new_s = error_wrapper(call_accept( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (new_s == invalid_socket) + return new_s; + +#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) + int optval = 1; + int result = error_wrapper(::setsockopt(new_s, + SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); + if (result != 0) + { + ::close(new_s); + return invalid_socket; + } +#endif + + ec = boost::system::error_code(); + return new_s; +} + +socket_type sync_accept(socket_type s, state_type state, + socket_addr_type* addr, std::size_t* addrlen, boost::system::error_code& ec) +{ + // Accept a socket. + for (;;) + { + // Try to complete the operation without blocking. + socket_type new_socket = socket_ops::accept(s, addr, addrlen, ec); + + // Check if operation succeeded. + if (new_socket != invalid_socket) + return new_socket; + + // Operation failed. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + { + if (state & user_set_non_blocking) + return invalid_socket; + // Fall through to retry operation. + } + else if (ec == boost::asio::error::connection_aborted) + { + if (state & enable_connection_aborted) + return invalid_socket; + // Fall through to retry operation. + } +#if defined(EPROTO) + else if (ec.value() == EPROTO) + { + if (state & enable_connection_aborted) + return invalid_socket; + // Fall through to retry operation. + } +#endif // defined(EPROTO) + else + return invalid_socket; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return invalid_socket; + } +} + +#if defined(BOOST_ASIO_HAS_IOCP) + +void complete_iocp_accept(socket_type s, + void* output_buffer, DWORD address_length, + socket_addr_type* addr, std::size_t* addrlen, + socket_type new_socket, boost::system::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + ec = boost::asio::error::connection_aborted; + + if (!ec) + { + // Get the address of the peer. + if (addr && addrlen) + { + LPSOCKADDR local_addr = 0; + int local_addr_length = 0; + LPSOCKADDR remote_addr = 0; + int remote_addr_length = 0; + GetAcceptExSockaddrs(output_buffer, 0, address_length, + address_length, &local_addr, &local_addr_length, + &remote_addr, &remote_addr_length); + if (static_cast(remote_addr_length) > *addrlen) + { + ec = boost::asio::error::invalid_argument; + } + else + { + using namespace std; // For memcpy. + memcpy(addr, remote_addr, remote_addr_length); + *addrlen = static_cast(remote_addr_length); + } + } + + // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname + // and getpeername will work on the accepted socket. + SOCKET update_ctx_param = s; + socket_ops::state_type state = 0; + socket_ops::setsockopt(new_socket, state, + SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, + &update_ctx_param, sizeof(SOCKET), ec); + } +} + +#else // defined(BOOST_ASIO_HAS_IOCP) + +bool non_blocking_accept(socket_type s, + state_type state, socket_addr_type* addr, std::size_t* addrlen, + boost::system::error_code& ec, socket_type& new_socket) +{ + for (;;) + { + // Accept the waiting connection. + new_socket = socket_ops::accept(s, addr, addrlen, ec); + + // Check if operation succeeded. + if (new_socket != invalid_socket) + return true; + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Operation failed. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + { + // Fall through to retry operation. + } + else if (ec == boost::asio::error::connection_aborted) + { + if (state & enable_connection_aborted) + return true; + // Fall through to retry operation. + } +#if defined(EPROTO) + else if (ec.value() == EPROTO) + { + if (state & enable_connection_aborted) + return true; + // Fall through to retry operation. + } +#endif // defined(EPROTO) + else + return true; + + return false; + } +} + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +template +inline int call_bind(SockLenType msghdr::*, + socket_type s, const socket_addr_type* addr, std::size_t addrlen) +{ + return ::bind(s, addr, (SockLenType)addrlen); +} + +int bind(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(call_bind( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +int close(socket_type s, state_type& state, + bool destruction, boost::system::error_code& ec) +{ + int result = 0; + if (s != invalid_socket) + { + // We don't want the destructor to block, so set the socket to linger in + // the background. If the user doesn't like this behaviour then they need + // to explicitly close the socket. + if (destruction && (state & user_set_linger)) + { + ::linger opt; + opt.l_onoff = 0; + opt.l_linger = 0; + boost::system::error_code ignored_ec; + socket_ops::setsockopt(s, state, SOL_SOCKET, + SO_LINGER, &opt, sizeof(opt), ignored_ec); + } + + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + result = error_wrapper(::closesocket(s), ec); +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + result = error_wrapper(::close(s), ec); +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + + if (result != 0 + && (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again)) + { + // According to UNIX Network Programming Vol. 1, it is possible for + // close() to fail with EWOULDBLOCK under certain circumstances. What + // isn't clear is the state of the descriptor after this error. The one + // current OS where this behaviour is seen, Windows, says that the socket + // remains open. Therefore we'll put the descriptor back into blocking + // mode and have another attempt at closing it. +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + ioctl_arg_type arg = 0; + ::ioctlsocket(s, FIONBIO, &arg); +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(__SYMBIAN32__) + int flags = ::fcntl(s, F_GETFL, 0); + if (flags >= 0) + ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK); +# else // defined(__SYMBIAN32__) + ioctl_arg_type arg = 0; + ::ioctl(s, FIONBIO, &arg); +# endif // defined(__SYMBIAN32__) +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + state &= ~non_blocking; + + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + result = error_wrapper(::closesocket(s), ec); +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + result = error_wrapper(::close(s), ec); +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + } + } + + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +bool set_user_non_blocking(socket_type s, + state_type& state, bool value, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return false; + } + + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + ioctl_arg_type arg = (value ? 1 : 0); + int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec); +#elif defined(__SYMBIAN32__) + int result = error_wrapper(::fcntl(s, F_GETFL, 0), ec); + if (result >= 0) + { + clear_last_error(); + int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); + result = error_wrapper(::fcntl(s, F_SETFL, flag), ec); + } +#else + ioctl_arg_type arg = (value ? 1 : 0); + int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec); +#endif + + if (result >= 0) + { + ec = boost::system::error_code(); + if (value) + state |= user_set_non_blocking; + else + { + // Clearing the user-set non-blocking mode always overrides any + // internally-set non-blocking flag. Any subsequent asynchronous + // operations will need to re-enable non-blocking I/O. + state &= ~(user_set_non_blocking | internal_non_blocking); + } + return true; + } + + return false; +} + +bool set_internal_non_blocking(socket_type s, + state_type& state, bool value, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return false; + } + + if (!value && (state & user_set_non_blocking)) + { + // It does not make sense to clear the internal non-blocking flag if the + // user still wants non-blocking behaviour. Return an error and let the + // caller figure out whether to update the user-set non-blocking flag. + ec = boost::asio::error::invalid_argument; + return false; + } + + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + ioctl_arg_type arg = (value ? 1 : 0); + int result = error_wrapper(::ioctlsocket(s, FIONBIO, &arg), ec); +#elif defined(__SYMBIAN32__) + int result = error_wrapper(::fcntl(s, F_GETFL, 0), ec); + if (result >= 0) + { + clear_last_error(); + int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); + result = error_wrapper(::fcntl(s, F_SETFL, flag), ec); + } +#else + ioctl_arg_type arg = (value ? 1 : 0); + int result = error_wrapper(::ioctl(s, FIONBIO, &arg), ec); +#endif + + if (result >= 0) + { + ec = boost::system::error_code(); + if (value) + state |= internal_non_blocking; + else + state &= ~internal_non_blocking; + return true; + } + + return false; +} + +int shutdown(socket_type s, int what, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(::shutdown(s, what), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +template +inline int call_connect(SockLenType msghdr::*, + socket_type s, const socket_addr_type* addr, std::size_t addrlen) +{ + return ::connect(s, addr, (SockLenType)addrlen); +} + +int connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(call_connect( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = boost::system::error_code(); +#if defined(__linux__) + else if (ec == boost::asio::error::try_again) + ec = boost::asio::error::no_buffer_space; +#endif // defined(__linux__) + return result; +} + +void sync_connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec) +{ + // Perform the connect operation. + socket_ops::connect(s, addr, addrlen, ec); + if (ec != boost::asio::error::in_progress + && ec != boost::asio::error::would_block) + { + // The connect operation finished immediately. + return; + } + + // Wait for socket to become ready. + if (socket_ops::poll_connect(s, -1, ec) < 0) + return; + + // Get the error code from the connect operation. + int connect_error = 0; + size_t connect_error_len = sizeof(connect_error); + if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR, + &connect_error, &connect_error_len, ec) == socket_error_retval) + return; + + // Return the result of the connect operation. + ec = boost::system::error_code(connect_error, + boost::asio::error::get_system_category()); +} + +#if defined(BOOST_ASIO_HAS_IOCP) + +void complete_iocp_connect(socket_type s, boost::system::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + switch (ec.value()) + { + case ERROR_CONNECTION_REFUSED: + ec = boost::asio::error::connection_refused; + break; + case ERROR_NETWORK_UNREACHABLE: + ec = boost::asio::error::network_unreachable; + break; + case ERROR_HOST_UNREACHABLE: + ec = boost::asio::error::host_unreachable; + break; + case ERROR_SEM_TIMEOUT: + ec = boost::asio::error::timed_out; + break; + default: + break; + } + + if (!ec) + { + // Need to set the SO_UPDATE_CONNECT_CONTEXT option so that getsockname + // and getpeername will work on the connected socket. + socket_ops::state_type state = 0; + const int so_update_connect_context = 0x7010; + socket_ops::setsockopt(s, state, SOL_SOCKET, + so_update_connect_context, 0, 0, ec); + } +} + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +bool non_blocking_connect(socket_type s, boost::system::error_code& ec) +{ + // Check if the connect operation has finished. This is required since we may + // get spurious readiness notifications from the reactor. +#if defined(BOOST_ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set write_fds; + FD_ZERO(&write_fds); + FD_SET(s, &write_fds); + fd_set except_fds; + FD_ZERO(&except_fds); + FD_SET(s, &except_fds); + timeval zero_timeout; + zero_timeout.tv_sec = 0; + zero_timeout.tv_usec = 0; + int ready = ::select(s + 1, 0, &write_fds, &except_fds, &zero_timeout); +#else // defined(BOOST_ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLOUT; + fds.revents = 0; + int ready = ::poll(&fds, 1, 0); +#endif // defined(BOOST_ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + if (ready == 0) + { + // The asynchronous connect operation is still in progress. + return false; + } + + // Get the error code from the connect operation. + int connect_error = 0; + size_t connect_error_len = sizeof(connect_error); + if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_ERROR, + &connect_error, &connect_error_len, ec) == 0) + { + if (connect_error) + { + ec = boost::system::error_code(connect_error, + boost::asio::error::get_system_category()); + } + else + ec = boost::system::error_code(); + } + + return true; +} + +int socketpair(int af, int type, int protocol, + socket_type sv[2], boost::system::error_code& ec) +{ +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + (void)(af); + (void)(type); + (void)(protocol); + (void)(sv); + ec = boost::asio::error::operation_not_supported; + return socket_error_retval; +#else + clear_last_error(); + int result = error_wrapper(::socketpair(af, type, protocol, sv), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +#endif +} + +bool sockatmark(socket_type s, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return false; + } + +#if defined(SIOCATMARK) + ioctl_arg_type value = 0; +# if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctlsocket(s, SIOCATMARK, &value), ec); +# else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctl(s, SIOCATMARK, &value), ec); +# endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + if (result == 0) + ec = boost::system::error_code(); +# if defined(ENOTTY) + if (ec.value() == ENOTTY) + ec = boost::asio::error::not_socket; +# endif // defined(ENOTTY) +#else // defined(SIOCATMARK) + int value = error_wrapper(::sockatmark(s), ec); + if (value != -1) + ec = boost::system::error_code(); +#endif // defined(SIOCATMARK) + + return ec ? false : value != 0; +} + +size_t available(socket_type s, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + ioctl_arg_type value = 0; +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctlsocket(s, FIONREAD, &value), ec); +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctl(s, FIONREAD, &value), ec); +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + if (result == 0) + ec = boost::system::error_code(); +#if defined(ENOTTY) + if (ec.value() == ENOTTY) + ec = boost::asio::error::not_socket; +#endif // defined(ENOTTY) + + return ec ? static_cast(0) : static_cast(value); +} + +int listen(socket_type s, int backlog, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(::listen(s, backlog), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +inline void init_buf_iov_base(void*& base, void* addr) +{ + base = addr; +} + +template +inline void init_buf_iov_base(T& base, void* addr) +{ + base = static_cast(addr); +} + +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +typedef WSABUF buf; +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +typedef iovec buf; +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +void init_buf(buf& b, void* data, size_t size) +{ +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + b.buf = static_cast(data); + b.len = static_cast(size); +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + init_buf_iov_base(b.iov_base, data); + b.iov_len = size; +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +} + +void init_buf(buf& b, const void* data, size_t size) +{ +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + b.buf = static_cast(const_cast(data)); + b.len = static_cast(size); +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + init_buf_iov_base(b.iov_base, const_cast(data)); + b.iov_len = size; +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +} + +inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr) +{ + name = addr; +} + +inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr) +{ + name = const_cast(addr); +} + +template +inline void init_msghdr_msg_name(T& name, socket_addr_type* addr) +{ + name = reinterpret_cast(addr); +} + +template +inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr) +{ + name = reinterpret_cast(const_cast(addr)); +} + +signed_size_type recv(socket_type s, buf* bufs, size_t count, + int flags, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + DWORD recv_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = error_wrapper(::WSARecv(s, bufs, + recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = boost::asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = boost::asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + result = 0; + if (result != 0) + return socket_error_retval; + ec = boost::system::error_code(); + return bytes_transferred; +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + msg.msg_iov = bufs; + msg.msg_iovlen = static_cast(count); + signed_size_type result = error_wrapper(::recvmsg(s, &msg, flags), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_recv(socket_type s, state_type state, buf* bufs, + size_t count, int flags, bool all_empty, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream is a no-op. + if (all_empty && (state & stream_oriented)) + { + ec = boost::system::error_code(); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec); + + // Check if operation succeeded. + if (bytes > 0) + return bytes; + + // Check for EOF. + if ((state & stream_oriented) && bytes == 0) + { + ec = boost::asio::error::eof; + return 0; + } + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return 0; + } +} + +#if defined(BOOST_ASIO_HAS_IOCP) + +void complete_iocp_recv(state_type state, + const weak_cancel_token_type& cancel_token, bool all_empty, + boost::system::error_code& ec, size_t bytes_transferred) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (cancel_token.expired()) + ec = boost::asio::error::operation_aborted; + else + ec = boost::asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = boost::asio::error::connection_refused; + } + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + { + ec.assign(0, ec.category()); + } + + // Check for connection closed. + else if (!ec && bytes_transferred == 0 + && (state & stream_oriented) != 0 + && !all_empty) + { + ec = boost::asio::error::eof; + } +} + +#else // defined(BOOST_ASIO_HAS_IOCP) + +bool non_blocking_recv(socket_type s, + buf* bufs, size_t count, int flags, bool is_stream, + boost::system::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = socket_ops::recv(s, bufs, count, flags, ec); + + // Check for end of stream. + if (is_stream && bytes == 0) + { + ec = boost::asio::error::eof; + return true; + } + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +signed_size_type recvfrom(socket_type s, buf* bufs, size_t count, + int flags, socket_addr_type* addr, std::size_t* addrlen, + boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + // Receive some data. + DWORD recv_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int tmp_addrlen = (int)*addrlen; + int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count, + &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec); + *addrlen = (std::size_t)tmp_addrlen; + if (ec.value() == ERROR_NETNAME_DELETED) + ec = boost::asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = boost::asio::error::connection_refused; + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + result = 0; + if (result != 0) + return socket_error_retval; + ec = boost::system::error_code(); + return bytes_transferred; +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + init_msghdr_msg_name(msg.msg_name, addr); + msg.msg_namelen = static_cast(*addrlen); + msg.msg_iov = bufs; + msg.msg_iovlen = static_cast(count); + signed_size_type result = error_wrapper(::recvmsg(s, &msg, flags), ec); + *addrlen = msg.msg_namelen; + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_recvfrom(socket_type s, state_type state, buf* bufs, + size_t count, int flags, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::recvfrom( + s, bufs, count, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return 0; + } +} + +#if defined(BOOST_ASIO_HAS_IOCP) + +void complete_iocp_recvfrom( + const weak_cancel_token_type& cancel_token, + boost::system::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (cancel_token.expired()) + ec = boost::asio::error::operation_aborted; + else + ec = boost::asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = boost::asio::error::connection_refused; + } + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + { + ec.assign(0, ec.category()); + } +} + +#else // defined(BOOST_ASIO_HAS_IOCP) + +bool non_blocking_recvfrom(socket_type s, + buf* bufs, size_t count, int flags, + socket_addr_type* addr, std::size_t* addrlen, + boost::system::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = socket_ops::recvfrom( + s, bufs, count, flags, addr, addrlen, ec); + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +signed_size_type recvmsg(socket_type s, buf* bufs, size_t count, + int in_flags, int& out_flags, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + out_flags = 0; + return socket_ops::recv(s, bufs, count, in_flags, ec); +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + msg.msg_iov = bufs; + msg.msg_iovlen = static_cast(count); + signed_size_type result = error_wrapper(::recvmsg(s, &msg, in_flags), ec); + if (result >= 0) + { + ec = boost::system::error_code(); + out_flags = msg.msg_flags; + } + else + out_flags = 0; + return result; +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_recvmsg(socket_type s, state_type state, + buf* bufs, size_t count, int in_flags, int& out_flags, + boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::recvmsg( + s, bufs, count, in_flags, out_flags, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_read(s, 0, -1, ec) < 0) + return 0; + } +} + +#if defined(BOOST_ASIO_HAS_IOCP) + +void complete_iocp_recvmsg( + const weak_cancel_token_type& cancel_token, + boost::system::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (cancel_token.expired()) + ec = boost::asio::error::operation_aborted; + else + ec = boost::asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = boost::asio::error::connection_refused; + } + else if (ec.value() == WSAEMSGSIZE || ec.value() == ERROR_MORE_DATA) + { + ec.assign(0, ec.category()); + } +} + +#else // defined(BOOST_ASIO_HAS_IOCP) + +bool non_blocking_recvmsg(socket_type s, + buf* bufs, size_t count, int in_flags, int& out_flags, + boost::system::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Read some data. + signed_size_type bytes = socket_ops::recvmsg( + s, bufs, count, in_flags, out_flags, ec); + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +signed_size_type send(socket_type s, const buf* bufs, size_t count, + int flags, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + // Send the data. + DWORD send_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + DWORD send_flags = flags; + int result = error_wrapper(::WSASend(s, const_cast(bufs), + send_buf_count, &bytes_transferred, send_flags, 0, 0), ec); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = boost::asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = boost::asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec = boost::system::error_code(); + return bytes_transferred; +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + msg.msg_iov = const_cast(bufs); + msg.msg_iovlen = static_cast(count); +#if defined(__linux__) + flags |= MSG_NOSIGNAL; +#endif // defined(__linux__) + signed_size_type result = error_wrapper(::sendmsg(s, &msg, flags), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_send(socket_type s, state_type state, const buf* bufs, + size_t count, int flags, bool all_empty, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes to a stream is a no-op. + if (all_empty && (state & stream_oriented)) + { + ec = boost::system::error_code(); + return 0; + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, 0, -1, ec) < 0) + return 0; + } +} + +#if defined(BOOST_ASIO_HAS_IOCP) + +void complete_iocp_send( + const weak_cancel_token_type& cancel_token, + boost::system::error_code& ec) +{ + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (cancel_token.expired()) + ec = boost::asio::error::operation_aborted; + else + ec = boost::asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = boost::asio::error::connection_refused; + } +} + +#else // defined(BOOST_ASIO_HAS_IOCP) + +bool non_blocking_send(socket_type s, + const buf* bufs, size_t count, int flags, + boost::system::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = socket_ops::send(s, bufs, count, flags, ec); + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +signed_size_type sendto(socket_type s, const buf* bufs, size_t count, + int flags, const socket_addr_type* addr, std::size_t addrlen, + boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + // Send the data. + DWORD send_buf_count = static_cast(count); + DWORD bytes_transferred = 0; + int result = error_wrapper(::WSASendTo(s, const_cast(bufs), + send_buf_count, &bytes_transferred, flags, addr, + static_cast(addrlen), 0, 0), ec); + if (ec.value() == ERROR_NETNAME_DELETED) + ec = boost::asio::error::connection_reset; + else if (ec.value() == ERROR_PORT_UNREACHABLE) + ec = boost::asio::error::connection_refused; + if (result != 0) + return socket_error_retval; + ec = boost::system::error_code(); + return bytes_transferred; +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + msghdr msg = msghdr(); + init_msghdr_msg_name(msg.msg_name, addr); + msg.msg_namelen = static_cast(addrlen); + msg.msg_iov = const_cast(bufs); + msg.msg_iovlen = static_cast(count); +#if defined(__linux__) + flags |= MSG_NOSIGNAL; +#endif // defined(__linux__) + signed_size_type result = error_wrapper(::sendmsg(s, &msg, flags), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +} + +size_t sync_sendto(socket_type s, state_type state, const buf* bufs, + size_t count, int flags, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // Write some data. + for (;;) + { + // Try to complete the operation without blocking. + signed_size_type bytes = socket_ops::sendto( + s, bufs, count, flags, addr, addrlen, ec); + + // Check if operation succeeded. + if (bytes >= 0) + return bytes; + + // Operation failed. + if ((state & user_set_non_blocking) + || (ec != boost::asio::error::would_block + && ec != boost::asio::error::try_again)) + return 0; + + // Wait for socket to become ready. + if (socket_ops::poll_write(s, 0, -1, ec) < 0) + return 0; + } +} + +#if !defined(BOOST_ASIO_HAS_IOCP) + +bool non_blocking_sendto(socket_type s, + const buf* bufs, size_t count, int flags, + const socket_addr_type* addr, std::size_t addrlen, + boost::system::error_code& ec, size_t& bytes_transferred) +{ + for (;;) + { + // Write some data. + signed_size_type bytes = socket_ops::sendto( + s, bufs, count, flags, addr, addrlen, ec); + + // Retry operation if interrupted by signal. + if (ec == boost::asio::error::interrupted) + continue; + + // Check if we need to run the operation again. + if (ec == boost::asio::error::would_block + || ec == boost::asio::error::try_again) + return false; + + // Operation is complete. + if (bytes >= 0) + { + ec = boost::system::error_code(); + bytes_transferred = bytes; + } + else + bytes_transferred = 0; + + return true; + } +} + +#endif // !defined(BOOST_ASIO_HAS_IOCP) + +socket_type socket(int af, int type, int protocol, + boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + socket_type s = error_wrapper(::WSASocketW(af, type, protocol, 0, 0, + WSA_FLAG_OVERLAPPED), ec); + if (s == invalid_socket) + return s; + + if (af == BOOST_ASIO_OS_DEF(AF_INET6)) + { + // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to + // false. This will only succeed on Windows Vista and later versions of + // Windows, where a dual-stack IPv4/v6 implementation is available. + DWORD optval = 0; + ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + reinterpret_cast(&optval), sizeof(optval)); + } + + ec = boost::system::error_code(); + + return s; +#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) + socket_type s = error_wrapper(::socket(af, type, protocol), ec); + if (s == invalid_socket) + return s; + + int optval = 1; + int result = error_wrapper(::setsockopt(s, + SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); + if (result != 0) + { + ::close(s); + return invalid_socket; + } + + return s; +#else + int s = error_wrapper(::socket(af, type, protocol), ec); + if (s >= 0) + ec = boost::system::error_code(); + return s; +#endif +} + +template +inline int call_setsockopt(SockLenType msghdr::*, + socket_type s, int level, int optname, + const void* optval, std::size_t optlen) +{ + return ::setsockopt(s, level, optname, + (const char*)optval, (SockLenType)optlen); +} + +int setsockopt(socket_type s, state_type& state, int level, int optname, + const void* optval, std::size_t optlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + if (level == custom_socket_option_level && optname == always_fail_option) + { + ec = boost::asio::error::invalid_argument; + return socket_error_retval; + } + + if (level == custom_socket_option_level + && optname == enable_connection_aborted_option) + { + if (optlen != sizeof(int)) + { + ec = boost::asio::error::invalid_argument; + return socket_error_retval; + } + + if (*static_cast(optval)) + state |= enable_connection_aborted; + else + state &= ~enable_connection_aborted; + ec = boost::system::error_code(); + return 0; + } + + if (level == SOL_SOCKET && optname == SO_LINGER) + state |= user_set_linger; + +#if defined(__BORLANDC__) + // Mysteriously, using the getsockopt and setsockopt functions directly with + // Borland C++ results in incorrect values being set and read. The bug can be + // worked around by using function addresses resolved with GetProcAddress. + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int); + if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt")) + { + clear_last_error(); + return error_wrapper(sso(s, level, optname, + reinterpret_cast(optval), + static_cast(optlen)), ec); + } + } + ec = boost::asio::error::fault; + return socket_error_retval; +#else // defined(__BORLANDC__) + clear_last_error(); + int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); + if (result == 0) + { + ec = boost::system::error_code(); + +#if defined(__MACH__) && defined(__APPLE__) \ + || defined(__NetBSD__) || defined(__FreeBSD__) \ + || defined(__OpenBSD__) || defined(__QNX__) + // To implement portable behaviour for SO_REUSEADDR with UDP sockets we + // need to also set SO_REUSEPORT on BSD-based platforms. + if ((state & datagram_oriented) + && level == SOL_SOCKET && optname == SO_REUSEADDR) + { + call_setsockopt(&msghdr::msg_namelen, s, + SOL_SOCKET, SO_REUSEPORT, optval, optlen); + } +#endif + } + + return result; +#endif // defined(__BORLANDC__) +} + +template +inline int call_getsockopt(SockLenType msghdr::*, + socket_type s, int level, int optname, + void* optval, std::size_t* optlen) +{ + SockLenType tmp_optlen = (SockLenType)*optlen; + int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen); + *optlen = (std::size_t)tmp_optlen; + return result; +} + +int getsockopt(socket_type s, state_type state, int level, int optname, + void* optval, size_t* optlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + if (level == custom_socket_option_level && optname == always_fail_option) + { + ec = boost::asio::error::invalid_argument; + return socket_error_retval; + } + + if (level == custom_socket_option_level + && optname == enable_connection_aborted_option) + { + if (*optlen != sizeof(int)) + { + ec = boost::asio::error::invalid_argument; + return socket_error_retval; + } + + *static_cast(optval) = (state & enable_connection_aborted) ? 1 : 0; + ec = boost::system::error_code(); + return 0; + } + +#if defined(__BORLANDC__) + // Mysteriously, using the getsockopt and setsockopt functions directly with + // Borland C++ results in incorrect values being set and read. The bug can be + // worked around by using function addresses resolved with GetProcAddress. + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*); + if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt")) + { + clear_last_error(); + int tmp_optlen = static_cast(*optlen); + int result = error_wrapper(gso(s, level, optname, + reinterpret_cast(optval), &tmp_optlen), ec); + *optlen = static_cast(tmp_optlen); + if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY + && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) + { + // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are + // only supported on Windows Vista and later. To simplify program logic + // we will fake success of getting this option and specify that the + // value is non-zero (i.e. true). This corresponds to the behavior of + // IPv6 sockets on Windows platforms pre-Vista. + *static_cast(optval) = 1; + ec = boost::system::error_code(); + } + return result; + } + } + ec = boost::asio::error::fault; + return socket_error_retval; +#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + clear_last_error(); + int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); + if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY + && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) + { + // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only + // supported on Windows Vista and later. To simplify program logic we will + // fake success of getting this option and specify that the value is + // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets + // on Windows platforms pre-Vista. + *static_cast(optval) = 1; + ec = boost::system::error_code(); + } + if (result == 0) + ec = boost::system::error_code(); + return result; +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + clear_last_error(); + int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); +#if defined(__linux__) + if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int) + && (optname == SO_SNDBUF || optname == SO_RCVBUF)) + { + // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel + // to set the buffer size to N*2. Linux puts additional stuff into the + // buffers so that only about half is actually available to the application. + // The retrieved value is divided by 2 here to make it appear as though the + // correct value has been set. + *static_cast(optval) /= 2; + } +#endif // defined(__linux__) + if (result == 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +} + +template +inline int call_getpeername(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = (SockLenType)*addrlen; + int result = ::getpeername(s, addr, &tmp_addrlen); + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +int getpeername(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, bool cached, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(BOOST_ASIO_WINDOWS) && !defined(BOOST_ASIO_WINDOWS_APP) \ + || defined(__CYGWIN__) + if (cached) + { + // Check if socket is still connected. + DWORD connect_time = 0; + size_t connect_time_len = sizeof(connect_time); + if (socket_ops::getsockopt(s, 0, SOL_SOCKET, SO_CONNECT_TIME, + &connect_time, &connect_time_len, ec) == socket_error_retval) + { + return socket_error_retval; + } + if (connect_time == 0xFFFFFFFF) + { + ec = boost::asio::error::not_connected; + return socket_error_retval; + } + + // The cached value is still valid. + ec = boost::system::error_code(); + return 0; + } +#else // defined(BOOST_ASIO_WINDOWS) && !defined(BOOST_ASIO_WINDOWS_APP) + // || defined(__CYGWIN__) + (void)cached; +#endif // defined(BOOST_ASIO_WINDOWS) && !defined(BOOST_ASIO_WINDOWS_APP) + // || defined(__CYGWIN__) + + clear_last_error(); + int result = error_wrapper(call_getpeername( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +template +inline int call_getsockname(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = (SockLenType)*addrlen; + int result = ::getsockname(s, addr, &tmp_addrlen); + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + +int getsockname(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); + int result = error_wrapper(call_getsockname( + &msghdr::msg_namelen, s, addr, addrlen), ec); + if (result == 0) + ec = boost::system::error_code(); + return result; +} + +int ioctl(socket_type s, state_type& state, int cmd, + ioctl_arg_type* arg, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec); +#elif defined(__MACH__) && defined(__APPLE__) \ + || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + int result = error_wrapper(::ioctl(s, + static_cast(cmd), arg), ec); +#else + int result = error_wrapper(::ioctl(s, cmd, arg), ec); +#endif + if (result >= 0) + { + ec = boost::system::error_code(); + + // When updating the non-blocking mode we always perform the ioctl syscall, + // even if the flags would otherwise indicate that the socket is already in + // the correct state. This ensures that the underlying socket is put into + // the state that has been requested by the user. If the ioctl syscall was + // successful then we need to update the flags to match. + if (cmd == static_cast(FIONBIO)) + { + if (*arg) + { + state |= user_set_non_blocking; + } + else + { + // Clearing the non-blocking mode always overrides any internally-set + // non-blocking flag. Any subsequent asynchronous operations will need + // to re-enable non-blocking I/O. + state &= ~(user_set_non_blocking | internal_non_blocking); + } + } + } + + return result; +} + +int select(int nfds, fd_set* readfds, fd_set* writefds, + fd_set* exceptfds, timeval* timeout, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + if (!readfds && !writefds && !exceptfds && timeout) + { + DWORD milliseconds = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; + if (milliseconds == 0) + milliseconds = 1; // Force context switch. + ::Sleep(milliseconds); + ec = boost::system::error_code(); + return 0; + } + + // The select() call allows timeout values measured in microseconds, but the + // system clock (as wrapped by boost::posix_time::microsec_clock) typically + // has a resolution of 10 milliseconds. This can lead to a spinning select + // reactor, meaning increased CPU usage, when waiting for the earliest + // scheduled timeout if it's less than 10 milliseconds away. To avoid a tight + // spin we'll use a minimum timeout of 1 millisecond. + if (timeout && timeout->tv_sec == 0 + && timeout->tv_usec > 0 && timeout->tv_usec < 1000) + timeout->tv_usec = 1000; +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +#if defined(__hpux) && defined(__SELECT) + timespec ts; + ts.tv_sec = timeout ? timeout->tv_sec : 0; + ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0; + return error_wrapper(::pselect(nfds, readfds, + writefds, exceptfds, timeout ? &ts : 0, 0), ec); +#else + int result = error_wrapper(::select(nfds, readfds, + writefds, exceptfds, timeout), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif +} + +int poll_read(socket_type s, state_type state, + int msec, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(BOOST_ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + timeval timeout_obj; + timeval* timeout; + if (state & user_set_non_blocking) + { + timeout_obj.tv_sec = 0; + timeout_obj.tv_usec = 0; + timeout = &timeout_obj; + } + else if (msec >= 0) + { + timeout_obj.tv_sec = msec / 1000; + timeout_obj.tv_usec = (msec % 1000) * 1000; + timeout = &timeout_obj; + } + else + timeout = 0; + clear_last_error(); + int result = error_wrapper(::select(s + 1, &fds, 0, 0, timeout), ec); +#else // defined(BOOST_ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLIN; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : msec; + clear_last_error(); + int result = error_wrapper(::poll(&fds, 1, timeout), ec); +#endif // defined(BOOST_ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + if (result == 0) + ec = (state & user_set_non_blocking) + ? boost::asio::error::would_block : boost::system::error_code(); + else if (result > 0) + ec = boost::system::error_code(); + return result; +} + +int poll_write(socket_type s, state_type state, + int msec, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(BOOST_ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + timeval timeout_obj; + timeval* timeout; + if (state & user_set_non_blocking) + { + timeout_obj.tv_sec = 0; + timeout_obj.tv_usec = 0; + timeout = &timeout_obj; + } + else if (msec >= 0) + { + timeout_obj.tv_sec = msec / 1000; + timeout_obj.tv_usec = (msec % 1000) * 1000; + timeout = &timeout_obj; + } + else + timeout = 0; + clear_last_error(); + int result = error_wrapper(::select(s + 1, 0, &fds, 0, timeout), ec); +#else // defined(BOOST_ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLOUT; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : msec; + clear_last_error(); + int result = error_wrapper(::poll(&fds, 1, timeout), ec); +#endif // defined(BOOST_ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + if (result == 0) + ec = (state & user_set_non_blocking) + ? boost::asio::error::would_block : boost::system::error_code(); + else if (result > 0) + ec = boost::system::error_code(); + return result; +} + +int poll_error(socket_type s, state_type state, + int msec, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(BOOST_ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set fds; + FD_ZERO(&fds); + FD_SET(s, &fds); + timeval timeout_obj; + timeval* timeout; + if (state & user_set_non_blocking) + { + timeout_obj.tv_sec = 0; + timeout_obj.tv_usec = 0; + timeout = &timeout_obj; + } + else if (msec >= 0) + { + timeout_obj.tv_sec = msec / 1000; + timeout_obj.tv_usec = (msec % 1000) * 1000; + timeout = &timeout_obj; + } + else + timeout = 0; + clear_last_error(); + int result = error_wrapper(::select(s + 1, 0, 0, &fds, timeout), ec); +#else // defined(BOOST_ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLPRI | POLLERR | POLLHUP; + fds.revents = 0; + int timeout = (state & user_set_non_blocking) ? 0 : msec; + clear_last_error(); + int result = error_wrapper(::poll(&fds, 1, timeout), ec); +#endif // defined(BOOST_ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + if (result == 0) + ec = (state & user_set_non_blocking) + ? boost::asio::error::would_block : boost::system::error_code(); + else if (result > 0) + ec = boost::system::error_code(); + return result; +} + +int poll_connect(socket_type s, int msec, boost::system::error_code& ec) +{ + if (s == invalid_socket) + { + ec = boost::asio::error::bad_descriptor; + return socket_error_retval; + } + +#if defined(BOOST_ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + fd_set write_fds; + FD_ZERO(&write_fds); + FD_SET(s, &write_fds); + fd_set except_fds; + FD_ZERO(&except_fds); + FD_SET(s, &except_fds); + timeval timeout_obj; + timeval* timeout; + if (msec >= 0) + { + timeout_obj.tv_sec = msec / 1000; + timeout_obj.tv_usec = (msec % 1000) * 1000; + timeout = &timeout_obj; + } + else + timeout = 0; + clear_last_error(); + int result = error_wrapper(::select( + s + 1, 0, &write_fds, &except_fds, timeout), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#else // defined(BOOST_ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + pollfd fds; + fds.fd = s; + fds.events = POLLOUT; + fds.revents = 0; + clear_last_error(); + int result = error_wrapper(::poll(&fds, 1, msec), ec); + if (result >= 0) + ec = boost::system::error_code(); + return result; +#endif // defined(BOOST_ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) +} + +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +const char* inet_ntop(int af, const void* src, char* dest, size_t length, + unsigned long scope_id, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + using namespace std; // For sprintf. + const unsigned char* bytes = static_cast(src); + if (af == BOOST_ASIO_OS_DEF(AF_INET)) + { + sprintf_s(dest, length, "%u.%u.%u.%u", + bytes[0], bytes[1], bytes[2], bytes[3]); + return dest; + } + else if (af == BOOST_ASIO_OS_DEF(AF_INET6)) + { + size_t n = 0, b = 0, z = 0; + while (n < length && b < 16) + { + if (bytes[b] == 0 && bytes[b + 1] == 0 && z == 0) + { + do b += 2; while (b < 16 && bytes[b] == 0 && bytes[b + 1] == 0); + n += sprintf_s(dest + n, length - n, ":%s", b < 16 ? "" : ":"), ++z; + } + else + { + n += sprintf_s(dest + n, length - n, "%s%x", b ? ":" : "", + (static_cast(bytes[b]) << 8) | bytes[b + 1]); + b += 2; + } + } + if (scope_id) + n += sprintf_s(dest + n, length - n, "%%%lu", scope_id); + return dest; + } + else + { + ec = boost::asio::error::address_family_not_supported; + return 0; + } +#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + using namespace std; // For memcpy. + + if (af != BOOST_ASIO_OS_DEF(AF_INET) && af != BOOST_ASIO_OS_DEF(AF_INET6)) + { + ec = boost::asio::error::address_family_not_supported; + return 0; + } + + union + { + socket_addr_type base; + sockaddr_storage_type storage; + sockaddr_in4_type v4; + sockaddr_in6_type v6; + } address; + DWORD address_length; + if (af == BOOST_ASIO_OS_DEF(AF_INET)) + { + address_length = sizeof(sockaddr_in4_type); + address.v4.sin_family = BOOST_ASIO_OS_DEF(AF_INET); + address.v4.sin_port = 0; + memcpy(&address.v4.sin_addr, src, sizeof(in4_addr_type)); + } + else // AF_INET6 + { + address_length = sizeof(sockaddr_in6_type); + address.v6.sin6_family = BOOST_ASIO_OS_DEF(AF_INET6); + address.v6.sin6_port = 0; + address.v6.sin6_flowinfo = 0; + address.v6.sin6_scope_id = scope_id; + memcpy(&address.v6.sin6_addr, src, sizeof(in6_addr_type)); + } + + DWORD string_length = static_cast(length); +#if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800)) + LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); + int result = error_wrapper(::WSAAddressToStringW(&address.base, + address_length, 0, string_buffer, &string_length), ec); + ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, + dest, static_cast(length), 0, 0); +#else + int result = error_wrapper(::WSAAddressToStringA( + &address.base, address_length, 0, dest, &string_length), ec); +#endif + + // Windows may set error code on success. + if (result != socket_error_retval) + ec = boost::system::error_code(); + + // Windows may not set an error code on failure. + else if (result == socket_error_retval && !ec) + ec = boost::asio::error::invalid_argument; + + return result == socket_error_retval ? 0 : dest; +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + const char* result = error_wrapper(::inet_ntop( + af, src, dest, static_cast(length)), ec); + if (result == 0 && !ec) + ec = boost::asio::error::invalid_argument; + if (result != 0 && af == BOOST_ASIO_OS_DEF(AF_INET6) && scope_id != 0) + { + using namespace std; // For strcat and sprintf. + char if_name[(IF_NAMESIZE > 21 ? IF_NAMESIZE : 21) + 1] = "%"; + const in6_addr_type* ipv6_address = static_cast(src); + bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe) + && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80)); + bool is_multicast_link_local = ((ipv6_address->s6_addr[0] == 0xff) + && ((ipv6_address->s6_addr[1] & 0x0f) == 0x02)); + if ((!is_link_local && !is_multicast_link_local) + || if_indextoname(static_cast(scope_id), if_name + 1) == 0) + sprintf(if_name + 1, "%lu", scope_id); + strcat(dest, if_name); + } + return result; +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +} + +int inet_pton(int af, const char* src, void* dest, + unsigned long* scope_id, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + using namespace std; // For sscanf. + unsigned char* bytes = static_cast(dest); + if (af == BOOST_ASIO_OS_DEF(AF_INET)) + { + unsigned int b0, b1, b2, b3; + if (sscanf_s(src, "%u.%u.%u.%u", &b0, &b1, &b2, &b3) != 4) + { + ec = boost::asio::error::invalid_argument; + return -1; + } + if (b0 > 255 || b1 > 255 || b2 > 255 || b3 > 255) + { + ec = boost::asio::error::invalid_argument; + return -1; + } + bytes[0] = static_cast(b0); + bytes[1] = static_cast(b1); + bytes[2] = static_cast(b2); + bytes[3] = static_cast(b3); + ec = boost::system::error_code(); + return 1; + } + else if (af == BOOST_ASIO_OS_DEF(AF_INET6)) + { + unsigned char* bytes = static_cast(dest); + std::memset(bytes, 0, 16); + unsigned char back_bytes[16] = { 0 }; + int num_front_bytes = 0, num_back_bytes = 0; + const char* p = src; + + enum { fword, fcolon, bword, scope, done } state = fword; + unsigned long current_word = 0; + while (state != done) + { + if (current_word > 0xFFFF) + { + ec = boost::asio::error::invalid_argument; + return -1; + } + + switch (state) + { + case fword: + if (*p >= '0' && *p <= '9') + current_word = current_word * 16 + *p++ - '0'; + else if (*p >= 'a' && *p <= 'f') + current_word = current_word * 16 + *p++ - 'a' + 10; + else if (*p >= 'A' && *p <= 'F') + current_word = current_word * 16 + *p++ - 'A' + 10; + else + { + if (num_front_bytes == 16) + { + ec = boost::asio::error::invalid_argument; + return -1; + } + + bytes[num_front_bytes++] = (current_word >> 8) & 0xFF; + bytes[num_front_bytes++] = current_word & 0xFF; + current_word = 0; + + if (*p == ':') + state = fcolon, ++p; + else if (*p == '%') + state = scope, ++p; + else if (*p == 0) + state = done; + else + { + ec = boost::asio::error::invalid_argument; + return -1; + } + } + break; + + case fcolon: + if (*p == ':') + state = bword, ++p; + else + state = fword; + break; + + case bword: + if (*p >= '0' && *p <= '9') + current_word = current_word * 16 + *p++ - '0'; + else if (*p >= 'a' && *p <= 'f') + current_word = current_word * 16 + *p++ - 'a' + 10; + else if (*p >= 'A' && *p <= 'F') + current_word = current_word * 16 + *p++ - 'A' + 10; + else + { + if (num_front_bytes + num_back_bytes == 16) + { + ec = boost::asio::error::invalid_argument; + return -1; + } + + back_bytes[num_back_bytes++] = (current_word >> 8) & 0xFF; + back_bytes[num_back_bytes++] = current_word & 0xFF; + current_word = 0; + + if (*p == ':') + state = bword, ++p; + else if (*p == '%') + state = scope, ++p; + else if (*p == 0) + state = done; + else + { + ec = boost::asio::error::invalid_argument; + return -1; + } + } + break; + + case scope: + if (*p >= '0' && *p <= '9') + current_word = current_word * 10 + *p++ - '0'; + else if (*p == 0) + *scope_id = current_word, state = done; + else + { + ec = boost::asio::error::invalid_argument; + return -1; + } + break; + + default: + break; + } + } + + for (int i = 0; i < num_back_bytes; ++i) + bytes[16 - num_back_bytes + i] = back_bytes[i]; + + ec = boost::system::error_code(); + return 1; + } + else + { + ec = boost::asio::error::address_family_not_supported; + return -1; + } +#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + using namespace std; // For memcpy and strcmp. + + if (af != BOOST_ASIO_OS_DEF(AF_INET) && af != BOOST_ASIO_OS_DEF(AF_INET6)) + { + ec = boost::asio::error::address_family_not_supported; + return -1; + } + + union + { + socket_addr_type base; + sockaddr_storage_type storage; + sockaddr_in4_type v4; + sockaddr_in6_type v6; + } address; + int address_length = sizeof(sockaddr_storage_type); +#if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800)) + int num_wide_chars = static_cast(strlen(src)) + 1; + LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); + ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); + int result = error_wrapper(::WSAStringToAddressW( + wide_buffer, af, 0, &address.base, &address_length), ec); +#else + int result = error_wrapper(::WSAStringToAddressA( + const_cast(src), af, 0, &address.base, &address_length), ec); +#endif + + if (af == BOOST_ASIO_OS_DEF(AF_INET)) + { + if (result != socket_error_retval) + { + memcpy(dest, &address.v4.sin_addr, sizeof(in4_addr_type)); + ec = boost::system::error_code(); + } + else if (strcmp(src, "255.255.255.255") == 0) + { + static_cast(dest)->s_addr = INADDR_NONE; + ec = boost::system::error_code(); + } + } + else // AF_INET6 + { + if (result != socket_error_retval) + { + memcpy(dest, &address.v6.sin6_addr, sizeof(in6_addr_type)); + if (scope_id) + *scope_id = address.v6.sin6_scope_id; + ec = boost::system::error_code(); + } + } + + // Windows may not set an error code on failure. + if (result == socket_error_retval && !ec) + ec = boost::asio::error::invalid_argument; + + if (result != socket_error_retval) + ec = boost::system::error_code(); + + return result == socket_error_retval ? -1 : 1; +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + using namespace std; // For strchr, memcpy and atoi. + + // On some platforms, inet_pton fails if an address string contains a scope + // id. Detect and remove the scope id before passing the string to inet_pton. + const bool is_v6 = (af == BOOST_ASIO_OS_DEF(AF_INET6)); + const char* if_name = is_v6 ? strchr(src, '%') : 0; + char src_buf[max_addr_v6_str_len + 1]; + const char* src_ptr = src; + if (if_name != 0) + { + if (if_name - src > max_addr_v6_str_len) + { + ec = boost::asio::error::invalid_argument; + return 0; + } + memcpy(src_buf, src, if_name - src); + src_buf[if_name - src] = 0; + src_ptr = src_buf; + } + + int result = error_wrapper(::inet_pton(af, src_ptr, dest), ec); + if (result <= 0 && !ec) + ec = boost::asio::error::invalid_argument; + if (result > 0 && is_v6 && scope_id) + { + using namespace std; // For strchr and atoi. + *scope_id = 0; + if (if_name != 0) + { + in6_addr_type* ipv6_address = static_cast(dest); + bool is_link_local = ((ipv6_address->s6_addr[0] == 0xfe) + && ((ipv6_address->s6_addr[1] & 0xc0) == 0x80)); + bool is_multicast_link_local = ((ipv6_address->s6_addr[0] == 0xff) + && ((ipv6_address->s6_addr[1] & 0x0f) == 0x02)); + if (is_link_local || is_multicast_link_local) + *scope_id = if_nametoindex(if_name + 1); + if (*scope_id == 0) + *scope_id = atoi(if_name + 1); + } + } + return result; +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +} + +int gethostname(char* name, int namelen, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + try + { + using namespace Windows::Foundation::Collections; + using namespace Windows::Networking; + using namespace Windows::Networking::Connectivity; + IVectorView^ hostnames = NetworkInformation::GetHostNames(); + for (unsigned i = 0; i < hostnames->Size; ++i) + { + HostName^ hostname = hostnames->GetAt(i); + if (hostname->Type == HostNameType::DomainName) + { + std::wstring_convert> converter; + std::string raw_name = converter.to_bytes(hostname->RawName->Data()); + if (namelen > 0 && raw_name.size() < static_cast(namelen)) + { + strcpy_s(name, namelen, raw_name.c_str()); + return 0; + } + } + } + return -1; + } + catch (Platform::Exception^ e) + { + ec = boost::system::error_code(e->HResult, + boost::system::system_category()); + return -1; + } +#else // defined(BOOST_ASIO_WINDOWS_RUNTIME) + int result = error_wrapper(::gethostname(name, namelen), ec); +# if defined(BOOST_ASIO_WINDOWS) + if (result == 0) + ec = boost::system::error_code(); +# endif // defined(BOOST_ASIO_WINDOWS) + return result; +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) +} + +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#if !defined(BOOST_ASIO_HAS_GETADDRINFO) + +// The following functions are only needed for emulation of getaddrinfo and +// getnameinfo. + +inline boost::system::error_code translate_netdb_error(int error) +{ + switch (error) + { + case 0: + return boost::system::error_code(); + case HOST_NOT_FOUND: + return boost::asio::error::host_not_found; + case TRY_AGAIN: + return boost::asio::error::host_not_found_try_again; + case NO_RECOVERY: + return boost::asio::error::no_recovery; + case NO_DATA: + return boost::asio::error::no_data; + default: + BOOST_ASIO_ASSERT(false); + return boost::asio::error::invalid_argument; + } +} + +inline hostent* gethostbyaddr(const char* addr, int length, int af, + hostent* result, char* buffer, int buflength, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + (void)(buffer); + (void)(buflength); + hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec); + if (!retval) + return 0; + ec = boost::system::error_code(); + *result = *retval; + return retval; +#elif defined(__sun) || defined(__QNX__) + int error = 0; + hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result, + buffer, buflength, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#elif defined(__MACH__) && defined(__APPLE__) + (void)(buffer); + (void)(buflength); + int error = 0; + hostent* retval = error_wrapper(::getipnodebyaddr( + addr, length, af, &error), ec); + if (error) + ec = translate_netdb_error(error); + if (!retval) + return 0; + *result = *retval; + return retval; +#else + hostent* retval = 0; + int error = 0; + error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer, + buflength, &retval, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#endif +} + +inline hostent* gethostbyname(const char* name, int af, struct hostent* result, + char* buffer, int buflength, int ai_flags, boost::system::error_code& ec) +{ + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + (void)(buffer); + (void)(buflength); + (void)(ai_flags); + if (af != BOOST_ASIO_OS_DEF(AF_INET)) + { + ec = boost::asio::error::address_family_not_supported; + return 0; + } + hostent* retval = error_wrapper(::gethostbyname(name), ec); + if (!retval) + return 0; + ec = boost::system::error_code(); + *result = *retval; + return result; +#elif defined(__sun) || defined(__QNX__) + (void)(ai_flags); + if (af != BOOST_ASIO_OS_DEF(AF_INET)) + { + ec = boost::asio::error::address_family_not_supported; + return 0; + } + int error = 0; + hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer, + buflength, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#elif defined(__MACH__) && defined(__APPLE__) + (void)(buffer); + (void)(buflength); + int error = 0; + hostent* retval = error_wrapper(::getipnodebyname( + name, af, ai_flags, &error), ec); + if (error) + ec = translate_netdb_error(error); + if (!retval) + return 0; + *result = *retval; + return retval; +#else + (void)(ai_flags); + if (af != BOOST_ASIO_OS_DEF(AF_INET)) + { + ec = boost::asio::error::address_family_not_supported; + return 0; + } + hostent* retval = 0; + int error = 0; + error_wrapper(::gethostbyname_r(name, result, + buffer, buflength, &retval, &error), ec); + if (error) + ec = translate_netdb_error(error); + return retval; +#endif +} + +inline void freehostent(hostent* h) +{ +#if defined(__MACH__) && defined(__APPLE__) + if (h) + ::freehostent(h); +#else + (void)(h); +#endif +} + +// Emulation of getaddrinfo based on implementation in: +// Stevens, W. R., UNIX Network Programming Vol. 1, 2nd Ed., Prentice-Hall 1998. + +struct gai_search +{ + const char* host; + int family; +}; + +inline int gai_nsearch(const char* host, + const addrinfo_type* hints, gai_search (&search)[2]) +{ + int search_count = 0; + if (host == 0 || host[0] == '\0') + { + if (hints->ai_flags & AI_PASSIVE) + { + // No host and AI_PASSIVE implies wildcard bind. + switch (hints->ai_family) + { + case BOOST_ASIO_OS_DEF(AF_INET): + search[search_count].host = "0.0.0.0"; + search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET); + ++search_count; + break; + case BOOST_ASIO_OS_DEF(AF_INET6): + search[search_count].host = "0::0"; + search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6); + ++search_count; + break; + case BOOST_ASIO_OS_DEF(AF_UNSPEC): + search[search_count].host = "0::0"; + search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6); + ++search_count; + search[search_count].host = "0.0.0.0"; + search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET); + ++search_count; + break; + default: + break; + } + } + else + { + // No host and not AI_PASSIVE means connect to local host. + switch (hints->ai_family) + { + case BOOST_ASIO_OS_DEF(AF_INET): + search[search_count].host = "localhost"; + search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET); + ++search_count; + break; + case BOOST_ASIO_OS_DEF(AF_INET6): + search[search_count].host = "localhost"; + search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6); + ++search_count; + break; + case BOOST_ASIO_OS_DEF(AF_UNSPEC): + search[search_count].host = "localhost"; + search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6); + ++search_count; + search[search_count].host = "localhost"; + search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET); + ++search_count; + break; + default: + break; + } + } + } + else + { + // Host is specified. + switch (hints->ai_family) + { + case BOOST_ASIO_OS_DEF(AF_INET): + search[search_count].host = host; + search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET); + ++search_count; + break; + case BOOST_ASIO_OS_DEF(AF_INET6): + search[search_count].host = host; + search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6); + ++search_count; + break; + case BOOST_ASIO_OS_DEF(AF_UNSPEC): + search[search_count].host = host; + search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET6); + ++search_count; + search[search_count].host = host; + search[search_count].family = BOOST_ASIO_OS_DEF(AF_INET); + ++search_count; + break; + default: + break; + } + } + return search_count; +} + +template +inline T* gai_alloc(std::size_t size = sizeof(T)) +{ + using namespace std; + T* p = static_cast(::operator new(size, std::nothrow)); + if (p) + memset(p, 0, size); + return p; +} + +inline void gai_free(void* p) +{ + ::operator delete(p); +} + +inline void gai_strcpy(char* target, const char* source, std::size_t max_size) +{ + using namespace std; +#if defined(BOOST_ASIO_HAS_SECURE_RTL) + strcpy_s(target, max_size, source); +#else // defined(BOOST_ASIO_HAS_SECURE_RTL) + *target = 0; + if (max_size > 0) + strncat(target, source, max_size - 1); +#endif // defined(BOOST_ASIO_HAS_SECURE_RTL) +} + +enum { gai_clone_flag = 1 << 30 }; + +inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints, + const void* addr, int family) +{ + using namespace std; + + addrinfo_type* ai = gai_alloc(); + if (ai == 0) + return EAI_MEMORY; + + ai->ai_next = 0; + **next = ai; + *next = &ai->ai_next; + + ai->ai_canonname = 0; + ai->ai_socktype = hints->ai_socktype; + if (ai->ai_socktype == 0) + ai->ai_flags |= gai_clone_flag; + ai->ai_protocol = hints->ai_protocol; + ai->ai_family = family; + + switch (ai->ai_family) + { + case BOOST_ASIO_OS_DEF(AF_INET): + { + sockaddr_in4_type* sinptr = gai_alloc(); + if (sinptr == 0) + return EAI_MEMORY; + sinptr->sin_family = BOOST_ASIO_OS_DEF(AF_INET); + memcpy(&sinptr->sin_addr, addr, sizeof(in4_addr_type)); + ai->ai_addr = reinterpret_cast(sinptr); + ai->ai_addrlen = sizeof(sockaddr_in4_type); + break; + } + case BOOST_ASIO_OS_DEF(AF_INET6): + { + sockaddr_in6_type* sin6ptr = gai_alloc(); + if (sin6ptr == 0) + return EAI_MEMORY; + sin6ptr->sin6_family = BOOST_ASIO_OS_DEF(AF_INET6); + memcpy(&sin6ptr->sin6_addr, addr, sizeof(in6_addr_type)); + ai->ai_addr = reinterpret_cast(sin6ptr); + ai->ai_addrlen = sizeof(sockaddr_in6_type); + break; + } + default: + break; + } + + return 0; +} + +inline addrinfo_type* gai_clone(addrinfo_type* ai) +{ + using namespace std; + + addrinfo_type* new_ai = gai_alloc(); + if (new_ai == 0) + return new_ai; + + new_ai->ai_next = ai->ai_next; + ai->ai_next = new_ai; + + new_ai->ai_flags = 0; + new_ai->ai_family = ai->ai_family; + new_ai->ai_socktype = ai->ai_socktype; + new_ai->ai_protocol = ai->ai_protocol; + new_ai->ai_canonname = 0; + new_ai->ai_addrlen = ai->ai_addrlen; + new_ai->ai_addr = gai_alloc(ai->ai_addrlen); + memcpy(new_ai->ai_addr, ai->ai_addr, ai->ai_addrlen); + + return new_ai; +} + +inline int gai_port(addrinfo_type* aihead, int port, int socktype) +{ + int num_found = 0; + + for (addrinfo_type* ai = aihead; ai; ai = ai->ai_next) + { + if (ai->ai_flags & gai_clone_flag) + { + if (ai->ai_socktype != 0) + { + ai = gai_clone(ai); + if (ai == 0) + return -1; + // ai now points to newly cloned entry. + } + } + else if (ai->ai_socktype != socktype) + { + // Ignore if mismatch on socket type. + continue; + } + + ai->ai_socktype = socktype; + + switch (ai->ai_family) + { + case BOOST_ASIO_OS_DEF(AF_INET): + { + sockaddr_in4_type* sinptr = + reinterpret_cast(ai->ai_addr); + sinptr->sin_port = port; + ++num_found; + break; + } + case BOOST_ASIO_OS_DEF(AF_INET6): + { + sockaddr_in6_type* sin6ptr = + reinterpret_cast(ai->ai_addr); + sin6ptr->sin6_port = port; + ++num_found; + break; + } + default: + break; + } + } + + return num_found; +} + +inline int gai_serv(addrinfo_type* aihead, + const addrinfo_type* hints, const char* serv) +{ + using namespace std; + + int num_found = 0; + + if ( +#if defined(AI_NUMERICSERV) + (hints->ai_flags & AI_NUMERICSERV) || +#endif + isdigit(static_cast(serv[0]))) + { + int port = htons(atoi(serv)); + if (hints->ai_socktype) + { + // Caller specifies socket type. + int rc = gai_port(aihead, port, hints->ai_socktype); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + else + { + // Caller does not specify socket type. + int rc = gai_port(aihead, port, SOCK_STREAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + rc = gai_port(aihead, port, SOCK_DGRAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + else + { + // Try service name with TCP first, then UDP. + if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_STREAM) + { + servent* sptr = getservbyname(serv, "tcp"); + if (sptr != 0) + { + int rc = gai_port(aihead, sptr->s_port, SOCK_STREAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + if (hints->ai_socktype == 0 || hints->ai_socktype == SOCK_DGRAM) + { + servent* sptr = getservbyname(serv, "udp"); + if (sptr != 0) + { + int rc = gai_port(aihead, sptr->s_port, SOCK_DGRAM); + if (rc < 0) + return EAI_MEMORY; + num_found += rc; + } + } + } + + if (num_found == 0) + { + if (hints->ai_socktype == 0) + { + // All calls to getservbyname() failed. + return EAI_NONAME; + } + else + { + // Service not supported for socket type. + return EAI_SERVICE; + } + } + + return 0; +} + +inline int gai_echeck(const char* host, const char* service, + int flags, int family, int socktype, int protocol) +{ + (void)(flags); + (void)(protocol); + + // Host or service must be specified. + if (host == 0 || host[0] == '\0') + if (service == 0 || service[0] == '\0') + return EAI_NONAME; + + // Check combination of family and socket type. + switch (family) + { + case BOOST_ASIO_OS_DEF(AF_UNSPEC): + break; + case BOOST_ASIO_OS_DEF(AF_INET): + case BOOST_ASIO_OS_DEF(AF_INET6): + if (service != 0 && service[0] != '\0') + if (socktype != 0 && socktype != SOCK_STREAM && socktype != SOCK_DGRAM) + return EAI_SOCKTYPE; + break; + default: + return EAI_FAMILY; + } + + return 0; +} + +inline void freeaddrinfo_emulation(addrinfo_type* aihead) +{ + addrinfo_type* ai = aihead; + while (ai) + { + gai_free(ai->ai_addr); + gai_free(ai->ai_canonname); + addrinfo_type* ainext = ai->ai_next; + gai_free(ai); + ai = ainext; + } +} + +inline int getaddrinfo_emulation(const char* host, const char* service, + const addrinfo_type* hintsp, addrinfo_type** result) +{ + // Set up linked list of addrinfo structures. + addrinfo_type* aihead = 0; + addrinfo_type** ainext = &aihead; + char* canon = 0; + + // Supply default hints if not specified by caller. + addrinfo_type hints = addrinfo_type(); + hints.ai_family = BOOST_ASIO_OS_DEF(AF_UNSPEC); + if (hintsp) + hints = *hintsp; + + // If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED + // and AI_ALL flags. +#if defined(AI_V4MAPPED) + if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_INET6)) + hints.ai_flags &= ~AI_V4MAPPED; +#endif +#if defined(AI_ALL) + if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_INET6)) + hints.ai_flags &= ~AI_ALL; +#endif + + // Basic error checking. + int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family, + hints.ai_socktype, hints.ai_protocol); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + return rc; + } + + gai_search search[2]; + int search_count = gai_nsearch(host, &hints, search); + for (gai_search* sptr = search; sptr < search + search_count; ++sptr) + { + // Check for IPv4 dotted decimal string. + in4_addr_type inaddr; + boost::system::error_code ec; + if (socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET), + sptr->host, &inaddr, 0, ec) == 1) + { + if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_UNSPEC) + && hints.ai_family != BOOST_ASIO_OS_DEF(AF_INET)) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return EAI_FAMILY; + } + if (sptr->family == BOOST_ASIO_OS_DEF(AF_INET)) + { + rc = gai_aistruct(&ainext, &hints, &inaddr, BOOST_ASIO_OS_DEF(AF_INET)); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return rc; + } + } + continue; + } + + // Check for IPv6 hex string. + in6_addr_type in6addr; + if (socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET6), + sptr->host, &in6addr, 0, ec) == 1) + { + if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_UNSPEC) + && hints.ai_family != BOOST_ASIO_OS_DEF(AF_INET6)) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return EAI_FAMILY; + } + if (sptr->family == BOOST_ASIO_OS_DEF(AF_INET6)) + { + rc = gai_aistruct(&ainext, &hints, &in6addr, + BOOST_ASIO_OS_DEF(AF_INET6)); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + return rc; + } + } + continue; + } + + // Look up hostname. + hostent hent; + char hbuf[8192] = ""; + hostent* hptr = socket_ops::gethostbyname(sptr->host, + sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec); + if (hptr == 0) + { + if (search_count == 2) + { + // Failure is OK if there are multiple searches. + continue; + } + freeaddrinfo_emulation(aihead); + gai_free(canon); + if (ec == boost::asio::error::host_not_found) + return EAI_NONAME; + if (ec == boost::asio::error::host_not_found_try_again) + return EAI_AGAIN; + if (ec == boost::asio::error::no_recovery) + return EAI_FAIL; + if (ec == boost::asio::error::no_data) + return EAI_NONAME; + return EAI_NONAME; + } + + // Check for address family mismatch if one was specified. + if (hints.ai_family != BOOST_ASIO_OS_DEF(AF_UNSPEC) + && hints.ai_family != hptr->h_addrtype) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + socket_ops::freehostent(hptr); + return EAI_FAMILY; + } + + // Save canonical name first time. + if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0] + && (hints.ai_flags & AI_CANONNAME) && canon == 0) + { + std::size_t canon_len = strlen(hptr->h_name) + 1; + canon = gai_alloc(canon_len); + if (canon == 0) + { + freeaddrinfo_emulation(aihead); + socket_ops::freehostent(hptr); + return EAI_MEMORY; + } + gai_strcpy(canon, hptr->h_name, canon_len); + } + + // Create an addrinfo structure for each returned address. + for (char** ap = hptr->h_addr_list; *ap; ++ap) + { + rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + gai_free(canon); + socket_ops::freehostent(hptr); + return EAI_FAMILY; + } + } + + socket_ops::freehostent(hptr); + } + + // Check if we found anything. + if (aihead == 0) + { + gai_free(canon); + return EAI_NONAME; + } + + // Return canonical name in first entry. + if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME)) + { + if (canon) + { + aihead->ai_canonname = canon; + canon = 0; + } + else + { + std::size_t canonname_len = strlen(search[0].host) + 1; + aihead->ai_canonname = gai_alloc(canonname_len); + if (aihead->ai_canonname == 0) + { + freeaddrinfo_emulation(aihead); + return EAI_MEMORY; + } + gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len); + } + } + gai_free(canon); + + // Process the service name. + if (service != 0 && service[0] != '\0') + { + rc = gai_serv(aihead, &hints, service); + if (rc != 0) + { + freeaddrinfo_emulation(aihead); + return rc; + } + } + + // Return result to caller. + *result = aihead; + return 0; +} + +inline boost::system::error_code getnameinfo_emulation( + const socket_addr_type* sa, std::size_t salen, char* host, + std::size_t hostlen, char* serv, std::size_t servlen, int flags, + boost::system::error_code& ec) +{ + using namespace std; + + const char* addr; + size_t addr_len; + unsigned short port; + switch (sa->sa_family) + { + case BOOST_ASIO_OS_DEF(AF_INET): + if (salen != sizeof(sockaddr_in4_type)) + { + return ec = boost::asio::error::invalid_argument; + } + addr = reinterpret_cast( + &reinterpret_cast(sa)->sin_addr); + addr_len = sizeof(in4_addr_type); + port = reinterpret_cast(sa)->sin_port; + break; + case BOOST_ASIO_OS_DEF(AF_INET6): + if (salen != sizeof(sockaddr_in6_type)) + { + return ec = boost::asio::error::invalid_argument; + } + addr = reinterpret_cast( + &reinterpret_cast(sa)->sin6_addr); + addr_len = sizeof(in6_addr_type); + port = reinterpret_cast(sa)->sin6_port; + break; + default: + return ec = boost::asio::error::address_family_not_supported; + } + + if (host && hostlen > 0) + { + if (flags & NI_NUMERICHOST) + { + if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0) + { + return ec; + } + } + else + { + hostent hent; + char hbuf[8192] = ""; + hostent* hptr = socket_ops::gethostbyaddr(addr, + static_cast(addr_len), sa->sa_family, + &hent, hbuf, sizeof(hbuf), ec); + if (hptr && hptr->h_name && hptr->h_name[0] != '\0') + { + if (flags & NI_NOFQDN) + { + char* dot = strchr(hptr->h_name, '.'); + if (dot) + { + *dot = 0; + } + } + gai_strcpy(host, hptr->h_name, hostlen); + socket_ops::freehostent(hptr); + } + else + { + socket_ops::freehostent(hptr); + if (flags & NI_NAMEREQD) + { + return ec = boost::asio::error::host_not_found; + } + if (socket_ops::inet_ntop(sa->sa_family, + addr, host, hostlen, 0, ec) == 0) + { + return ec; + } + } + } + } + + if (serv && servlen > 0) + { + if (flags & NI_NUMERICSERV) + { + if (servlen < 6) + { + return ec = boost::asio::error::no_buffer_space; + } +#if defined(BOOST_ASIO_HAS_SECURE_RTL) + sprintf_s(serv, servlen, "%u", ntohs(port)); +#else // defined(BOOST_ASIO_HAS_SECURE_RTL) + sprintf(serv, "%u", ntohs(port)); +#endif // defined(BOOST_ASIO_HAS_SECURE_RTL) + } + else + { +#if defined(BOOST_ASIO_HAS_PTHREADS) + static ::pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + ::pthread_mutex_lock(&mutex); +#endif // defined(BOOST_ASIO_HAS_PTHREADS) + servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0); + if (sptr && sptr->s_name && sptr->s_name[0] != '\0') + { + gai_strcpy(serv, sptr->s_name, servlen); + } + else + { + if (servlen < 6) + { + return ec = boost::asio::error::no_buffer_space; + } +#if defined(BOOST_ASIO_HAS_SECURE_RTL) + sprintf_s(serv, servlen, "%u", ntohs(port)); +#else // defined(BOOST_ASIO_HAS_SECURE_RTL) + sprintf(serv, "%u", ntohs(port)); +#endif // defined(BOOST_ASIO_HAS_SECURE_RTL) + } +#if defined(BOOST_ASIO_HAS_PTHREADS) + ::pthread_mutex_unlock(&mutex); +#endif // defined(BOOST_ASIO_HAS_PTHREADS) + } + } + + ec = boost::system::error_code(); + return ec; +} + +#endif // !defined(BOOST_ASIO_HAS_GETADDRINFO) + +inline boost::system::error_code translate_addrinfo_error(int error) +{ + switch (error) + { + case 0: + return boost::system::error_code(); + case EAI_AGAIN: + return boost::asio::error::host_not_found_try_again; + case EAI_BADFLAGS: + return boost::asio::error::invalid_argument; + case EAI_FAIL: + return boost::asio::error::no_recovery; + case EAI_FAMILY: + return boost::asio::error::address_family_not_supported; + case EAI_MEMORY: + return boost::asio::error::no_memory; + case EAI_NONAME: +#if defined(EAI_ADDRFAMILY) + case EAI_ADDRFAMILY: +#endif +#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) + case EAI_NODATA: +#endif + return boost::asio::error::host_not_found; + case EAI_SERVICE: + return boost::asio::error::service_not_found; + case EAI_SOCKTYPE: + return boost::asio::error::socket_type_not_supported; + default: // Possibly the non-portable EAI_SYSTEM. +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + return boost::system::error_code( + WSAGetLastError(), boost::asio::error::get_system_category()); +#else + return boost::system::error_code( + errno, boost::asio::error::get_system_category()); +#endif + } +} + +boost::system::error_code getaddrinfo(const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, boost::system::error_code& ec) +{ + host = (host && *host) ? host : 0; + service = (service && *service) ? service : 0; + clear_last_error(); +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(BOOST_ASIO_HAS_GETADDRINFO) + // Building for Windows XP, Windows Server 2003, or later. + int error = ::getaddrinfo(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *gai_t)(const char*, + const char*, const addrinfo_type*, addrinfo_type**); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo")) + { + int error = gai(host, service, &hints, result); + return ec = translate_addrinfo_error(error); + } + } + int error = getaddrinfo_emulation(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +# endif +#elif !defined(BOOST_ASIO_HAS_GETADDRINFO) + int error = getaddrinfo_emulation(host, service, &hints, result); + return ec = translate_addrinfo_error(error); +#else + int error = ::getaddrinfo(host, service, &hints, result); +#if defined(__MACH__) && defined(__APPLE__) + using namespace std; // For isdigit and atoi. + if (error == 0 && service && isdigit(static_cast(service[0]))) + { + u_short_type port = host_to_network_short(atoi(service)); + for (addrinfo_type* ai = *result; ai; ai = ai->ai_next) + { + switch (ai->ai_family) + { + case BOOST_ASIO_OS_DEF(AF_INET): + { + sockaddr_in4_type* sinptr = + reinterpret_cast(ai->ai_addr); + if (sinptr->sin_port == 0) + sinptr->sin_port = port; + break; + } + case BOOST_ASIO_OS_DEF(AF_INET6): + { + sockaddr_in6_type* sin6ptr = + reinterpret_cast(ai->ai_addr); + if (sin6ptr->sin6_port == 0) + sin6ptr->sin6_port = port; + break; + } + default: + break; + } + } + } +#endif + return ec = translate_addrinfo_error(error); +#endif +} + +boost::system::error_code background_getaddrinfo( + const weak_cancel_token_type& cancel_token, const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, boost::system::error_code& ec) +{ + if (cancel_token.expired()) + ec = boost::asio::error::operation_aborted; + else + socket_ops::getaddrinfo(host, service, hints, result, ec); + return ec; +} + +void freeaddrinfo(addrinfo_type* ai) +{ +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(BOOST_ASIO_HAS_GETADDRINFO) + // Building for Windows XP, Windows Server 2003, or later. + ::freeaddrinfo(ai); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *fai_t)(addrinfo_type*); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (fai_t fai = (fai_t)::GetProcAddress(winsock_module, "freeaddrinfo")) + { + fai(ai); + return; + } + } + freeaddrinfo_emulation(ai); +# endif +#elif !defined(BOOST_ASIO_HAS_GETADDRINFO) + freeaddrinfo_emulation(ai); +#else + ::freeaddrinfo(ai); +#endif +} + +boost::system::error_code getnameinfo(const socket_addr_type* addr, + std::size_t addrlen, char* host, std::size_t hostlen, + char* serv, std::size_t servlen, int flags, boost::system::error_code& ec) +{ +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(BOOST_ASIO_HAS_GETADDRINFO) + // Building for Windows XP, Windows Server 2003, or later. + clear_last_error(); + int error = ::getnameinfo(addr, static_cast(addrlen), + host, static_cast(hostlen), + serv, static_cast(servlen), flags); + return ec = translate_addrinfo_error(error); +# else + // Building for Windows 2000 or earlier. + typedef int (WSAAPI *gni_t)(const socket_addr_type*, + int, char*, DWORD, char*, DWORD, int); + if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) + { + if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo")) + { + clear_last_error(); + int error = gni(addr, static_cast(addrlen), + host, static_cast(hostlen), + serv, static_cast(servlen), flags); + return ec = translate_addrinfo_error(error); + } + } + clear_last_error(); + return getnameinfo_emulation(addr, addrlen, + host, hostlen, serv, servlen, flags, ec); +# endif +#elif !defined(BOOST_ASIO_HAS_GETADDRINFO) + using namespace std; // For memcpy. + sockaddr_storage_type tmp_addr; + memcpy(&tmp_addr, addr, addrlen); + addr = reinterpret_cast(&tmp_addr); + clear_last_error(); + return getnameinfo_emulation(addr, addrlen, + host, hostlen, serv, servlen, flags, ec); +#else + clear_last_error(); + int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags); + return ec = translate_addrinfo_error(error); +#endif +} + +boost::system::error_code sync_getnameinfo( + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, boost::system::error_code& ec) +{ + // First try resolving with the service name. If that fails try resolving + // but allow the service to be returned as a number. + int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0; + socket_ops::getnameinfo(addr, addrlen, host, + hostlen, serv, servlen, flags, ec); + if (ec) + { + socket_ops::getnameinfo(addr, addrlen, host, hostlen, + serv, servlen, flags | NI_NUMERICSERV, ec); + } + + return ec; +} + +boost::system::error_code background_getnameinfo( + const weak_cancel_token_type& cancel_token, + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, boost::system::error_code& ec) +{ + if (cancel_token.expired()) + { + ec = boost::asio::error::operation_aborted; + } + else + { + // First try resolving with the service name. If that fails try resolving + // but allow the service to be returned as a number. + int flags = (sock_type == SOCK_DGRAM) ? NI_DGRAM : 0; + socket_ops::getnameinfo(addr, addrlen, host, + hostlen, serv, servlen, flags, ec); + if (ec) + { + socket_ops::getnameinfo(addr, addrlen, host, hostlen, + serv, servlen, flags | NI_NUMERICSERV, ec); + } + } + + return ec; +} + +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +u_long_type network_to_host_long(u_long_type value) +{ +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + unsigned char* value_p = reinterpret_cast(&value); + u_long_type result = (static_cast(value_p[0]) << 24) + | (static_cast(value_p[1]) << 16) + | (static_cast(value_p[2]) << 8) + | static_cast(value_p[3]); + return result; +#else // defined(BOOST_ASIO_WINDOWS_RUNTIME) + return ntohl(value); +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) +} + +u_long_type host_to_network_long(u_long_type value) +{ +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + u_long_type result; + unsigned char* result_p = reinterpret_cast(&result); + result_p[0] = static_cast((value >> 24) & 0xFF); + result_p[1] = static_cast((value >> 16) & 0xFF); + result_p[2] = static_cast((value >> 8) & 0xFF); + result_p[3] = static_cast(value & 0xFF); + return result; +#else // defined(BOOST_ASIO_WINDOWS_RUNTIME) + return htonl(value); +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) +} + +u_short_type network_to_host_short(u_short_type value) +{ +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + unsigned char* value_p = reinterpret_cast(&value); + u_short_type result = (static_cast(value_p[0]) << 8) + | static_cast(value_p[1]); + return result; +#else // defined(BOOST_ASIO_WINDOWS_RUNTIME) + return ntohs(value); +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) +} + +u_short_type host_to_network_short(u_short_type value) +{ +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + u_short_type result; + unsigned char* result_p = reinterpret_cast(&result); + result_p[0] = static_cast((value >> 8) & 0xFF); + result_p[1] = static_cast(value & 0xFF); + return result; +#else // defined(BOOST_ASIO_WINDOWS_RUNTIME) + return htons(value); +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) +} + +} // namespace socket_ops +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SOCKET_OPS_IPP diff --git a/boost/asio/detail/impl/socket_select_interrupter.ipp b/boost/asio/detail/impl/socket_select_interrupter.ipp new file mode 100644 index 0000000..e09c5fb --- /dev/null +++ b/boost/asio/detail/impl/socket_select_interrupter.ipp @@ -0,0 +1,178 @@ +// +// detail/impl/socket_select_interrupter.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP +#define BOOST_ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#if defined(BOOST_ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +socket_select_interrupter::socket_select_interrupter() +{ + open_descriptors(); +} + +void socket_select_interrupter::open_descriptors() +{ + boost::system::error_code ec; + socket_holder acceptor(socket_ops::socket( + AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); + if (acceptor.get() == invalid_socket) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + int opt = 1; + socket_ops::state_type acceptor_state = 0; + socket_ops::setsockopt(acceptor.get(), acceptor_state, + SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec); + + using namespace std; // For memset. + sockaddr_in4_type addr; + std::size_t addr_len = sizeof(addr); + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = socket_ops::host_to_network_long(INADDR_LOOPBACK); + addr.sin_port = 0; + if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr, + addr_len, ec) == socket_error_retval) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr, + &addr_len, ec) == socket_error_retval) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + // Some broken firewalls on Windows will intermittently cause getsockname to + // return 0.0.0.0 when the socket is actually bound to 127.0.0.1. We + // explicitly specify the target address here to work around this problem. + if (addr.sin_addr.s_addr == socket_ops::host_to_network_long(INADDR_ANY)) + addr.sin_addr.s_addr = socket_ops::host_to_network_long(INADDR_LOOPBACK); + + if (socket_ops::listen(acceptor.get(), + SOMAXCONN, ec) == socket_error_retval) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + socket_holder client(socket_ops::socket( + AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); + if (client.get() == invalid_socket) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr, + addr_len, ec) == socket_error_retval) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec)); + if (server.get() == invalid_socket) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + ioctl_arg_type non_blocking = 1; + socket_ops::state_type client_state = 0; + if (socket_ops::ioctl(client.get(), client_state, + FIONBIO, &non_blocking, ec)) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + opt = 1; + socket_ops::setsockopt(client.get(), client_state, + IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); + + non_blocking = 1; + socket_ops::state_type server_state = 0; + if (socket_ops::ioctl(server.get(), server_state, + FIONBIO, &non_blocking, ec)) + boost::asio::detail::throw_error(ec, "socket_select_interrupter"); + + opt = 1; + socket_ops::setsockopt(server.get(), server_state, + IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); + + read_descriptor_ = server.release(); + write_descriptor_ = client.release(); +} + +socket_select_interrupter::~socket_select_interrupter() +{ + close_descriptors(); +} + +void socket_select_interrupter::close_descriptors() +{ + boost::system::error_code ec; + socket_ops::state_type state = socket_ops::internal_non_blocking; + if (read_descriptor_ != invalid_socket) + socket_ops::close(read_descriptor_, state, true, ec); + if (write_descriptor_ != invalid_socket) + socket_ops::close(write_descriptor_, state, true, ec); +} + +void socket_select_interrupter::recreate() +{ + close_descriptors(); + + write_descriptor_ = invalid_socket; + read_descriptor_ = invalid_socket; + + open_descriptors(); +} + +void socket_select_interrupter::interrupt() +{ + char byte = 0; + socket_ops::buf b; + socket_ops::init_buf(b, &byte, 1); + boost::system::error_code ec; + socket_ops::send(write_descriptor_, &b, 1, 0, ec); +} + +bool socket_select_interrupter::reset() +{ + char data[1024]; + socket_ops::buf b; + socket_ops::init_buf(b, data, sizeof(data)); + boost::system::error_code ec; + int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); + bool was_interrupted = (bytes_read > 0); + while (bytes_read == sizeof(data)) + bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); + return was_interrupted; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#endif // BOOST_ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP diff --git a/boost/asio/detail/impl/strand_executor_service.hpp b/boost/asio/detail/impl/strand_executor_service.hpp new file mode 100644 index 0000000..67eb836 --- /dev/null +++ b/boost/asio/detail/impl/strand_executor_service.hpp @@ -0,0 +1,181 @@ +// +// detail/impl/strand_executor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP +#define BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class strand_executor_service::invoker +{ +public: + invoker(const implementation_type& impl, Executor& ex) + : impl_(impl), + work_(ex) + { + } + + invoker(const invoker& other) + : impl_(other.impl_), + work_(other.work_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + invoker(invoker&& other) + : impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_)), + work_(BOOST_ASIO_MOVE_CAST(executor_work_guard)(other.work_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + struct on_invoker_exit + { + invoker* this_; + + ~on_invoker_exit() + { + this_->impl_->mutex_->lock(); + this_->impl_->ready_queue_.push(this_->impl_->waiting_queue_); + bool more_handlers = this_->impl_->locked_ = + !this_->impl_->ready_queue_.empty(); + this_->impl_->mutex_->unlock(); + + if (more_handlers) + { + Executor ex(this_->work_.get_executor()); + recycling_allocator allocator; + ex.post(BOOST_ASIO_MOVE_CAST(invoker)(*this_), allocator); + } + } + }; + + void operator()() + { + // Indicate that this strand is executing on the current thread. + call_stack::context ctx(impl_.get()); + + // Ensure the next handler, if any, is scheduled on block exit. + on_invoker_exit on_exit = { this }; + (void)on_exit; + + // Run all ready handlers. No lock is required since the ready queue is + // accessed only within the strand. + boost::system::error_code ec; + while (scheduler_operation* o = impl_->ready_queue_.front()) + { + impl_->ready_queue_.pop(); + o->complete(impl_.get(), ec, 0); + } + } + +private: + implementation_type impl_; + executor_work_guard work_; +}; + +template +void strand_executor_service::dispatch(const implementation_type& impl, + Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a) +{ + typedef typename decay::type function_type; + + // If we are already in the strand then the function can run immediately. + if (call_stack::contains(impl.get())) + { + // Make a local, non-const copy of the function. + function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(function)); + + fenced_block b(fenced_block::full); + boost_asio_handler_invoke_helpers::invoke(tmp, tmp); + return; + } + + // Allocate and construct an operation to wrap the function. + typedef executor_op op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(function), a); + + BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, + "strand_executor", impl.get(), 0, "dispatch")); + + // Add the function to the strand and schedule the strand if required. + bool first = enqueue(impl, p.p); + p.v = p.p = 0; + if (first) + ex.dispatch(invoker(impl, ex), a); +} + +// Request invocation of the given function and return immediately. +template +void strand_executor_service::post(const implementation_type& impl, + Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a) +{ + typedef typename decay::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef executor_op op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(function), a); + + BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, + "strand_executor", impl.get(), 0, "post")); + + // Add the function to the strand and schedule the strand if required. + bool first = enqueue(impl, p.p); + p.v = p.p = 0; + if (first) + ex.post(invoker(impl, ex), a); +} + +// Request invocation of the given function and return immediately. +template +void strand_executor_service::defer(const implementation_type& impl, + Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a) +{ + typedef typename decay::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef executor_op op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(function), a); + + BOOST_ASIO_HANDLER_CREATION((impl->service_->context(), *p.p, + "strand_executor", impl.get(), 0, "defer")); + + // Add the function to the strand and schedule the strand if required. + bool first = enqueue(impl, p.p); + p.v = p.p = 0; + if (first) + ex.defer(invoker(impl, ex), a); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP diff --git a/boost/asio/detail/impl/strand_executor_service.ipp b/boost/asio/detail/impl/strand_executor_service.ipp new file mode 100644 index 0000000..60681ea --- /dev/null +++ b/boost/asio/detail/impl/strand_executor_service.ipp @@ -0,0 +1,136 @@ +// +// detail/impl/strand_executor_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +strand_executor_service::strand_executor_service(execution_context& ctx) + : execution_context_service_base(ctx), + mutex_(), + salt_(0), + impl_list_(0) +{ +} + +void strand_executor_service::shutdown() +{ + op_queue ops; + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + strand_impl* impl = impl_list_; + while (impl) + { + impl->mutex_->lock(); + impl->shutdown_ = true; + ops.push(impl->waiting_queue_); + ops.push(impl->ready_queue_); + impl->mutex_->unlock(); + impl = impl->next_; + } +} + +strand_executor_service::implementation_type +strand_executor_service::create_implementation() +{ + implementation_type new_impl(new strand_impl); + new_impl->locked_ = false; + new_impl->shutdown_ = false; + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + // Select a mutex from the pool of shared mutexes. + std::size_t salt = salt_++; + std::size_t mutex_index = reinterpret_cast(new_impl.get()); + mutex_index += (reinterpret_cast(new_impl.get()) >> 3); + mutex_index ^= salt + 0x9e3779b9 + (mutex_index << 6) + (mutex_index >> 2); + mutex_index = mutex_index % num_mutexes; + if (!mutexes_[mutex_index].get()) + mutexes_[mutex_index].reset(new mutex); + new_impl->mutex_ = mutexes_[mutex_index].get(); + + // Insert implementation into linked list of all implementations. + new_impl->next_ = impl_list_; + new_impl->prev_ = 0; + if (impl_list_) + impl_list_->prev_ = new_impl.get(); + impl_list_ = new_impl.get(); + new_impl->service_ = this; + + return new_impl; +} + +strand_executor_service::strand_impl::~strand_impl() +{ + boost::asio::detail::mutex::scoped_lock lock(service_->mutex_); + + // Remove implementation from linked list of all implementations. + if (service_->impl_list_ == this) + service_->impl_list_ = next_; + if (prev_) + prev_->next_ = next_; + if (next_) + next_->prev_= prev_; +} + +bool strand_executor_service::enqueue(const implementation_type& impl, + scheduler_operation* op) +{ + impl->mutex_->lock(); + if (impl->shutdown_) + { + impl->mutex_->unlock(); + op->destroy(); + return false; + } + else if (impl->locked_) + { + // Some other function already holds the strand lock. Enqueue for later. + impl->waiting_queue_.push(op); + impl->mutex_->unlock(); + return false; + } + else + { + // The function is acquiring the strand lock and so is responsible for + // scheduling the strand. + impl->locked_ = true; + impl->mutex_->unlock(); + impl->ready_queue_.push(op); + return true; + } +} + +bool strand_executor_service::running_in_this_thread( + const implementation_type& impl) +{ + return !!call_stack::contains(impl.get()); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP diff --git a/boost/asio/detail/impl/strand_service.hpp b/boost/asio/detail/impl/strand_service.hpp new file mode 100644 index 0000000..7e82876 --- /dev/null +++ b/boost/asio/detail/impl/strand_service.hpp @@ -0,0 +1,120 @@ +// +// detail/impl/strand_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP +#define BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +inline strand_service::strand_impl::strand_impl() + : operation(&strand_service::do_complete), + locked_(false) +{ +} + +struct strand_service::on_dispatch_exit +{ + io_context_impl* io_context_; + strand_impl* impl_; + + ~on_dispatch_exit() + { + impl_->mutex_.lock(); + impl_->ready_queue_.push(impl_->waiting_queue_); + bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty(); + impl_->mutex_.unlock(); + + if (more_handlers) + io_context_->post_immediate_completion(impl_, false); + } +}; + +template +void strand_service::dispatch(strand_service::implementation_type& impl, + Handler& handler) +{ + // If we are already in the strand then the handler can run immediately. + if (call_stack::contains(impl)) + { + fenced_block b(fenced_block::full); + boost_asio_handler_invoke_helpers::invoke(handler, handler); + return; + } + + // Allocate and construct an operation to wrap the handler. + typedef completion_handler op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + BOOST_ASIO_HANDLER_CREATION((this->context(), + *p.p, "strand", impl, 0, "dispatch")); + + bool dispatch_immediately = do_dispatch(impl, p.p); + operation* o = p.p; + p.v = p.p = 0; + + if (dispatch_immediately) + { + // Indicate that this strand is executing on the current thread. + call_stack::context ctx(impl); + + // Ensure the next handler, if any, is scheduled on block exit. + on_dispatch_exit on_exit = { &io_context_, impl }; + (void)on_exit; + + completion_handler::do_complete( + &io_context_, o, boost::system::error_code(), 0); + } +} + +// Request the io_context to invoke the given handler and return immediately. +template +void strand_service::post(strand_service::implementation_type& impl, + Handler& handler) +{ + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef completion_handler op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler); + + BOOST_ASIO_HANDLER_CREATION((this->context(), + *p.p, "strand", impl, 0, "post")); + + do_post(impl, p.p, is_continuation); + p.v = p.p = 0; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP diff --git a/boost/asio/detail/impl/strand_service.ipp b/boost/asio/detail/impl/strand_service.ipp new file mode 100644 index 0000000..340f310 --- /dev/null +++ b/boost/asio/detail/impl/strand_service.ipp @@ -0,0 +1,179 @@ +// +// detail/impl/strand_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct strand_service::on_do_complete_exit +{ + io_context_impl* owner_; + strand_impl* impl_; + + ~on_do_complete_exit() + { + impl_->mutex_.lock(); + impl_->ready_queue_.push(impl_->waiting_queue_); + bool more_handlers = impl_->locked_ = !impl_->ready_queue_.empty(); + impl_->mutex_.unlock(); + + if (more_handlers) + owner_->post_immediate_completion(impl_, true); + } +}; + +strand_service::strand_service(boost::asio::io_context& io_context) + : boost::asio::detail::service_base(io_context), + io_context_(boost::asio::use_service(io_context)), + mutex_(), + salt_(0) +{ +} + +void strand_service::shutdown() +{ + op_queue ops; + + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + for (std::size_t i = 0; i < num_implementations; ++i) + { + if (strand_impl* impl = implementations_[i].get()) + { + ops.push(impl->waiting_queue_); + ops.push(impl->ready_queue_); + } + } +} + +void strand_service::construct(strand_service::implementation_type& impl) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + std::size_t salt = salt_++; +#if defined(BOOST_ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION) + std::size_t index = salt; +#else // defined(BOOST_ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION) + std::size_t index = reinterpret_cast(&impl); + index += (reinterpret_cast(&impl) >> 3); + index ^= salt + 0x9e3779b9 + (index << 6) + (index >> 2); +#endif // defined(BOOST_ASIO_ENABLE_SEQUENTIAL_STRAND_ALLOCATION) + index = index % num_implementations; + + if (!implementations_[index].get()) + implementations_[index].reset(new strand_impl); + impl = implementations_[index].get(); +} + +bool strand_service::running_in_this_thread( + const implementation_type& impl) const +{ + return call_stack::contains(impl) != 0; +} + +bool strand_service::do_dispatch(implementation_type& impl, operation* op) +{ + // If we are running inside the io_context, and no other handler already + // holds the strand lock, then the handler can run immediately. + bool can_dispatch = io_context_.can_dispatch(); + impl->mutex_.lock(); + if (can_dispatch && !impl->locked_) + { + // Immediate invocation is allowed. + impl->locked_ = true; + impl->mutex_.unlock(); + return true; + } + + if (impl->locked_) + { + // Some other handler already holds the strand lock. Enqueue for later. + impl->waiting_queue_.push(op); + impl->mutex_.unlock(); + } + else + { + // The handler is acquiring the strand lock and so is responsible for + // scheduling the strand. + impl->locked_ = true; + impl->mutex_.unlock(); + impl->ready_queue_.push(op); + io_context_.post_immediate_completion(impl, false); + } + + return false; +} + +void strand_service::do_post(implementation_type& impl, + operation* op, bool is_continuation) +{ + impl->mutex_.lock(); + if (impl->locked_) + { + // Some other handler already holds the strand lock. Enqueue for later. + impl->waiting_queue_.push(op); + impl->mutex_.unlock(); + } + else + { + // The handler is acquiring the strand lock and so is responsible for + // scheduling the strand. + impl->locked_ = true; + impl->mutex_.unlock(); + impl->ready_queue_.push(op); + io_context_.post_immediate_completion(impl, is_continuation); + } +} + +void strand_service::do_complete(void* owner, operation* base, + const boost::system::error_code& ec, std::size_t /*bytes_transferred*/) +{ + if (owner) + { + strand_impl* impl = static_cast(base); + + // Indicate that this strand is executing on the current thread. + call_stack::context ctx(impl); + + // Ensure the next handler, if any, is scheduled on block exit. + on_do_complete_exit on_exit; + on_exit.owner_ = static_cast(owner); + on_exit.impl_ = impl; + + // Run all ready handlers. No lock is required since the ready queue is + // accessed only within the strand. + while (operation* o = impl->ready_queue_.front()) + { + impl->ready_queue_.pop(); + o->complete(owner, ec, 0); + } + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP diff --git a/boost/asio/detail/impl/throw_error.ipp b/boost/asio/detail/impl/throw_error.ipp new file mode 100644 index 0000000..9483bd0 --- /dev/null +++ b/boost/asio/detail/impl/throw_error.ipp @@ -0,0 +1,47 @@ +// +// detail/impl/throw_error.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_THROW_ERROR_IPP +#define BOOST_ASIO_DETAIL_IMPL_THROW_ERROR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +void do_throw_error(const boost::system::error_code& err) +{ + boost::system::system_error e(err); + boost::asio::detail::throw_exception(e); +} + +void do_throw_error(const boost::system::error_code& err, const char* location) +{ + boost::system::system_error e(err, location); + boost::asio::detail::throw_exception(e); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_THROW_ERROR_IPP diff --git a/boost/asio/detail/impl/timer_queue_ptime.ipp b/boost/asio/detail/impl/timer_queue_ptime.ipp new file mode 100644 index 0000000..2566c9c --- /dev/null +++ b/boost/asio/detail/impl/timer_queue_ptime.ipp @@ -0,0 +1,93 @@ +// +// detail/impl/timer_queue_ptime.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP +#define BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +timer_queue >::timer_queue() +{ +} + +timer_queue >::~timer_queue() +{ +} + +bool timer_queue >::enqueue_timer( + const time_type& time, per_timer_data& timer, wait_op* op) +{ + return impl_.enqueue_timer(time, timer, op); +} + +bool timer_queue >::empty() const +{ + return impl_.empty(); +} + +long timer_queue >::wait_duration_msec( + long max_duration) const +{ + return impl_.wait_duration_msec(max_duration); +} + +long timer_queue >::wait_duration_usec( + long max_duration) const +{ + return impl_.wait_duration_usec(max_duration); +} + +void timer_queue >::get_ready_timers( + op_queue& ops) +{ + impl_.get_ready_timers(ops); +} + +void timer_queue >::get_all_timers( + op_queue& ops) +{ + impl_.get_all_timers(ops); +} + +std::size_t timer_queue >::cancel_timer( + per_timer_data& timer, op_queue& ops, std::size_t max_cancelled) +{ + return impl_.cancel_timer(timer, ops, max_cancelled); +} + +void timer_queue >::move_timer( + per_timer_data& target, per_timer_data& source) +{ + impl_.move_timer(target, source); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +#endif // BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP diff --git a/boost/asio/detail/impl/timer_queue_set.ipp b/boost/asio/detail/impl/timer_queue_set.ipp new file mode 100644 index 0000000..b738142 --- /dev/null +++ b/boost/asio/detail/impl/timer_queue_set.ipp @@ -0,0 +1,103 @@ +// +// detail/impl/timer_queue_set.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP +#define BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +timer_queue_set::timer_queue_set() + : first_(0) +{ +} + +void timer_queue_set::insert(timer_queue_base* q) +{ + q->next_ = first_; + first_ = q; +} + +void timer_queue_set::erase(timer_queue_base* q) +{ + if (first_) + { + if (q == first_) + { + first_ = q->next_; + q->next_ = 0; + return; + } + + for (timer_queue_base* p = first_; p->next_; p = p->next_) + { + if (p->next_ == q) + { + p->next_ = q->next_; + q->next_ = 0; + return; + } + } + } +} + +bool timer_queue_set::all_empty() const +{ + for (timer_queue_base* p = first_; p; p = p->next_) + if (!p->empty()) + return false; + return true; +} + +long timer_queue_set::wait_duration_msec(long max_duration) const +{ + long min_duration = max_duration; + for (timer_queue_base* p = first_; p; p = p->next_) + min_duration = p->wait_duration_msec(min_duration); + return min_duration; +} + +long timer_queue_set::wait_duration_usec(long max_duration) const +{ + long min_duration = max_duration; + for (timer_queue_base* p = first_; p; p = p->next_) + min_duration = p->wait_duration_usec(min_duration); + return min_duration; +} + +void timer_queue_set::get_ready_timers(op_queue& ops) +{ + for (timer_queue_base* p = first_; p; p = p->next_) + p->get_ready_timers(ops); +} + +void timer_queue_set::get_all_timers(op_queue& ops) +{ + for (timer_queue_base* p = first_; p; p = p->next_) + p->get_all_timers(ops); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP diff --git a/boost/asio/detail/impl/win_event.ipp b/boost/asio/detail/impl/win_event.ipp new file mode 100644 index 0000000..c6e1e35 --- /dev/null +++ b/boost/asio/detail/impl/win_event.ipp @@ -0,0 +1,78 @@ +// +// detail/win_event.ipp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_EVENT_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_EVENT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +win_event::win_event() + : state_(0) +{ +#if defined(BOOST_ASIO_WINDOWS_APP) + events_[0] = ::CreateEventExW(0, 0, + CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); +#else // defined(BOOST_ASIO_WINDOWS_APP) + events_[0] = ::CreateEventW(0, true, false, 0); +#endif // defined(BOOST_ASIO_WINDOWS_APP) + if (!events_[0]) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "event"); + } + +#if defined(BOOST_ASIO_WINDOWS_APP) + events_[1] = ::CreateEventExW(0, 0, 0, EVENT_ALL_ACCESS); +#else // defined(BOOST_ASIO_WINDOWS_APP) + events_[1] = ::CreateEventW(0, false, false, 0); +#endif // defined(BOOST_ASIO_WINDOWS_APP) + if (!events_[1]) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(events_[0]); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "event"); + } +} + +win_event::~win_event() +{ + ::CloseHandle(events_[0]); + ::CloseHandle(events_[1]); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_EVENT_IPP diff --git a/boost/asio/detail/impl/win_iocp_handle_service.ipp b/boost/asio/detail/impl/win_iocp_handle_service.ipp new file mode 100644 index 0000000..da33768 --- /dev/null +++ b/boost/asio/detail/impl/win_iocp_handle_service.ipp @@ -0,0 +1,527 @@ +// +// detail/impl/win_iocp_handle_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class win_iocp_handle_service::overlapped_wrapper + : public OVERLAPPED +{ +public: + explicit overlapped_wrapper(boost::system::error_code& ec) + { + Internal = 0; + InternalHigh = 0; + Offset = 0; + OffsetHigh = 0; + + // Create a non-signalled manual-reset event, for GetOverlappedResult. + hEvent = ::CreateEventW(0, TRUE, FALSE, 0); + if (hEvent) + { + // As documented in GetQueuedCompletionStatus, setting the low order + // bit of this event prevents our synchronous writes from being treated + // as completion port events. + DWORD_PTR tmp = reinterpret_cast(hEvent); + hEvent = reinterpret_cast(tmp | 1); + } + else + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + } + + ~overlapped_wrapper() + { + if (hEvent) + { + ::CloseHandle(hEvent); + } + } +}; + +win_iocp_handle_service::win_iocp_handle_service(execution_context& context) + : execution_context_service_base(context), + iocp_service_(boost::asio::use_service(context)), + mutex_(), + impl_list_(0) +{ +} + +void win_iocp_handle_service::shutdown() +{ + // Close all implementations, causing all operations to complete. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + implementation_type* impl = impl_list_; + while (impl) + { + close_for_destruction(*impl); + impl = impl->next_; + } +} + +void win_iocp_handle_service::construct( + win_iocp_handle_service::implementation_type& impl) +{ + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + + // Insert implementation into linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void win_iocp_handle_service::move_construct( + win_iocp_handle_service::implementation_type& impl, + win_iocp_handle_service::implementation_type& other_impl) +{ + impl.handle_ = other_impl.handle_; + other_impl.handle_ = INVALID_HANDLE_VALUE; + + impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_; + other_impl.safe_cancellation_thread_id_ = 0; + + // Insert implementation into linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void win_iocp_handle_service::move_assign( + win_iocp_handle_service::implementation_type& impl, + win_iocp_handle_service& other_service, + win_iocp_handle_service::implementation_type& other_impl) +{ + close_for_destruction(impl); + + if (this != &other_service) + { + // Remove implementation from linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; + } + + impl.handle_ = other_impl.handle_; + other_impl.handle_ = INVALID_HANDLE_VALUE; + + impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_; + other_impl.safe_cancellation_thread_id_ = 0; + + if (this != &other_service) + { + // Insert implementation into linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(other_service.mutex_); + impl.next_ = other_service.impl_list_; + impl.prev_ = 0; + if (other_service.impl_list_) + other_service.impl_list_->prev_ = &impl; + other_service.impl_list_ = &impl; + } +} + +void win_iocp_handle_service::destroy( + win_iocp_handle_service::implementation_type& impl) +{ + close_for_destruction(impl); + + // Remove implementation from linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; +} + +boost::system::error_code win_iocp_handle_service::assign( + win_iocp_handle_service::implementation_type& impl, + const native_handle_type& handle, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + if (iocp_service_.register_handle(handle, ec)) + return ec; + + impl.handle_ = handle; + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code win_iocp_handle_service::close( + win_iocp_handle_service::implementation_type& impl, + boost::system::error_code& ec) +{ + if (is_open(impl)) + { + BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle", + &impl, reinterpret_cast(impl.handle_), "close")); + + if (!::CloseHandle(impl.handle_)) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + else + { + ec = boost::system::error_code(); + } + + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + } + else + { + ec = boost::system::error_code(); + } + + return ec; +} + +boost::system::error_code win_iocp_handle_service::cancel( + win_iocp_handle_service::implementation_type& impl, + boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + + BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle", + &impl, reinterpret_cast(impl.handle_), "cancel")); + + if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( + ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) + { + // The version of Windows supports cancellation from any thread. + typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); + cancel_io_ex_t cancel_io_ex = reinterpret_cast( + reinterpret_cast(cancel_io_ex_ptr)); + if (!cancel_io_ex(impl.handle_, 0)) + { + DWORD last_error = ::GetLastError(); + if (last_error == ERROR_NOT_FOUND) + { + // ERROR_NOT_FOUND means that there were no operations to be + // cancelled. We swallow this error to match the behaviour on other + // platforms. + ec = boost::system::error_code(); + } + else + { + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + } + else + { + ec = boost::system::error_code(); + } + } + else if (impl.safe_cancellation_thread_id_ == 0) + { + // No operations have been started, so there's nothing to cancel. + ec = boost::system::error_code(); + } + else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) + { + // Asynchronous operations have been started from the current thread only, + // so it is safe to try to cancel them using CancelIo. + if (!::CancelIo(impl.handle_)) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + else + { + ec = boost::system::error_code(); + } + } + else + { + // Asynchronous operations have been started from more than one thread, + // so cancellation is not safe. + ec = boost::asio::error::operation_not_supported; + } + + return ec; +} + +size_t win_iocp_handle_service::do_write( + win_iocp_handle_service::implementation_type& impl, uint64_t offset, + const boost::asio::const_buffer& buffer, boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to write 0 bytes on a handle is a no-op. + if (buffer.size() == 0) + { + ec = boost::system::error_code(); + return 0; + } + + overlapped_wrapper overlapped(ec); + if (ec) + { + return 0; + } + + // Write the data. + overlapped.Offset = offset & 0xFFFFFFFF; + overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::WriteFile(impl.handle_, buffer.data(), + static_cast(buffer.size()), 0, &overlapped); + if (!ok) + { + DWORD last_error = ::GetLastError(); + if (last_error != ERROR_IO_PENDING) + { + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return 0; + } + } + + // Wait for the operation to complete. + DWORD bytes_transferred = 0; + ok = ::GetOverlappedResult(impl.handle_, + &overlapped, &bytes_transferred, TRUE); + if (!ok) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return 0; + } + + ec = boost::system::error_code(); + return bytes_transferred; +} + +void win_iocp_handle_service::start_write_op( + win_iocp_handle_service::implementation_type& impl, uint64_t offset, + const boost::asio::const_buffer& buffer, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + { + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + } + else if (buffer.size() == 0) + { + // A request to write 0 bytes on a handle is a no-op. + iocp_service_.on_completion(op); + } + else + { + DWORD bytes_transferred = 0; + op->Offset = offset & 0xFFFFFFFF; + op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::WriteFile(impl.handle_, buffer.data(), + static_cast(buffer.size()), + &bytes_transferred, op); + DWORD last_error = ::GetLastError(); + if (!ok && last_error != ERROR_IO_PENDING + && last_error != ERROR_MORE_DATA) + { + iocp_service_.on_completion(op, last_error, bytes_transferred); + } + else + { + iocp_service_.on_pending(op); + } + } +} + +size_t win_iocp_handle_service::do_read( + win_iocp_handle_service::implementation_type& impl, uint64_t offset, + const boost::asio::mutable_buffer& buffer, boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return 0; + } + + // A request to read 0 bytes on a stream handle is a no-op. + if (buffer.size() == 0) + { + ec = boost::system::error_code(); + return 0; + } + + overlapped_wrapper overlapped(ec); + if (ec) + { + return 0; + } + + // Read some data. + overlapped.Offset = offset & 0xFFFFFFFF; + overlapped.OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::ReadFile(impl.handle_, buffer.data(), + static_cast(buffer.size()), 0, &overlapped); + if (!ok) + { + DWORD last_error = ::GetLastError(); + if (last_error != ERROR_IO_PENDING && last_error != ERROR_MORE_DATA) + { + if (last_error == ERROR_HANDLE_EOF) + { + ec = boost::asio::error::eof; + } + else + { + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + return 0; + } + } + + // Wait for the operation to complete. + DWORD bytes_transferred = 0; + ok = ::GetOverlappedResult(impl.handle_, + &overlapped, &bytes_transferred, TRUE); + if (!ok) + { + DWORD last_error = ::GetLastError(); + if (last_error == ERROR_HANDLE_EOF) + { + ec = boost::asio::error::eof; + } + else + { + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + return (last_error == ERROR_MORE_DATA) ? bytes_transferred : 0; + } + + ec = boost::system::error_code(); + return bytes_transferred; +} + +void win_iocp_handle_service::start_read_op( + win_iocp_handle_service::implementation_type& impl, uint64_t offset, + const boost::asio::mutable_buffer& buffer, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + { + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + } + else if (buffer.size() == 0) + { + // A request to read 0 bytes on a handle is a no-op. + iocp_service_.on_completion(op); + } + else + { + DWORD bytes_transferred = 0; + op->Offset = offset & 0xFFFFFFFF; + op->OffsetHigh = (offset >> 32) & 0xFFFFFFFF; + BOOL ok = ::ReadFile(impl.handle_, buffer.data(), + static_cast(buffer.size()), + &bytes_transferred, op); + DWORD last_error = ::GetLastError(); + if (!ok && last_error != ERROR_IO_PENDING + && last_error != ERROR_MORE_DATA) + { + iocp_service_.on_completion(op, last_error, bytes_transferred); + } + else + { + iocp_service_.on_pending(op); + } + } +} + +void win_iocp_handle_service::update_cancellation_thread_id( + win_iocp_handle_service::implementation_type& impl) +{ + if (impl.safe_cancellation_thread_id_ == 0) + impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); + else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) + impl.safe_cancellation_thread_id_ = ~DWORD(0); +} + +void win_iocp_handle_service::close_for_destruction(implementation_type& impl) +{ + if (is_open(impl)) + { + BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), "handle", + &impl, reinterpret_cast(impl.handle_), "close")); + + ::CloseHandle(impl.handle_); + impl.handle_ = INVALID_HANDLE_VALUE; + impl.safe_cancellation_thread_id_ = 0; + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP diff --git a/boost/asio/detail/impl/win_iocp_io_context.hpp b/boost/asio/detail/impl/win_iocp_io_context.hpp new file mode 100644 index 0000000..830a07d --- /dev/null +++ b/boost/asio/detail/impl/win_iocp_io_context.hpp @@ -0,0 +1,105 @@ +// +// detail/impl/win_iocp_io_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +void win_iocp_io_context::add_timer_queue( + timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +template +void win_iocp_io_context::remove_timer_queue( + timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void win_iocp_io_context::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op) +{ + // If the service has been shut down we silently discard the timer. + if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) + { + post_immediate_completion(op, false); + return; + } + + mutex::scoped_lock lock(dispatch_mutex_); + + bool earliest = queue.enqueue_timer(time, timer, op); + work_started(); + if (earliest) + update_timeout(); +} + +template +std::size_t win_iocp_io_context::cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled) +{ + // If the service has been shut down we silently ignore the cancellation. + if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) + return 0; + + mutex::scoped_lock lock(dispatch_mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + post_deferred_completions(ops); + return n; +} + +template +void win_iocp_io_context::move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& to, + typename timer_queue::per_timer_data& from) +{ + boost::asio::detail::mutex::scoped_lock lock(dispatch_mutex_); + op_queue ops; + queue.cancel_timer(to, ops); + queue.move_timer(to, from); + lock.unlock(); + post_deferred_completions(ops); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP diff --git a/boost/asio/detail/impl/win_iocp_io_context.ipp b/boost/asio/detail/impl/win_iocp_io_context.ipp new file mode 100644 index 0000000..5bdc540 --- /dev/null +++ b/boost/asio/detail/impl/win_iocp_io_context.ipp @@ -0,0 +1,595 @@ +// +// detail/impl/win_iocp_io_context.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct win_iocp_io_context::thread_function +{ + explicit thread_function(win_iocp_io_context* s) + : this_(s) + { + } + + void operator()() + { + boost::system::error_code ec; + this_->run(ec); + } + + win_iocp_io_context* this_; +}; + +struct win_iocp_io_context::work_finished_on_block_exit +{ + ~work_finished_on_block_exit() + { + io_context_->work_finished(); + } + + win_iocp_io_context* io_context_; +}; + +struct win_iocp_io_context::timer_thread_function +{ + void operator()() + { + while (::InterlockedExchangeAdd(&io_context_->shutdown_, 0) == 0) + { + if (::WaitForSingleObject(io_context_->waitable_timer_.handle, + INFINITE) == WAIT_OBJECT_0) + { + ::InterlockedExchange(&io_context_->dispatch_required_, 1); + ::PostQueuedCompletionStatus(io_context_->iocp_.handle, + 0, wake_for_dispatch, 0); + } + } + } + + win_iocp_io_context* io_context_; +}; + +win_iocp_io_context::win_iocp_io_context( + boost::asio::execution_context& ctx, int concurrency_hint, bool own_thread) + : execution_context_service_base(ctx), + iocp_(), + outstanding_work_(0), + stopped_(0), + stop_event_posted_(0), + shutdown_(0), + gqcs_timeout_(get_gqcs_timeout()), + dispatch_required_(0), + concurrency_hint_(concurrency_hint) +{ + BOOST_ASIO_HANDLER_TRACKING_INIT; + + iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, + static_cast(concurrency_hint >= 0 ? concurrency_hint : DWORD(~0))); + if (!iocp_.handle) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "iocp"); + } + + if (own_thread) + { + ::InterlockedIncrement(&outstanding_work_); + thread_.reset(new boost::asio::detail::thread(thread_function(this))); + } +} + +win_iocp_io_context::~win_iocp_io_context() +{ + if (thread_.get()) + { + thread_->join(); + thread_.reset(); + } +} + +void win_iocp_io_context::shutdown() +{ + ::InterlockedExchange(&shutdown_, 1); + + if (timer_thread_.get()) + { + LARGE_INTEGER timeout; + timeout.QuadPart = 1; + ::SetWaitableTimer(waitable_timer_.handle, &timeout, 1, 0, 0, FALSE); + } + + if (thread_.get()) + { + thread_->join(); + thread_.reset(); + ::InterlockedDecrement(&outstanding_work_); + } + + while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0) + { + op_queue ops; + timer_queues_.get_all_timers(ops); + ops.push(completed_ops_); + if (!ops.empty()) + { + while (win_iocp_operation* op = ops.front()) + { + ops.pop(); + ::InterlockedDecrement(&outstanding_work_); + op->destroy(); + } + } + else + { + DWORD bytes_transferred = 0; + dword_ptr_t completion_key = 0; + LPOVERLAPPED overlapped = 0; + ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, + &completion_key, &overlapped, gqcs_timeout_); + if (overlapped) + { + ::InterlockedDecrement(&outstanding_work_); + static_cast(overlapped)->destroy(); + } + } + } + + if (timer_thread_.get()) + timer_thread_->join(); +} + +boost::system::error_code win_iocp_io_context::register_handle( + HANDLE handle, boost::system::error_code& ec) +{ + if (::CreateIoCompletionPort(handle, iocp_.handle, 0, 0) == 0) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + else + { + ec = boost::system::error_code(); + } + return ec; +} + +size_t win_iocp_io_context::run(boost::system::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); + + size_t n = 0; + while (do_one(INFINITE, ec)) + if (n != (std::numeric_limits::max)()) + ++n; + return n; +} + +size_t win_iocp_io_context::run_one(boost::system::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); + + return do_one(INFINITE, ec); +} + +size_t win_iocp_io_context::wait_one(long usec, boost::system::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); + + return do_one(usec < 0 ? INFINITE : ((usec - 1) / 1000 + 1), ec); +} + +size_t win_iocp_io_context::poll(boost::system::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); + + size_t n = 0; + while (do_one(0, ec)) + if (n != (std::numeric_limits::max)()) + ++n; + return n; +} + +size_t win_iocp_io_context::poll_one(boost::system::error_code& ec) +{ + if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + stop(); + ec = boost::system::error_code(); + return 0; + } + + win_iocp_thread_info this_thread; + thread_call_stack::context ctx(this, this_thread); + + return do_one(0, ec); +} + +void win_iocp_io_context::stop() +{ + if (::InterlockedExchange(&stopped_, 1) == 0) + { + if (::InterlockedExchange(&stop_event_posted_, 1) == 0) + { + if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "pqcs"); + } + } + } +} + +void win_iocp_io_context::post_deferred_completion(win_iocp_operation* op) +{ + // Flag the operation as ready. + op->ready_ = 1; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } +} + +void win_iocp_io_context::post_deferred_completions( + op_queue& ops) +{ + while (win_iocp_operation* op = ops.front()) + { + ops.pop(); + + // Flag the operation as ready. + op->ready_ = 1; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + completed_ops_.push(ops); + ::InterlockedExchange(&dispatch_required_, 1); + } + } +} + +void win_iocp_io_context::abandon_operations( + op_queue& ops) +{ + while (win_iocp_operation* op = ops.front()) + { + ops.pop(); + ::InterlockedDecrement(&outstanding_work_); + op->destroy(); + } +} + +void win_iocp_io_context::on_pending(win_iocp_operation* op) +{ + if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) + { + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } + } +} + +void win_iocp_io_context::on_completion(win_iocp_operation* op, + DWORD last_error, DWORD bytes_transferred) +{ + // Flag that the operation is ready for invocation. + op->ready_ = 1; + + // Store results in the OVERLAPPED structure. + op->Internal = reinterpret_cast( + &boost::asio::error::get_system_category()); + op->Offset = last_error; + op->OffsetHigh = bytes_transferred; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } +} + +void win_iocp_io_context::on_completion(win_iocp_operation* op, + const boost::system::error_code& ec, DWORD bytes_transferred) +{ + // Flag that the operation is ready for invocation. + op->ready_ = 1; + + // Store results in the OVERLAPPED structure. + op->Internal = reinterpret_cast(&ec.category()); + op->Offset = ec.value(); + op->OffsetHigh = bytes_transferred; + + // Enqueue the operation on the I/O completion port. + if (!::PostQueuedCompletionStatus(iocp_.handle, + 0, overlapped_contains_result, op)) + { + // Out of resources. Put on completed queue instead. + mutex::scoped_lock lock(dispatch_mutex_); + completed_ops_.push(op); + ::InterlockedExchange(&dispatch_required_, 1); + } +} + +size_t win_iocp_io_context::do_one(DWORD msec, boost::system::error_code& ec) +{ + for (;;) + { + // Try to acquire responsibility for dispatching timers and completed ops. + if (::InterlockedCompareExchange(&dispatch_required_, 0, 1) == 1) + { + mutex::scoped_lock lock(dispatch_mutex_); + + // Dispatch pending timers and operations. + op_queue ops; + ops.push(completed_ops_); + timer_queues_.get_ready_timers(ops); + post_deferred_completions(ops); + update_timeout(); + } + + // Get the next operation from the queue. + DWORD bytes_transferred = 0; + dword_ptr_t completion_key = 0; + LPOVERLAPPED overlapped = 0; + ::SetLastError(0); + BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, + &bytes_transferred, &completion_key, &overlapped, + msec < gqcs_timeout_ ? msec : gqcs_timeout_); + DWORD last_error = ::GetLastError(); + + if (overlapped) + { + win_iocp_operation* op = static_cast(overlapped); + boost::system::error_code result_ec(last_error, + boost::asio::error::get_system_category()); + + // We may have been passed the last_error and bytes_transferred in the + // OVERLAPPED structure itself. + if (completion_key == overlapped_contains_result) + { + result_ec = boost::system::error_code(static_cast(op->Offset), + *reinterpret_cast(op->Internal)); + bytes_transferred = op->OffsetHigh; + } + + // Otherwise ensure any result has been saved into the OVERLAPPED + // structure. + else + { + op->Internal = reinterpret_cast(&result_ec.category()); + op->Offset = result_ec.value(); + op->OffsetHigh = bytes_transferred; + } + + // Dispatch the operation only if ready. The operation may not be ready + // if the initiating function (e.g. a call to WSARecv) has not yet + // returned. This is because the initiating function still wants access + // to the operation's OVERLAPPED structure. + if (::InterlockedCompareExchange(&op->ready_, 1, 0) == 1) + { + // Ensure the count of outstanding work is decremented on block exit. + work_finished_on_block_exit on_exit = { this }; + (void)on_exit; + + op->complete(this, result_ec, bytes_transferred); + ec = boost::system::error_code(); + return 1; + } + } + else if (!ok) + { + if (last_error != WAIT_TIMEOUT) + { + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return 0; + } + + // If we're waiting indefinitely we need to keep going until we get a + // real handler. + if (msec == INFINITE) + continue; + + ec = boost::system::error_code(); + return 0; + } + else if (completion_key == wake_for_dispatch) + { + // We have been woken up to try to acquire responsibility for dispatching + // timers and completed operations. + } + else + { + // Indicate that there is no longer an in-flight stop event. + ::InterlockedExchange(&stop_event_posted_, 0); + + // The stopped_ flag is always checked to ensure that any leftover + // stop events from a previous run invocation are ignored. + if (::InterlockedExchangeAdd(&stopped_, 0) != 0) + { + // Wake up next thread that is blocked on GetQueuedCompletionStatus. + if (::InterlockedExchange(&stop_event_posted_, 1) == 0) + { + if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) + { + last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return 0; + } + } + + ec = boost::system::error_code(); + return 0; + } + } + } +} + +DWORD win_iocp_io_context::get_gqcs_timeout() +{ + OSVERSIONINFOEX osvi; + ZeroMemory(&osvi, sizeof(osvi)); + osvi.dwOSVersionInfoSize = sizeof(osvi); + osvi.dwMajorVersion = 6ul; + + const uint64_t condition_mask = ::VerSetConditionMask( + 0, VER_MAJORVERSION, VER_GREATER_EQUAL); + + if (!!::VerifyVersionInfo(&osvi, VER_MAJORVERSION, condition_mask)) + return INFINITE; + + return default_gqcs_timeout; +} + +void win_iocp_io_context::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(dispatch_mutex_); + + timer_queues_.insert(&queue); + + if (!waitable_timer_.handle) + { + waitable_timer_.handle = ::CreateWaitableTimer(0, FALSE, 0); + if (waitable_timer_.handle == 0) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "timer"); + } + + LARGE_INTEGER timeout; + timeout.QuadPart = -max_timeout_usec; + timeout.QuadPart *= 10; + ::SetWaitableTimer(waitable_timer_.handle, + &timeout, max_timeout_msec, 0, 0, FALSE); + } + + if (!timer_thread_.get()) + { + timer_thread_function thread_function = { this }; + timer_thread_.reset(new thread(thread_function, 65536)); + } +} + +void win_iocp_io_context::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(dispatch_mutex_); + + timer_queues_.erase(&queue); +} + +void win_iocp_io_context::update_timeout() +{ + if (timer_thread_.get()) + { + // There's no point updating the waitable timer if the new timeout period + // exceeds the maximum timeout. In that case, we might as well wait for the + // existing period of the timer to expire. + long timeout_usec = timer_queues_.wait_duration_usec(max_timeout_usec); + if (timeout_usec < max_timeout_usec) + { + LARGE_INTEGER timeout; + timeout.QuadPart = -timeout_usec; + timeout.QuadPart *= 10; + ::SetWaitableTimer(waitable_timer_.handle, + &timeout, max_timeout_msec, 0, 0, FALSE); + } + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP diff --git a/boost/asio/detail/impl/win_iocp_serial_port_service.ipp b/boost/asio/detail/impl/win_iocp_serial_port_service.ipp new file mode 100644 index 0000000..a8133fa --- /dev/null +++ b/boost/asio/detail/impl/win_iocp_serial_port_service.ipp @@ -0,0 +1,194 @@ +// +// detail/impl/win_iocp_serial_port_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) && defined(BOOST_ASIO_HAS_SERIAL_PORT) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +win_iocp_serial_port_service::win_iocp_serial_port_service( + execution_context& context) + : execution_context_service_base(context), + handle_service_(context) +{ +} + +void win_iocp_serial_port_service::shutdown() +{ +} + +boost::system::error_code win_iocp_serial_port_service::open( + win_iocp_serial_port_service::implementation_type& impl, + const std::string& device, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + // For convenience, add a leading \\.\ sequence if not already present. + std::string name = (device[0] == '\\') ? device : "\\\\.\\" + device; + + // Open a handle to the serial port. + ::HANDLE handle = ::CreateFileA(name.c_str(), + GENERIC_READ | GENERIC_WRITE, 0, 0, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + if (handle == INVALID_HANDLE_VALUE) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + // Determine the initial serial port parameters. + using namespace std; // For memset. + ::DCB dcb; + memset(&dcb, 0, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!::GetCommState(handle, &dcb)) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(handle); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + // Set some default serial port parameters. This implementation does not + // support changing all of these, so they might as well be in a known state. + dcb.fBinary = TRUE; // Win32 only supports binary mode. + dcb.fNull = FALSE; // Do not ignore NULL characters. + dcb.fAbortOnError = FALSE; // Ignore serial framing errors. + dcb.BaudRate = 0; // 0 baud by default + dcb.ByteSize = 8; // 8 bit bytes + dcb.fOutxCtsFlow = FALSE; // No flow control + dcb.fOutxDsrFlow = FALSE; + dcb.fDtrControl = DTR_CONTROL_DISABLE; + dcb.fDsrSensitivity = FALSE; + dcb.fOutX = FALSE; + dcb.fInX = FALSE; + dcb.fRtsControl = DTR_CONTROL_DISABLE; + dcb.fParity = FALSE; // No parity + dcb.Parity = NOPARITY; + dcb.StopBits = ONESTOPBIT; // One stop bit + if (!::SetCommState(handle, &dcb)) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(handle); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + // Set up timeouts so that the serial port will behave similarly to a + // network socket. Reads wait for at least one byte, then return with + // whatever they have. Writes return once everything is out the door. + ::COMMTIMEOUTS timeouts; + timeouts.ReadIntervalTimeout = 1; + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.ReadTotalTimeoutConstant = 0; + timeouts.WriteTotalTimeoutMultiplier = 0; + timeouts.WriteTotalTimeoutConstant = 0; + if (!::SetCommTimeouts(handle, &timeouts)) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(handle); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + // We're done. Take ownership of the serial port handle. + if (handle_service_.assign(impl, handle, ec)) + ::CloseHandle(handle); + return ec; +} + +boost::system::error_code win_iocp_serial_port_service::do_set_option( + win_iocp_serial_port_service::implementation_type& impl, + win_iocp_serial_port_service::store_function_type store, + const void* option, boost::system::error_code& ec) +{ + using namespace std; // For memcpy. + + ::DCB dcb; + memset(&dcb, 0, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!::GetCommState(handle_service_.native_handle(impl), &dcb)) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + if (store(option, dcb, ec)) + return ec; + + if (!::SetCommState(handle_service_.native_handle(impl), &dcb)) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code win_iocp_serial_port_service::do_get_option( + const win_iocp_serial_port_service::implementation_type& impl, + win_iocp_serial_port_service::load_function_type load, + void* option, boost::system::error_code& ec) const +{ + using namespace std; // For memset. + + ::DCB dcb; + memset(&dcb, 0, sizeof(DCB)); + dcb.DCBlength = sizeof(DCB); + if (!::GetCommState(handle_service_.native_handle(impl), &dcb)) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + return ec; + } + + return load(option, dcb, ec); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) && defined(BOOST_ASIO_HAS_SERIAL_PORT) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP diff --git a/boost/asio/detail/impl/win_iocp_socket_service_base.ipp b/boost/asio/detail/impl/win_iocp_socket_service_base.ipp new file mode 100644 index 0000000..5691cdb --- /dev/null +++ b/boost/asio/detail/impl/win_iocp_socket_service_base.ipp @@ -0,0 +1,802 @@ +// +// detail/impl/win_iocp_socket_service_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +win_iocp_socket_service_base::win_iocp_socket_service_base( + execution_context& context) + : context_(context), + iocp_service_(use_service(context)), + reactor_(0), + connect_ex_(0), + nt_set_info_(0), + mutex_(), + impl_list_(0) +{ +} + +void win_iocp_socket_service_base::base_shutdown() +{ + // Close all implementations, causing all operations to complete. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + base_implementation_type* impl = impl_list_; + while (impl) + { + close_for_destruction(*impl); + impl = impl->next_; + } +} + +void win_iocp_socket_service_base::construct( + win_iocp_socket_service_base::base_implementation_type& impl) +{ + impl.socket_ = invalid_socket; + impl.state_ = 0; + impl.cancel_token_.reset(); +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = 0; +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) + + // Insert implementation into linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void win_iocp_socket_service_base::base_move_construct( + win_iocp_socket_service_base::base_implementation_type& impl, + win_iocp_socket_service_base::base_implementation_type& other_impl) +{ + impl.socket_ = other_impl.socket_; + other_impl.socket_ = invalid_socket; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + impl.cancel_token_ = other_impl.cancel_token_; + other_impl.cancel_token_.reset(); + +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_; + other_impl.safe_cancellation_thread_id_ = 0; +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) + + // Insert implementation into linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; +} + +void win_iocp_socket_service_base::base_move_assign( + win_iocp_socket_service_base::base_implementation_type& impl, + win_iocp_socket_service_base& other_service, + win_iocp_socket_service_base::base_implementation_type& other_impl) +{ + close_for_destruction(impl); + + if (this != &other_service) + { + // Remove implementation from linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; + } + + impl.socket_ = other_impl.socket_; + other_impl.socket_ = invalid_socket; + + impl.state_ = other_impl.state_; + other_impl.state_ = 0; + + impl.cancel_token_ = other_impl.cancel_token_; + other_impl.cancel_token_.reset(); + +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = other_impl.safe_cancellation_thread_id_; + other_impl.safe_cancellation_thread_id_ = 0; +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) + + if (this != &other_service) + { + // Insert implementation into linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(other_service.mutex_); + impl.next_ = other_service.impl_list_; + impl.prev_ = 0; + if (other_service.impl_list_) + other_service.impl_list_->prev_ = &impl; + other_service.impl_list_ = &impl; + } +} + +void win_iocp_socket_service_base::destroy( + win_iocp_socket_service_base::base_implementation_type& impl) +{ + close_for_destruction(impl); + + // Remove implementation from linked list of all implementations. + boost::asio::detail::mutex::scoped_lock lock(mutex_); + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; +} + +boost::system::error_code win_iocp_socket_service_base::close( + win_iocp_socket_service_base::base_implementation_type& impl, + boost::system::error_code& ec) +{ + if (is_open(impl)) + { + BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), + "socket", &impl, impl.socket_, "close")); + + // Check if the reactor was created, in which case we need to close the + // socket on the reactor as well to cancel any operations that might be + // running there. + select_reactor* r = static_cast( + interlocked_compare_exchange_pointer( + reinterpret_cast(&reactor_), 0, 0)); + if (r) + r->deregister_descriptor(impl.socket_, impl.reactor_data_, true); + + socket_ops::close(impl.socket_, impl.state_, false, ec); + + if (r) + r->cleanup_descriptor_data(impl.reactor_data_); + } + else + { + ec = boost::system::error_code(); + } + + impl.socket_ = invalid_socket; + impl.state_ = 0; + impl.cancel_token_.reset(); +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = 0; +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) + + return ec; +} + +socket_type win_iocp_socket_service_base::release( + win_iocp_socket_service_base::base_implementation_type& impl, + boost::system::error_code& ec) +{ + if (!is_open(impl)) + return invalid_socket; + + cancel(impl, ec); + if (ec) + return invalid_socket; + + nt_set_info_fn fn = get_nt_set_info(); + if (fn == 0) + { + ec = boost::asio::error::operation_not_supported; + return invalid_socket; + } + + HANDLE sock_as_handle = reinterpret_cast(impl.socket_); + ULONG_PTR iosb[2] = { 0, 0 }; + void* info[2] = { 0, 0 }; + if (fn(sock_as_handle, iosb, &info, sizeof(info), + 61 /* FileReplaceCompletionInformation */)) + { + ec = boost::asio::error::operation_not_supported; + return invalid_socket; + } + + socket_type tmp = impl.socket_; + impl.socket_ = invalid_socket; + return tmp; +} + +boost::system::error_code win_iocp_socket_service_base::cancel( + win_iocp_socket_service_base::base_implementation_type& impl, + boost::system::error_code& ec) +{ + if (!is_open(impl)) + { + ec = boost::asio::error::bad_descriptor; + return ec; + } + + BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), + "socket", &impl, impl.socket_, "cancel")); + + if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( + ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) + { + // The version of Windows supports cancellation from any thread. + typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); + cancel_io_ex_t cancel_io_ex = reinterpret_cast( + reinterpret_cast(cancel_io_ex_ptr)); + socket_type sock = impl.socket_; + HANDLE sock_as_handle = reinterpret_cast(sock); + if (!cancel_io_ex(sock_as_handle, 0)) + { + DWORD last_error = ::GetLastError(); + if (last_error == ERROR_NOT_FOUND) + { + // ERROR_NOT_FOUND means that there were no operations to be + // cancelled. We swallow this error to match the behaviour on other + // platforms. + ec = boost::system::error_code(); + } + else + { + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + } + else + { + ec = boost::system::error_code(); + } + } +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + else if (impl.safe_cancellation_thread_id_ == 0) + { + // No operations have been started, so there's nothing to cancel. + ec = boost::system::error_code(); + } + else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) + { + // Asynchronous operations have been started from the current thread only, + // so it is safe to try to cancel them using CancelIo. + socket_type sock = impl.socket_; + HANDLE sock_as_handle = reinterpret_cast(sock); + if (!::CancelIo(sock_as_handle)) + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + else + { + ec = boost::system::error_code(); + } + } + else + { + // Asynchronous operations have been started from more than one thread, + // so cancellation is not safe. + ec = boost::asio::error::operation_not_supported; + } +#else // defined(BOOST_ASIO_ENABLE_CANCELIO) + else + { + // Cancellation is not supported as CancelIo may not be used. + ec = boost::asio::error::operation_not_supported; + } +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) + + // Cancel any operations started via the reactor. + if (!ec) + { + select_reactor* r = static_cast( + interlocked_compare_exchange_pointer( + reinterpret_cast(&reactor_), 0, 0)); + if (r) + r->cancel_ops(impl.socket_, impl.reactor_data_); + } + + return ec; +} + +boost::system::error_code win_iocp_socket_service_base::do_open( + win_iocp_socket_service_base::base_implementation_type& impl, + int family, int type, int protocol, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + socket_holder sock(socket_ops::socket(family, type, protocol, ec)); + if (sock.get() == invalid_socket) + return ec; + + HANDLE sock_as_handle = reinterpret_cast(sock.get()); + if (iocp_service_.register_handle(sock_as_handle, ec)) + return ec; + + impl.socket_ = sock.release(); + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + impl.cancel_token_.reset(static_cast(0), socket_ops::noop_deleter()); + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code win_iocp_socket_service_base::do_assign( + win_iocp_socket_service_base::base_implementation_type& impl, + int type, socket_type native_socket, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + HANDLE sock_as_handle = reinterpret_cast(native_socket); + if (iocp_service_.register_handle(sock_as_handle, ec)) + return ec; + + impl.socket_ = native_socket; + switch (type) + { + case SOCK_STREAM: impl.state_ = socket_ops::stream_oriented; break; + case SOCK_DGRAM: impl.state_ = socket_ops::datagram_oriented; break; + default: impl.state_ = 0; break; + } + impl.cancel_token_.reset(static_cast(0), socket_ops::noop_deleter()); + ec = boost::system::error_code(); + return ec; +} + +void win_iocp_socket_service_base::start_send_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (noop) + iocp_service_.on_completion(op); + else if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + int result = ::WSASend(impl.socket_, buffers, + static_cast(buffer_count), &bytes_transferred, flags, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_send_to_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + const socket_addr_type* addr, int addrlen, + socket_base::message_flags flags, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + int result = ::WSASendTo(impl.socket_, buffers, + static_cast(buffer_count), + &bytes_transferred, flags, addr, addrlen, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_receive_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (noop) + iocp_service_.on_completion(op); + else if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecv(impl.socket_, buffers, + static_cast(buffer_count), + &bytes_transferred, &recv_flags, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_NETNAME_DELETED) + last_error = WSAECONNRESET; + else if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_null_buffers_receive_op( + win_iocp_socket_service_base::base_implementation_type& impl, + socket_base::message_flags flags, reactor_op* op) +{ + if ((impl.state_ & socket_ops::stream_oriented) != 0) + { + // For stream sockets on Windows, we may issue a 0-byte overlapped + // WSARecv to wait until there is data available on the socket. + ::WSABUF buf = { 0, 0 }; + start_receive_op(impl, &buf, 1, flags, false, op); + } + else + { + start_reactor_op(impl, + (flags & socket_base::message_out_of_band) + ? select_reactor::except_op : select_reactor::read_op, + op); + } +} + +void win_iocp_socket_service_base::start_receive_from_op( + win_iocp_socket_service_base::base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr, + socket_base::message_flags flags, int* addrlen, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else + { + DWORD bytes_transferred = 0; + DWORD recv_flags = flags; + int result = ::WSARecvFrom(impl.socket_, buffers, + static_cast(buffer_count), + &bytes_transferred, &recv_flags, addr, addrlen, op, 0); + DWORD last_error = ::WSAGetLastError(); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + if (result != 0 && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error, bytes_transferred); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_accept_op( + win_iocp_socket_service_base::base_implementation_type& impl, + bool peer_is_open, socket_holder& new_socket, int family, int type, + int protocol, void* output_buffer, DWORD address_length, operation* op) +{ + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + if (!is_open(impl)) + iocp_service_.on_completion(op, boost::asio::error::bad_descriptor); + else if (peer_is_open) + iocp_service_.on_completion(op, boost::asio::error::already_open); + else + { + boost::system::error_code ec; + new_socket.reset(socket_ops::socket(family, type, protocol, ec)); + if (new_socket.get() == invalid_socket) + iocp_service_.on_completion(op, ec); + else + { + DWORD bytes_read = 0; + BOOL result = ::AcceptEx(impl.socket_, new_socket.get(), output_buffer, + 0, address_length, address_length, &bytes_read, op); + DWORD last_error = ::WSAGetLastError(); + if (!result && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error); + else + iocp_service_.on_pending(op); + } + } +} + +void win_iocp_socket_service_base::restart_accept_op( + socket_type s, socket_holder& new_socket, int family, int type, + int protocol, void* output_buffer, DWORD address_length, operation* op) +{ + new_socket.reset(); + iocp_service_.work_started(); + + boost::system::error_code ec; + new_socket.reset(socket_ops::socket(family, type, protocol, ec)); + if (new_socket.get() == invalid_socket) + iocp_service_.on_completion(op, ec); + else + { + DWORD bytes_read = 0; + BOOL result = ::AcceptEx(s, new_socket.get(), output_buffer, + 0, address_length, address_length, &bytes_read, op); + DWORD last_error = ::WSAGetLastError(); + if (!result && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error); + else + iocp_service_.on_pending(op); + } +} + +void win_iocp_socket_service_base::start_reactor_op( + win_iocp_socket_service_base::base_implementation_type& impl, + int op_type, reactor_op* op) +{ + select_reactor& r = get_reactor(); + update_cancellation_thread_id(impl); + + if (is_open(impl)) + { + r.start_op(op_type, impl.socket_, impl.reactor_data_, op, false, false); + return; + } + else + op->ec_ = boost::asio::error::bad_descriptor; + + iocp_service_.post_immediate_completion(op, false); +} + +void win_iocp_socket_service_base::start_connect_op( + win_iocp_socket_service_base::base_implementation_type& impl, + int family, int type, const socket_addr_type* addr, + std::size_t addrlen, win_iocp_socket_connect_op_base* op) +{ + // If ConnectEx is available, use that. + if (family == BOOST_ASIO_OS_DEF(AF_INET) + || family == BOOST_ASIO_OS_DEF(AF_INET6)) + { + if (connect_ex_fn connect_ex = get_connect_ex(impl, type)) + { + union address_union + { + socket_addr_type base; + sockaddr_in4_type v4; + sockaddr_in6_type v6; + } a; + + using namespace std; // For memset. + memset(&a, 0, sizeof(a)); + a.base.sa_family = family; + + socket_ops::bind(impl.socket_, &a.base, + family == BOOST_ASIO_OS_DEF(AF_INET) + ? sizeof(a.v4) : sizeof(a.v6), op->ec_); + if (op->ec_ && op->ec_ != boost::asio::error::invalid_argument) + { + iocp_service_.post_immediate_completion(op, false); + return; + } + + op->connect_ex_ = true; + update_cancellation_thread_id(impl); + iocp_service_.work_started(); + + BOOL result = connect_ex(impl.socket_, + addr, static_cast(addrlen), 0, 0, 0, op); + DWORD last_error = ::WSAGetLastError(); + if (!result && last_error != WSA_IO_PENDING) + iocp_service_.on_completion(op, last_error); + else + iocp_service_.on_pending(op); + return; + } + } + + // Otherwise, fall back to a reactor-based implementation. + select_reactor& r = get_reactor(); + update_cancellation_thread_id(impl); + + if ((impl.state_ & socket_ops::non_blocking) != 0 + || socket_ops::set_internal_non_blocking( + impl.socket_, impl.state_, true, op->ec_)) + { + if (socket_ops::connect(impl.socket_, addr, addrlen, op->ec_) != 0) + { + if (op->ec_ == boost::asio::error::in_progress + || op->ec_ == boost::asio::error::would_block) + { + op->ec_ = boost::system::error_code(); + r.start_op(select_reactor::connect_op, impl.socket_, + impl.reactor_data_, op, false, false); + return; + } + } + } + + r.post_immediate_completion(op, false); +} + +void win_iocp_socket_service_base::close_for_destruction( + win_iocp_socket_service_base::base_implementation_type& impl) +{ + if (is_open(impl)) + { + BOOST_ASIO_HANDLER_OPERATION((iocp_service_.context(), + "socket", &impl, impl.socket_, "close")); + + // Check if the reactor was created, in which case we need to close the + // socket on the reactor as well to cancel any operations that might be + // running there. + select_reactor* r = static_cast( + interlocked_compare_exchange_pointer( + reinterpret_cast(&reactor_), 0, 0)); + if (r) + r->deregister_descriptor(impl.socket_, impl.reactor_data_, true); + + boost::system::error_code ignored_ec; + socket_ops::close(impl.socket_, impl.state_, true, ignored_ec); + + if (r) + r->cleanup_descriptor_data(impl.reactor_data_); + } + + impl.socket_ = invalid_socket; + impl.state_ = 0; + impl.cancel_token_.reset(); +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + impl.safe_cancellation_thread_id_ = 0; +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) +} + +void win_iocp_socket_service_base::update_cancellation_thread_id( + win_iocp_socket_service_base::base_implementation_type& impl) +{ +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + if (impl.safe_cancellation_thread_id_ == 0) + impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); + else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) + impl.safe_cancellation_thread_id_ = ~DWORD(0); +#else // defined(BOOST_ASIO_ENABLE_CANCELIO) + (void)impl; +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) +} + +select_reactor& win_iocp_socket_service_base::get_reactor() +{ + select_reactor* r = static_cast( + interlocked_compare_exchange_pointer( + reinterpret_cast(&reactor_), 0, 0)); + if (!r) + { + r = &(use_service(context_)); + interlocked_exchange_pointer(reinterpret_cast(&reactor_), r); + } + return *r; +} + +win_iocp_socket_service_base::connect_ex_fn +win_iocp_socket_service_base::get_connect_ex( + win_iocp_socket_service_base::base_implementation_type& impl, int type) +{ +#if defined(BOOST_ASIO_DISABLE_CONNECTEX) + (void)impl; + (void)type; + return 0; +#else // defined(BOOST_ASIO_DISABLE_CONNECTEX) + if (type != BOOST_ASIO_OS_DEF(SOCK_STREAM) + && type != BOOST_ASIO_OS_DEF(SOCK_SEQPACKET)) + return 0; + + void* ptr = interlocked_compare_exchange_pointer(&connect_ex_, 0, 0); + if (!ptr) + { + GUID guid = { 0x25a207b9, 0xddf3, 0x4660, + { 0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e } }; + + DWORD bytes = 0; + if (::WSAIoctl(impl.socket_, SIO_GET_EXTENSION_FUNCTION_POINTER, + &guid, sizeof(guid), &ptr, sizeof(ptr), &bytes, 0, 0) != 0) + { + // Set connect_ex_ to a special value to indicate that ConnectEx is + // unavailable. That way we won't bother trying to look it up again. + ptr = this; + } + + interlocked_exchange_pointer(&connect_ex_, ptr); + } + + return reinterpret_cast(ptr == this ? 0 : ptr); +#endif // defined(BOOST_ASIO_DISABLE_CONNECTEX) +} + +win_iocp_socket_service_base::nt_set_info_fn +win_iocp_socket_service_base::get_nt_set_info() +{ + void* ptr = interlocked_compare_exchange_pointer(&nt_set_info_, 0, 0); + if (!ptr) + { + if (HMODULE h = ::GetModuleHandleA("NTDLL.DLL")) + ptr = reinterpret_cast(GetProcAddress(h, "NtSetInformationFile")); + + // On failure, set nt_set_info_ to a special value to indicate that the + // NtSetInformationFile function is unavailable. That way we won't bother + // trying to look it up again. + interlocked_exchange_pointer(&nt_set_info_, ptr ? ptr : this); + } + + return reinterpret_cast(ptr == this ? 0 : ptr); +} + +void* win_iocp_socket_service_base::interlocked_compare_exchange_pointer( + void** dest, void* exch, void* cmp) +{ +#if defined(_M_IX86) + return reinterpret_cast(InterlockedCompareExchange( + reinterpret_cast(dest), reinterpret_cast(exch), + reinterpret_cast(cmp))); +#else + return InterlockedCompareExchangePointer(dest, exch, cmp); +#endif +} + +void* win_iocp_socket_service_base::interlocked_exchange_pointer( + void** dest, void* val) +{ +#if defined(_M_IX86) + return reinterpret_cast(InterlockedExchange( + reinterpret_cast(dest), reinterpret_cast(val))); +#else + return InterlockedExchangePointer(dest, val); +#endif +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP diff --git a/boost/asio/detail/impl/win_mutex.ipp b/boost/asio/detail/impl/win_mutex.ipp new file mode 100644 index 0000000..809d40f --- /dev/null +++ b/boost/asio/detail/impl/win_mutex.ipp @@ -0,0 +1,86 @@ +// +// detail/impl/win_mutex.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_MUTEX_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_MUTEX_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +win_mutex::win_mutex() +{ + int error = do_init(); + boost::system::error_code ec(error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "mutex"); +} + +int win_mutex::do_init() +{ +#if defined(__MINGW32__) + // Not sure if MinGW supports structured exception handling, so for now + // we'll just call the Windows API and hope. +# if defined(UNDER_CE) + ::InitializeCriticalSection(&crit_section_); +# elif defined(BOOST_ASIO_WINDOWS_APP) + if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0)) + return ::GetLastError(); +# else + if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000)) + return ::GetLastError(); +# endif + return 0; +#else + __try + { +# if defined(UNDER_CE) + ::InitializeCriticalSection(&crit_section_); +# elif defined(BOOST_ASIO_WINDOWS_APP) + if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0)) + return ::GetLastError(); +# else + if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000)) + return ::GetLastError(); +# endif + } + __except(GetExceptionCode() == STATUS_NO_MEMORY + ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) + { + return ERROR_OUTOFMEMORY; + } + + return 0; +#endif +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_MUTEX_IPP diff --git a/boost/asio/detail/impl/win_object_handle_service.ipp b/boost/asio/detail/impl/win_object_handle_service.ipp new file mode 100644 index 0000000..f356a00 --- /dev/null +++ b/boost/asio/detail/impl/win_object_handle_service.ipp @@ -0,0 +1,450 @@ +// +// detail/impl/win_object_handle_service.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2011 Boris Schaeling (boris@highscore.de) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +win_object_handle_service::win_object_handle_service(execution_context& context) + : execution_context_service_base(context), + scheduler_(boost::asio::use_service(context)), + mutex_(), + impl_list_(0), + shutdown_(false) +{ +} + +void win_object_handle_service::shutdown() +{ + mutex::scoped_lock lock(mutex_); + + // Setting this flag to true prevents new objects from being registered, and + // new asynchronous wait operations from being started. We only need to worry + // about cleaning up the operations that are currently in progress. + shutdown_ = true; + + op_queue ops; + for (implementation_type* impl = impl_list_; impl; impl = impl->next_) + ops.push(impl->op_queue_); + + lock.unlock(); + + scheduler_.abandon_operations(ops); +} + +void win_object_handle_service::construct( + win_object_handle_service::implementation_type& impl) +{ + impl.handle_ = INVALID_HANDLE_VALUE; + impl.wait_handle_ = INVALID_HANDLE_VALUE; + impl.owner_ = this; + + // Insert implementation into linked list of all implementations. + mutex::scoped_lock lock(mutex_); + if (!shutdown_) + { + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; + } +} + +void win_object_handle_service::move_construct( + win_object_handle_service::implementation_type& impl, + win_object_handle_service::implementation_type& other_impl) +{ + mutex::scoped_lock lock(mutex_); + + // Insert implementation into linked list of all implementations. + if (!shutdown_) + { + impl.next_ = impl_list_; + impl.prev_ = 0; + if (impl_list_) + impl_list_->prev_ = &impl; + impl_list_ = &impl; + } + + impl.handle_ = other_impl.handle_; + other_impl.handle_ = INVALID_HANDLE_VALUE; + impl.wait_handle_ = other_impl.wait_handle_; + other_impl.wait_handle_ = INVALID_HANDLE_VALUE; + impl.op_queue_.push(other_impl.op_queue_); + impl.owner_ = this; + + // We must not hold the lock while calling UnregisterWaitEx. This is because + // the registered callback function might be invoked while we are waiting for + // UnregisterWaitEx to complete. + lock.unlock(); + + if (impl.wait_handle_ != INVALID_HANDLE_VALUE) + ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE); + + if (!impl.op_queue_.empty()) + register_wait_callback(impl, lock); +} + +void win_object_handle_service::move_assign( + win_object_handle_service::implementation_type& impl, + win_object_handle_service& other_service, + win_object_handle_service::implementation_type& other_impl) +{ + boost::system::error_code ignored_ec; + close(impl, ignored_ec); + + mutex::scoped_lock lock(mutex_); + + if (this != &other_service) + { + // Remove implementation from linked list of all implementations. + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; + } + + impl.handle_ = other_impl.handle_; + other_impl.handle_ = INVALID_HANDLE_VALUE; + impl.wait_handle_ = other_impl.wait_handle_; + other_impl.wait_handle_ = INVALID_HANDLE_VALUE; + impl.op_queue_.push(other_impl.op_queue_); + impl.owner_ = this; + + if (this != &other_service) + { + // Insert implementation into linked list of all implementations. + impl.next_ = other_service.impl_list_; + impl.prev_ = 0; + if (other_service.impl_list_) + other_service.impl_list_->prev_ = &impl; + other_service.impl_list_ = &impl; + } + + // We must not hold the lock while calling UnregisterWaitEx. This is because + // the registered callback function might be invoked while we are waiting for + // UnregisterWaitEx to complete. + lock.unlock(); + + if (impl.wait_handle_ != INVALID_HANDLE_VALUE) + ::UnregisterWaitEx(impl.wait_handle_, INVALID_HANDLE_VALUE); + + if (!impl.op_queue_.empty()) + register_wait_callback(impl, lock); +} + +void win_object_handle_service::destroy( + win_object_handle_service::implementation_type& impl) +{ + mutex::scoped_lock lock(mutex_); + + // Remove implementation from linked list of all implementations. + if (impl_list_ == &impl) + impl_list_ = impl.next_; + if (impl.prev_) + impl.prev_->next_ = impl.next_; + if (impl.next_) + impl.next_->prev_= impl.prev_; + impl.next_ = 0; + impl.prev_ = 0; + + if (is_open(impl)) + { + BOOST_ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle", + &impl, reinterpret_cast(impl.wait_handle_), "close")); + + HANDLE wait_handle = impl.wait_handle_; + impl.wait_handle_ = INVALID_HANDLE_VALUE; + + op_queue ops; + while (wait_op* op = impl.op_queue_.front()) + { + op->ec_ = boost::asio::error::operation_aborted; + impl.op_queue_.pop(); + ops.push(op); + } + + // We must not hold the lock while calling UnregisterWaitEx. This is + // because the registered callback function might be invoked while we are + // waiting for UnregisterWaitEx to complete. + lock.unlock(); + + if (wait_handle != INVALID_HANDLE_VALUE) + ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE); + + ::CloseHandle(impl.handle_); + impl.handle_ = INVALID_HANDLE_VALUE; + + scheduler_.post_deferred_completions(ops); + } +} + +boost::system::error_code win_object_handle_service::assign( + win_object_handle_service::implementation_type& impl, + const native_handle_type& handle, boost::system::error_code& ec) +{ + if (is_open(impl)) + { + ec = boost::asio::error::already_open; + return ec; + } + + impl.handle_ = handle; + ec = boost::system::error_code(); + return ec; +} + +boost::system::error_code win_object_handle_service::close( + win_object_handle_service::implementation_type& impl, + boost::system::error_code& ec) +{ + if (is_open(impl)) + { + BOOST_ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle", + &impl, reinterpret_cast(impl.wait_handle_), "close")); + + mutex::scoped_lock lock(mutex_); + + HANDLE wait_handle = impl.wait_handle_; + impl.wait_handle_ = INVALID_HANDLE_VALUE; + + op_queue completed_ops; + while (wait_op* op = impl.op_queue_.front()) + { + impl.op_queue_.pop(); + op->ec_ = boost::asio::error::operation_aborted; + completed_ops.push(op); + } + + // We must not hold the lock while calling UnregisterWaitEx. This is + // because the registered callback function might be invoked while we are + // waiting for UnregisterWaitEx to complete. + lock.unlock(); + + if (wait_handle != INVALID_HANDLE_VALUE) + ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE); + + if (::CloseHandle(impl.handle_)) + { + impl.handle_ = INVALID_HANDLE_VALUE; + ec = boost::system::error_code(); + } + else + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + } + + scheduler_.post_deferred_completions(completed_ops); + } + else + { + ec = boost::system::error_code(); + } + + return ec; +} + +boost::system::error_code win_object_handle_service::cancel( + win_object_handle_service::implementation_type& impl, + boost::system::error_code& ec) +{ + if (is_open(impl)) + { + BOOST_ASIO_HANDLER_OPERATION((scheduler_.context(), "object_handle", + &impl, reinterpret_cast(impl.wait_handle_), "cancel")); + + mutex::scoped_lock lock(mutex_); + + HANDLE wait_handle = impl.wait_handle_; + impl.wait_handle_ = INVALID_HANDLE_VALUE; + + op_queue completed_ops; + while (wait_op* op = impl.op_queue_.front()) + { + op->ec_ = boost::asio::error::operation_aborted; + impl.op_queue_.pop(); + completed_ops.push(op); + } + + // We must not hold the lock while calling UnregisterWaitEx. This is + // because the registered callback function might be invoked while we are + // waiting for UnregisterWaitEx to complete. + lock.unlock(); + + if (wait_handle != INVALID_HANDLE_VALUE) + ::UnregisterWaitEx(wait_handle, INVALID_HANDLE_VALUE); + + ec = boost::system::error_code(); + + scheduler_.post_deferred_completions(completed_ops); + } + else + { + ec = boost::asio::error::bad_descriptor; + } + + return ec; +} + +void win_object_handle_service::wait( + win_object_handle_service::implementation_type& impl, + boost::system::error_code& ec) +{ + switch (::WaitForSingleObject(impl.handle_, INFINITE)) + { + case WAIT_FAILED: + { + DWORD last_error = ::GetLastError(); + ec = boost::system::error_code(last_error, + boost::asio::error::get_system_category()); + break; + } + case WAIT_OBJECT_0: + case WAIT_ABANDONED: + default: + ec = boost::system::error_code(); + break; + } +} + +void win_object_handle_service::start_wait_op( + win_object_handle_service::implementation_type& impl, wait_op* op) +{ + scheduler_.work_started(); + + if (is_open(impl)) + { + mutex::scoped_lock lock(mutex_); + + if (!shutdown_) + { + impl.op_queue_.push(op); + + // Only the first operation to be queued gets to register a wait callback. + // Subsequent operations have to wait for the first to finish. + if (impl.op_queue_.front() == op) + register_wait_callback(impl, lock); + } + else + { + lock.unlock(); + scheduler_.post_deferred_completion(op); + } + } + else + { + op->ec_ = boost::asio::error::bad_descriptor; + scheduler_.post_deferred_completion(op); + } +} + +void win_object_handle_service::register_wait_callback( + win_object_handle_service::implementation_type& impl, + mutex::scoped_lock& lock) +{ + lock.lock(); + + if (!RegisterWaitForSingleObject(&impl.wait_handle_, + impl.handle_, &win_object_handle_service::wait_callback, + &impl, INFINITE, WT_EXECUTEONLYONCE)) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + + op_queue completed_ops; + while (wait_op* op = impl.op_queue_.front()) + { + op->ec_ = ec; + impl.op_queue_.pop(); + completed_ops.push(op); + } + + lock.unlock(); + scheduler_.post_deferred_completions(completed_ops); + } +} + +void win_object_handle_service::wait_callback(PVOID param, BOOLEAN) +{ + implementation_type* impl = static_cast(param); + mutex::scoped_lock lock(impl->owner_->mutex_); + + if (impl->wait_handle_ != INVALID_HANDLE_VALUE) + { + ::UnregisterWaitEx(impl->wait_handle_, NULL); + impl->wait_handle_ = INVALID_HANDLE_VALUE; + } + + if (wait_op* op = impl->op_queue_.front()) + { + op_queue completed_ops; + + op->ec_ = boost::system::error_code(); + impl->op_queue_.pop(); + completed_ops.push(op); + + if (!impl->op_queue_.empty()) + { + if (!RegisterWaitForSingleObject(&impl->wait_handle_, + impl->handle_, &win_object_handle_service::wait_callback, + param, INFINITE, WT_EXECUTEONLYONCE)) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + + while ((op = impl->op_queue_.front()) != 0) + { + op->ec_ = ec; + impl->op_queue_.pop(); + completed_ops.push(op); + } + } + } + + scheduler_impl& sched = impl->owner_->scheduler_; + lock.unlock(); + sched.post_deferred_completions(completed_ops); + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP diff --git a/boost/asio/detail/impl/win_static_mutex.ipp b/boost/asio/detail/impl/win_static_mutex.ipp new file mode 100644 index 0000000..ae53dbe --- /dev/null +++ b/boost/asio/detail/impl/win_static_mutex.ipp @@ -0,0 +1,138 @@ +// +// detail/impl/win_static_mutex.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_STATIC_MUTEX_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_STATIC_MUTEX_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +void win_static_mutex::init() +{ + int error = do_init(); + boost::system::error_code ec(error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "static_mutex"); +} + +int win_static_mutex::do_init() +{ + using namespace std; // For sprintf. + wchar_t mutex_name[128]; +#if defined(BOOST_ASIO_HAS_SECURE_RTL) + swprintf_s( +#else // defined(BOOST_ASIO_HAS_SECURE_RTL) + _snwprintf( +#endif // defined(BOOST_ASIO_HAS_SECURE_RTL) + mutex_name, 128, L"asio-58CCDC44-6264-4842-90C2-F3C545CB8AA7-%u-%p", + static_cast(::GetCurrentProcessId()), this); + +#if defined(BOOST_ASIO_WINDOWS_APP) + HANDLE mutex = ::CreateMutexExW(0, mutex_name, CREATE_MUTEX_INITIAL_OWNER, 0); +#else // defined(BOOST_ASIO_WINDOWS_APP) + HANDLE mutex = ::CreateMutexW(0, TRUE, mutex_name); +#endif // defined(BOOST_ASIO_WINDOWS_APP) + DWORD last_error = ::GetLastError(); + if (mutex == 0) + return ::GetLastError(); + + if (last_error == ERROR_ALREADY_EXISTS) + { +#if defined(BOOST_ASIO_WINDOWS_APP) + ::WaitForSingleObjectEx(mutex, INFINITE, false); +#else // defined(BOOST_ASIO_WINDOWS_APP) + ::WaitForSingleObject(mutex, INFINITE); +#endif // defined(BOOST_ASIO_WINDOWS_APP) + } + + if (initialised_) + { + ::ReleaseMutex(mutex); + ::CloseHandle(mutex); + return 0; + } + +#if defined(__MINGW32__) + // Not sure if MinGW supports structured exception handling, so for now + // we'll just call the Windows API and hope. +# if defined(UNDER_CE) + ::InitializeCriticalSection(&crit_section_); +# else + if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000)) + { + last_error = ::GetLastError(); + ::ReleaseMutex(mutex); + ::CloseHandle(mutex); + return last_error; + } +# endif +#else + __try + { +# if defined(UNDER_CE) + ::InitializeCriticalSection(&crit_section_); +# elif defined(BOOST_ASIO_WINDOWS_APP) + if (!::InitializeCriticalSectionEx(&crit_section_, 0, 0)) + { + last_error = ::GetLastError(); + ::ReleaseMutex(mutex); + ::CloseHandle(mutex); + return last_error; + } +# else + if (!::InitializeCriticalSectionAndSpinCount(&crit_section_, 0x80000000)) + { + last_error = ::GetLastError(); + ::ReleaseMutex(mutex); + ::CloseHandle(mutex); + return last_error; + } +# endif + } + __except(GetExceptionCode() == STATUS_NO_MEMORY + ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) + { + ::ReleaseMutex(mutex); + ::CloseHandle(mutex); + return ERROR_OUTOFMEMORY; + } +#endif + + initialised_ = true; + ::ReleaseMutex(mutex); + ::CloseHandle(mutex); + return 0; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_STATIC_MUTEX_IPP diff --git a/boost/asio/detail/impl/win_thread.ipp b/boost/asio/detail/impl/win_thread.ipp new file mode 100644 index 0000000..13faa07 --- /dev/null +++ b/boost/asio/detail/impl/win_thread.ipp @@ -0,0 +1,152 @@ +// +// detail/impl/win_thread.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_THREAD_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_THREAD_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_APP) \ + && !defined(UNDER_CE) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +win_thread::~win_thread() +{ + ::CloseHandle(thread_); + + // The exit_event_ handle is deliberately allowed to leak here since it + // is an error for the owner of an internal thread not to join() it. +} + +void win_thread::join() +{ + HANDLE handles[2] = { exit_event_, thread_ }; + ::WaitForMultipleObjects(2, handles, FALSE, INFINITE); + ::CloseHandle(exit_event_); + if (terminate_threads()) + { + ::TerminateThread(thread_, 0); + } + else + { + ::QueueUserAPC(apc_function, thread_, 0); + ::WaitForSingleObject(thread_, INFINITE); + } +} + +std::size_t win_thread::hardware_concurrency() +{ + SYSTEM_INFO system_info; + ::GetSystemInfo(&system_info); + return system_info.dwNumberOfProcessors; +} + +void win_thread::start_thread(func_base* arg, unsigned int stack_size) +{ + ::HANDLE entry_event = 0; + arg->entry_event_ = entry_event = ::CreateEventW(0, true, false, 0); + if (!entry_event) + { + DWORD last_error = ::GetLastError(); + delete arg; + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "thread.entry_event"); + } + + arg->exit_event_ = exit_event_ = ::CreateEventW(0, true, false, 0); + if (!exit_event_) + { + DWORD last_error = ::GetLastError(); + delete arg; + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "thread.exit_event"); + } + + unsigned int thread_id = 0; + thread_ = reinterpret_cast(::_beginthreadex(0, + stack_size, win_thread_function, arg, 0, &thread_id)); + if (!thread_) + { + DWORD last_error = ::GetLastError(); + delete arg; + if (entry_event) + ::CloseHandle(entry_event); + if (exit_event_) + ::CloseHandle(exit_event_); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "thread"); + } + + if (entry_event) + { + ::WaitForSingleObject(entry_event, INFINITE); + ::CloseHandle(entry_event); + } +} + +unsigned int __stdcall win_thread_function(void* arg) +{ + win_thread::auto_func_base_ptr func = { + static_cast(arg) }; + + ::SetEvent(func.ptr->entry_event_); + + func.ptr->run(); + + // Signal that the thread has finished its work, but rather than returning go + // to sleep to put the thread into a well known state. If the thread is being + // joined during global object destruction then it may be killed using + // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx + // call will be interrupted using QueueUserAPC and the thread will shut down + // cleanly. + HANDLE exit_event = func.ptr->exit_event_; + delete func.ptr; + func.ptr = 0; + ::SetEvent(exit_event); + ::SleepEx(INFINITE, TRUE); + + return 0; +} + +#if defined(WINVER) && (WINVER < 0x0500) +void __stdcall apc_function(ULONG) {} +#else +void __stdcall apc_function(ULONG_PTR) {} +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_APP) + // && !defined(UNDER_CE) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_THREAD_IPP diff --git a/boost/asio/detail/impl/win_tss_ptr.ipp b/boost/asio/detail/impl/win_tss_ptr.ipp new file mode 100644 index 0000000..8c6c5c6 --- /dev/null +++ b/boost/asio/detail/impl/win_tss_ptr.ipp @@ -0,0 +1,59 @@ +// +// detail/impl/win_tss_ptr.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP +#define BOOST_ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +DWORD win_tss_ptr_create() +{ +#if defined(UNDER_CE) + const DWORD out_of_indexes = 0xFFFFFFFF; +#else + const DWORD out_of_indexes = TLS_OUT_OF_INDEXES; +#endif + + DWORD tss_key = ::TlsAlloc(); + if (tss_key == out_of_indexes) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "tss"); + } + return tss_key; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS) + +#endif // BOOST_ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP diff --git a/boost/asio/detail/impl/winrt_timer_scheduler.hpp b/boost/asio/detail/impl/winrt_timer_scheduler.hpp new file mode 100644 index 0000000..89ac7a1 --- /dev/null +++ b/boost/asio/detail/impl/winrt_timer_scheduler.hpp @@ -0,0 +1,94 @@ +// +// detail/impl/winrt_timer_scheduler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_HPP +#define BOOST_ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +void winrt_timer_scheduler::add_timer_queue(timer_queue& queue) +{ + do_add_timer_queue(queue); +} + +// Remove a timer queue from the reactor. +template +void winrt_timer_scheduler::remove_timer_queue(timer_queue& queue) +{ + do_remove_timer_queue(queue); +} + +template +void winrt_timer_scheduler::schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + { + scheduler_.post_immediate_completion(op, false); + return; + } + + bool earliest = queue.enqueue_timer(time, timer, op); + scheduler_.work_started(); + if (earliest) + event_.signal(lock); +} + +template +std::size_t winrt_timer_scheduler::cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); + lock.unlock(); + scheduler_.post_deferred_completions(ops); + return n; +} + +template +void winrt_timer_scheduler::move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& to, + typename timer_queue::per_timer_data& from) +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + op_queue ops; + queue.cancel_timer(to, ops); + queue.move_timer(to, from); + lock.unlock(); + scheduler_.post_deferred_completions(ops); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#endif // BOOST_ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_HPP diff --git a/boost/asio/detail/impl/winrt_timer_scheduler.ipp b/boost/asio/detail/impl/winrt_timer_scheduler.ipp new file mode 100644 index 0000000..48cb29c --- /dev/null +++ b/boost/asio/detail/impl/winrt_timer_scheduler.ipp @@ -0,0 +1,123 @@ +// +// detail/impl/winrt_timer_scheduler.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_IPP +#define BOOST_ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +winrt_timer_scheduler::winrt_timer_scheduler(execution_context& context) + : execution_context_service_base(context), + scheduler_(use_service(context)), + mutex_(), + event_(), + timer_queues_(), + thread_(0), + stop_thread_(false), + shutdown_(false) +{ + thread_ = new boost::asio::detail::thread( + bind_handler(&winrt_timer_scheduler::call_run_thread, this)); +} + +winrt_timer_scheduler::~winrt_timer_scheduler() +{ + shutdown(); +} + +void winrt_timer_scheduler::shutdown() +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; + stop_thread_ = true; + event_.signal(lock); + lock.unlock(); + + if (thread_) + { + thread_->join(); + delete thread_; + thread_ = 0; + } + + op_queue ops; + timer_queues_.get_all_timers(ops); + scheduler_.abandon_operations(ops); +} + +void winrt_timer_scheduler::notify_fork(execution_context::fork_event) +{ +} + +void winrt_timer_scheduler::init_task() +{ +} + +void winrt_timer_scheduler::run_thread() +{ + boost::asio::detail::mutex::scoped_lock lock(mutex_); + while (!stop_thread_) + { + const long max_wait_duration = 5 * 60 * 1000000; + long wait_duration = timer_queues_.wait_duration_usec(max_wait_duration); + event_.wait_for_usec(lock, wait_duration); + event_.clear(lock); + op_queue ops; + timer_queues_.get_ready_timers(ops); + if (!ops.empty()) + { + lock.unlock(); + scheduler_.post_deferred_completions(ops); + lock.lock(); + } + } +} + +void winrt_timer_scheduler::call_run_thread(winrt_timer_scheduler* scheduler) +{ + scheduler->run_thread(); +} + +void winrt_timer_scheduler::do_add_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.insert(&queue); +} + +void winrt_timer_scheduler::do_remove_timer_queue(timer_queue_base& queue) +{ + mutex::scoped_lock lock(mutex_); + timer_queues_.erase(&queue); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#endif // BOOST_ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_IPP diff --git a/boost/asio/detail/impl/winsock_init.ipp b/boost/asio/detail/impl/winsock_init.ipp new file mode 100644 index 0000000..85b50df --- /dev/null +++ b/boost/asio/detail/impl/winsock_init.ipp @@ -0,0 +1,84 @@ +// +// detail/impl/winsock_init.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP +#define BOOST_ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +void winsock_init_base::startup(data& d, + unsigned char major, unsigned char minor) +{ + if (::InterlockedIncrement(&d.init_count_) == 1) + { + WSADATA wsa_data; + long result = ::WSAStartup(MAKEWORD(major, minor), &wsa_data); + ::InterlockedExchange(&d.result_, result); + } +} + +void winsock_init_base::manual_startup(data& d) +{ + if (::InterlockedIncrement(&d.init_count_) == 1) + { + ::InterlockedExchange(&d.result_, 0); + } +} + +void winsock_init_base::cleanup(data& d) +{ + if (::InterlockedDecrement(&d.init_count_) == 0) + { + ::WSACleanup(); + } +} + +void winsock_init_base::manual_cleanup(data& d) +{ + ::InterlockedDecrement(&d.init_count_); +} + +void winsock_init_base::throw_on_error(data& d) +{ + long result = ::InterlockedExchangeAdd(&d.result_, 0); + if (result != 0) + { + boost::system::error_code ec(result, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "winsock"); + } +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP diff --git a/boost/asio/detail/io_control.hpp b/boost/asio/detail/io_control.hpp new file mode 100644 index 0000000..4f091db --- /dev/null +++ b/boost/asio/detail/io_control.hpp @@ -0,0 +1,86 @@ +// +// detail/io_control.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IO_CONTROL_HPP +#define BOOST_ASIO_DETAIL_IO_CONTROL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { +namespace io_control { + +// I/O control command for getting number of bytes available. +class bytes_readable +{ +public: + // Default constructor. + bytes_readable() + : value_(0) + { + } + + // Construct with a specific command value. + bytes_readable(std::size_t value) + : value_(static_cast(value)) + { + } + + // Get the name of the IO control command. + int name() const + { + return static_cast(BOOST_ASIO_OS_DEF(FIONREAD)); + } + + // Set the value of the I/O control command. + void set(std::size_t value) + { + value_ = static_cast(value); + } + + // Get the current value of the I/O control command. + std::size_t get() const + { + return static_cast(value_); + } + + // Get the address of the command data. + detail::ioctl_arg_type* data() + { + return &value_; + } + + // Get the address of the command data. + const detail::ioctl_arg_type* data() const + { + return &value_; + } + +private: + detail::ioctl_arg_type value_; +}; + +} // namespace io_control +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IO_CONTROL_HPP diff --git a/boost/asio/detail/io_object_executor.hpp b/boost/asio/detail/io_object_executor.hpp new file mode 100644 index 0000000..5b5258f --- /dev/null +++ b/boost/asio/detail/io_object_executor.hpp @@ -0,0 +1,169 @@ +// +// io_object_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IO_OBJECT_EXECUTOR_HPP +#define BOOST_ASIO_DETAIL_IO_OBJECT_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Wrap the (potentially polymorphic) executor so that we can bypass it when +// dispatching on a target executor that has a native I/O implementation. +template +class io_object_executor +{ +public: + io_object_executor(const Executor& ex, + bool native_implementation) BOOST_ASIO_NOEXCEPT + : executor_(ex), + has_native_impl_(native_implementation) + { + } + + io_object_executor(const io_object_executor& other) BOOST_ASIO_NOEXCEPT + : executor_(other.executor_), + has_native_impl_(other.has_native_impl_) + { + } + + template + io_object_executor( + const io_object_executor& other) BOOST_ASIO_NOEXCEPT + : executor_(other.inner_executor()), + has_native_impl_(other.has_native_implementation()) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + io_object_executor(io_object_executor&& other) BOOST_ASIO_NOEXCEPT + : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)), + has_native_impl_(other.has_native_impl_) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + const Executor& inner_executor() const BOOST_ASIO_NOEXCEPT + { + return executor_; + } + + bool has_native_implementation() const BOOST_ASIO_NOEXCEPT + { + return has_native_impl_; + } + + execution_context& context() const BOOST_ASIO_NOEXCEPT + { + return executor_.context(); + } + + void on_work_started() const BOOST_ASIO_NOEXCEPT + { + if (is_same::value + || has_native_impl_) + { + // When using a native implementation, work is already counted by the + // execution context. + } + else + { + executor_.on_work_started(); + } + } + + void on_work_finished() const BOOST_ASIO_NOEXCEPT + { + if (is_same::value + || has_native_impl_) + { + // When using a native implementation, work is already counted by the + // execution context. + } + else + { + executor_.on_work_finished(); + } + } + + template + void dispatch(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const + { + if (is_same::value + || has_native_impl_) + { + // When using a native implementation, I/O completion handlers are + // already dispatched according to the execution context's executor's + // rules. We can call the function directly. +#if defined(BOOST_ASIO_HAS_MOVE) + if (is_same::type>::value) + { + boost_asio_handler_invoke_helpers::invoke(f, f); + return; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + typename decay::type function(BOOST_ASIO_MOVE_CAST(F)(f)); + boost_asio_handler_invoke_helpers::invoke(function, function); + } + else + { + executor_.dispatch(BOOST_ASIO_MOVE_CAST(F)(f), a); + } + } + + template + void post(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const + { + executor_.post(BOOST_ASIO_MOVE_CAST(F)(f), a); + } + + template + void defer(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const + { + executor_.defer(BOOST_ASIO_MOVE_CAST(F)(f), a); + } + + friend bool operator==(const io_object_executor& a, + const io_object_executor& b) BOOST_ASIO_NOEXCEPT + { + return a.executor_ == b.executor_ + && a.has_native_impl_ == b.has_native_impl_; + } + + friend bool operator!=(const io_object_executor& a, + const io_object_executor& b) BOOST_ASIO_NOEXCEPT + { + return a.executor_ != b.executor_ + || a.has_native_impl_ != b.has_native_impl_; + } + +private: + Executor executor_; + const bool has_native_impl_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IO_OBJECT_EXECUTOR_HPP diff --git a/boost/asio/detail/io_object_impl.hpp b/boost/asio/detail/io_object_impl.hpp new file mode 100644 index 0000000..be1a5e2 --- /dev/null +++ b/boost/asio/detail/io_object_impl.hpp @@ -0,0 +1,195 @@ +// +// io_object_impl.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IO_OBJECT_IMPL_HPP +#define BOOST_ASIO_DETAIL_IO_OBJECT_IMPL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +class executor; + +namespace detail { + +inline bool is_native_io_executor(const io_context::executor_type&) +{ + return true; +} + +template +inline bool is_native_io_executor(const Executor&, + typename enable_if::value>::type* = 0) +{ + return false; +} + +template +inline bool is_native_io_executor(const Executor& ex, + typename enable_if::value>::type* = 0) +{ +#if !defined (BOOST_ASIO_NO_TYPEID) + return ex.target_type() == typeid(io_context::executor_type); +#else // !defined (BOOST_ASIO_NO_TYPEID) + return false; +#endif // !defined (BOOST_ASIO_NO_TYPEID) +} + +template +class io_object_impl +{ +public: + // The type of the service that will be used to provide I/O operations. + typedef IoObjectService service_type; + + // The underlying implementation type of I/O object. + typedef typename service_type::implementation_type implementation_type; + + // The type of the executor associated with the object. + typedef Executor executor_type; + + // The type of executor to be used when implementing asynchronous operations. + typedef io_object_executor implementation_executor_type; + + // Construct an I/O object using an executor. + explicit io_object_impl(const executor_type& ex) + : service_(&boost::asio::use_service(ex.context())), + implementation_executor_(ex, (is_native_io_executor)(ex)) + { + service_->construct(implementation_); + } + + // Construct an I/O object using an execution context. + template + explicit io_object_impl(ExecutionContext& context, + typename enable_if::value>::type* = 0) + : service_(&boost::asio::use_service(context)), + implementation_executor_(context.get_executor(), + is_same::value) + { + service_->construct(implementation_); + } + +#if defined(BOOST_ASIO_HAS_MOVE) + // Move-construct an I/O object. + io_object_impl(io_object_impl&& other) + : service_(&other.get_service()), + implementation_executor_(other.get_implementation_executor()) + { + service_->move_construct(implementation_, other.implementation_); + } + + // Perform a converting move-construction of an I/O object. + template + io_object_impl(io_object_impl&& other) + : service_(&boost::asio::use_service( + other.get_implementation_executor().context())), + implementation_executor_(other.get_implementation_executor()) + { + service_->converting_move_construct(implementation_, + other.get_service(), other.get_implementation()); + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // Destructor. + ~io_object_impl() + { + service_->destroy(implementation_); + } + +#if defined(BOOST_ASIO_HAS_MOVE) + // Move-assign an I/O object. + io_object_impl& operator=(io_object_impl&& other) + { + if (this != &other) + { + service_->move_assign(implementation_, + *other.service_, other.implementation_); + implementation_executor_.~implementation_executor_type(); + new (&implementation_executor_) implementation_executor_type( + std::move(other.implementation_executor_)); + service_ = other.service_; + } + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return implementation_executor_.inner_executor(); + } + + // Get the executor to be used when implementing asynchronous operations. + const implementation_executor_type& get_implementation_executor() + BOOST_ASIO_NOEXCEPT + { + return implementation_executor_; + } + + // Get the service associated with the I/O object. + service_type& get_service() + { + return *service_; + } + + // Get the service associated with the I/O object. + const service_type& get_service() const + { + return *service_; + } + + // Get the underlying implementation of the I/O object. + implementation_type& get_implementation() + { + return implementation_; + } + + // Get the underlying implementation of the I/O object. + const implementation_type& get_implementation() const + { + return implementation_; + } + +private: + // Disallow copying and copy assignment. + io_object_impl(const io_object_impl&); + io_object_impl& operator=(const io_object_impl&); + + // The service associated with the I/O object. + service_type* service_; + + // The underlying implementation of the I/O object. + implementation_type implementation_; + + // The associated executor. + implementation_executor_type implementation_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IO_OBJECT_IMPL_HPP diff --git a/boost/asio/detail/is_buffer_sequence.hpp b/boost/asio/detail/is_buffer_sequence.hpp new file mode 100644 index 0000000..c521032 --- /dev/null +++ b/boost/asio/detail/is_buffer_sequence.hpp @@ -0,0 +1,314 @@ +// +// detail/is_buffer_sequence.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP +#define BOOST_ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { + +class mutable_buffer; +class const_buffer; + +namespace detail { + +struct buffer_sequence_memfns_base +{ + void begin(); + void end(); + void size(); + void max_size(); + void capacity(); + void data(); + void prepare(); + void commit(); + void consume(); + void grow(); + void shrink(); +}; + +template +struct buffer_sequence_memfns_derived + : T, buffer_sequence_memfns_base +{ +}; + +template +struct buffer_sequence_memfns_check +{ +}; + +#if defined(BOOST_ASIO_HAS_DECLTYPE) + +template +char buffer_sequence_begin_helper(...); + +template +char (&buffer_sequence_begin_helper(T* t, + typename enable_if::value>::type*))[2]; + +#else // defined(BOOST_ASIO_HAS_DECLTYPE) + +template +char (&buffer_sequence_begin_helper(...))[2]; + +template +char buffer_sequence_begin_helper(T* t, + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::begin>*); + +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + +#if defined(BOOST_ASIO_HAS_DECLTYPE) + +template +char buffer_sequence_end_helper(...); + +template +char (&buffer_sequence_end_helper(T* t, + typename enable_if::value>::type*))[2]; + +#else // defined(BOOST_ASIO_HAS_DECLTYPE) + +template +char (&buffer_sequence_end_helper(...))[2]; + +template +char buffer_sequence_end_helper(T* t, + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::end>*); + +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + +template +char (&size_memfn_helper(...))[2]; + +template +char size_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::size>*); + +template +char (&max_size_memfn_helper(...))[2]; + +template +char max_size_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::max_size>*); + +template +char (&capacity_memfn_helper(...))[2]; + +template +char capacity_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::capacity>*); + +template +char (&data_memfn_helper(...))[2]; + +template +char data_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::data>*); + +template +char (&prepare_memfn_helper(...))[2]; + +template +char prepare_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::prepare>*); + +template +char (&commit_memfn_helper(...))[2]; + +template +char commit_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::commit>*); + +template +char (&consume_memfn_helper(...))[2]; + +template +char consume_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::consume>*); + +template +char (&grow_memfn_helper(...))[2]; + +template +char grow_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::grow>*); + +template +char (&shrink_memfn_helper(...))[2]; + +template +char shrink_memfn_helper( + buffer_sequence_memfns_check< + void (buffer_sequence_memfns_base::*)(), + &buffer_sequence_memfns_derived::shrink>*); + +template +char (&buffer_sequence_element_type_helper(...))[2]; + +#if defined(BOOST_ASIO_HAS_DECLTYPE) + +template +char buffer_sequence_element_type_helper(T* t, + typename enable_if::value>::type*); + +#else // defined(BOOST_ASIO_HAS_DECLTYPE) + +template +char buffer_sequence_element_type_helper( + typename T::const_iterator*, + typename enable_if::value>::type*); + +#endif // defined(BOOST_ASIO_HAS_DECLTYPE) + +template +char (&const_buffers_type_typedef_helper(...))[2]; + +template +char const_buffers_type_typedef_helper( + typename T::const_buffers_type*); + +template +char (&mutable_buffers_type_typedef_helper(...))[2]; + +template +char mutable_buffers_type_typedef_helper( + typename T::mutable_buffers_type*); + +template +struct is_buffer_sequence_class + : integral_constant(0, 0)) != 1 && + sizeof(buffer_sequence_end_helper(0, 0)) != 1 && + sizeof(buffer_sequence_element_type_helper(0, 0)) == 1> +{ +}; + +template +struct is_buffer_sequence + : conditional::value, + is_buffer_sequence_class, + false_type>::type +{ +}; + +template <> +struct is_buffer_sequence + : true_type +{ +}; + +template <> +struct is_buffer_sequence + : true_type +{ +}; + +template <> +struct is_buffer_sequence + : true_type +{ +}; + +template <> +struct is_buffer_sequence + : false_type +{ +}; + +template +struct is_dynamic_buffer_class_v1 + : integral_constant(0)) != 1 && + sizeof(max_size_memfn_helper(0)) != 1 && + sizeof(capacity_memfn_helper(0)) != 1 && + sizeof(data_memfn_helper(0)) != 1 && + sizeof(consume_memfn_helper(0)) != 1 && + sizeof(prepare_memfn_helper(0)) != 1 && + sizeof(commit_memfn_helper(0)) != 1 && + sizeof(const_buffers_type_typedef_helper(0)) == 1 && + sizeof(mutable_buffers_type_typedef_helper(0)) == 1> +{ +}; + +template +struct is_dynamic_buffer_v1 + : conditional::value, + is_dynamic_buffer_class_v1, + false_type>::type +{ +}; + +template +struct is_dynamic_buffer_class_v2 + : integral_constant(0)) != 1 && + sizeof(max_size_memfn_helper(0)) != 1 && + sizeof(capacity_memfn_helper(0)) != 1 && + sizeof(data_memfn_helper(0)) != 1 && + sizeof(consume_memfn_helper(0)) != 1 && + sizeof(grow_memfn_helper(0)) != 1 && + sizeof(shrink_memfn_helper(0)) != 1 && + sizeof(const_buffers_type_typedef_helper(0)) == 1 && + sizeof(mutable_buffers_type_typedef_helper(0)) == 1> +{ +}; + +template +struct is_dynamic_buffer_v2 + : conditional::value, + is_dynamic_buffer_class_v2, + false_type>::type +{ +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP diff --git a/boost/asio/detail/is_executor.hpp b/boost/asio/detail/is_executor.hpp new file mode 100644 index 0000000..ffcbb97 --- /dev/null +++ b/boost/asio/detail/is_executor.hpp @@ -0,0 +1,128 @@ +// +// detail/is_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_IS_EXECUTOR_HPP +#define BOOST_ASIO_DETAIL_IS_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct executor_memfns_base +{ + void context(); + void on_work_started(); + void on_work_finished(); + void dispatch(); + void post(); + void defer(); +}; + +template +struct executor_memfns_derived + : T, executor_memfns_base +{ +}; + +template +struct executor_memfns_check +{ +}; + +template +char (&context_memfn_helper(...))[2]; + +template +char context_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived::context>*); + +template +char (&on_work_started_memfn_helper(...))[2]; + +template +char on_work_started_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived::on_work_started>*); + +template +char (&on_work_finished_memfn_helper(...))[2]; + +template +char on_work_finished_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived::on_work_finished>*); + +template +char (&dispatch_memfn_helper(...))[2]; + +template +char dispatch_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived::dispatch>*); + +template +char (&post_memfn_helper(...))[2]; + +template +char post_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived::post>*); + +template +char (&defer_memfn_helper(...))[2]; + +template +char defer_memfn_helper( + executor_memfns_check< + void (executor_memfns_base::*)(), + &executor_memfns_derived::defer>*); + +template +struct is_executor_class + : integral_constant(0)) != 1 && + sizeof(on_work_started_memfn_helper(0)) != 1 && + sizeof(on_work_finished_memfn_helper(0)) != 1 && + sizeof(dispatch_memfn_helper(0)) != 1 && + sizeof(post_memfn_helper(0)) != 1 && + sizeof(defer_memfn_helper(0)) != 1> +{ +}; + +template +struct is_executor + : conditional::value, + is_executor_class, + false_type>::type +{ +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_IS_EXECUTOR_HPP diff --git a/boost/asio/detail/keyword_tss_ptr.hpp b/boost/asio/detail/keyword_tss_ptr.hpp new file mode 100644 index 0000000..b877004 --- /dev/null +++ b/boost/asio/detail/keyword_tss_ptr.hpp @@ -0,0 +1,72 @@ +// +// detail/keyword_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_KEYWORD_TSS_PTR_HPP +#define BOOST_ASIO_DETAIL_KEYWORD_TSS_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class keyword_tss_ptr + : private noncopyable +{ +public: + // Constructor. + keyword_tss_ptr() + { + } + + // Destructor. + ~keyword_tss_ptr() + { + } + + // Get the value. + operator T*() const + { + return value_; + } + + // Set the value. + void operator=(T* value) + { + value_ = value; + } + +private: + static BOOST_ASIO_THREAD_KEYWORD T* value_; +}; + +template +BOOST_ASIO_THREAD_KEYWORD T* keyword_tss_ptr::value_; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION) + +#endif // BOOST_ASIO_DETAIL_KEYWORD_TSS_PTR_HPP diff --git a/boost/asio/detail/kqueue_reactor.hpp b/boost/asio/detail/kqueue_reactor.hpp new file mode 100644 index 0000000..a5de8fa --- /dev/null +++ b/boost/asio/detail/kqueue_reactor.hpp @@ -0,0 +1,244 @@ +// +// detail/kqueue_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_KQUEUE_REACTOR_HPP +#define BOOST_ASIO_DETAIL_KQUEUE_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_KQUEUE) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Older versions of Mac OS X may not define EV_OOBAND. +#if !defined(EV_OOBAND) +# define EV_OOBAND EV_FLAG1 +#endif // !defined(EV_OOBAND) + +#include + +namespace boost { +namespace asio { +namespace detail { + +class scheduler; + +class kqueue_reactor + : public execution_context_service_base +{ +private: + // The mutex type used by this reactor. + typedef conditionally_enabled_mutex mutex; + +public: + enum op_types { read_op = 0, write_op = 1, + connect_op = 1, except_op = 2, max_ops = 3 }; + + // Per-descriptor queues. + struct descriptor_state + { + descriptor_state(bool locking) : mutex_(locking) {} + + friend class kqueue_reactor; + friend class object_pool_access; + + descriptor_state* next_; + descriptor_state* prev_; + + mutex mutex_; + int descriptor_; + int num_kevents_; // 1 == read only, 2 == read and write + op_queue op_queue_[max_ops]; + bool shutdown_; + }; + + // Per-descriptor data. + typedef descriptor_state* per_descriptor_data; + + // Constructor. + BOOST_ASIO_DECL kqueue_reactor(boost::asio::execution_context& ctx); + + // Destructor. + BOOST_ASIO_DECL ~kqueue_reactor(); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown(); + + // Recreate internal descriptors following a fork. + BOOST_ASIO_DECL void notify_fork( + boost::asio::execution_context::fork_event fork_ev); + + // Initialise the task. + BOOST_ASIO_DECL void init_task(); + + // Register a socket with the reactor. Returns 0 on success, system error + // code on failure. + BOOST_ASIO_DECL int register_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data); + + // Register a descriptor with an associated single operation. Returns 0 on + // success, system error code on failure. + BOOST_ASIO_DECL int register_internal_descriptor( + int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op); + + // Move descriptor registration from one descriptor_data object to another. + BOOST_ASIO_DECL void move_descriptor(socket_type descriptor, + per_descriptor_data& target_descriptor_data, + per_descriptor_data& source_descriptor_data); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op, bool is_continuation) + { + scheduler_.post_immediate_completion(op, is_continuation); + } + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op, + bool is_continuation, bool allow_speculative); + + // Cancel all operations associated with the given descriptor. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + BOOST_ASIO_DECL void cancel_ops(socket_type descriptor, + per_descriptor_data& descriptor_data); + + // Cancel any operations that are running against the descriptor and remove + // its registration from the reactor. The reactor resources associated with + // the descriptor must be released by calling cleanup_descriptor_data. + BOOST_ASIO_DECL void deregister_descriptor(socket_type descriptor, + per_descriptor_data& descriptor_data, bool closing); + + // Remove the descriptor's registration from the reactor. The reactor + // resources associated with the descriptor must be released by calling + // cleanup_descriptor_data. + BOOST_ASIO_DECL void deregister_internal_descriptor( + socket_type descriptor, per_descriptor_data& descriptor_data); + + // Perform any post-deregistration cleanup tasks associated with the + // descriptor data. + BOOST_ASIO_DECL void cleanup_descriptor_data( + per_descriptor_data& descriptor_data); + + // Add a new timer queue to the reactor. + template + void add_timer_queue(timer_queue& queue); + + // Remove a timer queue from the reactor. + template + void remove_timer_queue(timer_queue& queue); + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template + void schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op); + + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. + template + std::size_t cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled = (std::numeric_limits::max)()); + + // Move the timer operations associated with the given timer. + template + void move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& target, + typename timer_queue::per_timer_data& source); + + // Run the kqueue loop. + BOOST_ASIO_DECL void run(long usec, op_queue& ops); + + // Interrupt the kqueue loop. + BOOST_ASIO_DECL void interrupt(); + +private: + // Create the kqueue file descriptor. Throws an exception if the descriptor + // cannot be created. + BOOST_ASIO_DECL static int do_kqueue_create(); + + // Allocate a new descriptor state object. + BOOST_ASIO_DECL descriptor_state* allocate_descriptor_state(); + + // Free an existing descriptor state object. + BOOST_ASIO_DECL void free_descriptor_state(descriptor_state* s); + + // Helper function to add a new timer queue. + BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // Get the timeout value for the kevent call. + BOOST_ASIO_DECL timespec* get_timeout(long usec, timespec& ts); + + // The scheduler used to post completions. + scheduler& scheduler_; + + // Mutex to protect access to internal data. + mutex mutex_; + + // The kqueue file descriptor. + int kqueue_fd_; + + // The interrupter is used to break a blocking kevent call. + select_interrupter interrupter_; + + // The timer queues. + timer_queue_set timer_queues_; + + // Whether the service has been shut down. + bool shutdown_; + + // Mutex to protect access to the registered descriptors. + mutex registered_descriptors_mutex_; + + // Keep track of all registered descriptors. + object_pool registered_descriptors_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_KQUEUE) + +#endif // BOOST_ASIO_DETAIL_KQUEUE_REACTOR_HPP diff --git a/boost/asio/detail/limits.hpp b/boost/asio/detail/limits.hpp new file mode 100644 index 0000000..036c599 --- /dev/null +++ b/boost/asio/detail/limits.hpp @@ -0,0 +1,26 @@ +// +// detail/limits.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2011 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_LIMITS_HPP +#define BOOST_ASIO_DETAIL_LIMITS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_BOOST_LIMITS) +# include +#else // defined(BOOST_ASIO_HAS_BOOST_LIMITS) +# include +#endif // defined(BOOST_ASIO_HAS_BOOST_LIMITS) + +#endif // BOOST_ASIO_DETAIL_LIMITS_HPP diff --git a/boost/asio/detail/macos_fenced_block.hpp b/boost/asio/detail/macos_fenced_block.hpp new file mode 100644 index 0000000..639fc65 --- /dev/null +++ b/boost/asio/detail/macos_fenced_block.hpp @@ -0,0 +1,64 @@ +// +// detail/macos_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(__MACH__) && defined(__APPLE__) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class macos_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit macos_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit macos_fenced_block(full_t) + { + OSMemoryBarrier(); + } + + // Destructor. + ~macos_fenced_block() + { + OSMemoryBarrier(); + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(__MACH__) && defined(__APPLE__) + +#endif // BOOST_ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP diff --git a/boost/asio/detail/memory.hpp b/boost/asio/detail/memory.hpp new file mode 100644 index 0000000..a18b4d9 --- /dev/null +++ b/boost/asio/detail/memory.hpp @@ -0,0 +1,72 @@ +// +// detail/memory.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_MEMORY_HPP +#define BOOST_ASIO_DETAIL_MEMORY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if !defined(BOOST_ASIO_HAS_STD_SHARED_PTR) +# include +# include +#endif // !defined(BOOST_ASIO_HAS_STD_SHARED_PTR) + +#if !defined(BOOST_ASIO_HAS_STD_ADDRESSOF) +# include +#endif // !defined(BOOST_ASIO_HAS_STD_ADDRESSOF) + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_HAS_STD_SHARED_PTR) +using std::shared_ptr; +using std::weak_ptr; +#else // defined(BOOST_ASIO_HAS_STD_SHARED_PTR) +using boost::shared_ptr; +using boost::weak_ptr; +#endif // defined(BOOST_ASIO_HAS_STD_SHARED_PTR) + +#if defined(BOOST_ASIO_HAS_STD_ADDRESSOF) +using std::addressof; +#else // defined(BOOST_ASIO_HAS_STD_ADDRESSOF) +using boost::addressof; +#endif // defined(BOOST_ASIO_HAS_STD_ADDRESSOF) + +} // namespace detail + +#if defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS) +using std::allocator_arg_t; +# define BOOST_ASIO_USES_ALLOCATOR(t) \ + namespace std { \ + template \ + struct uses_allocator : true_type {}; \ + } \ + /**/ +# define BOOST_ASIO_REBIND_ALLOC(alloc, t) \ + typename std::allocator_traits::template rebind_alloc + /**/ +#else // defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS) +struct allocator_arg_t {}; +# define BOOST_ASIO_USES_ALLOCATOR(t) +# define BOOST_ASIO_REBIND_ALLOC(alloc, t) \ + typename alloc::template rebind::other + /**/ +#endif // defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS) + +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_MEMORY_HPP diff --git a/boost/asio/detail/mutex.hpp b/boost/asio/detail/mutex.hpp new file mode 100644 index 0000000..e5e7526 --- /dev/null +++ b/boost/asio/detail/mutex.hpp @@ -0,0 +1,50 @@ +// +// detail/mutex.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_MUTEX_HPP +#define BOOST_ASIO_DETAIL_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_THREADS) +# include +#elif defined(BOOST_ASIO_WINDOWS) +# include +#elif defined(BOOST_ASIO_HAS_PTHREADS) +# include +#elif defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) +# include +#else +# error Only Windows, POSIX and std::mutex are supported! +#endif + +namespace boost { +namespace asio { +namespace detail { + +#if !defined(BOOST_ASIO_HAS_THREADS) +typedef null_mutex mutex; +#elif defined(BOOST_ASIO_WINDOWS) +typedef win_mutex mutex; +#elif defined(BOOST_ASIO_HAS_PTHREADS) +typedef posix_mutex mutex; +#elif defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) +typedef std_mutex mutex; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_MUTEX_HPP diff --git a/boost/asio/detail/non_const_lvalue.hpp b/boost/asio/detail/non_const_lvalue.hpp new file mode 100644 index 0000000..28e2a52 --- /dev/null +++ b/boost/asio/detail/non_const_lvalue.hpp @@ -0,0 +1,56 @@ +// +// detail/non_const_lvalue.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_NON_CONST_LVALUE_HPP +#define BOOST_ASIO_DETAIL_NON_CONST_LVALUE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +struct non_const_lvalue +{ +#if defined(BOOST_ASIO_HAS_MOVE) + explicit non_const_lvalue(T& t) + : value(static_cast::type>::value, + typename decay::type&, T&&>::type>(t)) + { + } + + typename conditional::type>::value, + typename decay::type&, typename decay::type>::type value; +#else // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + explicit non_const_lvalue(const typename decay::type& t) + : value(t) + { + } + + typename decay::type value; +#endif // defined(BOOST_ASIO_HAS_MOVE) +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_NON_CONST_LVALUE_HPP diff --git a/boost/asio/detail/noncopyable.hpp b/boost/asio/detail/noncopyable.hpp new file mode 100644 index 0000000..77cc71c --- /dev/null +++ b/boost/asio/detail/noncopyable.hpp @@ -0,0 +1,45 @@ +// +// detail/noncopyable.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_NONCOPYABLE_HPP +#define BOOST_ASIO_DETAIL_NONCOPYABLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class noncopyable +{ +protected: + noncopyable() {} + ~noncopyable() {} +private: + noncopyable(const noncopyable&); + const noncopyable& operator=(const noncopyable&); +}; + +} // namespace detail + +using boost::asio::detail::noncopyable; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_NONCOPYABLE_HPP diff --git a/boost/asio/detail/null_event.hpp b/boost/asio/detail/null_event.hpp new file mode 100644 index 0000000..8ffc17c --- /dev/null +++ b/boost/asio/detail/null_event.hpp @@ -0,0 +1,102 @@ +// +// detail/null_event.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_NULL_EVENT_HPP +#define BOOST_ASIO_DETAIL_NULL_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class null_event + : private noncopyable +{ +public: + // Constructor. + null_event() + { + } + + // Destructor. + ~null_event() + { + } + + // Signal the event. (Retained for backward compatibility.) + template + void signal(Lock&) + { + } + + // Signal all waiters. + template + void signal_all(Lock&) + { + } + + // Unlock the mutex and signal one waiter. + template + void unlock_and_signal_one(Lock&) + { + } + + // If there's a waiter, unlock the mutex and signal it. + template + bool maybe_unlock_and_signal_one(Lock&) + { + return false; + } + + // Reset the event. + template + void clear(Lock&) + { + } + + // Wait for the event to become signalled. + template + void wait(Lock&) + { + do_wait(); + } + + // Timed wait for the event to become signalled. + template + bool wait_for_usec(Lock&, long usec) + { + do_wait_for_usec(usec); + return true; + } + +private: + BOOST_ASIO_DECL static void do_wait(); + BOOST_ASIO_DECL static void do_wait_for_usec(long usec); +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_DETAIL_NULL_EVENT_HPP diff --git a/boost/asio/detail/null_fenced_block.hpp b/boost/asio/detail/null_fenced_block.hpp new file mode 100644 index 0000000..8fadff6 --- /dev/null +++ b/boost/asio/detail/null_fenced_block.hpp @@ -0,0 +1,49 @@ +// +// detail/null_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_NULL_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_NULL_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class null_fenced_block + : private noncopyable +{ +public: + enum half_or_full_t { half, full }; + + // Constructor. + explicit null_fenced_block(half_or_full_t) + { + } + + // Destructor. + ~null_fenced_block() + { + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_NULL_FENCED_BLOCK_HPP diff --git a/boost/asio/detail/null_global.hpp b/boost/asio/detail/null_global.hpp new file mode 100644 index 0000000..12303c2 --- /dev/null +++ b/boost/asio/detail/null_global.hpp @@ -0,0 +1,61 @@ +// +// detail/null_global.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_NULL_GLOBAL_HPP +#define BOOST_ASIO_DETAIL_NULL_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +struct null_global_impl +{ + null_global_impl() + : ptr_(0) + { + } + + // Destructor automatically cleans up the global. + ~null_global_impl() + { + delete ptr_; + } + + static null_global_impl instance_; + T* ptr_; +}; + +template +null_global_impl null_global_impl::instance_; + +template +T& null_global() +{ + if (null_global_impl::instance_.ptr_ == 0) + null_global_impl::instance_.ptr_ = new T; + return *null_global_impl::instance_.ptr_; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_NULL_GLOBAL_HPP diff --git a/boost/asio/detail/null_mutex.hpp b/boost/asio/detail/null_mutex.hpp new file mode 100644 index 0000000..7373675 --- /dev/null +++ b/boost/asio/detail/null_mutex.hpp @@ -0,0 +1,66 @@ +// +// detail/null_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_NULL_MUTEX_HPP +#define BOOST_ASIO_DETAIL_NULL_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_THREADS) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class null_mutex + : private noncopyable +{ +public: + typedef boost::asio::detail::scoped_lock scoped_lock; + + // Constructor. + null_mutex() + { + } + + // Destructor. + ~null_mutex() + { + } + + // Lock the mutex. + void lock() + { + } + + // Unlock the mutex. + void unlock() + { + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_HAS_THREADS) + +#endif // BOOST_ASIO_DETAIL_NULL_MUTEX_HPP diff --git a/boost/asio/detail/null_reactor.hpp b/boost/asio/detail/null_reactor.hpp new file mode 100644 index 0000000..4552e1c --- /dev/null +++ b/boost/asio/detail/null_reactor.hpp @@ -0,0 +1,70 @@ +// +// detail/null_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_NULL_REACTOR_HPP +#define BOOST_ASIO_DETAIL_NULL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) || defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class null_reactor + : public execution_context_service_base +{ +public: + // Constructor. + null_reactor(boost::asio::execution_context& ctx) + : execution_context_service_base(ctx) + { + } + + // Destructor. + ~null_reactor() + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + } + + // No-op because should never be called. + void run(long /*usec*/, op_queue& /*ops*/) + { + } + + // No-op. + void interrupt() + { + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) || defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#endif // BOOST_ASIO_DETAIL_NULL_REACTOR_HPP diff --git a/boost/asio/detail/null_signal_blocker.hpp b/boost/asio/detail/null_signal_blocker.hpp new file mode 100644 index 0000000..74f5b75 --- /dev/null +++ b/boost/asio/detail/null_signal_blocker.hpp @@ -0,0 +1,71 @@ +// +// detail/null_signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP +#define BOOST_ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_THREADS) \ + || defined(BOOST_ASIO_WINDOWS) \ + || defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class null_signal_blocker + : private noncopyable +{ +public: + // Constructor blocks all signals for the calling thread. + null_signal_blocker() + { + } + + // Destructor restores the previous signal mask. + ~null_signal_blocker() + { + } + + // Block all signals for the calling thread. + void block() + { + } + + // Restore the previous signal mask. + void unblock() + { + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_HAS_THREADS) + // || defined(BOOST_ASIO_WINDOWS) + // || defined(BOOST_ASIO_WINDOWS_RUNTIME) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + +#endif // BOOST_ASIO_DETAIL_NULL_SIGNAL_BLOCKER_HPP diff --git a/boost/asio/detail/null_socket_service.hpp b/boost/asio/detail/null_socket_service.hpp new file mode 100644 index 0000000..552d993 --- /dev/null +++ b/boost/asio/detail/null_socket_service.hpp @@ -0,0 +1,521 @@ +// +// detail/null_socket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_NULL_SOCKET_SERVICE_HPP +#define BOOST_ASIO_DETAIL_NULL_SOCKET_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class null_socket_service : + public execution_context_service_base > +{ +public: + // The protocol type. + typedef Protocol protocol_type; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The native type of a socket. + typedef int native_handle_type; + + // The implementation type of the socket. + struct implementation_type + { + }; + + // Constructor. + null_socket_service(execution_context& context) + : execution_context_service_base >(context) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + } + + // Construct a new socket implementation. + void construct(implementation_type&) + { + } + + // Move-construct a new socket implementation. + void move_construct(implementation_type&, implementation_type&) + { + } + + // Move-assign from another socket implementation. + void move_assign(implementation_type&, + null_socket_service&, implementation_type&) + { + } + + // Move-construct a new socket implementation from another protocol type. + template + void converting_move_construct(implementation_type&, + null_socket_service&, + typename null_socket_service::implementation_type&) + { + } + + // Destroy a socket implementation. + void destroy(implementation_type&) + { + } + + // Open a new socket implementation. + boost::system::error_code open(implementation_type&, + const protocol_type&, boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return ec; + } + + // Assign a native socket to a socket implementation. + boost::system::error_code assign(implementation_type&, const protocol_type&, + const native_handle_type&, boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return ec; + } + + // Determine whether the socket is open. + bool is_open(const implementation_type&) const + { + return false; + } + + // Destroy a socket implementation. + boost::system::error_code close(implementation_type&, + boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return ec; + } + + // Release ownership of the socket. + native_handle_type release(implementation_type&, + boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return 0; + } + + // Get the native socket representation. + native_handle_type native_handle(implementation_type&) + { + return 0; + } + + // Cancel all operations associated with the socket. + boost::system::error_code cancel(implementation_type&, + boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return ec; + } + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const implementation_type&, + boost::system::error_code& ec) const + { + ec = boost::asio::error::operation_not_supported; + return false; + } + + // Determine the number of bytes available for reading. + std::size_t available(const implementation_type&, + boost::system::error_code& ec) const + { + ec = boost::asio::error::operation_not_supported; + return 0; + } + + // Place the socket into the state where it will listen for new connections. + boost::system::error_code listen(implementation_type&, + int, boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return ec; + } + + // Perform an IO control command on the socket. + template + boost::system::error_code io_control(implementation_type&, + IO_Control_Command&, boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return ec; + } + + // Gets the non-blocking mode of the socket. + bool non_blocking(const implementation_type&) const + { + return false; + } + + // Sets the non-blocking mode of the socket. + boost::system::error_code non_blocking(implementation_type&, + bool, boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return ec; + } + + // Gets the non-blocking mode of the native socket implementation. + bool native_non_blocking(const implementation_type&) const + { + return false; + } + + // Sets the non-blocking mode of the native socket implementation. + boost::system::error_code native_non_blocking(implementation_type&, + bool, boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return ec; + } + + // Disable sends or receives on the socket. + boost::system::error_code shutdown(implementation_type&, + socket_base::shutdown_type, boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return ec; + } + + // Bind the socket to the specified local endpoint. + boost::system::error_code bind(implementation_type&, + const endpoint_type&, boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return ec; + } + + // Set a socket option. + template + boost::system::error_code set_option(implementation_type&, + const Option&, boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return ec; + } + + // Set a socket option. + template + boost::system::error_code get_option(const implementation_type&, + Option&, boost::system::error_code& ec) const + { + ec = boost::asio::error::operation_not_supported; + return ec; + } + + // Get the local endpoint. + endpoint_type local_endpoint(const implementation_type&, + boost::system::error_code& ec) const + { + ec = boost::asio::error::operation_not_supported; + return endpoint_type(); + } + + // Get the remote endpoint. + endpoint_type remote_endpoint(const implementation_type&, + boost::system::error_code& ec) const + { + ec = boost::asio::error::operation_not_supported; + return endpoint_type(); + } + + // Send the given data to the peer. + template + std::size_t send(implementation_type&, const ConstBufferSequence&, + socket_base::message_flags, boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return 0; + } + + // Wait until data can be sent without blocking. + std::size_t send(implementation_type&, const null_buffers&, + socket_base::message_flags, boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send(implementation_type&, const ConstBufferSequence&, + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) + { + boost::system::error_code ec = boost::asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + boost::asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Start an asynchronous wait until data can be sent without blocking. + template + void async_send(implementation_type&, const null_buffers&, + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) + { + boost::system::error_code ec = boost::asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + boost::asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Receive some data from the peer. Returns the number of bytes received. + template + std::size_t receive(implementation_type&, const MutableBufferSequence&, + socket_base::message_flags, boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return 0; + } + + // Wait until data can be received without blocking. + std::size_t receive(implementation_type&, const null_buffers&, + socket_base::message_flags, boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template + void async_receive(implementation_type&, const MutableBufferSequence&, + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) + { + boost::system::error_code ec = boost::asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + boost::asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Wait until data can be received without blocking. + template + void async_receive(implementation_type&, const null_buffers&, + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) + { + boost::system::error_code ec = boost::asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + boost::asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Receive some data with associated flags. Returns the number of bytes + // received. + template + std::size_t receive_with_flags(implementation_type&, + const MutableBufferSequence&, socket_base::message_flags, + socket_base::message_flags&, boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return 0; + } + + // Wait until data can be received without blocking. + std::size_t receive_with_flags(implementation_type&, + const null_buffers&, socket_base::message_flags, + socket_base::message_flags&, boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template + void async_receive_with_flags(implementation_type&, + const MutableBufferSequence&, socket_base::message_flags, + socket_base::message_flags&, Handler& handler, const IoExecutor& io_ex) + { + boost::system::error_code ec = boost::asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + boost::asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Wait until data can be received without blocking. + template + void async_receive_with_flags(implementation_type&, const null_buffers&, + socket_base::message_flags, socket_base::message_flags&, + Handler& handler, const IoExecutor& io_ex) + { + boost::system::error_code ec = boost::asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + boost::asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Send a datagram to the specified endpoint. Returns the number of bytes + // sent. + template + std::size_t send_to(implementation_type&, const ConstBufferSequence&, + const endpoint_type&, socket_base::message_flags, + boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return 0; + } + + // Wait until data can be sent without blocking. + std::size_t send_to(implementation_type&, const null_buffers&, + const endpoint_type&, socket_base::message_flags, + boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send_to(implementation_type&, const ConstBufferSequence&, + const endpoint_type&, socket_base::message_flags, + Handler& handler) + { + boost::system::error_code ec = boost::asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + boost::asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Start an asynchronous wait until data can be sent without blocking. + template + void async_send_to(implementation_type&, const null_buffers&, + const endpoint_type&, socket_base::message_flags, + Handler& handler, const IoExecutor& io_ex) + { + boost::system::error_code ec = boost::asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + boost::asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Receive a datagram with the endpoint of the sender. Returns the number of + // bytes received. + template + std::size_t receive_from(implementation_type&, const MutableBufferSequence&, + endpoint_type&, socket_base::message_flags, + boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return 0; + } + + // Wait until data can be received without blocking. + std::size_t receive_from(implementation_type&, const null_buffers&, + endpoint_type&, socket_base::message_flags, + boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received and + // the sender_endpoint object must both be valid for the lifetime of the + // asynchronous operation. + template + void async_receive_from(implementation_type&, const MutableBufferSequence&, + endpoint_type&, socket_base::message_flags, Handler& handler, + const IoExecutor& io_ex) + { + boost::system::error_code ec = boost::asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + boost::asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Wait until data can be received without blocking. + template + void async_receive_from(implementation_type&, const null_buffers&, + endpoint_type&, socket_base::message_flags, Handler& handler, + const IoExecutor& io_ex) + { + boost::system::error_code ec = boost::asio::error::operation_not_supported; + const std::size_t bytes_transferred = 0; + boost::asio::post(io_ex, detail::bind_handler( + handler, ec, bytes_transferred)); + } + + // Accept a new connection. + template + boost::system::error_code accept(implementation_type&, + Socket&, endpoint_type*, boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return ec; + } + + // Start an asynchronous accept. The peer and peer_endpoint objects + // must be valid until the accept's handler is invoked. + template + void async_accept(implementation_type&, Socket&, endpoint_type*, + Handler& handler, const IoExecutor& io_ex) + { + boost::system::error_code ec = boost::asio::error::operation_not_supported; + boost::asio::post(io_ex, detail::bind_handler(handler, ec)); + } + + // Connect the socket to the specified endpoint. + boost::system::error_code connect(implementation_type&, + const endpoint_type&, boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return ec; + } + + // Start an asynchronous connect. + template + void async_connect(implementation_type&, const endpoint_type&, + Handler& handler, const IoExecutor& io_ex) + { + boost::system::error_code ec = boost::asio::error::operation_not_supported; + boost::asio::post(io_ex, detail::bind_handler(handler, ec)); + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#endif // BOOST_ASIO_DETAIL_NULL_SOCKET_SERVICE_HPP diff --git a/boost/asio/detail/null_static_mutex.hpp b/boost/asio/detail/null_static_mutex.hpp new file mode 100644 index 0000000..f8f9ab4 --- /dev/null +++ b/boost/asio/detail/null_static_mutex.hpp @@ -0,0 +1,62 @@ +// +// detail/null_static_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_NULL_STATIC_MUTEX_HPP +#define BOOST_ASIO_DETAIL_NULL_STATIC_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_THREADS) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct null_static_mutex +{ + typedef boost::asio::detail::scoped_lock scoped_lock; + + // Initialise the mutex. + void init() + { + } + + // Lock the mutex. + void lock() + { + } + + // Unlock the mutex. + void unlock() + { + } + + int unused_; +}; + +#define BOOST_ASIO_NULL_STATIC_MUTEX_INIT { 0 } + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_HAS_THREADS) + +#endif // BOOST_ASIO_DETAIL_NULL_STATIC_MUTEX_HPP diff --git a/boost/asio/detail/null_thread.hpp b/boost/asio/detail/null_thread.hpp new file mode 100644 index 0000000..bd1360c --- /dev/null +++ b/boost/asio/detail/null_thread.hpp @@ -0,0 +1,69 @@ +// +// detail/null_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_NULL_THREAD_HPP +#define BOOST_ASIO_DETAIL_NULL_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_THREADS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class null_thread + : private noncopyable +{ +public: + // Constructor. + template + null_thread(Function, unsigned int = 0) + { + boost::asio::detail::throw_error( + boost::asio::error::operation_not_supported, "thread"); + } + + // Destructor. + ~null_thread() + { + } + + // Wait for the thread to exit. + void join() + { + } + + // Get number of CPUs. + static std::size_t hardware_concurrency() + { + return 1; + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_HAS_THREADS) + +#endif // BOOST_ASIO_DETAIL_NULL_THREAD_HPP diff --git a/boost/asio/detail/null_tss_ptr.hpp b/boost/asio/detail/null_tss_ptr.hpp new file mode 100644 index 0000000..eacf4ff --- /dev/null +++ b/boost/asio/detail/null_tss_ptr.hpp @@ -0,0 +1,70 @@ +// +// detail/null_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_NULL_TSS_PTR_HPP +#define BOOST_ASIO_DETAIL_NULL_TSS_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_THREADS) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class null_tss_ptr + : private noncopyable +{ +public: + // Constructor. + null_tss_ptr() + : value_(0) + { + } + + // Destructor. + ~null_tss_ptr() + { + } + + // Get the value. + operator T*() const + { + return value_; + } + + // Set the value. + void operator=(T* value) + { + value_ = value; + } + +private: + T* value_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_HAS_THREADS) + +#endif // BOOST_ASIO_DETAIL_NULL_TSS_PTR_HPP diff --git a/boost/asio/detail/object_pool.hpp b/boost/asio/detail/object_pool.hpp new file mode 100644 index 0000000..0eadf7a --- /dev/null +++ b/boost/asio/detail/object_pool.hpp @@ -0,0 +1,173 @@ +// +// detail/object_pool.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_OBJECT_POOL_HPP +#define BOOST_ASIO_DETAIL_OBJECT_POOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class object_pool; + +class object_pool_access +{ +public: + template + static Object* create() + { + return new Object; + } + + template + static Object* create(Arg arg) + { + return new Object(arg); + } + + template + static void destroy(Object* o) + { + delete o; + } + + template + static Object*& next(Object* o) + { + return o->next_; + } + + template + static Object*& prev(Object* o) + { + return o->prev_; + } +}; + +template +class object_pool + : private noncopyable +{ +public: + // Constructor. + object_pool() + : live_list_(0), + free_list_(0) + { + } + + // Destructor destroys all objects. + ~object_pool() + { + destroy_list(live_list_); + destroy_list(free_list_); + } + + // Get the object at the start of the live list. + Object* first() + { + return live_list_; + } + + // Allocate a new object. + Object* alloc() + { + Object* o = free_list_; + if (o) + free_list_ = object_pool_access::next(free_list_); + else + o = object_pool_access::create(); + + object_pool_access::next(o) = live_list_; + object_pool_access::prev(o) = 0; + if (live_list_) + object_pool_access::prev(live_list_) = o; + live_list_ = o; + + return o; + } + + // Allocate a new object with an argument. + template + Object* alloc(Arg arg) + { + Object* o = free_list_; + if (o) + free_list_ = object_pool_access::next(free_list_); + else + o = object_pool_access::create(arg); + + object_pool_access::next(o) = live_list_; + object_pool_access::prev(o) = 0; + if (live_list_) + object_pool_access::prev(live_list_) = o; + live_list_ = o; + + return o; + } + + // Free an object. Moves it to the free list. No destructors are run. + void free(Object* o) + { + if (live_list_ == o) + live_list_ = object_pool_access::next(o); + + if (object_pool_access::prev(o)) + { + object_pool_access::next(object_pool_access::prev(o)) + = object_pool_access::next(o); + } + + if (object_pool_access::next(o)) + { + object_pool_access::prev(object_pool_access::next(o)) + = object_pool_access::prev(o); + } + + object_pool_access::next(o) = free_list_; + object_pool_access::prev(o) = 0; + free_list_ = o; + } + +private: + // Helper function to destroy all elements in a list. + void destroy_list(Object* list) + { + while (list) + { + Object* o = list; + list = object_pool_access::next(o); + object_pool_access::destroy(o); + } + } + + // The list of live objects. + Object* live_list_; + + // The free list. + Object* free_list_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_OBJECT_POOL_HPP diff --git a/boost/asio/detail/old_win_sdk_compat.hpp b/boost/asio/detail/old_win_sdk_compat.hpp new file mode 100644 index 0000000..f5cb9d7 --- /dev/null +++ b/boost/asio/detail/old_win_sdk_compat.hpp @@ -0,0 +1,216 @@ +// +// detail/old_win_sdk_compat.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP +#define BOOST_ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +// Guess whether we are building against on old Platform SDK. +#if !defined(IN6ADDR_ANY_INIT) +#define BOOST_ASIO_HAS_OLD_WIN_SDK 1 +#endif // !defined(IN6ADDR_ANY_INIT) + +#if defined(BOOST_ASIO_HAS_OLD_WIN_SDK) + +// Emulation of types that are missing from old Platform SDKs. +// +// N.B. this emulation is also used if building for a Windows 2000 target with +// a recent (i.e. Vista or later) SDK, as the SDK does not provide IPv6 support +// in that case. + +#include + +namespace boost { +namespace asio { +namespace detail { + +enum +{ + sockaddr_storage_maxsize = 128, // Maximum size. + sockaddr_storage_alignsize = (sizeof(__int64)), // Desired alignment. + sockaddr_storage_pad1size = (sockaddr_storage_alignsize - sizeof(short)), + sockaddr_storage_pad2size = (sockaddr_storage_maxsize - + (sizeof(short) + sockaddr_storage_pad1size + sockaddr_storage_alignsize)) +}; + +struct sockaddr_storage_emulation +{ + short ss_family; + char __ss_pad1[sockaddr_storage_pad1size]; + __int64 __ss_align; + char __ss_pad2[sockaddr_storage_pad2size]; +}; + +struct in6_addr_emulation +{ + union + { + u_char Byte[16]; + u_short Word[8]; + } u; +}; + +#if !defined(s6_addr) +# define _S6_un u +# define _S6_u8 Byte +# define s6_addr _S6_un._S6_u8 +#endif // !defined(s6_addr) + +struct sockaddr_in6_emulation +{ + short sin6_family; + u_short sin6_port; + u_long sin6_flowinfo; + in6_addr_emulation sin6_addr; + u_long sin6_scope_id; +}; + +struct ipv6_mreq_emulation +{ + in6_addr_emulation ipv6mr_multiaddr; + unsigned int ipv6mr_interface; +}; + +struct addrinfo_emulation +{ + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char* ai_canonname; + sockaddr* ai_addr; + addrinfo_emulation* ai_next; +}; + +#if !defined(AI_PASSIVE) +# define AI_PASSIVE 0x1 +#endif + +#if !defined(AI_CANONNAME) +# define AI_CANONNAME 0x2 +#endif + +#if !defined(AI_NUMERICHOST) +# define AI_NUMERICHOST 0x4 +#endif + +#if !defined(EAI_AGAIN) +# define EAI_AGAIN WSATRY_AGAIN +#endif + +#if !defined(EAI_BADFLAGS) +# define EAI_BADFLAGS WSAEINVAL +#endif + +#if !defined(EAI_FAIL) +# define EAI_FAIL WSANO_RECOVERY +#endif + +#if !defined(EAI_FAMILY) +# define EAI_FAMILY WSAEAFNOSUPPORT +#endif + +#if !defined(EAI_MEMORY) +# define EAI_MEMORY WSA_NOT_ENOUGH_MEMORY +#endif + +#if !defined(EAI_NODATA) +# define EAI_NODATA WSANO_DATA +#endif + +#if !defined(EAI_NONAME) +# define EAI_NONAME WSAHOST_NOT_FOUND +#endif + +#if !defined(EAI_SERVICE) +# define EAI_SERVICE WSATYPE_NOT_FOUND +#endif + +#if !defined(EAI_SOCKTYPE) +# define EAI_SOCKTYPE WSAESOCKTNOSUPPORT +#endif + +#if !defined(NI_NOFQDN) +# define NI_NOFQDN 0x01 +#endif + +#if !defined(NI_NUMERICHOST) +# define NI_NUMERICHOST 0x02 +#endif + +#if !defined(NI_NAMEREQD) +# define NI_NAMEREQD 0x04 +#endif + +#if !defined(NI_NUMERICSERV) +# define NI_NUMERICSERV 0x08 +#endif + +#if !defined(NI_DGRAM) +# define NI_DGRAM 0x10 +#endif + +#if !defined(IPPROTO_IPV6) +# define IPPROTO_IPV6 41 +#endif + +#if !defined(IPV6_UNICAST_HOPS) +# define IPV6_UNICAST_HOPS 4 +#endif + +#if !defined(IPV6_MULTICAST_IF) +# define IPV6_MULTICAST_IF 9 +#endif + +#if !defined(IPV6_MULTICAST_HOPS) +# define IPV6_MULTICAST_HOPS 10 +#endif + +#if !defined(IPV6_MULTICAST_LOOP) +# define IPV6_MULTICAST_LOOP 11 +#endif + +#if !defined(IPV6_JOIN_GROUP) +# define IPV6_JOIN_GROUP 12 +#endif + +#if !defined(IPV6_LEAVE_GROUP) +# define IPV6_LEAVE_GROUP 13 +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_OLD_WIN_SDK) + +// Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY. +#if !defined(IPV6_V6ONLY) +# define IPV6_V6ONLY 27 +#endif + +// Some SDKs (e.g. Windows CE) don't define IPPROTO_ICMPV6. +#if !defined(IPPROTO_ICMPV6) +# define IPPROTO_ICMPV6 58 +#endif + +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_OLD_WIN_SDK_COMPAT_HPP diff --git a/boost/asio/detail/op_queue.hpp b/boost/asio/detail/op_queue.hpp new file mode 100644 index 0000000..b2cd608 --- /dev/null +++ b/boost/asio/detail/op_queue.hpp @@ -0,0 +1,164 @@ +// +// detail/op_queue.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_OP_QUEUE_HPP +#define BOOST_ASIO_DETAIL_OP_QUEUE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class op_queue; + +class op_queue_access +{ +public: + template + static Operation* next(Operation* o) + { + return static_cast(o->next_); + } + + template + static void next(Operation1*& o1, Operation2* o2) + { + o1->next_ = o2; + } + + template + static void destroy(Operation* o) + { + o->destroy(); + } + + template + static Operation*& front(op_queue& q) + { + return q.front_; + } + + template + static Operation*& back(op_queue& q) + { + return q.back_; + } +}; + +template +class op_queue + : private noncopyable +{ +public: + // Constructor. + op_queue() + : front_(0), + back_(0) + { + } + + // Destructor destroys all operations. + ~op_queue() + { + while (Operation* op = front_) + { + pop(); + op_queue_access::destroy(op); + } + } + + // Get the operation at the front of the queue. + Operation* front() + { + return front_; + } + + // Pop an operation from the front of the queue. + void pop() + { + if (front_) + { + Operation* tmp = front_; + front_ = op_queue_access::next(front_); + if (front_ == 0) + back_ = 0; + op_queue_access::next(tmp, static_cast(0)); + } + } + + // Push an operation on to the back of the queue. + void push(Operation* h) + { + op_queue_access::next(h, static_cast(0)); + if (back_) + { + op_queue_access::next(back_, h); + back_ = h; + } + else + { + front_ = back_ = h; + } + } + + // Push all operations from another queue on to the back of the queue. The + // source queue may contain operations of a derived type. + template + void push(op_queue& q) + { + if (Operation* other_front = op_queue_access::front(q)) + { + if (back_) + op_queue_access::next(back_, other_front); + else + front_ = other_front; + back_ = op_queue_access::back(q); + op_queue_access::front(q) = 0; + op_queue_access::back(q) = 0; + } + } + + // Whether the queue is empty. + bool empty() const + { + return front_ == 0; + } + + // Test whether an operation is already enqueued. + bool is_enqueued(Operation* o) const + { + return op_queue_access::next(o) != 0 || back_ == o; + } + +private: + friend class op_queue_access; + + // The front of the queue. + Operation* front_; + + // The back of the queue. + Operation* back_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_OP_QUEUE_HPP diff --git a/boost/asio/detail/operation.hpp b/boost/asio/detail/operation.hpp new file mode 100644 index 0000000..4baed81 --- /dev/null +++ b/boost/asio/detail/operation.hpp @@ -0,0 +1,40 @@ +// +// detail/operation.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_OPERATION_HPP +#define BOOST_ASIO_DETAIL_OPERATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#else +# include +#endif + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_HAS_IOCP) +typedef win_iocp_operation operation; +#else +typedef scheduler_operation operation; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_OPERATION_HPP diff --git a/boost/asio/detail/pipe_select_interrupter.hpp b/boost/asio/detail/pipe_select_interrupter.hpp new file mode 100644 index 0000000..01a467a --- /dev/null +++ b/boost/asio/detail/pipe_select_interrupter.hpp @@ -0,0 +1,91 @@ +// +// detail/pipe_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP +#define BOOST_ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_WINDOWS) +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) +#if !defined(__CYGWIN__) +#if !defined(__SYMBIAN32__) +#if !defined(BOOST_ASIO_HAS_EVENTFD) + +#include + +namespace boost { +namespace asio { +namespace detail { + +class pipe_select_interrupter +{ +public: + // Constructor. + BOOST_ASIO_DECL pipe_select_interrupter(); + + // Destructor. + BOOST_ASIO_DECL ~pipe_select_interrupter(); + + // Recreate the interrupter's descriptors. Used after a fork. + BOOST_ASIO_DECL void recreate(); + + // Interrupt the select call. + BOOST_ASIO_DECL void interrupt(); + + // Reset the select interrupt. Returns true if the call was interrupted. + BOOST_ASIO_DECL bool reset(); + + // Get the read descriptor to be passed to select. + int read_descriptor() const + { + return read_descriptor_; + } + +private: + // Open the descriptors. Throws on error. + BOOST_ASIO_DECL void open_descriptors(); + + // Close the descriptors. + BOOST_ASIO_DECL void close_descriptors(); + + // The read end of a connection used to interrupt the select call. This file + // descriptor is passed to select such that when it is time to stop, a single + // byte will be written on the other end of the connection and this + // descriptor will become readable. + int read_descriptor_; + + // The write end of a connection used to interrupt the select call. A single + // byte may be written to this to wake up the select which is waiting for the + // other end to become readable. + int write_descriptor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_ASIO_HAS_EVENTFD) +#endif // !defined(__SYMBIAN32__) +#endif // !defined(__CYGWIN__) +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) +#endif // !defined(BOOST_ASIO_WINDOWS) + +#endif // BOOST_ASIO_DETAIL_PIPE_SELECT_INTERRUPTER_HPP diff --git a/boost/asio/detail/pop_options.hpp b/boost/asio/detail/pop_options.hpp new file mode 100644 index 0000000..3346b96 --- /dev/null +++ b/boost/asio/detail/pop_options.hpp @@ -0,0 +1,141 @@ +// +// detail/pop_options.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// No header guard + +#if defined(__COMO__) + +// Comeau C++ + +#elif defined(__DMC__) + +// Digital Mars C++ + +#elif defined(__INTEL_COMPILER) || defined(__ICL) \ + || defined(__ICC) || defined(__ECC) + +// Intel C++ + +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# if !defined(BOOST_ASIO_DISABLE_VISIBILITY) +# pragma GCC visibility pop +# endif // !defined(BOOST_ASIO_DISABLE_VISIBILITY) +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) + +#elif defined(__clang__) + +// Clang + +# if defined(__OBJC__) +# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) +# if defined(BOOST_ASIO_OBJC_WORKAROUND) +# undef Protocol +# undef id +# undef BOOST_ASIO_OBJC_WORKAROUND +# endif +# endif +# endif + +# if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) +# if !defined(BOOST_ASIO_DISABLE_VISIBILITY) +# pragma GCC visibility pop +# endif // !defined(BOOST_ASIO_DISABLE_VISIBILITY) +# endif // !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) + +#elif defined(__GNUC__) + +// GNU C++ + +# if defined(__MINGW32__) || defined(__CYGWIN__) +# pragma pack (pop) +# endif + +# if defined(__OBJC__) +# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) +# if defined(BOOST_ASIO_OBJC_WORKAROUND) +# undef Protocol +# undef id +# undef BOOST_ASIO_OBJC_WORKAROUND +# endif +# endif +# endif + +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# if !defined(BOOST_ASIO_DISABLE_VISIBILITY) +# pragma GCC visibility pop +# endif // !defined(BOOST_ASIO_DISABLE_VISIBILITY) +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) + +# if (__GNUC__ >= 7) +# pragma GCC diagnostic pop +# endif // (__GNUC__ >= 7) + +#elif defined(__KCC) + +// Kai C++ + +#elif defined(__sgi) + +// SGI MIPSpro C++ + +#elif defined(__DECCXX) + +// Compaq Tru64 Unix cxx + +#elif defined(__ghs) + +// Greenhills C++ + +#elif defined(__BORLANDC__) + +// Borland C++ + +# pragma option pop +# pragma nopushoptwarn +# pragma nopackwarning + +#elif defined(__MWERKS__) + +// Metrowerks CodeWarrior + +#elif defined(__SUNPRO_CC) + +// Sun Workshop Compiler C++ + +#elif defined(__HP_aCC) + +// HP aCC + +#elif defined(__MRC__) || defined(__SC__) + +// MPW MrCpp or SCpp + +#elif defined(__IBMCPP__) + +// IBM Visual Age + +#elif defined(_MSC_VER) + +// Microsoft Visual C++ +// +// Must remain the last #elif since some other vendors (Metrowerks, for example) +// also #define _MSC_VER + +# pragma warning (pop) +# pragma pack (pop) + +# if defined(__cplusplus_cli) || defined(__cplusplus_winrt) +# if defined(BOOST_ASIO_CLR_WORKAROUND) +# undef generic +# undef BOOST_ASIO_CLR_WORKAROUND +# endif +# endif + +#endif diff --git a/boost/asio/detail/posix_event.hpp b/boost/asio/detail/posix_event.hpp new file mode 100644 index 0000000..98a796c --- /dev/null +++ b/boost/asio/detail/posix_event.hpp @@ -0,0 +1,164 @@ +// +// detail/posix_event.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_POSIX_EVENT_HPP +#define BOOST_ASIO_DETAIL_POSIX_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_PTHREADS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class posix_event + : private noncopyable +{ +public: + // Constructor. + BOOST_ASIO_DECL posix_event(); + + // Destructor. + ~posix_event() + { + ::pthread_cond_destroy(&cond_); + } + + // Signal the event. (Retained for backward compatibility.) + template + void signal(Lock& lock) + { + this->signal_all(lock); + } + + // Signal all waiters. + template + void signal_all(Lock& lock) + { + BOOST_ASIO_ASSERT(lock.locked()); + (void)lock; + state_ |= 1; + ::pthread_cond_broadcast(&cond_); // Ignore EINVAL. + } + + // Unlock the mutex and signal one waiter. + template + void unlock_and_signal_one(Lock& lock) + { + BOOST_ASIO_ASSERT(lock.locked()); + state_ |= 1; + bool have_waiters = (state_ > 1); + lock.unlock(); + if (have_waiters) + ::pthread_cond_signal(&cond_); // Ignore EINVAL. + } + + // If there's a waiter, unlock the mutex and signal it. + template + bool maybe_unlock_and_signal_one(Lock& lock) + { + BOOST_ASIO_ASSERT(lock.locked()); + state_ |= 1; + if (state_ > 1) + { + lock.unlock(); + ::pthread_cond_signal(&cond_); // Ignore EINVAL. + return true; + } + return false; + } + + // Reset the event. + template + void clear(Lock& lock) + { + BOOST_ASIO_ASSERT(lock.locked()); + (void)lock; + state_ &= ~std::size_t(1); + } + + // Wait for the event to become signalled. + template + void wait(Lock& lock) + { + BOOST_ASIO_ASSERT(lock.locked()); + while ((state_ & 1) == 0) + { + state_ += 2; + ::pthread_cond_wait(&cond_, &lock.mutex().mutex_); // Ignore EINVAL. + state_ -= 2; + } + } + + // Timed wait for the event to become signalled. + template + bool wait_for_usec(Lock& lock, long usec) + { + BOOST_ASIO_ASSERT(lock.locked()); + if ((state_ & 1) == 0) + { + state_ += 2; + timespec ts; +#if (defined(__MACH__) && defined(__APPLE__)) \ + || (defined(__ANDROID__) && (__ANDROID_API__ < 21) \ + && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)) + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + ::pthread_cond_timedwait_relative_np( + &cond_, &lock.mutex().mutex_, &ts); // Ignore EINVAL. +#else // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21) + // && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)) + if (::clock_gettime(CLOCK_MONOTONIC, &ts) == 0) + { + ts.tv_sec += usec / 1000000; + ts.tv_nsec += (usec % 1000000) * 1000; + ts.tv_sec += ts.tv_nsec / 1000000000; + ts.tv_nsec = ts.tv_nsec % 1000000000; + ::pthread_cond_timedwait(&cond_, + &lock.mutex().mutex_, &ts); // Ignore EINVAL. + } +#endif // (defined(__MACH__) && defined(__APPLE__)) + // || (defined(__ANDROID__) && (__ANDROID_API__ < 21) + // && defined(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE)) + state_ -= 2; + } + return (state_ & 1) != 0; + } + +private: + ::pthread_cond_t cond_; + std::size_t state_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_PTHREADS) + +#endif // BOOST_ASIO_DETAIL_POSIX_EVENT_HPP diff --git a/boost/asio/detail/posix_fd_set_adapter.hpp b/boost/asio/detail/posix_fd_set_adapter.hpp new file mode 100644 index 0000000..17faa56 --- /dev/null +++ b/boost/asio/detail/posix_fd_set_adapter.hpp @@ -0,0 +1,120 @@ +// +// detail/posix_fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP +#define BOOST_ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(__CYGWIN__) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements. +class posix_fd_set_adapter : noncopyable +{ +public: + posix_fd_set_adapter() + : max_descriptor_(invalid_socket) + { + using namespace std; // Needed for memset on Solaris. + FD_ZERO(&fd_set_); + } + + void reset() + { + using namespace std; // Needed for memset on Solaris. + FD_ZERO(&fd_set_); + } + + bool set(socket_type descriptor) + { + if (descriptor < (socket_type)FD_SETSIZE) + { + if (max_descriptor_ == invalid_socket || descriptor > max_descriptor_) + max_descriptor_ = descriptor; + FD_SET(descriptor, &fd_set_); + return true; + } + return false; + } + + void set(reactor_op_queue& operations, op_queue& ops) + { + reactor_op_queue::iterator i = operations.begin(); + while (i != operations.end()) + { + reactor_op_queue::iterator op_iter = i++; + if (!set(op_iter->first)) + { + boost::system::error_code ec(error::fd_set_failure); + operations.cancel_operations(op_iter, ops, ec); + } + } + } + + bool is_set(socket_type descriptor) const + { + return FD_ISSET(descriptor, &fd_set_) != 0; + } + + operator fd_set*() + { + return &fd_set_; + } + + socket_type max_descriptor() const + { + return max_descriptor_; + } + + void perform(reactor_op_queue& operations, + op_queue& ops) const + { + reactor_op_queue::iterator i = operations.begin(); + while (i != operations.end()) + { + reactor_op_queue::iterator op_iter = i++; + if (is_set(op_iter->first)) + operations.perform_operations(op_iter, ops); + } + } + +private: + mutable fd_set fd_set_; + socket_type max_descriptor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(__CYGWIN__) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#endif // BOOST_ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP diff --git a/boost/asio/detail/posix_global.hpp b/boost/asio/detail/posix_global.hpp new file mode 100644 index 0000000..357fe15 --- /dev/null +++ b/boost/asio/detail/posix_global.hpp @@ -0,0 +1,82 @@ +// +// detail/posix_global.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_POSIX_GLOBAL_HPP +#define BOOST_ASIO_DETAIL_POSIX_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_PTHREADS) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +struct posix_global_impl +{ + // Helper function to perform initialisation. + static void do_init() + { + instance_.static_ptr_ = instance_.ptr_ = new T; + } + + // Destructor automatically cleans up the global. + ~posix_global_impl() + { + delete static_ptr_; + } + + static ::pthread_once_t init_once_; + static T* static_ptr_; + static posix_global_impl instance_; + T* ptr_; +}; + +template +::pthread_once_t posix_global_impl::init_once_ = PTHREAD_ONCE_INIT; + +template +T* posix_global_impl::static_ptr_ = 0; + +template +posix_global_impl posix_global_impl::instance_; + +template +T& posix_global() +{ + int result = ::pthread_once( + &posix_global_impl::init_once_, + &posix_global_impl::do_init); + + if (result != 0) + std::terminate(); + + return *posix_global_impl::instance_.ptr_; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_PTHREADS) + +#endif // BOOST_ASIO_DETAIL_POSIX_GLOBAL_HPP diff --git a/boost/asio/detail/posix_mutex.hpp b/boost/asio/detail/posix_mutex.hpp new file mode 100644 index 0000000..1418ab5 --- /dev/null +++ b/boost/asio/detail/posix_mutex.hpp @@ -0,0 +1,78 @@ +// +// detail/posix_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_POSIX_MUTEX_HPP +#define BOOST_ASIO_DETAIL_POSIX_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_PTHREADS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class posix_event; + +class posix_mutex + : private noncopyable +{ +public: + typedef boost::asio::detail::scoped_lock scoped_lock; + + // Constructor. + BOOST_ASIO_DECL posix_mutex(); + + // Destructor. + ~posix_mutex() + { + ::pthread_mutex_destroy(&mutex_); // Ignore EBUSY. + } + + // Lock the mutex. + void lock() + { + (void)::pthread_mutex_lock(&mutex_); // Ignore EINVAL. + } + + // Unlock the mutex. + void unlock() + { + (void)::pthread_mutex_unlock(&mutex_); // Ignore EINVAL. + } + +private: + friend class posix_event; + ::pthread_mutex_t mutex_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_PTHREADS) + +#endif // BOOST_ASIO_DETAIL_POSIX_MUTEX_HPP diff --git a/boost/asio/detail/posix_signal_blocker.hpp b/boost/asio/detail/posix_signal_blocker.hpp new file mode 100644 index 0000000..729da81 --- /dev/null +++ b/boost/asio/detail/posix_signal_blocker.hpp @@ -0,0 +1,87 @@ +// +// detail/posix_signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP +#define BOOST_ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_PTHREADS) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class posix_signal_blocker + : private noncopyable +{ +public: + // Constructor blocks all signals for the calling thread. + posix_signal_blocker() + : blocked_(false) + { + sigset_t new_mask; + sigfillset(&new_mask); + blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0); + } + + // Destructor restores the previous signal mask. + ~posix_signal_blocker() + { + if (blocked_) + pthread_sigmask(SIG_SETMASK, &old_mask_, 0); + } + + // Block all signals for the calling thread. + void block() + { + if (!blocked_) + { + sigset_t new_mask; + sigfillset(&new_mask); + blocked_ = (pthread_sigmask(SIG_BLOCK, &new_mask, &old_mask_) == 0); + } + } + + // Restore the previous signal mask. + void unblock() + { + if (blocked_) + blocked_ = (pthread_sigmask(SIG_SETMASK, &old_mask_, 0) != 0); + } + +private: + // Have signals been blocked. + bool blocked_; + + // The previous signal mask. + sigset_t old_mask_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_PTHREADS) + +#endif // BOOST_ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP diff --git a/boost/asio/detail/posix_static_mutex.hpp b/boost/asio/detail/posix_static_mutex.hpp new file mode 100644 index 0000000..331868f --- /dev/null +++ b/boost/asio/detail/posix_static_mutex.hpp @@ -0,0 +1,66 @@ +// +// detail/posix_static_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_POSIX_STATIC_MUTEX_HPP +#define BOOST_ASIO_DETAIL_POSIX_STATIC_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_PTHREADS) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct posix_static_mutex +{ + typedef boost::asio::detail::scoped_lock scoped_lock; + + // Initialise the mutex. + void init() + { + // Nothing to do. + } + + // Lock the mutex. + void lock() + { + (void)::pthread_mutex_lock(&mutex_); // Ignore EINVAL. + } + + // Unlock the mutex. + void unlock() + { + (void)::pthread_mutex_unlock(&mutex_); // Ignore EINVAL. + } + + ::pthread_mutex_t mutex_; +}; + +#define BOOST_ASIO_POSIX_STATIC_MUTEX_INIT { PTHREAD_MUTEX_INITIALIZER } + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_PTHREADS) + +#endif // BOOST_ASIO_DETAIL_POSIX_STATIC_MUTEX_HPP diff --git a/boost/asio/detail/posix_thread.hpp b/boost/asio/detail/posix_thread.hpp new file mode 100644 index 0000000..b9cd594 --- /dev/null +++ b/boost/asio/detail/posix_thread.hpp @@ -0,0 +1,111 @@ +// +// detail/posix_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_POSIX_THREAD_HPP +#define BOOST_ASIO_DETAIL_POSIX_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_PTHREADS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +extern "C" +{ + BOOST_ASIO_DECL void* boost_asio_detail_posix_thread_function(void* arg); +} + +class posix_thread + : private noncopyable +{ +public: + // Constructor. + template + posix_thread(Function f, unsigned int = 0) + : joined_(false) + { + start_thread(new func(f)); + } + + // Destructor. + BOOST_ASIO_DECL ~posix_thread(); + + // Wait for the thread to exit. + BOOST_ASIO_DECL void join(); + + // Get number of CPUs. + BOOST_ASIO_DECL static std::size_t hardware_concurrency(); + +private: + friend void* boost_asio_detail_posix_thread_function(void* arg); + + class func_base + { + public: + virtual ~func_base() {} + virtual void run() = 0; + }; + + struct auto_func_base_ptr + { + func_base* ptr; + ~auto_func_base_ptr() { delete ptr; } + }; + + template + class func + : public func_base + { + public: + func(Function f) + : f_(f) + { + } + + virtual void run() + { + f_(); + } + + private: + Function f_; + }; + + BOOST_ASIO_DECL void start_thread(func_base* arg); + + ::pthread_t thread_; + bool joined_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_PTHREADS) + +#endif // BOOST_ASIO_DETAIL_POSIX_THREAD_HPP diff --git a/boost/asio/detail/posix_tss_ptr.hpp b/boost/asio/detail/posix_tss_ptr.hpp new file mode 100644 index 0000000..126c148 --- /dev/null +++ b/boost/asio/detail/posix_tss_ptr.hpp @@ -0,0 +1,81 @@ +// +// detail/posix_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_POSIX_TSS_PTR_HPP +#define BOOST_ASIO_DETAIL_POSIX_TSS_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_PTHREADS) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Helper function to create thread-specific storage. +BOOST_ASIO_DECL void posix_tss_ptr_create(pthread_key_t& key); + +template +class posix_tss_ptr + : private noncopyable +{ +public: + // Constructor. + posix_tss_ptr() + { + posix_tss_ptr_create(tss_key_); + } + + // Destructor. + ~posix_tss_ptr() + { + ::pthread_key_delete(tss_key_); + } + + // Get the value. + operator T*() const + { + return static_cast(::pthread_getspecific(tss_key_)); + } + + // Set the value. + void operator=(T* value) + { + ::pthread_setspecific(tss_key_, value); + } + +private: + // Thread-specific storage to allow unlocked access to determine whether a + // thread is a member of the pool. + pthread_key_t tss_key_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_PTHREADS) + +#endif // BOOST_ASIO_DETAIL_POSIX_TSS_PTR_HPP diff --git a/boost/asio/detail/push_options.hpp b/boost/asio/detail/push_options.hpp new file mode 100644 index 0000000..679ac27 --- /dev/null +++ b/boost/asio/detail/push_options.hpp @@ -0,0 +1,181 @@ +// +// detail/push_options.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// No header guard + +#if defined(__COMO__) + +// Comeau C++ + +#elif defined(__DMC__) + +// Digital Mars C++ + +#elif defined(__INTEL_COMPILER) || defined(__ICL) \ + || defined(__ICC) || defined(__ECC) + +// Intel C++ + +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# if !defined(BOOST_ASIO_DISABLE_VISIBILITY) +# pragma GCC visibility push (default) +# endif // !defined(BOOST_ASIO_DISABLE_VISIBILITY) +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) + +#elif defined(__clang__) + +// Clang + +# if defined(__OBJC__) +# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) +# if !defined(BOOST_ASIO_DISABLE_OBJC_WORKAROUND) +# if !defined(Protocol) && !defined(id) +# define Protocol cpp_Protocol +# define id cpp_id +# define BOOST_ASIO_OBJC_WORKAROUND +# endif +# endif +# endif +# endif + +# if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) +# if !defined(BOOST_ASIO_DISABLE_VISIBILITY) +# pragma GCC visibility push (default) +# endif // !defined(BOOST_ASIO_DISABLE_VISIBILITY) +# endif // !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) + +#elif defined(__GNUC__) + +// GNU C++ + +# if defined(__MINGW32__) || defined(__CYGWIN__) +# pragma pack (push, 8) +# endif + +# if defined(__OBJC__) +# if !defined(__APPLE_CC__) || (__APPLE_CC__ <= 1) +# if !defined(BOOST_ASIO_DISABLE_OBJC_WORKAROUND) +# if !defined(Protocol) && !defined(id) +# define Protocol cpp_Protocol +# define id cpp_id +# define BOOST_ASIO_OBJC_WORKAROUND +# endif +# endif +# endif +# endif + +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# if !defined(BOOST_ASIO_DISABLE_VISIBILITY) +# pragma GCC visibility push (default) +# endif // !defined(BOOST_ASIO_DISABLE_VISIBILITY) +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) + +# if (__GNUC__ >= 7) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +# endif // (__GNUC__ >= 7) + +#elif defined(__KCC) + +// Kai C++ + +#elif defined(__sgi) + +// SGI MIPSpro C++ + +#elif defined(__DECCXX) + +// Compaq Tru64 Unix cxx + +#elif defined(__ghs) + +// Greenhills C++ + +#elif defined(__BORLANDC__) + +// Borland C++ + +# pragma option push -a8 -b -Ve- -Vx- -w-inl -vi- +# pragma nopushoptwarn +# pragma nopackwarning +# if !defined(__MT__) +# error Multithreaded RTL must be selected. +# endif // !defined(__MT__) + +#elif defined(__MWERKS__) + +// Metrowerks CodeWarrior + +#elif defined(__SUNPRO_CC) + +// Sun Workshop Compiler C++ + +#elif defined(__HP_aCC) + +// HP aCC + +#elif defined(__MRC__) || defined(__SC__) + +// MPW MrCpp or SCpp + +#elif defined(__IBMCPP__) + +// IBM Visual Age + +#elif defined(_MSC_VER) + +// Microsoft Visual C++ +// +// Must remain the last #elif since some other vendors (Metrowerks, for example) +// also #define _MSC_VER + +# pragma warning (disable:4103) +# pragma warning (push) +# pragma warning (disable:4127) +# pragma warning (disable:4180) +# pragma warning (disable:4244) +# pragma warning (disable:4355) +# pragma warning (disable:4510) +# pragma warning (disable:4512) +# pragma warning (disable:4610) +# pragma warning (disable:4675) +# if (_MSC_VER < 1600) +// Visual Studio 2008 generates spurious warnings about unused parameters. +# pragma warning (disable:4100) +# endif // (_MSC_VER < 1600) +# if defined(_M_IX86) && defined(_Wp64) +// The /Wp64 option is broken. If you want to check 64 bit portability, use a +// 64 bit compiler! +# pragma warning (disable:4311) +# pragma warning (disable:4312) +# endif // defined(_M_IX86) && defined(_Wp64) +# pragma pack (push, 8) +// Note that if the /Og optimisation flag is enabled with MSVC6, the compiler +// has a tendency to incorrectly optimise away some calls to member template +// functions, even though those functions contain code that should not be +// optimised away! Therefore we will always disable this optimisation option +// for the MSVC6 compiler. +# if (_MSC_VER < 1300) +# pragma optimize ("g", off) +# endif +# if !defined(_MT) +# error Multithreaded RTL must be selected. +# endif // !defined(_MT) + +# if defined(__cplusplus_cli) || defined(__cplusplus_winrt) +# if !defined(BOOST_ASIO_DISABLE_CLR_WORKAROUND) +# if !defined(generic) +# define generic cpp_generic +# define BOOST_ASIO_CLR_WORKAROUND +# endif +# endif +# endif + +#endif diff --git a/boost/asio/detail/reactive_descriptor_service.hpp b/boost/asio/detail/reactive_descriptor_service.hpp new file mode 100644 index 0000000..beed44a --- /dev/null +++ b/boost/asio/detail/reactive_descriptor_service.hpp @@ -0,0 +1,393 @@ +// +// detail/reactive_descriptor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class reactive_descriptor_service : + public execution_context_service_base +{ +public: + // The native type of a descriptor. + typedef int native_handle_type; + + // The implementation type of the descriptor. + class implementation_type + : private boost::asio::detail::noncopyable + { + public: + // Default constructor. + implementation_type() + : descriptor_(-1), + state_(0) + { + } + + private: + // Only this service will have access to the internal values. + friend class reactive_descriptor_service; + + // The native descriptor representation. + int descriptor_; + + // The current state of the descriptor. + descriptor_ops::state_type state_; + + // Per-descriptor data used by the reactor. + reactor::per_descriptor_data reactor_data_; + }; + + // Constructor. + BOOST_ASIO_DECL reactive_descriptor_service(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown(); + + // Construct a new descriptor implementation. + BOOST_ASIO_DECL void construct(implementation_type& impl); + + // Move-construct a new descriptor implementation. + BOOST_ASIO_DECL void move_construct(implementation_type& impl, + implementation_type& other_impl); + + // Move-assign from another descriptor implementation. + BOOST_ASIO_DECL void move_assign(implementation_type& impl, + reactive_descriptor_service& other_service, + implementation_type& other_impl); + + // Destroy a descriptor implementation. + BOOST_ASIO_DECL void destroy(implementation_type& impl); + + // Assign a native descriptor to a descriptor implementation. + BOOST_ASIO_DECL boost::system::error_code assign(implementation_type& impl, + const native_handle_type& native_descriptor, + boost::system::error_code& ec); + + // Determine whether the descriptor is open. + bool is_open(const implementation_type& impl) const + { + return impl.descriptor_ != -1; + } + + // Destroy a descriptor implementation. + BOOST_ASIO_DECL boost::system::error_code close(implementation_type& impl, + boost::system::error_code& ec); + + // Get the native descriptor representation. + native_handle_type native_handle(const implementation_type& impl) const + { + return impl.descriptor_; + } + + // Release ownership of the native descriptor representation. + BOOST_ASIO_DECL native_handle_type release(implementation_type& impl); + + // Cancel all operations associated with the descriptor. + BOOST_ASIO_DECL boost::system::error_code cancel(implementation_type& impl, + boost::system::error_code& ec); + + // Perform an IO control command on the descriptor. + template + boost::system::error_code io_control(implementation_type& impl, + IO_Control_Command& command, boost::system::error_code& ec) + { + descriptor_ops::ioctl(impl.descriptor_, impl.state_, + command.name(), static_cast(command.data()), ec); + return ec; + } + + // Gets the non-blocking mode of the descriptor. + bool non_blocking(const implementation_type& impl) const + { + return (impl.state_ & descriptor_ops::user_set_non_blocking) != 0; + } + + // Sets the non-blocking mode of the descriptor. + boost::system::error_code non_blocking(implementation_type& impl, + bool mode, boost::system::error_code& ec) + { + descriptor_ops::set_user_non_blocking( + impl.descriptor_, impl.state_, mode, ec); + return ec; + } + + // Gets the non-blocking mode of the native descriptor implementation. + bool native_non_blocking(const implementation_type& impl) const + { + return (impl.state_ & descriptor_ops::internal_non_blocking) != 0; + } + + // Sets the non-blocking mode of the native descriptor implementation. + boost::system::error_code native_non_blocking(implementation_type& impl, + bool mode, boost::system::error_code& ec) + { + descriptor_ops::set_internal_non_blocking( + impl.descriptor_, impl.state_, mode, ec); + return ec; + } + + // Wait for the descriptor to become ready to read, ready to write, or to have + // pending error conditions. + boost::system::error_code wait(implementation_type& impl, + posix::descriptor_base::wait_type w, boost::system::error_code& ec) + { + switch (w) + { + case posix::descriptor_base::wait_read: + descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec); + break; + case posix::descriptor_base::wait_write: + descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec); + break; + case posix::descriptor_base::wait_error: + descriptor_ops::poll_error(impl.descriptor_, impl.state_, ec); + break; + default: + ec = boost::asio::error::invalid_argument; + break; + } + + return ec; + } + + // Asynchronously wait for the descriptor to become ready to read, ready to + // write, or to have pending error conditions. + template + void async_wait(implementation_type& impl, + posix::descriptor_base::wait_type w, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_wait_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_wait")); + + int op_type; + switch (w) + { + case posix::descriptor_base::wait_read: + op_type = reactor::read_op; + break; + case posix::descriptor_base::wait_write: + op_type = reactor::write_op; + break; + case posix::descriptor_base::wait_error: + op_type = reactor::except_op; + break; + default: + p.p->ec_ = boost::asio::error::invalid_argument; + reactor_.post_immediate_completion(p.p, is_continuation); + p.v = p.p = 0; + return; + } + + start_op(impl, op_type, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Write some data to the descriptor. + template + size_t write_some(implementation_type& impl, + const ConstBufferSequence& buffers, boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return descriptor_ops::sync_write(impl.descriptor_, impl.state_, + bufs.buffers(), bufs.count(), bufs.all_empty(), ec); + } + + // Wait until data can be written without blocking. + size_t write_some(implementation_type& impl, + const null_buffers&, boost::system::error_code& ec) + { + // Wait for descriptor to become ready. + descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec); + + return 0; + } + + // Start an asynchronous write. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_write_some(implementation_type& impl, + const ConstBufferSequence& buffers, Handler& handler, + const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef descriptor_write_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.descriptor_, buffers, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_write_some")); + + start_op(impl, reactor::write_op, p.p, is_continuation, true, + buffer_sequence_adapter::all_empty(buffers)); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be written without blocking. + template + void async_write_some(implementation_type& impl, + const null_buffers&, Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_write_some(null_buffers)")); + + start_op(impl, reactor::write_op, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Read some data from the stream. Returns the number of bytes read. + template + size_t read_some(implementation_type& impl, + const MutableBufferSequence& buffers, boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return descriptor_ops::sync_read(impl.descriptor_, impl.state_, + bufs.buffers(), bufs.count(), bufs.all_empty(), ec); + } + + // Wait until data can be read without blocking. + size_t read_some(implementation_type& impl, + const null_buffers&, boost::system::error_code& ec) + { + // Wait for descriptor to become ready. + descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec); + + return 0; + } + + // Start an asynchronous read. The buffer for the data being read must be + // valid for the lifetime of the asynchronous operation. + template + void async_read_some(implementation_type& impl, + const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef descriptor_read_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.descriptor_, buffers, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_read_some")); + + start_op(impl, reactor::read_op, p.p, is_continuation, true, + buffer_sequence_adapter::all_empty(buffers)); + p.v = p.p = 0; + } + + // Wait until data can be read without blocking. + template + void async_read_some(implementation_type& impl, + const null_buffers&, Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", + &impl, impl.descriptor_, "async_read_some(null_buffers)")); + + start_op(impl, reactor::read_op, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + +private: + // Start the asynchronous operation. + BOOST_ASIO_DECL void start_op(implementation_type& impl, int op_type, + reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop); + + // The selector that performs event demultiplexing for the service. + reactor& reactor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP diff --git a/boost/asio/detail/reactive_null_buffers_op.hpp b/boost/asio/detail/reactive_null_buffers_op.hpp new file mode 100644 index 0000000..fb25be3 --- /dev/null +++ b/boost/asio/detail/reactive_null_buffers_op.hpp @@ -0,0 +1,94 @@ +// +// detail/reactive_null_buffers_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_null_buffers_op : public reactor_op +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_null_buffers_op); + + reactive_null_buffers_op(Handler& handler, const IoExecutor& io_ex) + : reactor_op(&reactive_null_buffers_op::do_perform, + &reactive_null_buffers_op::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static status do_perform(reactor_op*) + { + return done; + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_null_buffers_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP diff --git a/boost/asio/detail/reactive_serial_port_service.hpp b/boost/asio/detail/reactive_serial_port_service.hpp new file mode 100644 index 0000000..ae752d0 --- /dev/null +++ b/boost/asio/detail/reactive_serial_port_service.hpp @@ -0,0 +1,240 @@ +// +// detail/reactive_serial_port_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_SERIAL_PORT) +#if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Extend reactive_descriptor_service to provide serial port support. +class reactive_serial_port_service : + public execution_context_service_base +{ +public: + // The native type of a serial port. + typedef reactive_descriptor_service::native_handle_type native_handle_type; + + // The implementation type of the serial port. + typedef reactive_descriptor_service::implementation_type implementation_type; + + BOOST_ASIO_DECL reactive_serial_port_service(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown(); + + // Construct a new serial port implementation. + void construct(implementation_type& impl) + { + descriptor_service_.construct(impl); + } + + // Move-construct a new serial port implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + descriptor_service_.move_construct(impl, other_impl); + } + + // Move-assign from another serial port implementation. + void move_assign(implementation_type& impl, + reactive_serial_port_service& other_service, + implementation_type& other_impl) + { + descriptor_service_.move_assign(impl, + other_service.descriptor_service_, other_impl); + } + + // Destroy a serial port implementation. + void destroy(implementation_type& impl) + { + descriptor_service_.destroy(impl); + } + + // Open the serial port using the specified device name. + BOOST_ASIO_DECL boost::system::error_code open(implementation_type& impl, + const std::string& device, boost::system::error_code& ec); + + // Assign a native descriptor to a serial port implementation. + boost::system::error_code assign(implementation_type& impl, + const native_handle_type& native_descriptor, + boost::system::error_code& ec) + { + return descriptor_service_.assign(impl, native_descriptor, ec); + } + + // Determine whether the serial port is open. + bool is_open(const implementation_type& impl) const + { + return descriptor_service_.is_open(impl); + } + + // Destroy a serial port implementation. + boost::system::error_code close(implementation_type& impl, + boost::system::error_code& ec) + { + return descriptor_service_.close(impl, ec); + } + + // Get the native serial port representation. + native_handle_type native_handle(implementation_type& impl) + { + return descriptor_service_.native_handle(impl); + } + + // Cancel all operations associated with the serial port. + boost::system::error_code cancel(implementation_type& impl, + boost::system::error_code& ec) + { + return descriptor_service_.cancel(impl, ec); + } + + // Set an option on the serial port. + template + boost::system::error_code set_option(implementation_type& impl, + const SettableSerialPortOption& option, boost::system::error_code& ec) + { + return do_set_option(impl, + &reactive_serial_port_service::store_option, + &option, ec); + } + + // Get an option from the serial port. + template + boost::system::error_code get_option(const implementation_type& impl, + GettableSerialPortOption& option, boost::system::error_code& ec) const + { + return do_get_option(impl, + &reactive_serial_port_service::load_option, + &option, ec); + } + + // Send a break sequence to the serial port. + boost::system::error_code send_break(implementation_type& impl, + boost::system::error_code& ec) + { + errno = 0; + descriptor_ops::error_wrapper(::tcsendbreak( + descriptor_service_.native_handle(impl), 0), ec); + return ec; + } + + // Write the given data. Returns the number of bytes sent. + template + size_t write_some(implementation_type& impl, + const ConstBufferSequence& buffers, boost::system::error_code& ec) + { + return descriptor_service_.write_some(impl, buffers, ec); + } + + // Start an asynchronous write. The data being written must be valid for the + // lifetime of the asynchronous operation. + template + void async_write_some(implementation_type& impl, + const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + descriptor_service_.async_write_some(impl, buffers, handler, io_ex); + } + + // Read some data. Returns the number of bytes received. + template + size_t read_some(implementation_type& impl, + const MutableBufferSequence& buffers, boost::system::error_code& ec) + { + return descriptor_service_.read_some(impl, buffers, ec); + } + + // Start an asynchronous read. The buffer for the data being received must be + // valid for the lifetime of the asynchronous operation. + template + void async_read_some(implementation_type& impl, + const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + descriptor_service_.async_read_some(impl, buffers, handler, io_ex); + } + +private: + // Function pointer type for storing a serial port option. + typedef boost::system::error_code (*store_function_type)( + const void*, termios&, boost::system::error_code&); + + // Helper function template to store a serial port option. + template + static boost::system::error_code store_option(const void* option, + termios& storage, boost::system::error_code& ec) + { + static_cast(option)->store(storage, ec); + return ec; + } + + // Helper function to set a serial port option. + BOOST_ASIO_DECL boost::system::error_code do_set_option( + implementation_type& impl, store_function_type store, + const void* option, boost::system::error_code& ec); + + // Function pointer type for loading a serial port option. + typedef boost::system::error_code (*load_function_type)( + void*, const termios&, boost::system::error_code&); + + // Helper function template to load a serial port option. + template + static boost::system::error_code load_option(void* option, + const termios& storage, boost::system::error_code& ec) + { + static_cast(option)->load(storage, ec); + return ec; + } + + // Helper function to get a serial port option. + BOOST_ASIO_DECL boost::system::error_code do_get_option( + const implementation_type& impl, load_function_type load, + void* option, boost::system::error_code& ec) const; + + // The implementation used for initiating asynchronous operations. + reactive_descriptor_service descriptor_service_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) +#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SERIAL_PORT_SERVICE_HPP diff --git a/boost/asio/detail/reactive_socket_accept_op.hpp b/boost/asio/detail/reactive_socket_accept_op.hpp new file mode 100644 index 0000000..972e016 --- /dev/null +++ b/boost/asio/detail/reactive_socket_accept_op.hpp @@ -0,0 +1,232 @@ +// +// detail/reactive_socket_accept_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_socket_accept_op_base : public reactor_op +{ +public: + reactive_socket_accept_op_base(socket_type socket, + socket_ops::state_type state, Socket& peer, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, func_type complete_func) + : reactor_op(&reactive_socket_accept_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + peer_(peer), + protocol_(protocol), + peer_endpoint_(peer_endpoint), + addrlen_(peer_endpoint ? peer_endpoint->capacity() : 0) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_accept_op_base* o( + static_cast(base)); + + socket_type new_socket = invalid_socket; + status result = socket_ops::non_blocking_accept(o->socket_, + o->state_, o->peer_endpoint_ ? o->peer_endpoint_->data() : 0, + o->peer_endpoint_ ? &o->addrlen_ : 0, o->ec_, new_socket) + ? done : not_done; + o->new_socket_.reset(new_socket); + + BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_accept", o->ec_)); + + return result; + } + + void do_assign() + { + if (new_socket_.get() != invalid_socket) + { + if (peer_endpoint_) + peer_endpoint_->resize(addrlen_); + peer_.assign(protocol_, new_socket_.get(), ec_); + if (!ec_) + new_socket_.release(); + } + } + +private: + socket_type socket_; + socket_ops::state_type state_; + socket_holder new_socket_; + Socket& peer_; + Protocol protocol_; + typename Protocol::endpoint* peer_endpoint_; + std::size_t addrlen_; +}; + +template +class reactive_socket_accept_op : + public reactive_socket_accept_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_accept_op); + + reactive_socket_accept_op(socket_type socket, + socket_ops::state_type state, Socket& peer, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, Handler& handler, + const IoExecutor& io_ex) + : reactive_socket_accept_op_base(socket, state, peer, + protocol, peer_endpoint, &reactive_socket_accept_op::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_accept_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + // On success, assign new connection to peer socket object. + if (owner) + o->do_assign(); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1 + handler(o->handler_, o->ec_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + IoExecutor io_executor_; +}; + +#if defined(BOOST_ASIO_HAS_MOVE) + +template +class reactive_socket_move_accept_op : + private Protocol::socket::template rebind_executor::other, + public reactive_socket_accept_op_base< + typename Protocol::socket::template rebind_executor::other, + Protocol> +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_move_accept_op); + + reactive_socket_move_accept_op(const PeerIoExecutor& peer_io_ex, + socket_type socket, socket_ops::state_type state, + const Protocol& protocol, typename Protocol::endpoint* peer_endpoint, + Handler& handler, const IoExecutor& io_ex) + : peer_socket_type(peer_io_ex), + reactive_socket_accept_op_base( + socket, state, *this, protocol, peer_endpoint, + &reactive_socket_move_accept_op::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_move_accept_op* o( + static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + // On success, assign new connection to peer socket object. + if (owner) + o->do_assign(); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::move_binder2 + handler(0, BOOST_ASIO_MOVE_CAST(Handler)(o->handler_), o->ec_, + BOOST_ASIO_MOVE_CAST(peer_socket_type)(*o)); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + typedef typename Protocol::socket::template + rebind_executor::other peer_socket_type; + + Handler handler_; + IoExecutor io_executor_; +}; + +#endif // defined(BOOST_ASIO_HAS_MOVE) + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP diff --git a/boost/asio/detail/reactive_socket_connect_op.hpp b/boost/asio/detail/reactive_socket_connect_op.hpp new file mode 100644 index 0000000..e8701da --- /dev/null +++ b/boost/asio/detail/reactive_socket_connect_op.hpp @@ -0,0 +1,118 @@ +// +// detail/reactive_socket_connect_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class reactive_socket_connect_op_base : public reactor_op +{ +public: + reactive_socket_connect_op_base(socket_type socket, func_type complete_func) + : reactor_op(&reactive_socket_connect_op_base::do_perform, complete_func), + socket_(socket) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_connect_op_base* o( + static_cast(base)); + + status result = socket_ops::non_blocking_connect( + o->socket_, o->ec_) ? done : not_done; + + BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_connect", o->ec_)); + + return result; + } + +private: + socket_type socket_; +}; + +template +class reactive_socket_connect_op : public reactive_socket_connect_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_connect_op); + + reactive_socket_connect_op(socket_type socket, + Handler& handler, const IoExecutor& io_ex) + : reactive_socket_connect_op_base(socket, + &reactive_socket_connect_op::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_connect_op* o + (static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1 + handler(o->handler_, o->ec_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP diff --git a/boost/asio/detail/reactive_socket_recv_op.hpp b/boost/asio/detail/reactive_socket_recv_op.hpp new file mode 100644 index 0000000..1d6889d --- /dev/null +++ b/boost/asio/detail/reactive_socket_recv_op.hpp @@ -0,0 +1,139 @@ +// +// detail/reactive_socket_recv_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_socket_recv_op_base : public reactor_op +{ +public: + reactive_socket_recv_op_base(socket_type socket, + socket_ops::state_type state, const MutableBufferSequence& buffers, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&reactive_socket_recv_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + buffers_(buffers), + flags_(flags) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_recv_op_base* o( + static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + status result = socket_ops::non_blocking_recv(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + (o->state_ & socket_ops::stream_oriented) != 0, + o->ec_, o->bytes_transferred_) ? done : not_done; + + if (result == done) + if ((o->state_ & socket_ops::stream_oriented) != 0) + if (o->bytes_transferred_ == 0) + result = done_and_exhausted; + + BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recv", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + socket_type socket_; + socket_ops::state_type state_; + MutableBufferSequence buffers_; + socket_base::message_flags flags_; +}; + +template +class reactive_socket_recv_op : + public reactive_socket_recv_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op); + + reactive_socket_recv_op(socket_type socket, socket_ops::state_type state, + const MutableBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + : reactive_socket_recv_op_base(socket, state, + buffers, flags, &reactive_socket_recv_op::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_recv_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP diff --git a/boost/asio/detail/reactive_socket_recvfrom_op.hpp b/boost/asio/detail/reactive_socket_recvfrom_op.hpp new file mode 100644 index 0000000..09aceba --- /dev/null +++ b/boost/asio/detail/reactive_socket_recvfrom_op.hpp @@ -0,0 +1,144 @@ +// +// detail/reactive_socket_recvfrom_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_socket_recvfrom_op_base : public reactor_op +{ +public: + reactive_socket_recvfrom_op_base(socket_type socket, int protocol_type, + const MutableBufferSequence& buffers, Endpoint& endpoint, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&reactive_socket_recvfrom_op_base::do_perform, complete_func), + socket_(socket), + protocol_type_(protocol_type), + buffers_(buffers), + sender_endpoint_(endpoint), + flags_(flags) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_recvfrom_op_base* o( + static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + std::size_t addr_len = o->sender_endpoint_.capacity(); + status result = socket_ops::non_blocking_recvfrom(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->sender_endpoint_.data(), &addr_len, + o->ec_, o->bytes_transferred_) ? done : not_done; + + if (result && !o->ec_) + o->sender_endpoint_.resize(addr_len); + + BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recvfrom", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + socket_type socket_; + int protocol_type_; + MutableBufferSequence buffers_; + Endpoint& sender_endpoint_; + socket_base::message_flags flags_; +}; + +template +class reactive_socket_recvfrom_op : + public reactive_socket_recvfrom_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op); + + reactive_socket_recvfrom_op(socket_type socket, int protocol_type, + const MutableBufferSequence& buffers, Endpoint& endpoint, + socket_base::message_flags flags, Handler& handler, + const IoExecutor& io_ex) + : reactive_socket_recvfrom_op_base( + socket, protocol_type, buffers, endpoint, flags, + &reactive_socket_recvfrom_op::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_recvfrom_op* o( + static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP diff --git a/boost/asio/detail/reactive_socket_recvmsg_op.hpp b/boost/asio/detail/reactive_socket_recvmsg_op.hpp new file mode 100644 index 0000000..bb65a19 --- /dev/null +++ b/boost/asio/detail/reactive_socket_recvmsg_op.hpp @@ -0,0 +1,137 @@ +// +// detail/reactive_socket_recvmsg_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_socket_recvmsg_op_base : public reactor_op +{ +public: + reactive_socket_recvmsg_op_base(socket_type socket, + const MutableBufferSequence& buffers, socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, func_type complete_func) + : reactor_op(&reactive_socket_recvmsg_op_base::do_perform, complete_func), + socket_(socket), + buffers_(buffers), + in_flags_(in_flags), + out_flags_(out_flags) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_recvmsg_op_base* o( + static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + status result = socket_ops::non_blocking_recvmsg(o->socket_, + bufs.buffers(), bufs.count(), + o->in_flags_, o->out_flags_, + o->ec_, o->bytes_transferred_) ? done : not_done; + + BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_recvmsg", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + socket_type socket_; + MutableBufferSequence buffers_; + socket_base::message_flags in_flags_; + socket_base::message_flags& out_flags_; +}; + +template +class reactive_socket_recvmsg_op : + public reactive_socket_recvmsg_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvmsg_op); + + reactive_socket_recvmsg_op(socket_type socket, + const MutableBufferSequence& buffers, socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, Handler& handler, + const IoExecutor& io_ex) + : reactive_socket_recvmsg_op_base(socket, buffers, + in_flags, out_flags, &reactive_socket_recvmsg_op::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_recvmsg_op* o( + static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP diff --git a/boost/asio/detail/reactive_socket_send_op.hpp b/boost/asio/detail/reactive_socket_send_op.hpp new file mode 100644 index 0000000..6be6081 --- /dev/null +++ b/boost/asio/detail/reactive_socket_send_op.hpp @@ -0,0 +1,138 @@ +// +// detail/reactive_socket_send_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_socket_send_op_base : public reactor_op +{ +public: + reactive_socket_send_op_base(socket_type socket, + socket_ops::state_type state, const ConstBufferSequence& buffers, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&reactive_socket_send_op_base::do_perform, complete_func), + socket_(socket), + state_(state), + buffers_(buffers), + flags_(flags) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_send_op_base* o( + static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + status result = socket_ops::non_blocking_send(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->ec_, o->bytes_transferred_) ? done : not_done; + + if (result == done) + if ((o->state_ & socket_ops::stream_oriented) != 0) + if (o->bytes_transferred_ < bufs.total_size()) + result = done_and_exhausted; + + BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_send", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + socket_type socket_; + socket_ops::state_type state_; + ConstBufferSequence buffers_; + socket_base::message_flags flags_; +}; + +template +class reactive_socket_send_op : + public reactive_socket_send_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_send_op); + + reactive_socket_send_op(socket_type socket, socket_ops::state_type state, + const ConstBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + : reactive_socket_send_op_base(socket, + state, buffers, flags, &reactive_socket_send_op::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_send_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP diff --git a/boost/asio/detail/reactive_socket_sendto_op.hpp b/boost/asio/detail/reactive_socket_sendto_op.hpp new file mode 100644 index 0000000..3429a75 --- /dev/null +++ b/boost/asio/detail/reactive_socket_sendto_op.hpp @@ -0,0 +1,136 @@ +// +// detail/reactive_socket_sendto_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_socket_sendto_op_base : public reactor_op +{ +public: + reactive_socket_sendto_op_base(socket_type socket, + const ConstBufferSequence& buffers, const Endpoint& endpoint, + socket_base::message_flags flags, func_type complete_func) + : reactor_op(&reactive_socket_sendto_op_base::do_perform, complete_func), + socket_(socket), + buffers_(buffers), + destination_(endpoint), + flags_(flags) + { + } + + static status do_perform(reactor_op* base) + { + reactive_socket_sendto_op_base* o( + static_cast(base)); + + buffer_sequence_adapter bufs(o->buffers_); + + status result = socket_ops::non_blocking_sendto(o->socket_, + bufs.buffers(), bufs.count(), o->flags_, + o->destination_.data(), o->destination_.size(), + o->ec_, o->bytes_transferred_) ? done : not_done; + + BOOST_ASIO_HANDLER_REACTOR_OPERATION((*o, "non_blocking_sendto", + o->ec_, o->bytes_transferred_)); + + return result; + } + +private: + socket_type socket_; + ConstBufferSequence buffers_; + Endpoint destination_; + socket_base::message_flags flags_; +}; + +template +class reactive_socket_sendto_op : + public reactive_socket_sendto_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_sendto_op); + + reactive_socket_sendto_op(socket_type socket, + const ConstBufferSequence& buffers, const Endpoint& endpoint, + socket_base::message_flags flags, Handler& handler, + const IoExecutor& io_ex) + : reactive_socket_sendto_op_base(socket, + buffers, endpoint, flags, &reactive_socket_sendto_op::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_socket_sendto_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->bytes_transferred_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP diff --git a/boost/asio/detail/reactive_socket_service.hpp b/boost/asio/detail/reactive_socket_service.hpp new file mode 100644 index 0000000..fb3a0e4 --- /dev/null +++ b/boost/asio/detail/reactive_socket_service.hpp @@ -0,0 +1,507 @@ +// +// detail/reactive_socket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_socket_service : + public execution_context_service_base >, + public reactive_socket_service_base +{ +public: + // The protocol type. + typedef Protocol protocol_type; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The native type of a socket. + typedef socket_type native_handle_type; + + // The implementation type of the socket. + struct implementation_type : + reactive_socket_service_base::base_implementation_type + { + // Default constructor. + implementation_type() + : protocol_(endpoint_type().protocol()) + { + } + + // The protocol associated with the socket. + protocol_type protocol_; + }; + + // Constructor. + reactive_socket_service(execution_context& context) + : execution_context_service_base< + reactive_socket_service >(context), + reactive_socket_service_base(context) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + this->base_shutdown(); + } + + // Move-construct a new socket implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + this->base_move_construct(impl, other_impl); + + impl.protocol_ = other_impl.protocol_; + other_impl.protocol_ = endpoint_type().protocol(); + } + + // Move-assign from another socket implementation. + void move_assign(implementation_type& impl, + reactive_socket_service_base& other_service, + implementation_type& other_impl) + { + this->base_move_assign(impl, other_service, other_impl); + + impl.protocol_ = other_impl.protocol_; + other_impl.protocol_ = endpoint_type().protocol(); + } + + // Move-construct a new socket implementation from another protocol type. + template + void converting_move_construct(implementation_type& impl, + reactive_socket_service&, + typename reactive_socket_service< + Protocol1>::implementation_type& other_impl) + { + this->base_move_construct(impl, other_impl); + + impl.protocol_ = protocol_type(other_impl.protocol_); + other_impl.protocol_ = typename Protocol1::endpoint().protocol(); + } + + // Open a new socket implementation. + boost::system::error_code open(implementation_type& impl, + const protocol_type& protocol, boost::system::error_code& ec) + { + if (!do_open(impl, protocol.family(), + protocol.type(), protocol.protocol(), ec)) + impl.protocol_ = protocol; + return ec; + } + + // Assign a native socket to a socket implementation. + boost::system::error_code assign(implementation_type& impl, + const protocol_type& protocol, const native_handle_type& native_socket, + boost::system::error_code& ec) + { + if (!do_assign(impl, protocol.type(), native_socket, ec)) + impl.protocol_ = protocol; + return ec; + } + + // Get the native socket representation. + native_handle_type native_handle(implementation_type& impl) + { + return impl.socket_; + } + + // Bind the socket to the specified local endpoint. + boost::system::error_code bind(implementation_type& impl, + const endpoint_type& endpoint, boost::system::error_code& ec) + { + socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); + return ec; + } + + // Set a socket option. + template + boost::system::error_code set_option(implementation_type& impl, + const Option& option, boost::system::error_code& ec) + { + socket_ops::setsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), option.size(impl.protocol_), ec); + return ec; + } + + // Set a socket option. + template + boost::system::error_code get_option(const implementation_type& impl, + Option& option, boost::system::error_code& ec) const + { + std::size_t size = option.size(impl.protocol_); + socket_ops::getsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), &size, ec); + if (!ec) + option.resize(impl.protocol_, size); + return ec; + } + + // Get the local endpoint. + endpoint_type local_endpoint(const implementation_type& impl, + boost::system::error_code& ec) const + { + endpoint_type endpoint; + std::size_t addr_len = endpoint.capacity(); + if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) + return endpoint_type(); + endpoint.resize(addr_len); + return endpoint; + } + + // Get the remote endpoint. + endpoint_type remote_endpoint(const implementation_type& impl, + boost::system::error_code& ec) const + { + endpoint_type endpoint; + std::size_t addr_len = endpoint.capacity(); + if (socket_ops::getpeername(impl.socket_, + endpoint.data(), &addr_len, false, ec)) + return endpoint_type(); + endpoint.resize(addr_len); + return endpoint; + } + + // Disable sends or receives on the socket. + boost::system::error_code shutdown(base_implementation_type& impl, + socket_base::shutdown_type what, boost::system::error_code& ec) + { + socket_ops::shutdown(impl.socket_, what, ec); + return ec; + } + + // Send a datagram to the specified endpoint. Returns the number of bytes + // sent. + template + size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_sendto(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, + destination.data(), destination.size(), ec); + } + + // Wait until data can be sent without blocking. + size_t send_to(implementation_type& impl, const null_buffers&, + const endpoint_type&, socket_base::message_flags, + boost::system::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send_to(implementation_type& impl, + const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_sendto_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.socket_, buffers, + destination, flags, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_send_to")); + + start_op(impl, reactor::write_op, p.p, is_continuation, true, false); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template + void async_send_to(implementation_type& impl, const null_buffers&, + const endpoint_type&, socket_base::message_flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_send_to(null_buffers)")); + + start_op(impl, reactor::write_op, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Receive a datagram with the endpoint of the sender. Returns the number of + // bytes received. + template + size_t receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + std::size_t addr_len = sender_endpoint.capacity(); + std::size_t bytes_recvd = socket_ops::sync_recvfrom( + impl.socket_, impl.state_, bufs.buffers(), bufs.count(), + flags, sender_endpoint.data(), &addr_len, ec); + + if (!ec) + sender_endpoint.resize(addr_len); + + return bytes_recvd; + } + + // Wait until data can be received without blocking. + size_t receive_from(implementation_type& impl, const null_buffers&, + endpoint_type& sender_endpoint, socket_base::message_flags, + boost::system::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + // Reset endpoint since it can be given no sensible value at this time. + sender_endpoint = endpoint_type(); + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received and + // the sender_endpoint object must both be valid for the lifetime of the + // asynchronous operation. + template + void async_receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, + socket_base::message_flags flags, Handler& handler, + const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_recvfrom_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + int protocol = impl.protocol_.type(); + p.p = new (p.v) op(impl.socket_, protocol, buffers, + sender_endpoint, flags, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive_from")); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, is_continuation, true, false); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template + void async_receive_from(implementation_type& impl, const null_buffers&, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive_from(null_buffers)")); + + // Reset endpoint since it can be given no sensible value at this time. + sender_endpoint = endpoint_type(); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Accept a new connection. + template + boost::system::error_code accept(implementation_type& impl, + Socket& peer, endpoint_type* peer_endpoint, boost::system::error_code& ec) + { + // We cannot accept a socket that is already open. + if (peer.is_open()) + { + ec = boost::asio::error::already_open; + return ec; + } + + std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; + socket_holder new_socket(socket_ops::sync_accept(impl.socket_, + impl.state_, peer_endpoint ? peer_endpoint->data() : 0, + peer_endpoint ? &addr_len : 0, ec)); + + // On success, assign new connection to peer socket object. + if (new_socket.get() != invalid_socket) + { + if (peer_endpoint) + peer_endpoint->resize(addr_len); + peer.assign(impl.protocol_, new_socket.get(), ec); + if (!ec) + new_socket.release(); + } + + return ec; + } + + // Start an asynchronous accept. The peer and peer_endpoint objects must be + // valid until the accept's handler is invoked. + template + void async_accept(implementation_type& impl, Socket& peer, + endpoint_type* peer_endpoint, Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_accept_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.socket_, impl.state_, peer, + impl.protocol_, peer_endpoint, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_accept")); + + start_accept_op(impl, p.p, is_continuation, peer.is_open()); + p.v = p.p = 0; + } + +#if defined(BOOST_ASIO_HAS_MOVE) + // Start an asynchronous accept. The peer_endpoint object must be valid until + // the accept's handler is invoked. + template + void async_move_accept(implementation_type& impl, + const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_move_accept_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(peer_io_ex, impl.socket_, impl.state_, + impl.protocol_, peer_endpoint, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_accept")); + + start_accept_op(impl, p.p, is_continuation, false); + p.v = p.p = 0; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // Connect the socket to the specified endpoint. + boost::system::error_code connect(implementation_type& impl, + const endpoint_type& peer_endpoint, boost::system::error_code& ec) + { + socket_ops::sync_connect(impl.socket_, + peer_endpoint.data(), peer_endpoint.size(), ec); + return ec; + } + + // Start an asynchronous connect. + template + void async_connect(implementation_type& impl, + const endpoint_type& peer_endpoint, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_connect_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.socket_, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_connect")); + + start_connect_op(impl, p.p, is_continuation, + peer_endpoint.data(), peer_endpoint.size()); + p.v = p.p = 0; + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP diff --git a/boost/asio/detail/reactive_socket_service_base.hpp b/boost/asio/detail/reactive_socket_service_base.hpp new file mode 100644 index 0000000..26fb828 --- /dev/null +++ b/boost/asio/detail/reactive_socket_service_base.hpp @@ -0,0 +1,520 @@ +// +// detail/reactive_socket_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_IOCP) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class reactive_socket_service_base +{ +public: + // The native type of a socket. + typedef socket_type native_handle_type; + + // The implementation type of the socket. + struct base_implementation_type + { + // The native socket representation. + socket_type socket_; + + // The current state of the socket. + socket_ops::state_type state_; + + // Per-descriptor data used by the reactor. + reactor::per_descriptor_data reactor_data_; + }; + + // Constructor. + BOOST_ASIO_DECL reactive_socket_service_base(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void base_shutdown(); + + // Construct a new socket implementation. + BOOST_ASIO_DECL void construct(base_implementation_type& impl); + + // Move-construct a new socket implementation. + BOOST_ASIO_DECL void base_move_construct(base_implementation_type& impl, + base_implementation_type& other_impl); + + // Move-assign from another socket implementation. + BOOST_ASIO_DECL void base_move_assign(base_implementation_type& impl, + reactive_socket_service_base& other_service, + base_implementation_type& other_impl); + + // Destroy a socket implementation. + BOOST_ASIO_DECL void destroy(base_implementation_type& impl); + + // Determine whether the socket is open. + bool is_open(const base_implementation_type& impl) const + { + return impl.socket_ != invalid_socket; + } + + // Destroy a socket implementation. + BOOST_ASIO_DECL boost::system::error_code close( + base_implementation_type& impl, boost::system::error_code& ec); + + // Release ownership of the socket. + BOOST_ASIO_DECL socket_type release( + base_implementation_type& impl, boost::system::error_code& ec); + + // Get the native socket representation. + native_handle_type native_handle(base_implementation_type& impl) + { + return impl.socket_; + } + + // Cancel all operations associated with the socket. + BOOST_ASIO_DECL boost::system::error_code cancel( + base_implementation_type& impl, boost::system::error_code& ec); + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const base_implementation_type& impl, + boost::system::error_code& ec) const + { + return socket_ops::sockatmark(impl.socket_, ec); + } + + // Determine the number of bytes available for reading. + std::size_t available(const base_implementation_type& impl, + boost::system::error_code& ec) const + { + return socket_ops::available(impl.socket_, ec); + } + + // Place the socket into the state where it will listen for new connections. + boost::system::error_code listen(base_implementation_type& impl, + int backlog, boost::system::error_code& ec) + { + socket_ops::listen(impl.socket_, backlog, ec); + return ec; + } + + // Perform an IO control command on the socket. + template + boost::system::error_code io_control(base_implementation_type& impl, + IO_Control_Command& command, boost::system::error_code& ec) + { + socket_ops::ioctl(impl.socket_, impl.state_, command.name(), + static_cast(command.data()), ec); + return ec; + } + + // Gets the non-blocking mode of the socket. + bool non_blocking(const base_implementation_type& impl) const + { + return (impl.state_ & socket_ops::user_set_non_blocking) != 0; + } + + // Sets the non-blocking mode of the socket. + boost::system::error_code non_blocking(base_implementation_type& impl, + bool mode, boost::system::error_code& ec) + { + socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec); + return ec; + } + + // Gets the non-blocking mode of the native socket implementation. + bool native_non_blocking(const base_implementation_type& impl) const + { + return (impl.state_ & socket_ops::internal_non_blocking) != 0; + } + + // Sets the non-blocking mode of the native socket implementation. + boost::system::error_code native_non_blocking(base_implementation_type& impl, + bool mode, boost::system::error_code& ec) + { + socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec); + return ec; + } + + // Wait for the socket to become ready to read, ready to write, or to have + // pending error conditions. + boost::system::error_code wait(base_implementation_type& impl, + socket_base::wait_type w, boost::system::error_code& ec) + { + switch (w) + { + case socket_base::wait_read: + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + break; + case socket_base::wait_write: + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + break; + case socket_base::wait_error: + socket_ops::poll_error(impl.socket_, impl.state_, -1, ec); + break; + default: + ec = boost::asio::error::invalid_argument; + break; + } + + return ec; + } + + // Asynchronously wait for the socket to become ready to read, ready to + // write, or to have pending error conditions. + template + void async_wait(base_implementation_type& impl, + socket_base::wait_type w, Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_wait_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_wait")); + + int op_type; + switch (w) + { + case socket_base::wait_read: + op_type = reactor::read_op; + break; + case socket_base::wait_write: + op_type = reactor::write_op; + break; + case socket_base::wait_error: + op_type = reactor::except_op; + break; + default: + p.p->ec_ = boost::asio::error::invalid_argument; + reactor_.post_immediate_completion(p.p, is_continuation); + p.v = p.p = 0; + return; + } + + start_op(impl, op_type, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Send the given data to the peer. + template + size_t send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_send(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be sent without blocking. + size_t send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, boost::system::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send(base_implementation_type& impl, + const ConstBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_send_op< + ConstBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.socket_, impl.state_, + buffers, flags, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_send")); + + start_op(impl, reactor::write_op, p.p, is_continuation, true, + ((impl.state_ & socket_ops::stream_oriented) + && buffer_sequence_adapter::all_empty(buffers))); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template + void async_send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_send(null_buffers)")); + + start_op(impl, reactor::write_op, p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Receive some data from the peer. Returns the number of bytes received. + template + size_t receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_recv(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be received without blocking. + size_t receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, boost::system::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template + void async_receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_recv_op< + MutableBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.socket_, impl.state_, + buffers, flags, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive")); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, is_continuation, + (flags & socket_base::message_out_of_band) == 0, + ((impl.state_ & socket_ops::stream_oriented) + && buffer_sequence_adapter::all_empty(buffers))); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template + void async_receive(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive(null_buffers)")); + + start_op(impl, + (flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, is_continuation, false, false); + p.v = p.p = 0; + } + + // Receive some data with associated flags. Returns the number of bytes + // received. + template + size_t receive_with_flags(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_recvmsg(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), in_flags, out_flags, ec); + } + + // Wait until data can be received without blocking. + size_t receive_with_flags(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags, + socket_base::message_flags& out_flags, boost::system::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + // Clear out_flags, since we cannot give it any other sensible value when + // performing a null_buffers operation. + out_flags = 0; + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template + void async_receive_with_flags(base_implementation_type& impl, + const MutableBufferSequence& buffers, socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, Handler& handler, + const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_socket_recvmsg_op< + MutableBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.socket_, buffers, + in_flags, out_flags, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive_with_flags")); + + start_op(impl, + (in_flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, is_continuation, + (in_flags & socket_base::message_out_of_band) == 0, false); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template + void async_receive_with_flags(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, Handler& handler, + const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef reactive_null_buffers_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "socket", + &impl, impl.socket_, "async_receive_with_flags(null_buffers)")); + + // Clear out_flags, since we cannot give it any other sensible value when + // performing a null_buffers operation. + out_flags = 0; + + start_op(impl, + (in_flags & socket_base::message_out_of_band) + ? reactor::except_op : reactor::read_op, + p.p, is_continuation, false, false); + p.v = p.p = 0; + } + +protected: + // Open a new socket implementation. + BOOST_ASIO_DECL boost::system::error_code do_open( + base_implementation_type& impl, int af, + int type, int protocol, boost::system::error_code& ec); + + // Assign a native socket to a socket implementation. + BOOST_ASIO_DECL boost::system::error_code do_assign( + base_implementation_type& impl, int type, + const native_handle_type& native_socket, boost::system::error_code& ec); + + // Start the asynchronous read or write operation. + BOOST_ASIO_DECL void start_op(base_implementation_type& impl, int op_type, + reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop); + + // Start the asynchronous accept operation. + BOOST_ASIO_DECL void start_accept_op(base_implementation_type& impl, + reactor_op* op, bool is_continuation, bool peer_is_open); + + // Start the asynchronous connect operation. + BOOST_ASIO_DECL void start_connect_op(base_implementation_type& impl, + reactor_op* op, bool is_continuation, + const socket_addr_type* addr, size_t addrlen); + + // The selector that performs event demultiplexing for the service. + reactor& reactor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // !defined(BOOST_ASIO_HAS_IOCP) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_BASE_HPP diff --git a/boost/asio/detail/reactive_wait_op.hpp b/boost/asio/detail/reactive_wait_op.hpp new file mode 100644 index 0000000..021059d --- /dev/null +++ b/boost/asio/detail/reactive_wait_op.hpp @@ -0,0 +1,94 @@ +// +// detail/reactive_wait_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTIVE_WAIT_OP_HPP +#define BOOST_ASIO_DETAIL_REACTIVE_WAIT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactive_wait_op : public reactor_op +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_wait_op); + + reactive_wait_op(Handler& handler, const IoExecutor& io_ex) + : reactor_op(&reactive_wait_op::do_perform, + &reactive_wait_op::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static status do_perform(reactor_op*) + { + return done; + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + reactive_wait_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1 + handler(o->handler_, o->ec_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTIVE_WAIT_OP_HPP diff --git a/boost/asio/detail/reactor.hpp b/boost/asio/detail/reactor.hpp new file mode 100644 index 0000000..bfe999b --- /dev/null +++ b/boost/asio/detail/reactor.hpp @@ -0,0 +1,32 @@ +// +// detail/reactor.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTOR_HPP +#define BOOST_ASIO_DETAIL_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_EPOLL) +# include +#elif defined(BOOST_ASIO_HAS_KQUEUE) +# include +#elif defined(BOOST_ASIO_HAS_DEV_POLL) +# include +#elif defined(BOOST_ASIO_HAS_IOCP) || defined(BOOST_ASIO_WINDOWS_RUNTIME) +# include +#else +# include +#endif + +#endif // BOOST_ASIO_DETAIL_REACTOR_HPP diff --git a/boost/asio/detail/reactor_fwd.hpp b/boost/asio/detail/reactor_fwd.hpp new file mode 100644 index 0000000..2ea1eec --- /dev/null +++ b/boost/asio/detail/reactor_fwd.hpp @@ -0,0 +1,42 @@ +// +// detail/reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTOR_FWD_HPP +#define BOOST_ASIO_DETAIL_REACTOR_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_HAS_IOCP) || defined(BOOST_ASIO_WINDOWS_RUNTIME) +typedef class null_reactor reactor; +#elif defined(BOOST_ASIO_HAS_IOCP) +typedef class select_reactor reactor; +#elif defined(BOOST_ASIO_HAS_EPOLL) +typedef class epoll_reactor reactor; +#elif defined(BOOST_ASIO_HAS_KQUEUE) +typedef class kqueue_reactor reactor; +#elif defined(BOOST_ASIO_HAS_DEV_POLL) +typedef class dev_poll_reactor reactor; +#else +typedef class select_reactor reactor; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_REACTOR_FWD_HPP diff --git a/boost/asio/detail/reactor_op.hpp b/boost/asio/detail/reactor_op.hpp new file mode 100644 index 0000000..4c399a5 --- /dev/null +++ b/boost/asio/detail/reactor_op.hpp @@ -0,0 +1,67 @@ +// +// detail/reactor_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTOR_OP_HPP +#define BOOST_ASIO_DETAIL_REACTOR_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class reactor_op + : public operation +{ +public: + // The error code to be passed to the completion handler. + boost::system::error_code ec_; + + // The number of bytes transferred, to be passed to the completion handler. + std::size_t bytes_transferred_; + + // Status returned by perform function. May be used to decide whether it is + // worth performing more operations on the descriptor immediately. + enum status { not_done, done, done_and_exhausted }; + + // Perform the operation. Returns true if it is finished. + status perform() + { + return perform_func_(this); + } + +protected: + typedef status (*perform_func_type)(reactor_op*); + + reactor_op(perform_func_type perform_func, func_type complete_func) + : operation(complete_func), + bytes_transferred_(0), + perform_func_(perform_func) + { + } + +private: + perform_func_type perform_func_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTOR_OP_HPP diff --git a/boost/asio/detail/reactor_op_queue.hpp b/boost/asio/detail/reactor_op_queue.hpp new file mode 100644 index 0000000..dd28b6d --- /dev/null +++ b/boost/asio/detail/reactor_op_queue.hpp @@ -0,0 +1,170 @@ +// +// detail/reactor_op_queue.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REACTOR_OP_QUEUE_HPP +#define BOOST_ASIO_DETAIL_REACTOR_OP_QUEUE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class reactor_op_queue + : private noncopyable +{ +public: + typedef Descriptor key_type; + + struct mapped_type : op_queue + { + mapped_type() {} + mapped_type(const mapped_type&) {} + void operator=(const mapped_type&) {} + }; + + typedef typename hash_map::value_type value_type; + typedef typename hash_map::iterator iterator; + + // Constructor. + reactor_op_queue() + : operations_() + { + } + + // Obtain iterators to all registered descriptors. + iterator begin() { return operations_.begin(); } + iterator end() { return operations_.end(); } + + // Add a new operation to the queue. Returns true if this is the only + // operation for the given descriptor, in which case the reactor's event + // demultiplexing function call may need to be interrupted and restarted. + bool enqueue_operation(Descriptor descriptor, reactor_op* op) + { + std::pair entry = + operations_.insert(value_type(descriptor, mapped_type())); + entry.first->second.push(op); + return entry.second; + } + + // Cancel all operations associated with the descriptor identified by the + // supplied iterator. Any operations pending for the descriptor will be + // cancelled. Returns true if any operations were cancelled, in which case + // the reactor's event demultiplexing function may need to be interrupted and + // restarted. + bool cancel_operations(iterator i, op_queue& ops, + const boost::system::error_code& ec = + boost::asio::error::operation_aborted) + { + if (i != operations_.end()) + { + while (reactor_op* op = i->second.front()) + { + op->ec_ = ec; + i->second.pop(); + ops.push(op); + } + operations_.erase(i); + return true; + } + + return false; + } + + // Cancel all operations associated with the descriptor. Any operations + // pending for the descriptor will be cancelled. Returns true if any + // operations were cancelled, in which case the reactor's event + // demultiplexing function may need to be interrupted and restarted. + bool cancel_operations(Descriptor descriptor, op_queue& ops, + const boost::system::error_code& ec = + boost::asio::error::operation_aborted) + { + return this->cancel_operations(operations_.find(descriptor), ops, ec); + } + + // Whether there are no operations in the queue. + bool empty() const + { + return operations_.empty(); + } + + // Determine whether there are any operations associated with the descriptor. + bool has_operation(Descriptor descriptor) const + { + return operations_.find(descriptor) != operations_.end(); + } + + // Perform the operations corresponding to the descriptor identified by the + // supplied iterator. Returns true if there are still unfinished operations + // queued for the descriptor. + bool perform_operations(iterator i, op_queue& ops) + { + if (i != operations_.end()) + { + while (reactor_op* op = i->second.front()) + { + if (op->perform()) + { + i->second.pop(); + ops.push(op); + } + else + { + return true; + } + } + operations_.erase(i); + } + return false; + } + + // Perform the operations corresponding to the descriptor. Returns true if + // there are still unfinished operations queued for the descriptor. + bool perform_operations(Descriptor descriptor, op_queue& ops) + { + return this->perform_operations(operations_.find(descriptor), ops); + } + + // Get all operations owned by the queue. + void get_all_operations(op_queue& ops) + { + iterator i = operations_.begin(); + while (i != operations_.end()) + { + iterator op_iter = i++; + ops.push(op_iter->second); + operations_.erase(op_iter); + } + } + +private: + // The operations that are currently executing asynchronously. + hash_map operations_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_REACTOR_OP_QUEUE_HPP diff --git a/boost/asio/detail/recycling_allocator.hpp b/boost/asio/detail/recycling_allocator.hpp new file mode 100644 index 0000000..74003bf --- /dev/null +++ b/boost/asio/detail/recycling_allocator.hpp @@ -0,0 +1,108 @@ +// +// detail/recycling_allocator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP +#define BOOST_ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class recycling_allocator +{ +public: + typedef T value_type; + + template + struct rebind + { + typedef recycling_allocator other; + }; + + recycling_allocator() + { + } + + template + recycling_allocator(const recycling_allocator&) + { + } + + T* allocate(std::size_t n) + { + typedef thread_context::thread_call_stack call_stack; + void* p = thread_info_base::allocate(Purpose(), + call_stack::top(), sizeof(T) * n); + return static_cast(p); + } + + void deallocate(T* p, std::size_t n) + { + typedef thread_context::thread_call_stack call_stack; + thread_info_base::deallocate(Purpose(), + call_stack::top(), p, sizeof(T) * n); + } +}; + +template +class recycling_allocator +{ +public: + typedef void value_type; + + template + struct rebind + { + typedef recycling_allocator other; + }; + + recycling_allocator() + { + } + + template + recycling_allocator(const recycling_allocator&) + { + } +}; + +template +struct get_recycling_allocator +{ + typedef Allocator type; + static type get(const Allocator& a) { return a; } +}; + +template +struct get_recycling_allocator, Purpose> +{ + typedef recycling_allocator type; + static type get(const std::allocator&) { return type(); } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP diff --git a/boost/asio/detail/regex_fwd.hpp b/boost/asio/detail/regex_fwd.hpp new file mode 100644 index 0000000..a2dd26d --- /dev/null +++ b/boost/asio/detail/regex_fwd.hpp @@ -0,0 +1,35 @@ +// +// detail/regex_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_REGEX_FWD_HPP +#define BOOST_ASIO_DETAIL_REGEX_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if defined(BOOST_ASIO_HAS_BOOST_REGEX) + +#include +#include + +namespace boost { + +template +struct sub_match; + +template +class match_results; + +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) + +#endif // BOOST_ASIO_DETAIL_REGEX_FWD_HPP diff --git a/boost/asio/detail/resolve_endpoint_op.hpp b/boost/asio/detail/resolve_endpoint_op.hpp new file mode 100644 index 0000000..72df8d9 --- /dev/null +++ b/boost/asio/detail/resolve_endpoint_op.hpp @@ -0,0 +1,138 @@ +// +// detail/resolve_endpoint_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP +#define BOOST_ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#else // defined(BOOST_ASIO_HAS_IOCP) +# include +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class resolve_endpoint_op : public resolve_op +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(resolve_endpoint_op); + + typedef typename Protocol::endpoint endpoint_type; + typedef boost::asio::ip::basic_resolver_results results_type; + +#if defined(BOOST_ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + + resolve_endpoint_op(socket_ops::weak_cancel_token_type cancel_token, + const endpoint_type& endpoint, scheduler_impl& sched, + Handler& handler, const IoExecutor& io_ex) + : resolve_op(&resolve_endpoint_op::do_complete), + cancel_token_(cancel_token), + endpoint_(endpoint), + scheduler_(sched), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the operation object. + resolve_endpoint_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + if (owner && owner != &o->scheduler_) + { + // The operation is being run on the worker io_context. Time to perform + // the resolver operation. + + // Perform the blocking endpoint resolution operation. + char host_name[NI_MAXHOST]; + char service_name[NI_MAXSERV]; + socket_ops::background_getnameinfo(o->cancel_token_, o->endpoint_.data(), + o->endpoint_.size(), host_name, NI_MAXHOST, service_name, NI_MAXSERV, + o->endpoint_.protocol().type(), o->ec_); + o->results_ = results_type::create(o->endpoint_, host_name, service_name); + + // Pass operation back to main io_context for completion. + o->scheduler_.post_deferred_completion(o); + p.v = p.p = 0; + } + else + { + // The operation has been returned to the main io_context. The completion + // handler is ready to be delivered. + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an upcall, + // a sub-object of the handler may be the true owner of the memory + // associated with the handler. Consequently, a local copy of the handler + // is required to ensure that any owning sub-object remains valid until + // after we have deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, o->results_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + endpoint_type endpoint_; + scheduler_impl& scheduler_; + Handler handler_; + IoExecutor io_executor_; + results_type results_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP diff --git a/boost/asio/detail/resolve_op.hpp b/boost/asio/detail/resolve_op.hpp new file mode 100644 index 0000000..2be7b19 --- /dev/null +++ b/boost/asio/detail/resolve_op.hpp @@ -0,0 +1,47 @@ +// +// detail/resolve_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_RESOLVE_OP_HPP +#define BOOST_ASIO_DETAIL_RESOLVE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class resolve_op : public operation +{ +public: + // The error code to be passed to the completion handler. + boost::system::error_code ec_; + +protected: + resolve_op(func_type complete_func) + : operation(complete_func) + { + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_RESOLVE_OP_HPP diff --git a/boost/asio/detail/resolve_query_op.hpp b/boost/asio/detail/resolve_query_op.hpp new file mode 100644 index 0000000..11d5989 --- /dev/null +++ b/boost/asio/detail/resolve_query_op.hpp @@ -0,0 +1,150 @@ +// +// detail/resolve_query_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_RESOLVE_QUERY_OP_HPP +#define BOOST_ASIO_DETAIL_RESOLVE_QUERY_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#else // defined(BOOST_ASIO_HAS_IOCP) +# include +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class resolve_query_op : public resolve_op +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(resolve_query_op); + + typedef boost::asio::ip::basic_resolver_query query_type; + typedef boost::asio::ip::basic_resolver_results results_type; + +#if defined(BOOST_ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + + resolve_query_op(socket_ops::weak_cancel_token_type cancel_token, + const query_type& query, scheduler_impl& sched, + Handler& handler, const IoExecutor& io_ex) + : resolve_op(&resolve_query_op::do_complete), + cancel_token_(cancel_token), + query_(query), + scheduler_(sched), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex), + addrinfo_(0) + { + handler_work::start(handler_, io_executor_); + } + + ~resolve_query_op() + { + if (addrinfo_) + socket_ops::freeaddrinfo(addrinfo_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the operation object. + resolve_query_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + + if (owner && owner != &o->scheduler_) + { + // The operation is being run on the worker io_context. Time to perform + // the resolver operation. + + // Perform the blocking host resolution operation. + socket_ops::background_getaddrinfo(o->cancel_token_, + o->query_.host_name().c_str(), o->query_.service_name().c_str(), + o->query_.hints(), &o->addrinfo_, o->ec_); + + // Pass operation back to main io_context for completion. + o->scheduler_.post_deferred_completion(o); + p.v = p.p = 0; + } + else + { + // The operation has been returned to the main io_context. The completion + // handler is ready to be delivered. + + // Take ownership of the operation's outstanding work. + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated + // before the upcall is made. Even if we're not about to make an upcall, + // a sub-object of the handler may be the true owner of the memory + // associated with the handler. Consequently, a local copy of the handler + // is required to ensure that any owning sub-object remains valid until + // after we have deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, results_type()); + p.h = boost::asio::detail::addressof(handler.handler_); + if (o->addrinfo_) + { + handler.arg2_ = results_type::create(o->addrinfo_, + o->query_.host_name(), o->query_.service_name()); + } + p.reset(); + + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + query_type query_; + scheduler_impl& scheduler_; + Handler handler_; + IoExecutor io_executor_; + boost::asio::detail::addrinfo_type* addrinfo_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_RESOLVE_QUERY_OP_HPP diff --git a/boost/asio/detail/resolver_service.hpp b/boost/asio/detail/resolver_service.hpp new file mode 100644 index 0000000..744b75c --- /dev/null +++ b/boost/asio/detail/resolver_service.hpp @@ -0,0 +1,147 @@ +// +// detail/resolver_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_RESOLVER_SERVICE_HPP +#define BOOST_ASIO_DETAIL_RESOLVER_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class resolver_service : + public execution_context_service_base >, + public resolver_service_base +{ +public: + // The implementation type of the resolver. A cancellation token is used to + // indicate to the background thread that the operation has been cancelled. + typedef socket_ops::shared_cancel_token_type implementation_type; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The query type. + typedef boost::asio::ip::basic_resolver_query query_type; + + // The results type. + typedef boost::asio::ip::basic_resolver_results results_type; + + // Constructor. + resolver_service(execution_context& context) + : execution_context_service_base >(context), + resolver_service_base(context) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + this->base_shutdown(); + } + + // Perform any fork-related housekeeping. + void notify_fork(execution_context::fork_event fork_ev) + { + this->base_notify_fork(fork_ev); + } + + // Resolve a query to a list of entries. + results_type resolve(implementation_type&, const query_type& query, + boost::system::error_code& ec) + { + boost::asio::detail::addrinfo_type* address_info = 0; + + socket_ops::getaddrinfo(query.host_name().c_str(), + query.service_name().c_str(), query.hints(), &address_info, ec); + auto_addrinfo auto_address_info(address_info); + + return ec ? results_type() : results_type::create( + address_info, query.host_name(), query.service_name()); + } + + // Asynchronously resolve a query to a list of entries. + template + void async_resolve(implementation_type& impl, const query_type& query, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef resolve_query_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl, query, scheduler_, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((scheduler_.context(), + *p.p, "resolver", &impl, 0, "async_resolve")); + + start_resolve_op(p.p); + p.v = p.p = 0; + } + + // Resolve an endpoint to a list of entries. + results_type resolve(implementation_type&, + const endpoint_type& endpoint, boost::system::error_code& ec) + { + char host_name[NI_MAXHOST]; + char service_name[NI_MAXSERV]; + socket_ops::sync_getnameinfo(endpoint.data(), endpoint.size(), + host_name, NI_MAXHOST, service_name, NI_MAXSERV, + endpoint.protocol().type(), ec); + + return ec ? results_type() : results_type::create( + endpoint, host_name, service_name); + } + + // Asynchronously resolve an endpoint to a list of entries. + template + void async_resolve(implementation_type& impl, const endpoint_type& endpoint, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef resolve_endpoint_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl, endpoint, scheduler_, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((scheduler_.context(), + *p.p, "resolver", &impl, 0, "async_resolve")); + + start_resolve_op(p.p); + p.v = p.p = 0; + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#endif // BOOST_ASIO_DETAIL_RESOLVER_SERVICE_HPP diff --git a/boost/asio/detail/resolver_service_base.hpp b/boost/asio/detail/resolver_service_base.hpp new file mode 100644 index 0000000..8e1ff5b --- /dev/null +++ b/boost/asio/detail/resolver_service_base.hpp @@ -0,0 +1,145 @@ +// +// detail/resolver_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP +#define BOOST_ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#else // defined(BOOST_ASIO_HAS_IOCP) +# include +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#include + +namespace boost { +namespace asio { +namespace detail { + +class resolver_service_base +{ +public: + // The implementation type of the resolver. A cancellation token is used to + // indicate to the background thread that the operation has been cancelled. + typedef socket_ops::shared_cancel_token_type implementation_type; + + // Constructor. + BOOST_ASIO_DECL resolver_service_base(execution_context& context); + + // Destructor. + BOOST_ASIO_DECL ~resolver_service_base(); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void base_shutdown(); + + // Perform any fork-related housekeeping. + BOOST_ASIO_DECL void base_notify_fork( + execution_context::fork_event fork_ev); + + // Construct a new resolver implementation. + BOOST_ASIO_DECL void construct(implementation_type& impl); + + // Destroy a resolver implementation. + BOOST_ASIO_DECL void destroy(implementation_type&); + + // Move-construct a new resolver implementation. + BOOST_ASIO_DECL void move_construct(implementation_type& impl, + implementation_type& other_impl); + + // Move-assign from another resolver implementation. + BOOST_ASIO_DECL void move_assign(implementation_type& impl, + resolver_service_base& other_service, + implementation_type& other_impl); + + // Cancel pending asynchronous operations. + BOOST_ASIO_DECL void cancel(implementation_type& impl); + +protected: + // Helper function to start an asynchronous resolve operation. + BOOST_ASIO_DECL void start_resolve_op(resolve_op* op); + +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // Helper class to perform exception-safe cleanup of addrinfo objects. + class auto_addrinfo + : private boost::asio::detail::noncopyable + { + public: + explicit auto_addrinfo(boost::asio::detail::addrinfo_type* ai) + : ai_(ai) + { + } + + ~auto_addrinfo() + { + if (ai_) + socket_ops::freeaddrinfo(ai_); + } + + operator boost::asio::detail::addrinfo_type*() + { + return ai_; + } + + private: + boost::asio::detail::addrinfo_type* ai_; + }; +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + + // Helper class to run the work scheduler in a thread. + class work_scheduler_runner; + + // Start the work scheduler if it's not already running. + BOOST_ASIO_DECL void start_work_thread(); + + // The scheduler implementation used to post completions. +#if defined(BOOST_ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; + +private: + // Mutex to protect access to internal data. + boost::asio::detail::mutex mutex_; + + // Private scheduler used for performing asynchronous host resolution. + boost::asio::detail::scoped_ptr work_scheduler_; + + // Thread used for running the work io_context's run loop. + boost::asio::detail::scoped_ptr work_thread_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP diff --git a/boost/asio/detail/scheduler.hpp b/boost/asio/detail/scheduler.hpp new file mode 100644 index 0000000..e386181 --- /dev/null +++ b/boost/asio/detail/scheduler.hpp @@ -0,0 +1,226 @@ +// +// detail/scheduler.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SCHEDULER_HPP +#define BOOST_ASIO_DETAIL_SCHEDULER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct scheduler_thread_info; + +class scheduler + : public execution_context_service_base, + public thread_context +{ +public: + typedef scheduler_operation operation; + + // Constructor. Specifies the number of concurrent threads that are likely to + // run the scheduler. If set to 1 certain optimisation are performed. + BOOST_ASIO_DECL scheduler(boost::asio::execution_context& ctx, + int concurrency_hint = 0, bool own_thread = true); + + // Destructor. + BOOST_ASIO_DECL ~scheduler(); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown(); + + // Initialise the task, if required. + BOOST_ASIO_DECL void init_task(); + + // Run the event loop until interrupted or no more work. + BOOST_ASIO_DECL std::size_t run(boost::system::error_code& ec); + + // Run until interrupted or one operation is performed. + BOOST_ASIO_DECL std::size_t run_one(boost::system::error_code& ec); + + // Run until timeout, interrupted, or one operation is performed. + BOOST_ASIO_DECL std::size_t wait_one( + long usec, boost::system::error_code& ec); + + // Poll for operations without blocking. + BOOST_ASIO_DECL std::size_t poll(boost::system::error_code& ec); + + // Poll for one operation without blocking. + BOOST_ASIO_DECL std::size_t poll_one(boost::system::error_code& ec); + + // Interrupt the event processing loop. + BOOST_ASIO_DECL void stop(); + + // Determine whether the scheduler is stopped. + BOOST_ASIO_DECL bool stopped() const; + + // Restart in preparation for a subsequent run invocation. + BOOST_ASIO_DECL void restart(); + + // Notify that some work has started. + void work_started() + { + ++outstanding_work_; + } + + // Used to compensate for a forthcoming work_finished call. Must be called + // from within a scheduler-owned thread. + BOOST_ASIO_DECL void compensating_work_started(); + + // Notify that some work has finished. + void work_finished() + { + if (--outstanding_work_ == 0) + stop(); + } + + // Return whether a handler can be dispatched immediately. + bool can_dispatch() + { + return thread_call_stack::contains(this) != 0; + } + + // Request invocation of the given operation and return immediately. Assumes + // that work_started() has not yet been called for the operation. + BOOST_ASIO_DECL void post_immediate_completion( + operation* op, bool is_continuation); + + // Request invocation of the given operation and return immediately. Assumes + // that work_started() was previously called for the operation. + BOOST_ASIO_DECL void post_deferred_completion(operation* op); + + // Request invocation of the given operations and return immediately. Assumes + // that work_started() was previously called for each operation. + BOOST_ASIO_DECL void post_deferred_completions(op_queue& ops); + + // Enqueue the given operation following a failed attempt to dispatch the + // operation for immediate invocation. + BOOST_ASIO_DECL void do_dispatch(operation* op); + + // Process unfinished operations as part of a shutdownoperation. Assumes that + // work_started() was previously called for the operations. + BOOST_ASIO_DECL void abandon_operations(op_queue& ops); + + // Get the concurrency hint that was used to initialise the scheduler. + int concurrency_hint() const + { + return concurrency_hint_; + } + +private: + // The mutex type used by this scheduler. + typedef conditionally_enabled_mutex mutex; + + // The event type used by this scheduler. + typedef conditionally_enabled_event event; + + // Structure containing thread-specific data. + typedef scheduler_thread_info thread_info; + + // Run at most one operation. May block. + BOOST_ASIO_DECL std::size_t do_run_one(mutex::scoped_lock& lock, + thread_info& this_thread, const boost::system::error_code& ec); + + // Run at most one operation with a timeout. May block. + BOOST_ASIO_DECL std::size_t do_wait_one(mutex::scoped_lock& lock, + thread_info& this_thread, long usec, const boost::system::error_code& ec); + + // Poll for at most one operation. + BOOST_ASIO_DECL std::size_t do_poll_one(mutex::scoped_lock& lock, + thread_info& this_thread, const boost::system::error_code& ec); + + // Stop the task and all idle threads. + BOOST_ASIO_DECL void stop_all_threads(mutex::scoped_lock& lock); + + // Wake a single idle thread, or the task, and always unlock the mutex. + BOOST_ASIO_DECL void wake_one_thread_and_unlock( + mutex::scoped_lock& lock); + + // Helper class to run the scheduler in its own thread. + class thread_function; + friend class thread_function; + + // Helper class to perform task-related operations on block exit. + struct task_cleanup; + friend struct task_cleanup; + + // Helper class to call work-related operations on block exit. + struct work_cleanup; + friend struct work_cleanup; + + // Whether to optimise for single-threaded use cases. + const bool one_thread_; + + // Mutex to protect access to internal data. + mutable mutex mutex_; + + // Event to wake up blocked threads. + event wakeup_event_; + + // The task to be run by this service. + reactor* task_; + + // Operation object to represent the position of the task in the queue. + struct task_operation : operation + { + task_operation() : operation(0) {} + } task_operation_; + + // Whether the task has been interrupted. + bool task_interrupted_; + + // The count of unfinished work. + atomic_count outstanding_work_; + + // The queue of handlers that are ready to be delivered. + op_queue op_queue_; + + // Flag to indicate that the dispatcher has been stopped. + bool stopped_; + + // Flag to indicate that the dispatcher has been shut down. + bool shutdown_; + + // The concurrency hint used to initialise the scheduler. + const int concurrency_hint_; + + // The thread that is running the scheduler. + boost::asio::detail::thread* thread_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_DETAIL_SCHEDULER_HPP diff --git a/boost/asio/detail/scheduler_operation.hpp b/boost/asio/detail/scheduler_operation.hpp new file mode 100644 index 0000000..df6237f --- /dev/null +++ b/boost/asio/detail/scheduler_operation.hpp @@ -0,0 +1,80 @@ +// +// detail/scheduler_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SCHEDULER_OPERATION_HPP +#define BOOST_ASIO_DETAIL_SCHEDULER_OPERATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class scheduler; + +// Base class for all operations. A function pointer is used instead of virtual +// functions to avoid the associated overhead. +class scheduler_operation BOOST_ASIO_INHERIT_TRACKED_HANDLER +{ +public: + typedef scheduler_operation operation_type; + + void complete(void* owner, const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + func_(owner, this, ec, bytes_transferred); + } + + void destroy() + { + func_(0, this, boost::system::error_code(), 0); + } + +protected: + typedef void (*func_type)(void*, + scheduler_operation*, + const boost::system::error_code&, std::size_t); + + scheduler_operation(func_type func) + : next_(0), + func_(func), + task_result_(0) + { + } + + // Prevents deletion through this type. + ~scheduler_operation() + { + } + +private: + friend class op_queue_access; + scheduler_operation* next_; + func_type func_; +protected: + friend class scheduler; + unsigned int task_result_; // Passed into bytes transferred. +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SCHEDULER_OPERATION_HPP diff --git a/boost/asio/detail/scheduler_thread_info.hpp b/boost/asio/detail/scheduler_thread_info.hpp new file mode 100644 index 0000000..f9b556a --- /dev/null +++ b/boost/asio/detail/scheduler_thread_info.hpp @@ -0,0 +1,42 @@ +// +// detail/scheduler_thread_info.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP +#define BOOST_ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class scheduler; +class scheduler_operation; + +struct scheduler_thread_info : public thread_info_base +{ + op_queue private_op_queue; + long private_outstanding_work; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP diff --git a/boost/asio/detail/scoped_lock.hpp b/boost/asio/detail/scoped_lock.hpp new file mode 100644 index 0000000..7423929 --- /dev/null +++ b/boost/asio/detail/scoped_lock.hpp @@ -0,0 +1,103 @@ +// +// detail/scoped_lock.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SCOPED_LOCK_HPP +#define BOOST_ASIO_DETAIL_SCOPED_LOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Helper class to lock and unlock a mutex automatically. +template +class scoped_lock + : private noncopyable +{ +public: + // Tag type used to distinguish constructors. + enum adopt_lock_t { adopt_lock }; + + // Constructor adopts a lock that is already held. + scoped_lock(Mutex& m, adopt_lock_t) + : mutex_(m), + locked_(true) + { + } + + // Constructor acquires the lock. + explicit scoped_lock(Mutex& m) + : mutex_(m) + { + mutex_.lock(); + locked_ = true; + } + + // Destructor releases the lock. + ~scoped_lock() + { + if (locked_) + mutex_.unlock(); + } + + // Explicitly acquire the lock. + void lock() + { + if (!locked_) + { + mutex_.lock(); + locked_ = true; + } + } + + // Explicitly release the lock. + void unlock() + { + if (locked_) + { + mutex_.unlock(); + locked_ = false; + } + } + + // Test whether the lock is held. + bool locked() const + { + return locked_; + } + + // Get the underlying mutex. + Mutex& mutex() + { + return mutex_; + } + +private: + // The underlying mutex. + Mutex& mutex_; + + // Whether the mutex is currently locked or unlocked. + bool locked_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SCOPED_LOCK_HPP diff --git a/boost/asio/detail/scoped_ptr.hpp b/boost/asio/detail/scoped_ptr.hpp new file mode 100644 index 0000000..707be72 --- /dev/null +++ b/boost/asio/detail/scoped_ptr.hpp @@ -0,0 +1,89 @@ +// +// detail/scoped_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SCOPED_PTR_HPP +#define BOOST_ASIO_DETAIL_SCOPED_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class scoped_ptr +{ +public: + // Constructor. + explicit scoped_ptr(T* p = 0) + : p_(p) + { + } + + // Destructor. + ~scoped_ptr() + { + delete p_; + } + + // Access. + T* get() + { + return p_; + } + + // Access. + T* operator->() + { + return p_; + } + + // Dereference. + T& operator*() + { + return *p_; + } + + // Reset pointer. + void reset(T* p = 0) + { + delete p_; + p_ = p; + } + + // Release ownership of the pointer. + T* release() + { + T* tmp = p_; + p_ = 0; + return tmp; + } + +private: + // Disallow copying and assignment. + scoped_ptr(const scoped_ptr&); + scoped_ptr& operator=(const scoped_ptr&); + + T* p_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SCOPED_PTR_HPP diff --git a/boost/asio/detail/select_interrupter.hpp b/boost/asio/detail/select_interrupter.hpp new file mode 100644 index 0000000..0c2dd91 --- /dev/null +++ b/boost/asio/detail/select_interrupter.hpp @@ -0,0 +1,48 @@ +// +// detail/select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SELECT_INTERRUPTER_HPP +#define BOOST_ASIO_DETAIL_SELECT_INTERRUPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__) +# include +#elif defined(BOOST_ASIO_HAS_EVENTFD) +# include +#else +# include +#endif + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__) +typedef socket_select_interrupter select_interrupter; +#elif defined(BOOST_ASIO_HAS_EVENTFD) +typedef eventfd_select_interrupter select_interrupter; +#else +typedef pipe_select_interrupter select_interrupter; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#endif // BOOST_ASIO_DETAIL_SELECT_INTERRUPTER_HPP diff --git a/boost/asio/detail/select_reactor.hpp b/boost/asio/detail/select_reactor.hpp new file mode 100644 index 0000000..435ce04 --- /dev/null +++ b/boost/asio/detail/select_reactor.hpp @@ -0,0 +1,240 @@ +// +// detail/select_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SELECT_REACTOR_HPP +#define BOOST_ASIO_DETAIL_SELECT_REACTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) \ + || (!defined(BOOST_ASIO_HAS_DEV_POLL) \ + && !defined(BOOST_ASIO_HAS_EPOLL) \ + && !defined(BOOST_ASIO_HAS_KQUEUE) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME)) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#include + +namespace boost { +namespace asio { +namespace detail { + +class select_reactor + : public execution_context_service_base +{ +public: +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + enum op_types { read_op = 0, write_op = 1, except_op = 2, + max_select_ops = 3, connect_op = 3, max_ops = 4 }; +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + enum op_types { read_op = 0, write_op = 1, except_op = 2, + max_select_ops = 3, connect_op = 1, max_ops = 3 }; +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + + // Per-descriptor data. + struct per_descriptor_data + { + }; + + // Constructor. + BOOST_ASIO_DECL select_reactor(boost::asio::execution_context& ctx); + + // Destructor. + BOOST_ASIO_DECL ~select_reactor(); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown(); + + // Recreate internal descriptors following a fork. + BOOST_ASIO_DECL void notify_fork( + boost::asio::execution_context::fork_event fork_ev); + + // Initialise the task, but only if the reactor is not in its own thread. + BOOST_ASIO_DECL void init_task(); + + // Register a socket with the reactor. Returns 0 on success, system error + // code on failure. + BOOST_ASIO_DECL int register_descriptor(socket_type, per_descriptor_data&); + + // Register a descriptor with an associated single operation. Returns 0 on + // success, system error code on failure. + BOOST_ASIO_DECL int register_internal_descriptor( + int op_type, socket_type descriptor, + per_descriptor_data& descriptor_data, reactor_op* op); + + // Post a reactor operation for immediate completion. + void post_immediate_completion(reactor_op* op, bool is_continuation) + { + scheduler_.post_immediate_completion(op, is_continuation); + } + + // Start a new operation. The reactor operation will be performed when the + // given descriptor is flagged as ready, or an error has occurred. + BOOST_ASIO_DECL void start_op(int op_type, socket_type descriptor, + per_descriptor_data&, reactor_op* op, bool is_continuation, bool); + + // Cancel all operations associated with the given descriptor. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + BOOST_ASIO_DECL void cancel_ops(socket_type descriptor, per_descriptor_data&); + + // Cancel any operations that are running against the descriptor and remove + // its registration from the reactor. The reactor resources associated with + // the descriptor must be released by calling cleanup_descriptor_data. + BOOST_ASIO_DECL void deregister_descriptor(socket_type descriptor, + per_descriptor_data&, bool closing); + + // Remove the descriptor's registration from the reactor. The reactor + // resources associated with the descriptor must be released by calling + // cleanup_descriptor_data. + BOOST_ASIO_DECL void deregister_internal_descriptor( + socket_type descriptor, per_descriptor_data&); + + // Perform any post-deregistration cleanup tasks associated with the + // descriptor data. + BOOST_ASIO_DECL void cleanup_descriptor_data(per_descriptor_data&); + + // Move descriptor registration from one descriptor_data object to another. + BOOST_ASIO_DECL void move_descriptor(socket_type descriptor, + per_descriptor_data& target_descriptor_data, + per_descriptor_data& source_descriptor_data); + + // Add a new timer queue to the reactor. + template + void add_timer_queue(timer_queue& queue); + + // Remove a timer queue from the reactor. + template + void remove_timer_queue(timer_queue& queue); + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template + void schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op); + + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. + template + std::size_t cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled = (std::numeric_limits::max)()); + + // Move the timer operations associated with the given timer. + template + void move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& target, + typename timer_queue::per_timer_data& source); + + // Run select once until interrupted or events are ready to be dispatched. + BOOST_ASIO_DECL void run(long usec, op_queue& ops); + + // Interrupt the select loop. + BOOST_ASIO_DECL void interrupt(); + +private: +#if defined(BOOST_ASIO_HAS_IOCP) + // Run the select loop in the thread. + BOOST_ASIO_DECL void run_thread(); +#endif // defined(BOOST_ASIO_HAS_IOCP) + + // Helper function to add a new timer queue. + BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // Get the timeout value for the select call. + BOOST_ASIO_DECL timeval* get_timeout(long usec, timeval& tv); + + // Cancel all operations associated with the given descriptor. This function + // does not acquire the select_reactor's mutex. + BOOST_ASIO_DECL void cancel_ops_unlocked(socket_type descriptor, + const boost::system::error_code& ec); + + // The scheduler implementation used to post completions. +# if defined(BOOST_ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_type; +# else // defined(BOOST_ASIO_HAS_IOCP) + typedef class scheduler scheduler_type; +# endif // defined(BOOST_ASIO_HAS_IOCP) + scheduler_type& scheduler_; + + // Mutex to protect access to internal data. + boost::asio::detail::mutex mutex_; + + // The interrupter is used to break a blocking select call. + select_interrupter interrupter_; + + // The queues of read, write and except operations. + reactor_op_queue op_queue_[max_ops]; + + // The file descriptor sets to be passed to the select system call. + fd_set_adapter fd_sets_[max_select_ops]; + + // The timer queues. + timer_queue_set timer_queues_; + +#if defined(BOOST_ASIO_HAS_IOCP) + // Helper class to run the reactor loop in a thread. + class thread_function; + friend class thread_function; + + // Does the reactor loop thread need to stop. + bool stop_thread_; + + // The thread that is running the reactor loop. + boost::asio::detail::thread* thread_; +#endif // defined(BOOST_ASIO_HAS_IOCP) + + // Whether the service has been shut down. + bool shutdown_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_IOCP) + // || (!defined(BOOST_ASIO_HAS_DEV_POLL) + // && !defined(BOOST_ASIO_HAS_EPOLL) + // && !defined(BOOST_ASIO_HAS_KQUEUE) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME)) + +#endif // BOOST_ASIO_DETAIL_SELECT_REACTOR_HPP diff --git a/boost/asio/detail/service_registry.hpp b/boost/asio/detail/service_registry.hpp new file mode 100644 index 0000000..35140ef --- /dev/null +++ b/boost/asio/detail/service_registry.hpp @@ -0,0 +1,166 @@ +// +// detail/service_registry.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SERVICE_REGISTRY_HPP +#define BOOST_ASIO_DETAIL_SERVICE_REGISTRY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +class io_context; + +namespace detail { + +template +class typeid_wrapper {}; + +class service_registry + : private noncopyable +{ +public: + // Constructor. + BOOST_ASIO_DECL service_registry(execution_context& owner); + + // Destructor. + BOOST_ASIO_DECL ~service_registry(); + + // Shutdown all services. + BOOST_ASIO_DECL void shutdown_services(); + + // Destroy all services. + BOOST_ASIO_DECL void destroy_services(); + + // Notify all services of a fork event. + BOOST_ASIO_DECL void notify_fork(execution_context::fork_event fork_ev); + + // Get the service object corresponding to the specified service type. Will + // create a new service object automatically if no such object already + // exists. Ownership of the service object is not transferred to the caller. + template + Service& use_service(); + + // Get the service object corresponding to the specified service type. Will + // create a new service object automatically if no such object already + // exists. Ownership of the service object is not transferred to the caller. + // This overload is used for backwards compatibility with services that + // inherit from io_context::service. + template + Service& use_service(io_context& owner); + + // Add a service object. Throws on error, in which case ownership of the + // object is retained by the caller. + template + void add_service(Service* new_service); + + // Check whether a service object of the specified type already exists. + template + bool has_service() const; + +private: + // Initalise a service's key when the key_type typedef is not available. + template + static void init_key(execution_context::service::key& key, ...); + +#if !defined(BOOST_ASIO_NO_TYPEID) + // Initalise a service's key when the key_type typedef is available. + template + static void init_key(execution_context::service::key& key, + typename enable_if< + is_base_of::value>::type*); +#endif // !defined(BOOST_ASIO_NO_TYPEID) + + // Initialise a service's key based on its id. + BOOST_ASIO_DECL static void init_key_from_id( + execution_context::service::key& key, + const execution_context::id& id); + +#if !defined(BOOST_ASIO_NO_TYPEID) + // Initialise a service's key based on its id. + template + static void init_key_from_id(execution_context::service::key& key, + const service_id& /*id*/); +#endif // !defined(BOOST_ASIO_NO_TYPEID) + + // Check if a service matches the given id. + BOOST_ASIO_DECL static bool keys_match( + const execution_context::service::key& key1, + const execution_context::service::key& key2); + + // The type of a factory function used for creating a service instance. + typedef execution_context::service*(*factory_type)(void*); + + // Factory function for creating a service instance. + template + static execution_context::service* create(void* owner); + + // Destroy a service instance. + BOOST_ASIO_DECL static void destroy(execution_context::service* service); + + // Helper class to manage service pointers. + struct auto_service_ptr; + friend struct auto_service_ptr; + struct auto_service_ptr + { + execution_context::service* ptr_; + ~auto_service_ptr() { destroy(ptr_); } + }; + + // Get the service object corresponding to the specified service key. Will + // create a new service object automatically if no such object already + // exists. Ownership of the service object is not transferred to the caller. + BOOST_ASIO_DECL execution_context::service* do_use_service( + const execution_context::service::key& key, + factory_type factory, void* owner); + + // Add a service object. Throws on error, in which case ownership of the + // object is retained by the caller. + BOOST_ASIO_DECL void do_add_service( + const execution_context::service::key& key, + execution_context::service* new_service); + + // Check whether a service object with the specified key already exists. + BOOST_ASIO_DECL bool do_has_service( + const execution_context::service::key& key) const; + + // Mutex to protect access to internal data. + mutable boost::asio::detail::mutex mutex_; + + // The owner of this service registry and the services it contains. + execution_context& owner_; + + // The first service in the list of contained services. + execution_context::service* first_service_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_DETAIL_SERVICE_REGISTRY_HPP diff --git a/boost/asio/detail/signal_blocker.hpp b/boost/asio/detail/signal_blocker.hpp new file mode 100644 index 0000000..9f5b6f5 --- /dev/null +++ b/boost/asio/detail/signal_blocker.hpp @@ -0,0 +1,46 @@ +// +// detail/signal_blocker.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SIGNAL_BLOCKER_HPP +#define BOOST_ASIO_DETAIL_SIGNAL_BLOCKER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_THREADS) || defined(BOOST_ASIO_WINDOWS) \ + || defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + || defined(__CYGWIN__) || defined(__SYMBIAN32__) +# include +#elif defined(BOOST_ASIO_HAS_PTHREADS) +# include +#else +# error Only Windows and POSIX are supported! +#endif + +namespace boost { +namespace asio { +namespace detail { + +#if !defined(BOOST_ASIO_HAS_THREADS) || defined(BOOST_ASIO_WINDOWS) \ + || defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + || defined(__CYGWIN__) || defined(__SYMBIAN32__) +typedef null_signal_blocker signal_blocker; +#elif defined(BOOST_ASIO_HAS_PTHREADS) +typedef posix_signal_blocker signal_blocker; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_SIGNAL_BLOCKER_HPP diff --git a/boost/asio/detail/signal_handler.hpp b/boost/asio/detail/signal_handler.hpp new file mode 100644 index 0000000..3796c3b --- /dev/null +++ b/boost/asio/detail/signal_handler.hpp @@ -0,0 +1,90 @@ +// +// detail/signal_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SIGNAL_HANDLER_HPP +#define BOOST_ASIO_DETAIL_SIGNAL_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class signal_handler : public signal_op +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(signal_handler); + + signal_handler(Handler& h, const IoExecutor& io_ex) + : signal_op(&signal_handler::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(h)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + signal_handler* h(static_cast(base)); + ptr p = { boost::asio::detail::addressof(h->handler_), h, h }; + handler_work w(h->handler_, h->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*h)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(h->handler_, h->ec_, h->signal_number_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SIGNAL_HANDLER_HPP diff --git a/boost/asio/detail/signal_init.hpp b/boost/asio/detail/signal_init.hpp new file mode 100644 index 0000000..9fb87e5 --- /dev/null +++ b/boost/asio/detail/signal_init.hpp @@ -0,0 +1,49 @@ +// +// detail/signal_init.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SIGNAL_INIT_HPP +#define BOOST_ASIO_DETAIL_SIGNAL_INIT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class signal_init +{ +public: + // Constructor. + signal_init() + { + std::signal(Signal, SIG_IGN); + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_SIGNAL_INIT_HPP diff --git a/boost/asio/detail/signal_op.hpp b/boost/asio/detail/signal_op.hpp new file mode 100644 index 0000000..d7719f4 --- /dev/null +++ b/boost/asio/detail/signal_op.hpp @@ -0,0 +1,51 @@ +// +// detail/signal_op.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SIGNAL_OP_HPP +#define BOOST_ASIO_DETAIL_SIGNAL_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class signal_op + : public operation +{ +public: + // The error code to be passed to the completion handler. + boost::system::error_code ec_; + + // The signal number to be passed to the completion handler. + int signal_number_; + +protected: + signal_op(func_type func) + : operation(func), + signal_number_(0) + { + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SIGNAL_OP_HPP diff --git a/boost/asio/detail/signal_set_service.hpp b/boost/asio/detail/signal_set_service.hpp new file mode 100644 index 0000000..baaf856 --- /dev/null +++ b/boost/asio/detail/signal_set_service.hpp @@ -0,0 +1,231 @@ +// +// detail/signal_set_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP +#define BOOST_ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#else // defined(BOOST_ASIO_HAS_IOCP) +# include +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) +# include +#endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + +#include + +namespace boost { +namespace asio { +namespace detail { + +#if defined(NSIG) && (NSIG > 0) +enum { max_signal_number = NSIG }; +#else +enum { max_signal_number = 128 }; +#endif + +extern BOOST_ASIO_DECL struct signal_state* get_signal_state(); + +extern "C" BOOST_ASIO_DECL void boost_asio_signal_handler(int signal_number); + +class signal_set_service : + public execution_context_service_base +{ +public: + // Type used for tracking an individual signal registration. + class registration + { + public: + // Default constructor. + registration() + : signal_number_(0), + queue_(0), + undelivered_(0), + next_in_table_(0), + prev_in_table_(0), + next_in_set_(0) + { + } + + private: + // Only this service will have access to the internal values. + friend class signal_set_service; + + // The signal number that is registered. + int signal_number_; + + // The waiting signal handlers. + op_queue* queue_; + + // The number of undelivered signals. + std::size_t undelivered_; + + // Pointers to adjacent registrations in the registrations_ table. + registration* next_in_table_; + registration* prev_in_table_; + + // Link to next registration in the signal set. + registration* next_in_set_; + }; + + // The implementation type of the signal_set. + class implementation_type + { + public: + // Default constructor. + implementation_type() + : signals_(0) + { + } + + private: + // Only this service will have access to the internal values. + friend class signal_set_service; + + // The pending signal handlers. + op_queue queue_; + + // Linked list of registered signals. + registration* signals_; + }; + + // Constructor. + BOOST_ASIO_DECL signal_set_service(execution_context& context); + + // Destructor. + BOOST_ASIO_DECL ~signal_set_service(); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown(); + + // Perform fork-related housekeeping. + BOOST_ASIO_DECL void notify_fork( + boost::asio::execution_context::fork_event fork_ev); + + // Construct a new signal_set implementation. + BOOST_ASIO_DECL void construct(implementation_type& impl); + + // Destroy a signal_set implementation. + BOOST_ASIO_DECL void destroy(implementation_type& impl); + + // Add a signal to a signal_set. + BOOST_ASIO_DECL boost::system::error_code add(implementation_type& impl, + int signal_number, boost::system::error_code& ec); + + // Remove a signal to a signal_set. + BOOST_ASIO_DECL boost::system::error_code remove(implementation_type& impl, + int signal_number, boost::system::error_code& ec); + + // Remove all signals from a signal_set. + BOOST_ASIO_DECL boost::system::error_code clear(implementation_type& impl, + boost::system::error_code& ec); + + // Cancel all operations associated with the signal set. + BOOST_ASIO_DECL boost::system::error_code cancel(implementation_type& impl, + boost::system::error_code& ec); + + // Start an asynchronous operation to wait for a signal to be delivered. + template + void async_wait(implementation_type& impl, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef signal_handler op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((scheduler_.context(), + *p.p, "signal_set", &impl, 0, "async_wait")); + + start_wait_op(impl, p.p); + p.v = p.p = 0; + } + + // Deliver notification that a particular signal occurred. + BOOST_ASIO_DECL static void deliver_signal(int signal_number); + +private: + // Helper function to add a service to the global signal state. + BOOST_ASIO_DECL static void add_service(signal_set_service* service); + + // Helper function to remove a service from the global signal state. + BOOST_ASIO_DECL static void remove_service(signal_set_service* service); + + // Helper function to create the pipe descriptors. + BOOST_ASIO_DECL static void open_descriptors(); + + // Helper function to close the pipe descriptors. + BOOST_ASIO_DECL static void close_descriptors(); + + // Helper function to start a wait operation. + BOOST_ASIO_DECL void start_wait_op(implementation_type& impl, signal_op* op); + + // The scheduler used for dispatching handlers. +#if defined(BOOST_ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; + +#if !defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ + && !defined(__CYGWIN__) + // The type used for registering for pipe reactor notifications. + class pipe_read_op; + + // The reactor used for waiting for pipe readiness. + reactor& reactor_; + + // The per-descriptor reactor data used for the pipe. + reactor::per_descriptor_data reactor_data_; +#endif // !defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) + // && !defined(__CYGWIN__) + + // A mapping from signal number to the registered signal sets. + registration* registrations_[max_signal_number]; + + // Pointers to adjacent services in linked list. + signal_set_service* next_; + signal_set_service* prev_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP diff --git a/boost/asio/detail/socket_holder.hpp b/boost/asio/detail/socket_holder.hpp new file mode 100644 index 0000000..c96e982 --- /dev/null +++ b/boost/asio/detail/socket_holder.hpp @@ -0,0 +1,100 @@ +// +// detail/socket_holder.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SOCKET_HOLDER_HPP +#define BOOST_ASIO_DETAIL_SOCKET_HOLDER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Implement the resource acquisition is initialisation idiom for sockets. +class socket_holder + : private noncopyable +{ +public: + // Construct as an uninitialised socket. + socket_holder() + : socket_(invalid_socket) + { + } + + // Construct to take ownership of the specified socket. + explicit socket_holder(socket_type s) + : socket_(s) + { + } + + // Destructor. + ~socket_holder() + { + if (socket_ != invalid_socket) + { + boost::system::error_code ec; + socket_ops::state_type state = 0; + socket_ops::close(socket_, state, true, ec); + } + } + + // Get the underlying socket. + socket_type get() const + { + return socket_; + } + + // Reset to an uninitialised socket. + void reset() + { + if (socket_ != invalid_socket) + { + boost::system::error_code ec; + socket_ops::state_type state = 0; + socket_ops::close(socket_, state, true, ec); + socket_ = invalid_socket; + } + } + + // Reset to take ownership of the specified socket. + void reset(socket_type s) + { + reset(); + socket_ = s; + } + + // Release ownership of the socket. + socket_type release() + { + socket_type tmp = socket_; + socket_ = invalid_socket; + return tmp; + } + +private: + // The underlying socket. + socket_type socket_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SOCKET_HOLDER_HPP diff --git a/boost/asio/detail/socket_ops.hpp b/boost/asio/detail/socket_ops.hpp new file mode 100644 index 0000000..506a06d --- /dev/null +++ b/boost/asio/detail/socket_ops.hpp @@ -0,0 +1,339 @@ +// +// detail/socket_ops.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SOCKET_OPS_HPP +#define BOOST_ASIO_DETAIL_SOCKET_OPS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { +namespace socket_ops { + +// Socket state bits. +enum +{ + // The user wants a non-blocking socket. + user_set_non_blocking = 1, + + // The socket has been set non-blocking. + internal_non_blocking = 2, + + // Helper "state" used to determine whether the socket is non-blocking. + non_blocking = user_set_non_blocking | internal_non_blocking, + + // User wants connection_aborted errors, which are disabled by default. + enable_connection_aborted = 4, + + // The user set the linger option. Needs to be checked when closing. + user_set_linger = 8, + + // The socket is stream-oriented. + stream_oriented = 16, + + // The socket is datagram-oriented. + datagram_oriented = 32, + + // The socket may have been dup()-ed. + possible_dup = 64 +}; + +typedef unsigned char state_type; + +struct noop_deleter { void operator()(void*) {} }; +typedef shared_ptr shared_cancel_token_type; +typedef weak_ptr weak_cancel_token_type; + +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +BOOST_ASIO_DECL socket_type accept(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec); + +BOOST_ASIO_DECL socket_type sync_accept(socket_type s, + state_type state, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec); + +#if defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL void complete_iocp_accept(socket_type s, + void* output_buffer, DWORD address_length, + socket_addr_type* addr, std::size_t* addrlen, + socket_type new_socket, boost::system::error_code& ec); + +#else // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL bool non_blocking_accept(socket_type s, + state_type state, socket_addr_type* addr, std::size_t* addrlen, + boost::system::error_code& ec, socket_type& new_socket); + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL int bind(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec); + +BOOST_ASIO_DECL int close(socket_type s, state_type& state, + bool destruction, boost::system::error_code& ec); + +BOOST_ASIO_DECL bool set_user_non_blocking(socket_type s, + state_type& state, bool value, boost::system::error_code& ec); + +BOOST_ASIO_DECL bool set_internal_non_blocking(socket_type s, + state_type& state, bool value, boost::system::error_code& ec); + +BOOST_ASIO_DECL int shutdown(socket_type s, + int what, boost::system::error_code& ec); + +BOOST_ASIO_DECL int connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec); + +BOOST_ASIO_DECL void sync_connect(socket_type s, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec); + +#if defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL void complete_iocp_connect(socket_type s, + boost::system::error_code& ec); + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL bool non_blocking_connect(socket_type s, + boost::system::error_code& ec); + +BOOST_ASIO_DECL int socketpair(int af, int type, int protocol, + socket_type sv[2], boost::system::error_code& ec); + +BOOST_ASIO_DECL bool sockatmark(socket_type s, boost::system::error_code& ec); + +BOOST_ASIO_DECL size_t available(socket_type s, boost::system::error_code& ec); + +BOOST_ASIO_DECL int listen(socket_type s, + int backlog, boost::system::error_code& ec); + +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +typedef WSABUF buf; +#else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +typedef iovec buf; +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +BOOST_ASIO_DECL void init_buf(buf& b, void* data, size_t size); + +BOOST_ASIO_DECL void init_buf(buf& b, const void* data, size_t size); + +BOOST_ASIO_DECL signed_size_type recv(socket_type s, buf* bufs, + size_t count, int flags, boost::system::error_code& ec); + +BOOST_ASIO_DECL size_t sync_recv(socket_type s, state_type state, buf* bufs, + size_t count, int flags, bool all_empty, boost::system::error_code& ec); + +#if defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL void complete_iocp_recv(state_type state, + const weak_cancel_token_type& cancel_token, bool all_empty, + boost::system::error_code& ec, size_t bytes_transferred); + +#else // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL bool non_blocking_recv(socket_type s, + buf* bufs, size_t count, int flags, bool is_stream, + boost::system::error_code& ec, size_t& bytes_transferred); + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL signed_size_type recvfrom(socket_type s, buf* bufs, + size_t count, int flags, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec); + +BOOST_ASIO_DECL size_t sync_recvfrom(socket_type s, state_type state, + buf* bufs, size_t count, int flags, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec); + +#if defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL void complete_iocp_recvfrom( + const weak_cancel_token_type& cancel_token, + boost::system::error_code& ec); + +#else // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL bool non_blocking_recvfrom(socket_type s, + buf* bufs, size_t count, int flags, + socket_addr_type* addr, std::size_t* addrlen, + boost::system::error_code& ec, size_t& bytes_transferred); + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL signed_size_type recvmsg(socket_type s, buf* bufs, + size_t count, int in_flags, int& out_flags, + boost::system::error_code& ec); + +BOOST_ASIO_DECL size_t sync_recvmsg(socket_type s, state_type state, + buf* bufs, size_t count, int in_flags, int& out_flags, + boost::system::error_code& ec); + +#if defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL void complete_iocp_recvmsg( + const weak_cancel_token_type& cancel_token, + boost::system::error_code& ec); + +#else // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL bool non_blocking_recvmsg(socket_type s, + buf* bufs, size_t count, int in_flags, int& out_flags, + boost::system::error_code& ec, size_t& bytes_transferred); + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL signed_size_type send(socket_type s, const buf* bufs, + size_t count, int flags, boost::system::error_code& ec); + +BOOST_ASIO_DECL size_t sync_send(socket_type s, state_type state, + const buf* bufs, size_t count, int flags, + bool all_empty, boost::system::error_code& ec); + +#if defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL void complete_iocp_send( + const weak_cancel_token_type& cancel_token, + boost::system::error_code& ec); + +#else // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL bool non_blocking_send(socket_type s, + const buf* bufs, size_t count, int flags, + boost::system::error_code& ec, size_t& bytes_transferred); + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL signed_size_type sendto(socket_type s, const buf* bufs, + size_t count, int flags, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec); + +BOOST_ASIO_DECL size_t sync_sendto(socket_type s, state_type state, + const buf* bufs, size_t count, int flags, const socket_addr_type* addr, + std::size_t addrlen, boost::system::error_code& ec); + +#if !defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL bool non_blocking_sendto(socket_type s, + const buf* bufs, size_t count, int flags, + const socket_addr_type* addr, std::size_t addrlen, + boost::system::error_code& ec, size_t& bytes_transferred); + +#endif // !defined(BOOST_ASIO_HAS_IOCP) + +BOOST_ASIO_DECL socket_type socket(int af, int type, int protocol, + boost::system::error_code& ec); + +BOOST_ASIO_DECL int setsockopt(socket_type s, state_type& state, + int level, int optname, const void* optval, + std::size_t optlen, boost::system::error_code& ec); + +BOOST_ASIO_DECL int getsockopt(socket_type s, state_type state, + int level, int optname, void* optval, + size_t* optlen, boost::system::error_code& ec); + +BOOST_ASIO_DECL int getpeername(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, bool cached, boost::system::error_code& ec); + +BOOST_ASIO_DECL int getsockname(socket_type s, socket_addr_type* addr, + std::size_t* addrlen, boost::system::error_code& ec); + +BOOST_ASIO_DECL int ioctl(socket_type s, state_type& state, + int cmd, ioctl_arg_type* arg, boost::system::error_code& ec); + +BOOST_ASIO_DECL int select(int nfds, fd_set* readfds, fd_set* writefds, + fd_set* exceptfds, timeval* timeout, boost::system::error_code& ec); + +BOOST_ASIO_DECL int poll_read(socket_type s, + state_type state, int msec, boost::system::error_code& ec); + +BOOST_ASIO_DECL int poll_write(socket_type s, + state_type state, int msec, boost::system::error_code& ec); + +BOOST_ASIO_DECL int poll_error(socket_type s, + state_type state, int msec, boost::system::error_code& ec); + +BOOST_ASIO_DECL int poll_connect(socket_type s, + int msec, boost::system::error_code& ec); + +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +BOOST_ASIO_DECL const char* inet_ntop(int af, const void* src, char* dest, + size_t length, unsigned long scope_id, boost::system::error_code& ec); + +BOOST_ASIO_DECL int inet_pton(int af, const char* src, void* dest, + unsigned long* scope_id, boost::system::error_code& ec); + +BOOST_ASIO_DECL int gethostname(char* name, + int namelen, boost::system::error_code& ec); + +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +BOOST_ASIO_DECL boost::system::error_code getaddrinfo(const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, boost::system::error_code& ec); + +BOOST_ASIO_DECL boost::system::error_code background_getaddrinfo( + const weak_cancel_token_type& cancel_token, const char* host, + const char* service, const addrinfo_type& hints, + addrinfo_type** result, boost::system::error_code& ec); + +BOOST_ASIO_DECL void freeaddrinfo(addrinfo_type* ai); + +BOOST_ASIO_DECL boost::system::error_code getnameinfo( + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int flags, boost::system::error_code& ec); + +BOOST_ASIO_DECL boost::system::error_code sync_getnameinfo( + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, boost::system::error_code& ec); + +BOOST_ASIO_DECL boost::system::error_code background_getnameinfo( + const weak_cancel_token_type& cancel_token, + const socket_addr_type* addr, std::size_t addrlen, + char* host, std::size_t hostlen, char* serv, + std::size_t servlen, int sock_type, boost::system::error_code& ec); + +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +BOOST_ASIO_DECL u_long_type network_to_host_long(u_long_type value); + +BOOST_ASIO_DECL u_long_type host_to_network_long(u_long_type value); + +BOOST_ASIO_DECL u_short_type network_to_host_short(u_short_type value); + +BOOST_ASIO_DECL u_short_type host_to_network_short(u_short_type value); + +} // namespace socket_ops +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_DETAIL_SOCKET_OPS_HPP diff --git a/boost/asio/detail/socket_option.hpp b/boost/asio/detail/socket_option.hpp new file mode 100644 index 0000000..8a77b12 --- /dev/null +++ b/boost/asio/detail/socket_option.hpp @@ -0,0 +1,318 @@ +// +// detail/socket_option.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SOCKET_OPTION_HPP +#define BOOST_ASIO_DETAIL_SOCKET_OPTION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { +namespace socket_option { + +// Helper template for implementing boolean-based options. +template +class boolean +{ +public: + // Default constructor. + boolean() + : value_(0) + { + } + + // Construct with a specific option value. + explicit boolean(bool v) + : value_(v ? 1 : 0) + { + } + + // Set the current value of the boolean. + boolean& operator=(bool v) + { + value_ = v ? 1 : 0; + return *this; + } + + // Get the current value of the boolean. + bool value() const + { + return !!value_; + } + + // Convert to bool. + operator bool() const + { + return !!value_; + } + + // Test for false. + bool operator!() const + { + return !value_; + } + + // Get the level of the socket option. + template + int level(const Protocol&) const + { + return Level; + } + + // Get the name of the socket option. + template + int name(const Protocol&) const + { + return Name; + } + + // Get the address of the boolean data. + template + int* data(const Protocol&) + { + return &value_; + } + + // Get the address of the boolean data. + template + const int* data(const Protocol&) const + { + return &value_; + } + + // Get the size of the boolean data. + template + std::size_t size(const Protocol&) const + { + return sizeof(value_); + } + + // Set the size of the boolean data. + template + void resize(const Protocol&, std::size_t s) + { + // On some platforms (e.g. Windows Vista), the getsockopt function will + // return the size of a boolean socket option as one byte, even though a + // four byte integer was passed in. + switch (s) + { + case sizeof(char): + value_ = *reinterpret_cast(&value_) ? 1 : 0; + break; + case sizeof(value_): + break; + default: + { + std::length_error ex("boolean socket option resize"); + boost::asio::detail::throw_exception(ex); + } + } + } + +private: + int value_; +}; + +// Helper template for implementing integer options. +template +class integer +{ +public: + // Default constructor. + integer() + : value_(0) + { + } + + // Construct with a specific option value. + explicit integer(int v) + : value_(v) + { + } + + // Set the value of the int option. + integer& operator=(int v) + { + value_ = v; + return *this; + } + + // Get the current value of the int option. + int value() const + { + return value_; + } + + // Get the level of the socket option. + template + int level(const Protocol&) const + { + return Level; + } + + // Get the name of the socket option. + template + int name(const Protocol&) const + { + return Name; + } + + // Get the address of the int data. + template + int* data(const Protocol&) + { + return &value_; + } + + // Get the address of the int data. + template + const int* data(const Protocol&) const + { + return &value_; + } + + // Get the size of the int data. + template + std::size_t size(const Protocol&) const + { + return sizeof(value_); + } + + // Set the size of the int data. + template + void resize(const Protocol&, std::size_t s) + { + if (s != sizeof(value_)) + { + std::length_error ex("integer socket option resize"); + boost::asio::detail::throw_exception(ex); + } + } + +private: + int value_; +}; + +// Helper template for implementing linger options. +template +class linger +{ +public: + // Default constructor. + linger() + { + value_.l_onoff = 0; + value_.l_linger = 0; + } + + // Construct with specific option values. + linger(bool e, int t) + { + enabled(e); + timeout BOOST_ASIO_PREVENT_MACRO_SUBSTITUTION(t); + } + + // Set the value for whether linger is enabled. + void enabled(bool value) + { + value_.l_onoff = value ? 1 : 0; + } + + // Get the value for whether linger is enabled. + bool enabled() const + { + return value_.l_onoff != 0; + } + + // Set the value for the linger timeout. + void timeout BOOST_ASIO_PREVENT_MACRO_SUBSTITUTION(int value) + { +#if defined(WIN32) + value_.l_linger = static_cast(value); +#else + value_.l_linger = value; +#endif + } + + // Get the value for the linger timeout. + int timeout BOOST_ASIO_PREVENT_MACRO_SUBSTITUTION() const + { + return static_cast(value_.l_linger); + } + + // Get the level of the socket option. + template + int level(const Protocol&) const + { + return Level; + } + + // Get the name of the socket option. + template + int name(const Protocol&) const + { + return Name; + } + + // Get the address of the linger data. + template + detail::linger_type* data(const Protocol&) + { + return &value_; + } + + // Get the address of the linger data. + template + const detail::linger_type* data(const Protocol&) const + { + return &value_; + } + + // Get the size of the linger data. + template + std::size_t size(const Protocol&) const + { + return sizeof(value_); + } + + // Set the size of the int data. + template + void resize(const Protocol&, std::size_t s) + { + if (s != sizeof(value_)) + { + std::length_error ex("linger socket option resize"); + boost::asio::detail::throw_exception(ex); + } + } + +private: + detail::linger_type value_; +}; + +} // namespace socket_option +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SOCKET_OPTION_HPP diff --git a/boost/asio/detail/socket_select_interrupter.hpp b/boost/asio/detail/socket_select_interrupter.hpp new file mode 100644 index 0000000..fc81270 --- /dev/null +++ b/boost/asio/detail/socket_select_interrupter.hpp @@ -0,0 +1,93 @@ +// +// detail/socket_select_interrupter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP +#define BOOST_ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#if defined(BOOST_ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(__SYMBIAN32__) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class socket_select_interrupter +{ +public: + // Constructor. + BOOST_ASIO_DECL socket_select_interrupter(); + + // Destructor. + BOOST_ASIO_DECL ~socket_select_interrupter(); + + // Recreate the interrupter's descriptors. Used after a fork. + BOOST_ASIO_DECL void recreate(); + + // Interrupt the select call. + BOOST_ASIO_DECL void interrupt(); + + // Reset the select interrupt. Returns true if the call was interrupted. + BOOST_ASIO_DECL bool reset(); + + // Get the read descriptor to be passed to select. + socket_type read_descriptor() const + { + return read_descriptor_; + } + +private: + // Open the descriptors. Throws on error. + BOOST_ASIO_DECL void open_descriptors(); + + // Close the descriptors. + BOOST_ASIO_DECL void close_descriptors(); + + // The read end of a connection used to interrupt the select call. This file + // descriptor is passed to select such that when it is time to stop, a single + // byte will be written on the other end of the connection and this + // descriptor will become readable. + socket_type read_descriptor_; + + // The write end of a connection used to interrupt the select call. A single + // byte may be written to this to wake up the select which is waiting for the + // other end to become readable. + socket_type write_descriptor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_WINDOWS) + // || defined(__CYGWIN__) + // || defined(__SYMBIAN32__) + +#endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#endif // BOOST_ASIO_DETAIL_SOCKET_SELECT_INTERRUPTER_HPP diff --git a/boost/asio/detail/socket_types.hpp b/boost/asio/detail/socket_types.hpp new file mode 100644 index 0000000..867caa5 --- /dev/null +++ b/boost/asio/detail/socket_types.hpp @@ -0,0 +1,418 @@ +// +// detail/socket_types.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SOCKET_TYPES_HPP +#define BOOST_ASIO_DETAIL_SOCKET_TYPES_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +// Empty. +#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# if defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) +# error WinSock.h has already been included +# endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) +# if defined(__BORLANDC__) +# include // Needed for __errno +# if !defined(_WSPIAPI_H_) +# define _WSPIAPI_H_ +# define BOOST_ASIO_WSPIAPI_H_DEFINED +# endif // !defined(_WSPIAPI_H_) +# endif // defined(__BORLANDC__) +# include +# include +# if defined(WINAPI_FAMILY) +# if ((WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP) != 0) +# include +# endif // ((WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP) != 0) +# endif // defined(WINAPI_FAMILY) +# if !defined(BOOST_ASIO_WINDOWS_APP) +# include +# endif // !defined(BOOST_ASIO_WINDOWS_APP) +# if defined(BOOST_ASIO_WSPIAPI_H_DEFINED) +# undef _WSPIAPI_H_ +# undef BOOST_ASIO_WSPIAPI_H_DEFINED +# endif // defined(BOOST_ASIO_WSPIAPI_H_DEFINED) +# if !defined(BOOST_ASIO_NO_DEFAULT_LINKED_LIBS) +# if defined(UNDER_CE) +# pragma comment(lib, "ws2.lib") +# elif defined(_MSC_VER) || defined(__BORLANDC__) +# pragma comment(lib, "ws2_32.lib") +# if !defined(BOOST_ASIO_WINDOWS_APP) +# pragma comment(lib, "mswsock.lib") +# endif // !defined(BOOST_ASIO_WINDOWS_APP) +# endif // defined(_MSC_VER) || defined(__BORLANDC__) +# endif // !defined(BOOST_ASIO_NO_DEFAULT_LINKED_LIBS) +# include +#else +# include +# if (defined(__MACH__) && defined(__APPLE__)) \ + || defined(__FreeBSD__) || defined(__NetBSD__) \ + || defined(__OpenBSD__) || defined(__linux__) \ + || defined(__EMSCRIPTEN__) +# include +# elif !defined(__SYMBIAN32__) +# include +# endif +# include +# include +# include +# if defined(__hpux) +# include +# endif +# if !defined(__hpux) || defined(__SELECT) +# include +# endif +# include +# include +# include +# include +# if !defined(__SYMBIAN32__) +# include +# endif +# include +# include +# include +# include +# if defined(__sun) +# include +# include +# endif +#endif + +#include + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +const int max_addr_v4_str_len = 256; +const int max_addr_v6_str_len = 256; +typedef unsigned __int32 u_long_type; +typedef unsigned __int16 u_short_type; +struct in4_addr_type { u_long_type s_addr; }; +struct in4_mreq_type { in4_addr_type imr_multiaddr, imr_interface; }; +struct in6_addr_type { unsigned char s6_addr[16]; }; +struct in6_mreq_type { in6_addr_type ipv6mr_multiaddr; + unsigned long ipv6mr_interface; }; +struct socket_addr_type { int sa_family; }; +struct sockaddr_in4_type { int sin_family; + in4_addr_type sin_addr; u_short_type sin_port; }; +struct sockaddr_in6_type { int sin6_family; + in6_addr_type sin6_addr; u_short_type sin6_port; + u_long_type sin6_flowinfo; u_long_type sin6_scope_id; }; +struct sockaddr_storage_type { int ss_family; + unsigned char ss_bytes[128 - sizeof(int)]; }; +struct addrinfo_type { int ai_flags; + int ai_family, ai_socktype, ai_protocol; + int ai_addrlen; const void* ai_addr; + const char* ai_canonname; addrinfo_type* ai_next; }; +struct linger_type { u_short_type l_onoff, l_linger; }; +typedef u_long_type ioctl_arg_type; +typedef int signed_size_type; +# define BOOST_ASIO_OS_DEF(c) BOOST_ASIO_OS_DEF_##c +# define BOOST_ASIO_OS_DEF_AF_UNSPEC 0 +# define BOOST_ASIO_OS_DEF_AF_INET 2 +# define BOOST_ASIO_OS_DEF_AF_INET6 23 +# define BOOST_ASIO_OS_DEF_SOCK_STREAM 1 +# define BOOST_ASIO_OS_DEF_SOCK_DGRAM 2 +# define BOOST_ASIO_OS_DEF_SOCK_RAW 3 +# define BOOST_ASIO_OS_DEF_SOCK_SEQPACKET 5 +# define BOOST_ASIO_OS_DEF_IPPROTO_IP 0 +# define BOOST_ASIO_OS_DEF_IPPROTO_IPV6 41 +# define BOOST_ASIO_OS_DEF_IPPROTO_TCP 6 +# define BOOST_ASIO_OS_DEF_IPPROTO_UDP 17 +# define BOOST_ASIO_OS_DEF_IPPROTO_ICMP 1 +# define BOOST_ASIO_OS_DEF_IPPROTO_ICMPV6 58 +# define BOOST_ASIO_OS_DEF_FIONBIO 1 +# define BOOST_ASIO_OS_DEF_FIONREAD 2 +# define BOOST_ASIO_OS_DEF_INADDR_ANY 0 +# define BOOST_ASIO_OS_DEF_MSG_OOB 0x1 +# define BOOST_ASIO_OS_DEF_MSG_PEEK 0x2 +# define BOOST_ASIO_OS_DEF_MSG_DONTROUTE 0x4 +# define BOOST_ASIO_OS_DEF_MSG_EOR 0 // Not supported. +# define BOOST_ASIO_OS_DEF_SHUT_RD 0x0 +# define BOOST_ASIO_OS_DEF_SHUT_WR 0x1 +# define BOOST_ASIO_OS_DEF_SHUT_RDWR 0x2 +# define BOOST_ASIO_OS_DEF_SOMAXCONN 0x7fffffff +# define BOOST_ASIO_OS_DEF_SOL_SOCKET 0xffff +# define BOOST_ASIO_OS_DEF_SO_BROADCAST 0x20 +# define BOOST_ASIO_OS_DEF_SO_DEBUG 0x1 +# define BOOST_ASIO_OS_DEF_SO_DONTROUTE 0x10 +# define BOOST_ASIO_OS_DEF_SO_KEEPALIVE 0x8 +# define BOOST_ASIO_OS_DEF_SO_LINGER 0x80 +# define BOOST_ASIO_OS_DEF_SO_OOBINLINE 0x100 +# define BOOST_ASIO_OS_DEF_SO_SNDBUF 0x1001 +# define BOOST_ASIO_OS_DEF_SO_RCVBUF 0x1002 +# define BOOST_ASIO_OS_DEF_SO_SNDLOWAT 0x1003 +# define BOOST_ASIO_OS_DEF_SO_RCVLOWAT 0x1004 +# define BOOST_ASIO_OS_DEF_SO_REUSEADDR 0x4 +# define BOOST_ASIO_OS_DEF_TCP_NODELAY 0x1 +# define BOOST_ASIO_OS_DEF_IP_MULTICAST_IF 2 +# define BOOST_ASIO_OS_DEF_IP_MULTICAST_TTL 3 +# define BOOST_ASIO_OS_DEF_IP_MULTICAST_LOOP 4 +# define BOOST_ASIO_OS_DEF_IP_ADD_MEMBERSHIP 5 +# define BOOST_ASIO_OS_DEF_IP_DROP_MEMBERSHIP 6 +# define BOOST_ASIO_OS_DEF_IP_TTL 7 +# define BOOST_ASIO_OS_DEF_IPV6_UNICAST_HOPS 4 +# define BOOST_ASIO_OS_DEF_IPV6_MULTICAST_IF 9 +# define BOOST_ASIO_OS_DEF_IPV6_MULTICAST_HOPS 10 +# define BOOST_ASIO_OS_DEF_IPV6_MULTICAST_LOOP 11 +# define BOOST_ASIO_OS_DEF_IPV6_JOIN_GROUP 12 +# define BOOST_ASIO_OS_DEF_IPV6_LEAVE_GROUP 13 +# define BOOST_ASIO_OS_DEF_AI_CANONNAME 0x2 +# define BOOST_ASIO_OS_DEF_AI_PASSIVE 0x1 +# define BOOST_ASIO_OS_DEF_AI_NUMERICHOST 0x4 +# define BOOST_ASIO_OS_DEF_AI_NUMERICSERV 0x8 +# define BOOST_ASIO_OS_DEF_AI_V4MAPPED 0x800 +# define BOOST_ASIO_OS_DEF_AI_ALL 0x100 +# define BOOST_ASIO_OS_DEF_AI_ADDRCONFIG 0x400 +#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +typedef SOCKET socket_type; +const SOCKET invalid_socket = INVALID_SOCKET; +const int socket_error_retval = SOCKET_ERROR; +const int max_addr_v4_str_len = 256; +const int max_addr_v6_str_len = 256; +typedef sockaddr socket_addr_type; +typedef in_addr in4_addr_type; +typedef ip_mreq in4_mreq_type; +typedef sockaddr_in sockaddr_in4_type; +# if defined(BOOST_ASIO_HAS_OLD_WIN_SDK) +typedef in6_addr_emulation in6_addr_type; +typedef ipv6_mreq_emulation in6_mreq_type; +typedef sockaddr_in6_emulation sockaddr_in6_type; +typedef sockaddr_storage_emulation sockaddr_storage_type; +typedef addrinfo_emulation addrinfo_type; +# else +typedef in6_addr in6_addr_type; +typedef ipv6_mreq in6_mreq_type; +typedef sockaddr_in6 sockaddr_in6_type; +typedef sockaddr_storage sockaddr_storage_type; +typedef addrinfo addrinfo_type; +# endif +typedef ::linger linger_type; +typedef unsigned long ioctl_arg_type; +typedef u_long u_long_type; +typedef u_short u_short_type; +typedef int signed_size_type; +# define BOOST_ASIO_OS_DEF(c) BOOST_ASIO_OS_DEF_##c +# define BOOST_ASIO_OS_DEF_AF_UNSPEC AF_UNSPEC +# define BOOST_ASIO_OS_DEF_AF_INET AF_INET +# define BOOST_ASIO_OS_DEF_AF_INET6 AF_INET6 +# define BOOST_ASIO_OS_DEF_SOCK_STREAM SOCK_STREAM +# define BOOST_ASIO_OS_DEF_SOCK_DGRAM SOCK_DGRAM +# define BOOST_ASIO_OS_DEF_SOCK_RAW SOCK_RAW +# define BOOST_ASIO_OS_DEF_SOCK_SEQPACKET SOCK_SEQPACKET +# define BOOST_ASIO_OS_DEF_IPPROTO_IP IPPROTO_IP +# define BOOST_ASIO_OS_DEF_IPPROTO_IPV6 IPPROTO_IPV6 +# define BOOST_ASIO_OS_DEF_IPPROTO_TCP IPPROTO_TCP +# define BOOST_ASIO_OS_DEF_IPPROTO_UDP IPPROTO_UDP +# define BOOST_ASIO_OS_DEF_IPPROTO_ICMP IPPROTO_ICMP +# define BOOST_ASIO_OS_DEF_IPPROTO_ICMPV6 IPPROTO_ICMPV6 +# define BOOST_ASIO_OS_DEF_FIONBIO FIONBIO +# define BOOST_ASIO_OS_DEF_FIONREAD FIONREAD +# define BOOST_ASIO_OS_DEF_INADDR_ANY INADDR_ANY +# define BOOST_ASIO_OS_DEF_MSG_OOB MSG_OOB +# define BOOST_ASIO_OS_DEF_MSG_PEEK MSG_PEEK +# define BOOST_ASIO_OS_DEF_MSG_DONTROUTE MSG_DONTROUTE +# define BOOST_ASIO_OS_DEF_MSG_EOR 0 // Not supported on Windows. +# define BOOST_ASIO_OS_DEF_SHUT_RD SD_RECEIVE +# define BOOST_ASIO_OS_DEF_SHUT_WR SD_SEND +# define BOOST_ASIO_OS_DEF_SHUT_RDWR SD_BOTH +# define BOOST_ASIO_OS_DEF_SOMAXCONN SOMAXCONN +# define BOOST_ASIO_OS_DEF_SOL_SOCKET SOL_SOCKET +# define BOOST_ASIO_OS_DEF_SO_BROADCAST SO_BROADCAST +# define BOOST_ASIO_OS_DEF_SO_DEBUG SO_DEBUG +# define BOOST_ASIO_OS_DEF_SO_DONTROUTE SO_DONTROUTE +# define BOOST_ASIO_OS_DEF_SO_KEEPALIVE SO_KEEPALIVE +# define BOOST_ASIO_OS_DEF_SO_LINGER SO_LINGER +# define BOOST_ASIO_OS_DEF_SO_OOBINLINE SO_OOBINLINE +# define BOOST_ASIO_OS_DEF_SO_SNDBUF SO_SNDBUF +# define BOOST_ASIO_OS_DEF_SO_RCVBUF SO_RCVBUF +# define BOOST_ASIO_OS_DEF_SO_SNDLOWAT SO_SNDLOWAT +# define BOOST_ASIO_OS_DEF_SO_RCVLOWAT SO_RCVLOWAT +# define BOOST_ASIO_OS_DEF_SO_REUSEADDR SO_REUSEADDR +# define BOOST_ASIO_OS_DEF_TCP_NODELAY TCP_NODELAY +# define BOOST_ASIO_OS_DEF_IP_MULTICAST_IF IP_MULTICAST_IF +# define BOOST_ASIO_OS_DEF_IP_MULTICAST_TTL IP_MULTICAST_TTL +# define BOOST_ASIO_OS_DEF_IP_MULTICAST_LOOP IP_MULTICAST_LOOP +# define BOOST_ASIO_OS_DEF_IP_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP +# define BOOST_ASIO_OS_DEF_IP_DROP_MEMBERSHIP IP_DROP_MEMBERSHIP +# define BOOST_ASIO_OS_DEF_IP_TTL IP_TTL +# define BOOST_ASIO_OS_DEF_IPV6_UNICAST_HOPS IPV6_UNICAST_HOPS +# define BOOST_ASIO_OS_DEF_IPV6_MULTICAST_IF IPV6_MULTICAST_IF +# define BOOST_ASIO_OS_DEF_IPV6_MULTICAST_HOPS IPV6_MULTICAST_HOPS +# define BOOST_ASIO_OS_DEF_IPV6_MULTICAST_LOOP IPV6_MULTICAST_LOOP +# define BOOST_ASIO_OS_DEF_IPV6_JOIN_GROUP IPV6_JOIN_GROUP +# define BOOST_ASIO_OS_DEF_IPV6_LEAVE_GROUP IPV6_LEAVE_GROUP +# define BOOST_ASIO_OS_DEF_AI_CANONNAME AI_CANONNAME +# define BOOST_ASIO_OS_DEF_AI_PASSIVE AI_PASSIVE +# define BOOST_ASIO_OS_DEF_AI_NUMERICHOST AI_NUMERICHOST +# if defined(AI_NUMERICSERV) +# define BOOST_ASIO_OS_DEF_AI_NUMERICSERV AI_NUMERICSERV +# else +# define BOOST_ASIO_OS_DEF_AI_NUMERICSERV 0 +# endif +# if defined(AI_V4MAPPED) +# define BOOST_ASIO_OS_DEF_AI_V4MAPPED AI_V4MAPPED +# else +# define BOOST_ASIO_OS_DEF_AI_V4MAPPED 0 +# endif +# if defined(AI_ALL) +# define BOOST_ASIO_OS_DEF_AI_ALL AI_ALL +# else +# define BOOST_ASIO_OS_DEF_AI_ALL 0 +# endif +# if defined(AI_ADDRCONFIG) +# define BOOST_ASIO_OS_DEF_AI_ADDRCONFIG AI_ADDRCONFIG +# else +# define BOOST_ASIO_OS_DEF_AI_ADDRCONFIG 0 +# endif +# if defined (_WIN32_WINNT) +const int max_iov_len = 64; +# else +const int max_iov_len = 16; +# endif +#else +typedef int socket_type; +const int invalid_socket = -1; +const int socket_error_retval = -1; +const int max_addr_v4_str_len = INET_ADDRSTRLEN; +#if defined(INET6_ADDRSTRLEN) +const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE; +#else // defined(INET6_ADDRSTRLEN) +const int max_addr_v6_str_len = 256; +#endif // defined(INET6_ADDRSTRLEN) +typedef sockaddr socket_addr_type; +typedef in_addr in4_addr_type; +# if defined(__hpux) +// HP-UX doesn't provide ip_mreq when _XOPEN_SOURCE_EXTENDED is defined. +struct in4_mreq_type +{ + struct in_addr imr_multiaddr; + struct in_addr imr_interface; +}; +# else +typedef ip_mreq in4_mreq_type; +# endif +typedef sockaddr_in sockaddr_in4_type; +typedef in6_addr in6_addr_type; +typedef ipv6_mreq in6_mreq_type; +typedef sockaddr_in6 sockaddr_in6_type; +typedef sockaddr_storage sockaddr_storage_type; +typedef sockaddr_un sockaddr_un_type; +typedef addrinfo addrinfo_type; +typedef ::linger linger_type; +typedef int ioctl_arg_type; +typedef uint32_t u_long_type; +typedef uint16_t u_short_type; +#if defined(BOOST_ASIO_HAS_SSIZE_T) +typedef ssize_t signed_size_type; +#else // defined(BOOST_ASIO_HAS_SSIZE_T) +typedef int signed_size_type; +#endif // defined(BOOST_ASIO_HAS_SSIZE_T) +# define BOOST_ASIO_OS_DEF(c) BOOST_ASIO_OS_DEF_##c +# define BOOST_ASIO_OS_DEF_AF_UNSPEC AF_UNSPEC +# define BOOST_ASIO_OS_DEF_AF_INET AF_INET +# define BOOST_ASIO_OS_DEF_AF_INET6 AF_INET6 +# define BOOST_ASIO_OS_DEF_SOCK_STREAM SOCK_STREAM +# define BOOST_ASIO_OS_DEF_SOCK_DGRAM SOCK_DGRAM +# define BOOST_ASIO_OS_DEF_SOCK_RAW SOCK_RAW +# define BOOST_ASIO_OS_DEF_SOCK_SEQPACKET SOCK_SEQPACKET +# define BOOST_ASIO_OS_DEF_IPPROTO_IP IPPROTO_IP +# define BOOST_ASIO_OS_DEF_IPPROTO_IPV6 IPPROTO_IPV6 +# define BOOST_ASIO_OS_DEF_IPPROTO_TCP IPPROTO_TCP +# define BOOST_ASIO_OS_DEF_IPPROTO_UDP IPPROTO_UDP +# define BOOST_ASIO_OS_DEF_IPPROTO_ICMP IPPROTO_ICMP +# define BOOST_ASIO_OS_DEF_IPPROTO_ICMPV6 IPPROTO_ICMPV6 +# define BOOST_ASIO_OS_DEF_FIONBIO FIONBIO +# define BOOST_ASIO_OS_DEF_FIONREAD FIONREAD +# define BOOST_ASIO_OS_DEF_INADDR_ANY INADDR_ANY +# define BOOST_ASIO_OS_DEF_MSG_OOB MSG_OOB +# define BOOST_ASIO_OS_DEF_MSG_PEEK MSG_PEEK +# define BOOST_ASIO_OS_DEF_MSG_DONTROUTE MSG_DONTROUTE +# define BOOST_ASIO_OS_DEF_MSG_EOR MSG_EOR +# define BOOST_ASIO_OS_DEF_SHUT_RD SHUT_RD +# define BOOST_ASIO_OS_DEF_SHUT_WR SHUT_WR +# define BOOST_ASIO_OS_DEF_SHUT_RDWR SHUT_RDWR +# define BOOST_ASIO_OS_DEF_SOMAXCONN SOMAXCONN +# define BOOST_ASIO_OS_DEF_SOL_SOCKET SOL_SOCKET +# define BOOST_ASIO_OS_DEF_SO_BROADCAST SO_BROADCAST +# define BOOST_ASIO_OS_DEF_SO_DEBUG SO_DEBUG +# define BOOST_ASIO_OS_DEF_SO_DONTROUTE SO_DONTROUTE +# define BOOST_ASIO_OS_DEF_SO_KEEPALIVE SO_KEEPALIVE +# define BOOST_ASIO_OS_DEF_SO_LINGER SO_LINGER +# define BOOST_ASIO_OS_DEF_SO_OOBINLINE SO_OOBINLINE +# define BOOST_ASIO_OS_DEF_SO_SNDBUF SO_SNDBUF +# define BOOST_ASIO_OS_DEF_SO_RCVBUF SO_RCVBUF +# define BOOST_ASIO_OS_DEF_SO_SNDLOWAT SO_SNDLOWAT +# define BOOST_ASIO_OS_DEF_SO_RCVLOWAT SO_RCVLOWAT +# define BOOST_ASIO_OS_DEF_SO_REUSEADDR SO_REUSEADDR +# define BOOST_ASIO_OS_DEF_TCP_NODELAY TCP_NODELAY +# define BOOST_ASIO_OS_DEF_IP_MULTICAST_IF IP_MULTICAST_IF +# define BOOST_ASIO_OS_DEF_IP_MULTICAST_TTL IP_MULTICAST_TTL +# define BOOST_ASIO_OS_DEF_IP_MULTICAST_LOOP IP_MULTICAST_LOOP +# define BOOST_ASIO_OS_DEF_IP_ADD_MEMBERSHIP IP_ADD_MEMBERSHIP +# define BOOST_ASIO_OS_DEF_IP_DROP_MEMBERSHIP IP_DROP_MEMBERSHIP +# define BOOST_ASIO_OS_DEF_IP_TTL IP_TTL +# define BOOST_ASIO_OS_DEF_IPV6_UNICAST_HOPS IPV6_UNICAST_HOPS +# define BOOST_ASIO_OS_DEF_IPV6_MULTICAST_IF IPV6_MULTICAST_IF +# define BOOST_ASIO_OS_DEF_IPV6_MULTICAST_HOPS IPV6_MULTICAST_HOPS +# define BOOST_ASIO_OS_DEF_IPV6_MULTICAST_LOOP IPV6_MULTICAST_LOOP +# define BOOST_ASIO_OS_DEF_IPV6_JOIN_GROUP IPV6_JOIN_GROUP +# define BOOST_ASIO_OS_DEF_IPV6_LEAVE_GROUP IPV6_LEAVE_GROUP +# define BOOST_ASIO_OS_DEF_AI_CANONNAME AI_CANONNAME +# define BOOST_ASIO_OS_DEF_AI_PASSIVE AI_PASSIVE +# define BOOST_ASIO_OS_DEF_AI_NUMERICHOST AI_NUMERICHOST +# if defined(AI_NUMERICSERV) +# define BOOST_ASIO_OS_DEF_AI_NUMERICSERV AI_NUMERICSERV +# else +# define BOOST_ASIO_OS_DEF_AI_NUMERICSERV 0 +# endif +// Note: QNX Neutrino 6.3 defines AI_V4MAPPED, AI_ALL and AI_ADDRCONFIG but +// does not implement them. Therefore they are specifically excluded here. +# if defined(AI_V4MAPPED) && !defined(__QNXNTO__) +# define BOOST_ASIO_OS_DEF_AI_V4MAPPED AI_V4MAPPED +# else +# define BOOST_ASIO_OS_DEF_AI_V4MAPPED 0 +# endif +# if defined(AI_ALL) && !defined(__QNXNTO__) +# define BOOST_ASIO_OS_DEF_AI_ALL AI_ALL +# else +# define BOOST_ASIO_OS_DEF_AI_ALL 0 +# endif +# if defined(AI_ADDRCONFIG) && !defined(__QNXNTO__) +# define BOOST_ASIO_OS_DEF_AI_ADDRCONFIG AI_ADDRCONFIG +# else +# define BOOST_ASIO_OS_DEF_AI_ADDRCONFIG 0 +# endif +# if defined(IOV_MAX) +const int max_iov_len = IOV_MAX; +# else +// POSIX platforms are not required to define IOV_MAX. +const int max_iov_len = 16; +# endif +#endif +const int custom_socket_option_level = 0xA5100000; +const int enable_connection_aborted_option = 1; +const int always_fail_option = 2; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_SOCKET_TYPES_HPP diff --git a/boost/asio/detail/solaris_fenced_block.hpp b/boost/asio/detail/solaris_fenced_block.hpp new file mode 100644 index 0000000..aa7fca3 --- /dev/null +++ b/boost/asio/detail/solaris_fenced_block.hpp @@ -0,0 +1,64 @@ +// +// detail/solaris_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(__sun) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class solaris_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit solaris_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit solaris_fenced_block(full_t) + { + membar_consumer(); + } + + // Destructor. + ~solaris_fenced_block() + { + membar_producer(); + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(__sun) + +#endif // BOOST_ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP diff --git a/boost/asio/detail/static_mutex.hpp b/boost/asio/detail/static_mutex.hpp new file mode 100644 index 0000000..b6194e4 --- /dev/null +++ b/boost/asio/detail/static_mutex.hpp @@ -0,0 +1,54 @@ +// +// detail/static_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_STATIC_MUTEX_HPP +#define BOOST_ASIO_DETAIL_STATIC_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_THREADS) +# include +#elif defined(BOOST_ASIO_WINDOWS) +# include +#elif defined(BOOST_ASIO_HAS_PTHREADS) +# include +#elif defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) +# include +#else +# error Only Windows and POSIX are supported! +#endif + +namespace boost { +namespace asio { +namespace detail { + +#if !defined(BOOST_ASIO_HAS_THREADS) +typedef null_static_mutex static_mutex; +# define BOOST_ASIO_STATIC_MUTEX_INIT BOOST_ASIO_NULL_STATIC_MUTEX_INIT +#elif defined(BOOST_ASIO_WINDOWS) +typedef win_static_mutex static_mutex; +# define BOOST_ASIO_STATIC_MUTEX_INIT BOOST_ASIO_WIN_STATIC_MUTEX_INIT +#elif defined(BOOST_ASIO_HAS_PTHREADS) +typedef posix_static_mutex static_mutex; +# define BOOST_ASIO_STATIC_MUTEX_INIT BOOST_ASIO_POSIX_STATIC_MUTEX_INIT +#elif defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) +typedef std_static_mutex static_mutex; +# define BOOST_ASIO_STATIC_MUTEX_INIT BOOST_ASIO_STD_STATIC_MUTEX_INIT +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_STATIC_MUTEX_HPP diff --git a/boost/asio/detail/std_event.hpp b/boost/asio/detail/std_event.hpp new file mode 100644 index 0000000..9532ec9 --- /dev/null +++ b/boost/asio/detail/std_event.hpp @@ -0,0 +1,178 @@ +// +// detail/std_event.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_STD_EVENT_HPP +#define BOOST_ASIO_DETAIL_STD_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class std_event + : private noncopyable +{ +public: + // Constructor. + std_event() + : state_(0) + { + } + + // Destructor. + ~std_event() + { + } + + // Signal the event. (Retained for backward compatibility.) + template + void signal(Lock& lock) + { + this->signal_all(lock); + } + + // Signal all waiters. + template + void signal_all(Lock& lock) + { + BOOST_ASIO_ASSERT(lock.locked()); + (void)lock; + state_ |= 1; + cond_.notify_all(); + } + + // Unlock the mutex and signal one waiter. + template + void unlock_and_signal_one(Lock& lock) + { + BOOST_ASIO_ASSERT(lock.locked()); + state_ |= 1; + bool have_waiters = (state_ > 1); + lock.unlock(); + if (have_waiters) + cond_.notify_one(); + } + + // If there's a waiter, unlock the mutex and signal it. + template + bool maybe_unlock_and_signal_one(Lock& lock) + { + BOOST_ASIO_ASSERT(lock.locked()); + state_ |= 1; + if (state_ > 1) + { + lock.unlock(); + cond_.notify_one(); + return true; + } + return false; + } + + // Reset the event. + template + void clear(Lock& lock) + { + BOOST_ASIO_ASSERT(lock.locked()); + (void)lock; + state_ &= ~std::size_t(1); + } + + // Wait for the event to become signalled. + template + void wait(Lock& lock) + { + BOOST_ASIO_ASSERT(lock.locked()); + unique_lock_adapter u_lock(lock); + while ((state_ & 1) == 0) + { + waiter w(state_); + cond_.wait(u_lock.unique_lock_); + } + } + + // Timed wait for the event to become signalled. + template + bool wait_for_usec(Lock& lock, long usec) + { + BOOST_ASIO_ASSERT(lock.locked()); + unique_lock_adapter u_lock(lock); + if ((state_ & 1) == 0) + { + waiter w(state_); + cond_.wait_for(u_lock.unique_lock_, std::chrono::microseconds(usec)); + } + return (state_ & 1) != 0; + } + +private: + // Helper class to temporarily adapt a scoped_lock into a unique_lock so that + // it can be passed to std::condition_variable::wait(). + struct unique_lock_adapter + { + template + explicit unique_lock_adapter(Lock& lock) + : unique_lock_(lock.mutex().mutex_, std::adopt_lock) + { + } + + ~unique_lock_adapter() + { + unique_lock_.release(); + } + + std::unique_lock unique_lock_; + }; + + // Helper to increment and decrement the state to track outstanding waiters. + class waiter + { + public: + explicit waiter(std::size_t& state) + : state_(state) + { + state_ += 2; + } + + ~waiter() + { + state_ -= 2; + } + + private: + std::size_t& state_; + }; + + std::condition_variable cond_; + std::size_t state_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +#endif // BOOST_ASIO_DETAIL_STD_EVENT_HPP diff --git a/boost/asio/detail/std_fenced_block.hpp b/boost/asio/detail/std_fenced_block.hpp new file mode 100644 index 0000000..2d87752 --- /dev/null +++ b/boost/asio/detail/std_fenced_block.hpp @@ -0,0 +1,64 @@ +// +// detail/std_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_STD_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_STD_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_STD_ATOMIC) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class std_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit std_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit std_fenced_block(full_t) + { + std::atomic_thread_fence(std::memory_order_acquire); + } + + // Destructor. + ~std_fenced_block() + { + std::atomic_thread_fence(std::memory_order_release); + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_STD_ATOMIC) + +#endif // BOOST_ASIO_DETAIL_STD_FENCED_BLOCK_HPP diff --git a/boost/asio/detail/std_global.hpp b/boost/asio/detail/std_global.hpp new file mode 100644 index 0000000..1c19afe --- /dev/null +++ b/boost/asio/detail/std_global.hpp @@ -0,0 +1,72 @@ +// +// detail/std_global.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_STD_GLOBAL_HPP +#define BOOST_ASIO_DETAIL_STD_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_STD_CALL_ONCE) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +struct std_global_impl +{ + // Helper function to perform initialisation. + static void do_init() + { + instance_.ptr_ = new T; + } + + // Destructor automatically cleans up the global. + ~std_global_impl() + { + delete ptr_; + } + + static std::once_flag init_once_; + static std_global_impl instance_; + T* ptr_; +}; + +template +std::once_flag std_global_impl::init_once_; + +template +std_global_impl std_global_impl::instance_; + +template +T& std_global() +{ + std::call_once(std_global_impl::init_once_, &std_global_impl::do_init); + return *std_global_impl::instance_.ptr_; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_STD_CALL_ONCE) + +#endif // BOOST_ASIO_DETAIL_STD_GLOBAL_HPP diff --git a/boost/asio/detail/std_mutex.hpp b/boost/asio/detail/std_mutex.hpp new file mode 100644 index 0000000..7bd17cb --- /dev/null +++ b/boost/asio/detail/std_mutex.hpp @@ -0,0 +1,75 @@ +// +// detail/std_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_STD_MUTEX_HPP +#define BOOST_ASIO_DETAIL_STD_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class std_event; + +class std_mutex + : private noncopyable +{ +public: + typedef boost::asio::detail::scoped_lock scoped_lock; + + // Constructor. + std_mutex() + { + } + + // Destructor. + ~std_mutex() + { + } + + // Lock the mutex. + void lock() + { + mutex_.lock(); + } + + // Unlock the mutex. + void unlock() + { + mutex_.unlock(); + } + +private: + friend class std_event; + std::mutex mutex_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +#endif // BOOST_ASIO_DETAIL_STD_MUTEX_HPP diff --git a/boost/asio/detail/std_static_mutex.hpp b/boost/asio/detail/std_static_mutex.hpp new file mode 100644 index 0000000..9b0581e --- /dev/null +++ b/boost/asio/detail/std_static_mutex.hpp @@ -0,0 +1,83 @@ +// +// detail/std_static_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_STD_STATIC_MUTEX_HPP +#define BOOST_ASIO_DETAIL_STD_STATIC_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class std_event; + +class std_static_mutex + : private noncopyable +{ +public: + typedef boost::asio::detail::scoped_lock scoped_lock; + + // Constructor. + std_static_mutex(int) + { + } + + // Destructor. + ~std_static_mutex() + { + } + + // Initialise the mutex. + void init() + { + // Nothing to do. + } + + // Lock the mutex. + void lock() + { + mutex_.lock(); + } + + // Unlock the mutex. + void unlock() + { + mutex_.unlock(); + } + +private: + friend class std_event; + std::mutex mutex_; +}; + +#define BOOST_ASIO_STD_STATIC_MUTEX_INIT 0 + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) + +#endif // BOOST_ASIO_DETAIL_STD_STATIC_MUTEX_HPP diff --git a/boost/asio/detail/std_thread.hpp b/boost/asio/detail/std_thread.hpp new file mode 100644 index 0000000..314a06c --- /dev/null +++ b/boost/asio/detail/std_thread.hpp @@ -0,0 +1,73 @@ +// +// detail/std_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_STD_THREAD_HPP +#define BOOST_ASIO_DETAIL_STD_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_STD_THREAD) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class std_thread + : private noncopyable +{ +public: + // Constructor. + template + std_thread(Function f, unsigned int = 0) + : thread_(f) + { + } + + // Destructor. + ~std_thread() + { + join(); + } + + // Wait for the thread to exit. + void join() + { + if (thread_.joinable()) + thread_.join(); + } + + // Get number of CPUs. + static std::size_t hardware_concurrency() + { + return std::thread::hardware_concurrency(); + } + +private: + std::thread thread_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_STD_THREAD) + +#endif // BOOST_ASIO_DETAIL_STD_THREAD_HPP diff --git a/boost/asio/detail/strand_executor_service.hpp b/boost/asio/detail/strand_executor_service.hpp new file mode 100644 index 0000000..4fc9327 --- /dev/null +++ b/boost/asio/detail/strand_executor_service.hpp @@ -0,0 +1,144 @@ +// +// detail/strand_executor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP +#define BOOST_ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Default service implementation for a strand. +class strand_executor_service + : public execution_context_service_base +{ +public: + // The underlying implementation of a strand. + class strand_impl + { + public: + BOOST_ASIO_DECL ~strand_impl(); + + private: + friend class strand_executor_service; + + // Mutex to protect access to internal data. + mutex* mutex_; + + // Indicates whether the strand is currently "locked" by a handler. This + // means that there is a handler upcall in progress, or that the strand + // itself has been scheduled in order to invoke some pending handlers. + bool locked_; + + // Indicates that the strand has been shut down and will accept no further + // handlers. + bool shutdown_; + + // The handlers that are waiting on the strand but should not be run until + // after the next time the strand is scheduled. This queue must only be + // modified while the mutex is locked. + op_queue waiting_queue_; + + // The handlers that are ready to be run. Logically speaking, these are the + // handlers that hold the strand's lock. The ready queue is only modified + // from within the strand and so may be accessed without locking the mutex. + op_queue ready_queue_; + + // Pointers to adjacent handle implementations in linked list. + strand_impl* next_; + strand_impl* prev_; + + // The strand service in where the implementation is held. + strand_executor_service* service_; + }; + + typedef shared_ptr implementation_type; + + // Construct a new strand service for the specified context. + BOOST_ASIO_DECL explicit strand_executor_service(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown(); + + // Create a new strand_executor implementation. + BOOST_ASIO_DECL implementation_type create_implementation(); + + // Request invocation of the given function. + template + static void dispatch(const implementation_type& impl, Executor& ex, + BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a); + + // Request invocation of the given function and return immediately. + template + static void post(const implementation_type& impl, Executor& ex, + BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a); + + // Request invocation of the given function and return immediately. + template + static void defer(const implementation_type& impl, Executor& ex, + BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a); + + // Determine whether the strand is running in the current thread. + BOOST_ASIO_DECL static bool running_in_this_thread( + const implementation_type& impl); + +private: + friend class strand_impl; + template class invoker; + + // Adds a function to the strand. Returns true if it acquires the lock. + BOOST_ASIO_DECL static bool enqueue(const implementation_type& impl, + scheduler_operation* op); + + // Mutex to protect access to the service-wide state. + mutex mutex_; + + // Number of mutexes shared between all strand objects. + enum { num_mutexes = 193 }; + + // Pool of mutexes. + scoped_ptr mutexes_[num_mutexes]; + + // Extra value used when hashing to prevent recycled memory locations from + // getting the same mutex. + std::size_t salt_; + + // The head of a linked list of all implementations. + strand_impl* impl_list_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP diff --git a/boost/asio/detail/strand_service.hpp b/boost/asio/detail/strand_service.hpp new file mode 100644 index 0000000..14271c4 --- /dev/null +++ b/boost/asio/detail/strand_service.hpp @@ -0,0 +1,144 @@ +// +// detail/strand_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP +#define BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Default service implementation for a strand. +class strand_service + : public boost::asio::detail::service_base +{ +private: + // Helper class to re-post the strand on exit. + struct on_do_complete_exit; + + // Helper class to re-post the strand on exit. + struct on_dispatch_exit; + +public: + + // The underlying implementation of a strand. + class strand_impl + : public operation + { + public: + strand_impl(); + + private: + // Only this service will have access to the internal values. + friend class strand_service; + friend struct on_do_complete_exit; + friend struct on_dispatch_exit; + + // Mutex to protect access to internal data. + boost::asio::detail::mutex mutex_; + + // Indicates whether the strand is currently "locked" by a handler. This + // means that there is a handler upcall in progress, or that the strand + // itself has been scheduled in order to invoke some pending handlers. + bool locked_; + + // The handlers that are waiting on the strand but should not be run until + // after the next time the strand is scheduled. This queue must only be + // modified while the mutex is locked. + op_queue waiting_queue_; + + // The handlers that are ready to be run. Logically speaking, these are the + // handlers that hold the strand's lock. The ready queue is only modified + // from within the strand and so may be accessed without locking the mutex. + op_queue ready_queue_; + }; + + typedef strand_impl* implementation_type; + + // Construct a new strand service for the specified io_context. + BOOST_ASIO_DECL explicit strand_service(boost::asio::io_context& io_context); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown(); + + // Construct a new strand implementation. + BOOST_ASIO_DECL void construct(implementation_type& impl); + + // Request the io_context to invoke the given handler. + template + void dispatch(implementation_type& impl, Handler& handler); + + // Request the io_context to invoke the given handler and return immediately. + template + void post(implementation_type& impl, Handler& handler); + + // Determine whether the strand is running in the current thread. + BOOST_ASIO_DECL bool running_in_this_thread( + const implementation_type& impl) const; + +private: + // Helper function to dispatch a handler. Returns true if the handler should + // be dispatched immediately. + BOOST_ASIO_DECL bool do_dispatch(implementation_type& impl, operation* op); + + // Helper fiunction to post a handler. + BOOST_ASIO_DECL void do_post(implementation_type& impl, + operation* op, bool is_continuation); + + BOOST_ASIO_DECL static void do_complete(void* owner, + operation* base, const boost::system::error_code& ec, + std::size_t bytes_transferred); + + // The io_context implementation used to post completions. + io_context_impl& io_context_; + + // Mutex to protect access to the array of implementations. + boost::asio::detail::mutex mutex_; + + // Number of implementations shared between all strand objects. +#if defined(BOOST_ASIO_STRAND_IMPLEMENTATIONS) + enum { num_implementations = BOOST_ASIO_STRAND_IMPLEMENTATIONS }; +#else // defined(BOOST_ASIO_STRAND_IMPLEMENTATIONS) + enum { num_implementations = 193 }; +#endif // defined(BOOST_ASIO_STRAND_IMPLEMENTATIONS) + + // Pool of implementations. + scoped_ptr implementations_[num_implementations]; + + // Extra value used when hashing to prevent recycled memory locations from + // getting the same strand implementation. + std::size_t salt_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP diff --git a/boost/asio/detail/string_view.hpp b/boost/asio/detail/string_view.hpp new file mode 100644 index 0000000..07080c1 --- /dev/null +++ b/boost/asio/detail/string_view.hpp @@ -0,0 +1,49 @@ +// +// detail/string_view.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_STRING_VIEW_HPP +#define BOOST_ASIO_DETAIL_STRING_VIEW_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_STRING_VIEW) + +#if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) +# include +#elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# include +#else // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +# error BOOST_ASIO_HAS_STRING_VIEW is set but no string_view is available +#endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + +namespace boost { +namespace asio { + +#if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) +using std::basic_string_view; +using std::string_view; +#elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) +using std::experimental::basic_string_view; +using std::experimental::string_view; +#endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) + +} // namespace asio +} // namespace boost + +# define BOOST_ASIO_STRING_VIEW_PARAM boost::asio::string_view +#else // defined(BOOST_ASIO_HAS_STRING_VIEW) +# define BOOST_ASIO_STRING_VIEW_PARAM const std::string& +#endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + +#endif // BOOST_ASIO_DETAIL_STRING_VIEW_HPP diff --git a/boost/asio/detail/thread.hpp b/boost/asio/detail/thread.hpp new file mode 100644 index 0000000..a888d52 --- /dev/null +++ b/boost/asio/detail/thread.hpp @@ -0,0 +1,62 @@ +// +// detail/thread.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_THREAD_HPP +#define BOOST_ASIO_DETAIL_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_THREADS) +# include +#elif defined(BOOST_ASIO_WINDOWS) +# if defined(UNDER_CE) +# include +# elif defined(BOOST_ASIO_WINDOWS_APP) +# include +# else +# include +# endif +#elif defined(BOOST_ASIO_HAS_PTHREADS) +# include +#elif defined(BOOST_ASIO_HAS_STD_THREAD) +# include +#else +# error Only Windows, POSIX and std::thread are supported! +#endif + +namespace boost { +namespace asio { +namespace detail { + +#if !defined(BOOST_ASIO_HAS_THREADS) +typedef null_thread thread; +#elif defined(BOOST_ASIO_WINDOWS) +# if defined(UNDER_CE) +typedef wince_thread thread; +# elif defined(BOOST_ASIO_WINDOWS_APP) +typedef winapp_thread thread; +# else +typedef win_thread thread; +# endif +#elif defined(BOOST_ASIO_HAS_PTHREADS) +typedef posix_thread thread; +#elif defined(BOOST_ASIO_HAS_STD_THREAD) +typedef std_thread thread; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_THREAD_HPP diff --git a/boost/asio/detail/thread_context.hpp b/boost/asio/detail/thread_context.hpp new file mode 100644 index 0000000..2005a0d --- /dev/null +++ b/boost/asio/detail/thread_context.hpp @@ -0,0 +1,44 @@ +// +// detail/thread_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_THREAD_CONTEXT_HPP +#define BOOST_ASIO_DETAIL_THREAD_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class thread_info_base; + +// Base class for things that manage threads (scheduler, win_iocp_io_context). +class thread_context +{ +public: + // Per-thread call stack to track the state of each thread in the context. + typedef call_stack thread_call_stack; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_THREAD_CONTEXT_HPP diff --git a/boost/asio/detail/thread_group.hpp b/boost/asio/detail/thread_group.hpp new file mode 100644 index 0000000..c6a4a99 --- /dev/null +++ b/boost/asio/detail/thread_group.hpp @@ -0,0 +1,97 @@ +// +// detail/thread_group.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_THREAD_GROUP_HPP +#define BOOST_ASIO_DETAIL_THREAD_GROUP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +namespace boost { +namespace asio { +namespace detail { + +class thread_group +{ +public: + // Constructor initialises an empty thread group. + thread_group() + : first_(0) + { + } + + // Destructor joins any remaining threads in the group. + ~thread_group() + { + join(); + } + + // Create a new thread in the group. + template + void create_thread(Function f) + { + first_ = new item(f, first_); + } + + // Create new threads in the group. + template + void create_threads(Function f, std::size_t num_threads) + { + for (std::size_t i = 0; i < num_threads; ++i) + create_thread(f); + } + + // Wait for all threads in the group to exit. + void join() + { + while (first_) + { + first_->thread_.join(); + item* tmp = first_; + first_ = first_->next_; + delete tmp; + } + } + + // Test whether the group is empty. + bool empty() const + { + return first_ == 0; + } + +private: + // Structure used to track a single thread in the group. + struct item + { + template + explicit item(Function f, item* next) + : thread_(f), + next_(next) + { + } + + boost::asio::detail::thread thread_; + item* next_; + }; + + // The first thread in the group. + item* first_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_THREAD_GROUP_HPP diff --git a/boost/asio/detail/thread_info_base.hpp b/boost/asio/detail/thread_info_base.hpp new file mode 100644 index 0000000..6b7a20c --- /dev/null +++ b/boost/asio/detail/thread_info_base.hpp @@ -0,0 +1,128 @@ +// +// detail/thread_info_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_THREAD_INFO_BASE_HPP +#define BOOST_ASIO_DETAIL_THREAD_INFO_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class thread_info_base + : private noncopyable +{ +public: + struct default_tag + { + enum { mem_index = 0 }; + }; + + struct awaitable_frame_tag + { + enum { mem_index = 1 }; + }; + + struct executor_function_tag + { + enum { mem_index = 2 }; + }; + + thread_info_base() + { + for (int i = 0; i < max_mem_index; ++i) + reusable_memory_[i] = 0; + } + + ~thread_info_base() + { + for (int i = 0; i < max_mem_index; ++i) + if (reusable_memory_[i]) + ::operator delete(reusable_memory_[i]); + } + + static void* allocate(thread_info_base* this_thread, std::size_t size) + { + return allocate(default_tag(), this_thread, size); + } + + static void deallocate(thread_info_base* this_thread, + void* pointer, std::size_t size) + { + deallocate(default_tag(), this_thread, pointer, size); + } + + template + static void* allocate(Purpose, thread_info_base* this_thread, + std::size_t size) + { + std::size_t chunks = (size + chunk_size - 1) / chunk_size; + + if (this_thread && this_thread->reusable_memory_[Purpose::mem_index]) + { + void* const pointer = this_thread->reusable_memory_[Purpose::mem_index]; + this_thread->reusable_memory_[Purpose::mem_index] = 0; + + unsigned char* const mem = static_cast(pointer); + if (static_cast(mem[0]) >= chunks) + { + mem[size] = mem[0]; + return pointer; + } + + ::operator delete(pointer); + } + + void* const pointer = ::operator new(chunks * chunk_size + 1); + unsigned char* const mem = static_cast(pointer); + mem[size] = (chunks <= UCHAR_MAX) ? static_cast(chunks) : 0; + return pointer; + } + + template + static void deallocate(Purpose, thread_info_base* this_thread, + void* pointer, std::size_t size) + { + if (size <= chunk_size * UCHAR_MAX) + { + if (this_thread && this_thread->reusable_memory_[Purpose::mem_index] == 0) + { + unsigned char* const mem = static_cast(pointer); + mem[0] = mem[size]; + this_thread->reusable_memory_[Purpose::mem_index] = pointer; + return; + } + } + + ::operator delete(pointer); + } + +private: + enum { chunk_size = 4 }; + enum { max_mem_index = 3 }; + void* reusable_memory_[max_mem_index]; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_THREAD_INFO_BASE_HPP diff --git a/boost/asio/detail/throw_error.hpp b/boost/asio/detail/throw_error.hpp new file mode 100644 index 0000000..d31c859 --- /dev/null +++ b/boost/asio/detail/throw_error.hpp @@ -0,0 +1,55 @@ +// +// detail/throw_error.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_THROW_ERROR_HPP +#define BOOST_ASIO_DETAIL_THROW_ERROR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +BOOST_ASIO_DECL void do_throw_error(const boost::system::error_code& err); + +BOOST_ASIO_DECL void do_throw_error(const boost::system::error_code& err, + const char* location); + +inline void throw_error(const boost::system::error_code& err) +{ + if (err) + do_throw_error(err); +} + +inline void throw_error(const boost::system::error_code& err, + const char* location) +{ + if (err) + do_throw_error(err, location); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_DETAIL_THROW_ERROR_HPP diff --git a/boost/asio/detail/throw_exception.hpp b/boost/asio/detail/throw_exception.hpp new file mode 100644 index 0000000..6190419 --- /dev/null +++ b/boost/asio/detail/throw_exception.hpp @@ -0,0 +1,53 @@ +// +// detail/throw_exception.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_THROW_EXCEPTION_HPP +#define BOOST_ASIO_DETAIL_THROW_EXCEPTION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION) +# include +#endif // defined(BOOST_ASIO_BOOST_THROW_EXCEPTION) + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION) +using boost::throw_exception; +#else // defined(BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION) + +// Declare the throw_exception function for all targets. +template +void throw_exception(const Exception& e); + +// Only define the throw_exception function when exceptions are enabled. +// Otherwise, it is up to the application to provide a definition of this +// function. +# if !defined(BOOST_ASIO_NO_EXCEPTIONS) +template +void throw_exception(const Exception& e) +{ + throw e; +} +# endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) + +#endif // defined(BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION) + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_THROW_EXCEPTION_HPP diff --git a/boost/asio/detail/timer_queue.hpp b/boost/asio/detail/timer_queue.hpp new file mode 100644 index 0000000..9ce6995 --- /dev/null +++ b/boost/asio/detail/timer_queue.hpp @@ -0,0 +1,362 @@ +// +// detail/timer_queue.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_TIMER_QUEUE_HPP +#define BOOST_ASIO_DETAIL_TIMER_QUEUE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class timer_queue + : public timer_queue_base +{ +public: + // The time type. + typedef typename Time_Traits::time_type time_type; + + // The duration type. + typedef typename Time_Traits::duration_type duration_type; + + // Per-timer data. + class per_timer_data + { + public: + per_timer_data() : + heap_index_((std::numeric_limits::max)()), + next_(0), prev_(0) + { + } + + private: + friend class timer_queue; + + // The operations waiting on the timer. + op_queue op_queue_; + + // The index of the timer in the heap. + std::size_t heap_index_; + + // Pointers to adjacent timers in a linked list. + per_timer_data* next_; + per_timer_data* prev_; + }; + + // Constructor. + timer_queue() + : timers_(), + heap_() + { + } + + // Add a new timer to the queue. Returns true if this is the timer that is + // earliest in the queue, in which case the reactor's event demultiplexing + // function call may need to be interrupted and restarted. + bool enqueue_timer(const time_type& time, per_timer_data& timer, wait_op* op) + { + // Enqueue the timer object. + if (timer.prev_ == 0 && &timer != timers_) + { + if (this->is_positive_infinity(time)) + { + // No heap entry is required for timers that never expire. + timer.heap_index_ = (std::numeric_limits::max)(); + } + else + { + // Put the new timer at the correct position in the heap. This is done + // first since push_back() can throw due to allocation failure. + timer.heap_index_ = heap_.size(); + heap_entry entry = { time, &timer }; + heap_.push_back(entry); + up_heap(heap_.size() - 1); + } + + // Insert the new timer into the linked list of active timers. + timer.next_ = timers_; + timer.prev_ = 0; + if (timers_) + timers_->prev_ = &timer; + timers_ = &timer; + } + + // Enqueue the individual timer operation. + timer.op_queue_.push(op); + + // Interrupt reactor only if newly added timer is first to expire. + return timer.heap_index_ == 0 && timer.op_queue_.front() == op; + } + + // Whether there are no timers in the queue. + virtual bool empty() const + { + return timers_ == 0; + } + + // Get the time for the timer that is earliest in the queue. + virtual long wait_duration_msec(long max_duration) const + { + if (heap_.empty()) + return max_duration; + + return this->to_msec( + Time_Traits::to_posix_duration( + Time_Traits::subtract(heap_[0].time_, Time_Traits::now())), + max_duration); + } + + // Get the time for the timer that is earliest in the queue. + virtual long wait_duration_usec(long max_duration) const + { + if (heap_.empty()) + return max_duration; + + return this->to_usec( + Time_Traits::to_posix_duration( + Time_Traits::subtract(heap_[0].time_, Time_Traits::now())), + max_duration); + } + + // Dequeue all timers not later than the current time. + virtual void get_ready_timers(op_queue& ops) + { + if (!heap_.empty()) + { + const time_type now = Time_Traits::now(); + while (!heap_.empty() && !Time_Traits::less_than(now, heap_[0].time_)) + { + per_timer_data* timer = heap_[0].timer_; + ops.push(timer->op_queue_); + remove_timer(*timer); + } + } + } + + // Dequeue all timers. + virtual void get_all_timers(op_queue& ops) + { + while (timers_) + { + per_timer_data* timer = timers_; + timers_ = timers_->next_; + ops.push(timer->op_queue_); + timer->next_ = 0; + timer->prev_ = 0; + } + + heap_.clear(); + } + + // Cancel and dequeue operations for the given timer. + std::size_t cancel_timer(per_timer_data& timer, op_queue& ops, + std::size_t max_cancelled = (std::numeric_limits::max)()) + { + std::size_t num_cancelled = 0; + if (timer.prev_ != 0 || &timer == timers_) + { + while (wait_op* op = (num_cancelled != max_cancelled) + ? timer.op_queue_.front() : 0) + { + op->ec_ = boost::asio::error::operation_aborted; + timer.op_queue_.pop(); + ops.push(op); + ++num_cancelled; + } + if (timer.op_queue_.empty()) + remove_timer(timer); + } + return num_cancelled; + } + + // Move operations from one timer to another, empty timer. + void move_timer(per_timer_data& target, per_timer_data& source) + { + target.op_queue_.push(source.op_queue_); + + target.heap_index_ = source.heap_index_; + source.heap_index_ = (std::numeric_limits::max)(); + + if (target.heap_index_ < heap_.size()) + heap_[target.heap_index_].timer_ = ⌖ + + if (timers_ == &source) + timers_ = ⌖ + if (source.prev_) + source.prev_->next_ = ⌖ + if (source.next_) + source.next_->prev_= ⌖ + target.next_ = source.next_; + target.prev_ = source.prev_; + source.next_ = 0; + source.prev_ = 0; + } + +private: + // Move the item at the given index up the heap to its correct position. + void up_heap(std::size_t index) + { + while (index > 0) + { + std::size_t parent = (index - 1) / 2; + if (!Time_Traits::less_than(heap_[index].time_, heap_[parent].time_)) + break; + swap_heap(index, parent); + index = parent; + } + } + + // Move the item at the given index down the heap to its correct position. + void down_heap(std::size_t index) + { + std::size_t child = index * 2 + 1; + while (child < heap_.size()) + { + std::size_t min_child = (child + 1 == heap_.size() + || Time_Traits::less_than( + heap_[child].time_, heap_[child + 1].time_)) + ? child : child + 1; + if (Time_Traits::less_than(heap_[index].time_, heap_[min_child].time_)) + break; + swap_heap(index, min_child); + index = min_child; + child = index * 2 + 1; + } + } + + // Swap two entries in the heap. + void swap_heap(std::size_t index1, std::size_t index2) + { + heap_entry tmp = heap_[index1]; + heap_[index1] = heap_[index2]; + heap_[index2] = tmp; + heap_[index1].timer_->heap_index_ = index1; + heap_[index2].timer_->heap_index_ = index2; + } + + // Remove a timer from the heap and list of timers. + void remove_timer(per_timer_data& timer) + { + // Remove the timer from the heap. + std::size_t index = timer.heap_index_; + if (!heap_.empty() && index < heap_.size()) + { + if (index == heap_.size() - 1) + { + timer.heap_index_ = (std::numeric_limits::max)(); + heap_.pop_back(); + } + else + { + swap_heap(index, heap_.size() - 1); + timer.heap_index_ = (std::numeric_limits::max)(); + heap_.pop_back(); + if (index > 0 && Time_Traits::less_than( + heap_[index].time_, heap_[(index - 1) / 2].time_)) + up_heap(index); + else + down_heap(index); + } + } + + // Remove the timer from the linked list of active timers. + if (timers_ == &timer) + timers_ = timer.next_; + if (timer.prev_) + timer.prev_->next_ = timer.next_; + if (timer.next_) + timer.next_->prev_= timer.prev_; + timer.next_ = 0; + timer.prev_ = 0; + } + + // Determine if the specified absolute time is positive infinity. + template + static bool is_positive_infinity(const Time_Type&) + { + return false; + } + + // Determine if the specified absolute time is positive infinity. + template + static bool is_positive_infinity( + const boost::date_time::base_time& time) + { + return time.is_pos_infinity(); + } + + // Helper function to convert a duration into milliseconds. + template + long to_msec(const Duration& d, long max_duration) const + { + if (d.ticks() <= 0) + return 0; + int64_t msec = d.total_milliseconds(); + if (msec == 0) + return 1; + if (msec > max_duration) + return max_duration; + return static_cast(msec); + } + + // Helper function to convert a duration into microseconds. + template + long to_usec(const Duration& d, long max_duration) const + { + if (d.ticks() <= 0) + return 0; + int64_t usec = d.total_microseconds(); + if (usec == 0) + return 1; + if (usec > max_duration) + return max_duration; + return static_cast(usec); + } + + // The head of a linked list of all active timers. + per_timer_data* timers_; + + struct heap_entry + { + // The time when the timer should fire. + time_type time_; + + // The associated timer with enqueued operations. + per_timer_data* timer_; + }; + + // The heap of timers, with the earliest timer at the front. + std::vector heap_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_HPP diff --git a/boost/asio/detail/timer_queue_base.hpp b/boost/asio/detail/timer_queue_base.hpp new file mode 100644 index 0000000..c95a2a5 --- /dev/null +++ b/boost/asio/detail/timer_queue_base.hpp @@ -0,0 +1,70 @@ +// +// detail/timer_queue_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_TIMER_QUEUE_BASE_HPP +#define BOOST_ASIO_DETAIL_TIMER_QUEUE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class timer_queue_base + : private noncopyable +{ +public: + // Constructor. + timer_queue_base() : next_(0) {} + + // Destructor. + virtual ~timer_queue_base() {} + + // Whether there are no timers in the queue. + virtual bool empty() const = 0; + + // Get the time to wait until the next timer. + virtual long wait_duration_msec(long max_duration) const = 0; + + // Get the time to wait until the next timer. + virtual long wait_duration_usec(long max_duration) const = 0; + + // Dequeue all ready timers. + virtual void get_ready_timers(op_queue& ops) = 0; + + // Dequeue all timers. + virtual void get_all_timers(op_queue& ops) = 0; + +private: + friend class timer_queue_set; + + // Next timer queue in the set. + timer_queue_base* next_; +}; + +template +class timer_queue; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_BASE_HPP diff --git a/boost/asio/detail/timer_queue_ptime.hpp b/boost/asio/detail/timer_queue_ptime.hpp new file mode 100644 index 0000000..d803bef --- /dev/null +++ b/boost/asio/detail/timer_queue_ptime.hpp @@ -0,0 +1,101 @@ +// +// detail/timer_queue_ptime.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_TIMER_QUEUE_PTIME_HPP +#define BOOST_ASIO_DETAIL_TIMER_QUEUE_PTIME_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct forwarding_posix_time_traits : time_traits {}; + +// Template specialisation for the commonly used instantation. +template <> +class timer_queue > + : public timer_queue_base +{ +public: + // The time type. + typedef boost::posix_time::ptime time_type; + + // The duration type. + typedef boost::posix_time::time_duration duration_type; + + // Per-timer data. + typedef timer_queue::per_timer_data + per_timer_data; + + // Constructor. + BOOST_ASIO_DECL timer_queue(); + + // Destructor. + BOOST_ASIO_DECL virtual ~timer_queue(); + + // Add a new timer to the queue. Returns true if this is the timer that is + // earliest in the queue, in which case the reactor's event demultiplexing + // function call may need to be interrupted and restarted. + BOOST_ASIO_DECL bool enqueue_timer(const time_type& time, + per_timer_data& timer, wait_op* op); + + // Whether there are no timers in the queue. + BOOST_ASIO_DECL virtual bool empty() const; + + // Get the time for the timer that is earliest in the queue. + BOOST_ASIO_DECL virtual long wait_duration_msec(long max_duration) const; + + // Get the time for the timer that is earliest in the queue. + BOOST_ASIO_DECL virtual long wait_duration_usec(long max_duration) const; + + // Dequeue all timers not later than the current time. + BOOST_ASIO_DECL virtual void get_ready_timers(op_queue& ops); + + // Dequeue all timers. + BOOST_ASIO_DECL virtual void get_all_timers(op_queue& ops); + + // Cancel and dequeue operations for the given timer. + BOOST_ASIO_DECL std::size_t cancel_timer( + per_timer_data& timer, op_queue& ops, + std::size_t max_cancelled = (std::numeric_limits::max)()); + + // Move operations from one timer to another, empty timer. + BOOST_ASIO_DECL void move_timer(per_timer_data& target, + per_timer_data& source); + +private: + timer_queue impl_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + +#endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_PTIME_HPP diff --git a/boost/asio/detail/timer_queue_set.hpp b/boost/asio/detail/timer_queue_set.hpp new file mode 100644 index 0000000..9b25e20 --- /dev/null +++ b/boost/asio/detail/timer_queue_set.hpp @@ -0,0 +1,68 @@ +// +// detail/timer_queue_set.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_TIMER_QUEUE_SET_HPP +#define BOOST_ASIO_DETAIL_TIMER_QUEUE_SET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class timer_queue_set +{ +public: + // Constructor. + BOOST_ASIO_DECL timer_queue_set(); + + // Add a timer queue to the set. + BOOST_ASIO_DECL void insert(timer_queue_base* q); + + // Remove a timer queue from the set. + BOOST_ASIO_DECL void erase(timer_queue_base* q); + + // Determine whether all queues are empty. + BOOST_ASIO_DECL bool all_empty() const; + + // Get the wait duration in milliseconds. + BOOST_ASIO_DECL long wait_duration_msec(long max_duration) const; + + // Get the wait duration in microseconds. + BOOST_ASIO_DECL long wait_duration_usec(long max_duration) const; + + // Dequeue all ready timers. + BOOST_ASIO_DECL void get_ready_timers(op_queue& ops); + + // Dequeue all timers. + BOOST_ASIO_DECL void get_all_timers(op_queue& ops); + +private: + timer_queue_base* first_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_SET_HPP diff --git a/boost/asio/detail/timer_scheduler.hpp b/boost/asio/detail/timer_scheduler.hpp new file mode 100644 index 0000000..9d68a60 --- /dev/null +++ b/boost/asio/detail/timer_scheduler.hpp @@ -0,0 +1,35 @@ +// +// detail/timer_scheduler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_TIMER_SCHEDULER_HPP +#define BOOST_ASIO_DETAIL_TIMER_SCHEDULER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +# include +#elif defined(BOOST_ASIO_HAS_IOCP) +# include +#elif defined(BOOST_ASIO_HAS_EPOLL) +# include +#elif defined(BOOST_ASIO_HAS_KQUEUE) +# include +#elif defined(BOOST_ASIO_HAS_DEV_POLL) +# include +#else +# include +#endif + +#endif // BOOST_ASIO_DETAIL_TIMER_SCHEDULER_HPP diff --git a/boost/asio/detail/timer_scheduler_fwd.hpp b/boost/asio/detail/timer_scheduler_fwd.hpp new file mode 100644 index 0000000..0675edf --- /dev/null +++ b/boost/asio/detail/timer_scheduler_fwd.hpp @@ -0,0 +1,42 @@ +// +// detail/timer_scheduler_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP +#define BOOST_ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +typedef class winrt_timer_scheduler timer_scheduler; +#elif defined(BOOST_ASIO_HAS_IOCP) +typedef class win_iocp_io_context timer_scheduler; +#elif defined(BOOST_ASIO_HAS_EPOLL) +typedef class epoll_reactor timer_scheduler; +#elif defined(BOOST_ASIO_HAS_KQUEUE) +typedef class kqueue_reactor timer_scheduler; +#elif defined(BOOST_ASIO_HAS_DEV_POLL) +typedef class dev_poll_reactor timer_scheduler; +#else +typedef class select_reactor timer_scheduler; +#endif + +} // namespace detail +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_TIMER_SCHEDULER_FWD_HPP diff --git a/boost/asio/detail/tss_ptr.hpp b/boost/asio/detail/tss_ptr.hpp new file mode 100644 index 0000000..a7c87d2 --- /dev/null +++ b/boost/asio/detail/tss_ptr.hpp @@ -0,0 +1,71 @@ +// +// detail/tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_TSS_PTR_HPP +#define BOOST_ASIO_DETAIL_TSS_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_THREADS) +# include +#elif defined(BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION) +# include +#elif defined(BOOST_ASIO_WINDOWS) +# include +#elif defined(BOOST_ASIO_HAS_PTHREADS) +# include +#else +# error Only Windows and POSIX are supported! +#endif + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class tss_ptr +#if !defined(BOOST_ASIO_HAS_THREADS) + : public null_tss_ptr +#elif defined(BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION) + : public keyword_tss_ptr +#elif defined(BOOST_ASIO_WINDOWS) + : public win_tss_ptr +#elif defined(BOOST_ASIO_HAS_PTHREADS) + : public posix_tss_ptr +#endif +{ +public: + void operator=(T* value) + { +#if !defined(BOOST_ASIO_HAS_THREADS) + null_tss_ptr::operator=(value); +#elif defined(BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION) + keyword_tss_ptr::operator=(value); +#elif defined(BOOST_ASIO_WINDOWS) + win_tss_ptr::operator=(value); +#elif defined(BOOST_ASIO_HAS_PTHREADS) + posix_tss_ptr::operator=(value); +#endif + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_TSS_PTR_HPP diff --git a/boost/asio/detail/type_traits.hpp b/boost/asio/detail/type_traits.hpp new file mode 100644 index 0000000..c53a7e7 --- /dev/null +++ b/boost/asio/detail/type_traits.hpp @@ -0,0 +1,88 @@ +// +// detail/type_traits.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_TYPE_TRAITS_HPP +#define BOOST_ASIO_DETAIL_TYPE_TRAITS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) +# include +#else // defined(BOOST_ASIO_HAS_TYPE_TRAITS) +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif // defined(BOOST_ASIO_HAS_TYPE_TRAITS) + +namespace boost { +namespace asio { + +#if defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) +using std::add_const; +using std::conditional; +using std::decay; +using std::enable_if; +using std::false_type; +using std::integral_constant; +using std::is_base_of; +using std::is_class; +using std::is_const; +using std::is_convertible; +using std::is_function; +using std::is_same; +using std::remove_pointer; +using std::remove_reference; +#if defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT) +template struct result_of; +template +struct result_of : std::invoke_result {}; +#else // defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT) +using std::result_of; +#endif // defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT) +using std::true_type; +#else // defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) +using boost::add_const; +template +struct enable_if : boost::enable_if_c {}; +using boost::conditional; +using boost::decay; +using boost::false_type; +using boost::integral_constant; +using boost::is_base_of; +using boost::is_class; +using boost::is_const; +using boost::is_convertible; +using boost::is_function; +using boost::is_same; +using boost::remove_pointer; +using boost::remove_reference; +using boost::result_of; +using boost::true_type; +#endif // defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) + +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_DETAIL_TYPE_TRAITS_HPP diff --git a/boost/asio/detail/variadic_templates.hpp b/boost/asio/detail/variadic_templates.hpp new file mode 100644 index 0000000..f552b4b --- /dev/null +++ b/boost/asio/detail/variadic_templates.hpp @@ -0,0 +1,133 @@ +// +// detail/variadic_templates.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_VARIADIC_TEMPLATES_HPP +#define BOOST_ASIO_DETAIL_VARIADIC_TEMPLATES_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +# define BOOST_ASIO_VARIADIC_TPARAMS(n) BOOST_ASIO_VARIADIC_TPARAMS_##n + +# define BOOST_ASIO_VARIADIC_TPARAMS_1 \ + typename T1 +# define BOOST_ASIO_VARIADIC_TPARAMS_2 \ + typename T1, typename T2 +# define BOOST_ASIO_VARIADIC_TPARAMS_3 \ + typename T1, typename T2, typename T3 +# define BOOST_ASIO_VARIADIC_TPARAMS_4 \ + typename T1, typename T2, typename T3, typename T4 +# define BOOST_ASIO_VARIADIC_TPARAMS_5 \ + typename T1, typename T2, typename T3, typename T4, typename T5 + +# define BOOST_ASIO_VARIADIC_TARGS(n) BOOST_ASIO_VARIADIC_TARGS_##n + +# define BOOST_ASIO_VARIADIC_TARGS_1 T1 +# define BOOST_ASIO_VARIADIC_TARGS_2 T1, T2 +# define BOOST_ASIO_VARIADIC_TARGS_3 T1, T2, T3 +# define BOOST_ASIO_VARIADIC_TARGS_4 T1, T2, T3, T4 +# define BOOST_ASIO_VARIADIC_TARGS_5 T1, T2, T3, T4, T5 + +# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS(n) \ + BOOST_ASIO_VARIADIC_BYVAL_PARAMS_##n + +# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_1 T1 x1 +# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_2 T1 x1, T2 x2 +# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_3 T1 x1, T2 x2, T3 x3 +# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_4 T1 x1, T2 x2, T3 x3, T4 x4 +# define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_5 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5 + +# define BOOST_ASIO_VARIADIC_BYVAL_ARGS(n) \ + BOOST_ASIO_VARIADIC_BYVAL_ARGS_##n + +# define BOOST_ASIO_VARIADIC_BYVAL_ARGS_1 x1 +# define BOOST_ASIO_VARIADIC_BYVAL_ARGS_2 x1, x2 +# define BOOST_ASIO_VARIADIC_BYVAL_ARGS_3 x1, x2, x3 +# define BOOST_ASIO_VARIADIC_BYVAL_ARGS_4 x1, x2, x3, x4 +# define BOOST_ASIO_VARIADIC_BYVAL_ARGS_5 x1, x2, x3, x4, x5 + +# define BOOST_ASIO_VARIADIC_CONSTREF_PARAMS(n) \ + BOOST_ASIO_VARIADIC_CONSTREF_PARAMS_##n + +# define BOOST_ASIO_VARIADIC_CONSTREF_PARAMS_1 \ + const T1& x1 +# define BOOST_ASIO_VARIADIC_CONSTREF_PARAMS_2 \ + const T1& x1, const T2& x2 +# define BOOST_ASIO_VARIADIC_CONSTREF_PARAMS_3 \ + const T1& x1, const T2& x2, const T3& x3 +# define BOOST_ASIO_VARIADIC_CONSTREF_PARAMS_4 \ + const T1& x1, const T2& x2, const T3& x3, const T4& x4 +# define BOOST_ASIO_VARIADIC_CONSTREF_PARAMS_5 \ + const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5 + +# define BOOST_ASIO_VARIADIC_MOVE_PARAMS(n) \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS_##n + +# define BOOST_ASIO_VARIADIC_MOVE_PARAMS_1 \ + BOOST_ASIO_MOVE_ARG(T1) x1 +# define BOOST_ASIO_VARIADIC_MOVE_PARAMS_2 \ + BOOST_ASIO_MOVE_ARG(T1) x1, BOOST_ASIO_MOVE_ARG(T2) x2 +# define BOOST_ASIO_VARIADIC_MOVE_PARAMS_3 \ + BOOST_ASIO_MOVE_ARG(T1) x1, BOOST_ASIO_MOVE_ARG(T2) x2, \ + BOOST_ASIO_MOVE_ARG(T3) x3 +# define BOOST_ASIO_VARIADIC_MOVE_PARAMS_4 \ + BOOST_ASIO_MOVE_ARG(T1) x1, BOOST_ASIO_MOVE_ARG(T2) x2, \ + BOOST_ASIO_MOVE_ARG(T3) x3, BOOST_ASIO_MOVE_ARG(T4) x4 +# define BOOST_ASIO_VARIADIC_MOVE_PARAMS_5 \ + BOOST_ASIO_MOVE_ARG(T1) x1, BOOST_ASIO_MOVE_ARG(T2) x2, \ + BOOST_ASIO_MOVE_ARG(T3) x3, BOOST_ASIO_MOVE_ARG(T4) x4, \ + BOOST_ASIO_MOVE_ARG(T5) x5 + +# define BOOST_ASIO_VARIADIC_MOVE_ARGS(n) \ + BOOST_ASIO_VARIADIC_MOVE_ARGS_##n + +# define BOOST_ASIO_VARIADIC_MOVE_ARGS_1 \ + BOOST_ASIO_MOVE_CAST(T1)(x1) +# define BOOST_ASIO_VARIADIC_MOVE_ARGS_2 \ + BOOST_ASIO_MOVE_CAST(T1)(x1), BOOST_ASIO_MOVE_CAST(T2)(x2) +# define BOOST_ASIO_VARIADIC_MOVE_ARGS_3 \ + BOOST_ASIO_MOVE_CAST(T1)(x1), BOOST_ASIO_MOVE_CAST(T2)(x2), \ + BOOST_ASIO_MOVE_CAST(T3)(x3) +# define BOOST_ASIO_VARIADIC_MOVE_ARGS_4 \ + BOOST_ASIO_MOVE_CAST(T1)(x1), BOOST_ASIO_MOVE_CAST(T2)(x2), \ + BOOST_ASIO_MOVE_CAST(T3)(x3), BOOST_ASIO_MOVE_CAST(T4)(x4) +# define BOOST_ASIO_VARIADIC_MOVE_ARGS_5 \ + BOOST_ASIO_MOVE_CAST(T1)(x1), BOOST_ASIO_MOVE_CAST(T2)(x2), \ + BOOST_ASIO_MOVE_CAST(T3)(x3), BOOST_ASIO_MOVE_CAST(T4)(x4), \ + BOOST_ASIO_MOVE_CAST(T5)(x5) + +# define BOOST_ASIO_VARIADIC_DECAY(n) \ + BOOST_ASIO_VARIADIC_DECAY_##n + +# define BOOST_ASIO_VARIADIC_DECAY_1 \ + typename decay::type +# define BOOST_ASIO_VARIADIC_DECAY_2 \ + typename decay::type, typename decay::type +# define BOOST_ASIO_VARIADIC_DECAY_3 \ + typename decay::type, typename decay::type, \ + typename decay::type +# define BOOST_ASIO_VARIADIC_DECAY_4 \ + typename decay::type, typename decay::type, \ + typename decay::type, typename decay::type +# define BOOST_ASIO_VARIADIC_DECAY_5 \ + typename decay::type, typename decay::type, \ + typename decay::type, typename decay::type, \ + typename decay::type + +# define BOOST_ASIO_VARIADIC_GENERATE(m) m(1) m(2) m(3) m(4) m(5) + +#endif // !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#endif // BOOST_ASIO_DETAIL_VARIADIC_TEMPLATES_HPP diff --git a/boost/asio/detail/wait_handler.hpp b/boost/asio/detail/wait_handler.hpp new file mode 100644 index 0000000..b947734 --- /dev/null +++ b/boost/asio/detail/wait_handler.hpp @@ -0,0 +1,89 @@ +// +// detail/wait_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WAIT_HANDLER_HPP +#define BOOST_ASIO_DETAIL_WAIT_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class wait_handler : public wait_op +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(wait_handler); + + wait_handler(Handler& h, const IoExecutor& ex) + : wait_op(&wait_handler::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(h)), + io_executor_(ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& /*ec*/, + std::size_t /*bytes_transferred*/) + { + // Take ownership of the handler object. + wait_handler* h(static_cast(base)); + ptr p = { boost::asio::detail::addressof(h->handler_), h, h }; + handler_work w(h->handler_, h->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*h)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1 + handler(h->handler_, h->ec_); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_WAIT_HANDLER_HPP diff --git a/boost/asio/detail/wait_op.hpp b/boost/asio/detail/wait_op.hpp new file mode 100644 index 0000000..a6b88f6 --- /dev/null +++ b/boost/asio/detail/wait_op.hpp @@ -0,0 +1,47 @@ +// +// detail/wait_op.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WAIT_OP_HPP +#define BOOST_ASIO_DETAIL_WAIT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class wait_op + : public operation +{ +public: + // The error code to be passed to the completion handler. + boost::system::error_code ec_; + +protected: + wait_op(func_type func) + : operation(func) + { + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_WAIT_OP_HPP diff --git a/boost/asio/detail/win_event.hpp b/boost/asio/detail/win_event.hpp new file mode 100644 index 0000000..08de010 --- /dev/null +++ b/boost/asio/detail/win_event.hpp @@ -0,0 +1,153 @@ +// +// detail/win_event.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_EVENT_HPP +#define BOOST_ASIO_DETAIL_WIN_EVENT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class win_event + : private noncopyable +{ +public: + // Constructor. + BOOST_ASIO_DECL win_event(); + + // Destructor. + BOOST_ASIO_DECL ~win_event(); + + // Signal the event. (Retained for backward compatibility.) + template + void signal(Lock& lock) + { + this->signal_all(lock); + } + + // Signal all waiters. + template + void signal_all(Lock& lock) + { + BOOST_ASIO_ASSERT(lock.locked()); + (void)lock; + state_ |= 1; + ::SetEvent(events_[0]); + } + + // Unlock the mutex and signal one waiter. + template + void unlock_and_signal_one(Lock& lock) + { + BOOST_ASIO_ASSERT(lock.locked()); + state_ |= 1; + bool have_waiters = (state_ > 1); + lock.unlock(); + if (have_waiters) + ::SetEvent(events_[1]); + } + + // If there's a waiter, unlock the mutex and signal it. + template + bool maybe_unlock_and_signal_one(Lock& lock) + { + BOOST_ASIO_ASSERT(lock.locked()); + state_ |= 1; + if (state_ > 1) + { + lock.unlock(); + ::SetEvent(events_[1]); + return true; + } + return false; + } + + // Reset the event. + template + void clear(Lock& lock) + { + BOOST_ASIO_ASSERT(lock.locked()); + (void)lock; + ::ResetEvent(events_[0]); + state_ &= ~std::size_t(1); + } + + // Wait for the event to become signalled. + template + void wait(Lock& lock) + { + BOOST_ASIO_ASSERT(lock.locked()); + while ((state_ & 1) == 0) + { + state_ += 2; + lock.unlock(); +#if defined(BOOST_ASIO_WINDOWS_APP) + ::WaitForMultipleObjectsEx(2, events_, false, INFINITE, false); +#else // defined(BOOST_ASIO_WINDOWS_APP) + ::WaitForMultipleObjects(2, events_, false, INFINITE); +#endif // defined(BOOST_ASIO_WINDOWS_APP) + lock.lock(); + state_ -= 2; + } + } + + // Timed wait for the event to become signalled. + template + bool wait_for_usec(Lock& lock, long usec) + { + BOOST_ASIO_ASSERT(lock.locked()); + if ((state_ & 1) == 0) + { + state_ += 2; + lock.unlock(); + DWORD msec = usec > 0 ? (usec < 1000 ? 1 : usec / 1000) : 0; +#if defined(BOOST_ASIO_WINDOWS_APP) + ::WaitForMultipleObjectsEx(2, events_, false, msec, false); +#else // defined(BOOST_ASIO_WINDOWS_APP) + ::WaitForMultipleObjects(2, events_, false, msec); +#endif // defined(BOOST_ASIO_WINDOWS_APP) + lock.lock(); + state_ -= 2; + } + return (state_ & 1) != 0; + } + +private: + HANDLE events_[2]; + std::size_t state_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_WINDOWS) + +#endif // BOOST_ASIO_DETAIL_WIN_EVENT_HPP diff --git a/boost/asio/detail/win_fd_set_adapter.hpp b/boost/asio/detail/win_fd_set_adapter.hpp new file mode 100644 index 0000000..3f66d4a --- /dev/null +++ b/boost/asio/detail/win_fd_set_adapter.hpp @@ -0,0 +1,151 @@ +// +// detail/win_fd_set_adapter.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP +#define BOOST_ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Adapts the FD_SET type to meet the Descriptor_Set concept's requirements. +class win_fd_set_adapter : noncopyable +{ +public: + enum { default_fd_set_size = 1024 }; + + win_fd_set_adapter() + : capacity_(default_fd_set_size), + max_descriptor_(invalid_socket) + { + fd_set_ = static_cast(::operator new( + sizeof(win_fd_set) - sizeof(SOCKET) + + sizeof(SOCKET) * (capacity_))); + fd_set_->fd_count = 0; + } + + ~win_fd_set_adapter() + { + ::operator delete(fd_set_); + } + + void reset() + { + fd_set_->fd_count = 0; + max_descriptor_ = invalid_socket; + } + + bool set(socket_type descriptor) + { + for (u_int i = 0; i < fd_set_->fd_count; ++i) + if (fd_set_->fd_array[i] == descriptor) + return true; + + reserve(fd_set_->fd_count + 1); + fd_set_->fd_array[fd_set_->fd_count++] = descriptor; + return true; + } + + void set(reactor_op_queue& operations, op_queue&) + { + reactor_op_queue::iterator i = operations.begin(); + while (i != operations.end()) + { + reactor_op_queue::iterator op_iter = i++; + reserve(fd_set_->fd_count + 1); + fd_set_->fd_array[fd_set_->fd_count++] = op_iter->first; + } + } + + bool is_set(socket_type descriptor) const + { + return !!__WSAFDIsSet(descriptor, + const_cast(reinterpret_cast(fd_set_))); + } + + operator fd_set*() + { + return reinterpret_cast(fd_set_); + } + + socket_type max_descriptor() const + { + return max_descriptor_; + } + + void perform(reactor_op_queue& operations, + op_queue& ops) const + { + for (u_int i = 0; i < fd_set_->fd_count; ++i) + operations.perform_operations(fd_set_->fd_array[i], ops); + } + +private: + // This structure is defined to be compatible with the Windows API fd_set + // structure, but without being dependent on the value of FD_SETSIZE. We use + // the "struct hack" to allow the number of descriptors to be varied at + // runtime. + struct win_fd_set + { + u_int fd_count; + SOCKET fd_array[1]; + }; + + // Increase the fd_set_ capacity to at least the specified number of elements. + void reserve(u_int n) + { + if (n <= capacity_) + return; + + u_int new_capacity = capacity_ + capacity_ / 2; + if (new_capacity < n) + new_capacity = n; + + win_fd_set* new_fd_set = static_cast(::operator new( + sizeof(win_fd_set) - sizeof(SOCKET) + + sizeof(SOCKET) * (new_capacity))); + + new_fd_set->fd_count = fd_set_->fd_count; + for (u_int i = 0; i < fd_set_->fd_count; ++i) + new_fd_set->fd_array[i] = fd_set_->fd_array[i]; + + ::operator delete(fd_set_); + fd_set_ = new_fd_set; + capacity_ = new_capacity; + } + + win_fd_set* fd_set_; + u_int capacity_; + socket_type max_descriptor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP diff --git a/boost/asio/detail/win_fenced_block.hpp b/boost/asio/detail/win_fenced_block.hpp new file mode 100644 index 0000000..42aee2d --- /dev/null +++ b/boost/asio/detail/win_fenced_block.hpp @@ -0,0 +1,92 @@ +// +// detail/win_fenced_block.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_FENCED_BLOCK_HPP +#define BOOST_ASIO_DETAIL_WIN_FENCED_BLOCK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS) && !defined(UNDER_CE) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class win_fenced_block + : private noncopyable +{ +public: + enum half_t { half }; + enum full_t { full }; + + // Constructor for a half fenced block. + explicit win_fenced_block(half_t) + { + } + + // Constructor for a full fenced block. + explicit win_fenced_block(full_t) + { +#if defined(__BORLANDC__) + LONG barrier = 0; + ::InterlockedExchange(&barrier, 1); +#elif defined(BOOST_ASIO_MSVC) \ + && ((BOOST_ASIO_MSVC < 1400) || !defined(MemoryBarrier)) +# if defined(_M_IX86) +# pragma warning(push) +# pragma warning(disable:4793) + LONG barrier; + __asm { xchg barrier, eax } +# pragma warning(pop) +# endif // defined(_M_IX86) +#else + MemoryBarrier(); +#endif + } + + // Destructor. + ~win_fenced_block() + { +#if defined(__BORLANDC__) + LONG barrier = 0; + ::InterlockedExchange(&barrier, 1); +#elif defined(BOOST_ASIO_MSVC) \ + && ((BOOST_ASIO_MSVC < 1400) || !defined(MemoryBarrier)) +# if defined(_M_IX86) +# pragma warning(push) +# pragma warning(disable:4793) + LONG barrier; + __asm { xchg barrier, eax } +# pragma warning(pop) +# endif // defined(_M_IX86) +#else + MemoryBarrier(); +#endif + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS) && !defined(UNDER_CE) + +#endif // BOOST_ASIO_DETAIL_WIN_FENCED_BLOCK_HPP diff --git a/boost/asio/detail/win_global.hpp b/boost/asio/detail/win_global.hpp new file mode 100644 index 0000000..1165579 --- /dev/null +++ b/boost/asio/detail/win_global.hpp @@ -0,0 +1,73 @@ +// +// detail/win_global.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_GLOBAL_HPP +#define BOOST_ASIO_DETAIL_WIN_GLOBAL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +struct win_global_impl +{ + // Destructor automatically cleans up the global. + ~win_global_impl() + { + delete ptr_; + } + + static win_global_impl instance_; + static static_mutex mutex_; + T* ptr_; + static tss_ptr tss_ptr_; +}; + +template +win_global_impl win_global_impl::instance_ = { 0 }; + +template +static_mutex win_global_impl::mutex_ = BOOST_ASIO_STATIC_MUTEX_INIT; + +template +tss_ptr win_global_impl::tss_ptr_; + +template +T& win_global() +{ + if (static_cast(win_global_impl::tss_ptr_) == 0) + { + win_global_impl::mutex_.init(); + static_mutex::scoped_lock lock(win_global_impl::mutex_); + if (win_global_impl::instance_.ptr_ == 0) + win_global_impl::instance_.ptr_ = new T; + win_global_impl::tss_ptr_ = win_global_impl::instance_.ptr_; + } + + return *win_global_impl::tss_ptr_; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_WIN_GLOBAL_HPP diff --git a/boost/asio/detail/win_iocp_handle_read_op.hpp b/boost/asio/detail/win_iocp_handle_read_op.hpp new file mode 100644 index 0000000..04675ab --- /dev/null +++ b/boost/asio/detail/win_iocp_handle_read_op.hpp @@ -0,0 +1,115 @@ +// +// detail/win_iocp_handle_read_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_handle_read_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_read_op); + + win_iocp_handle_read_op(const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + : operation(&win_iocp_handle_read_op::do_complete), + buffers_(buffers), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& result_ec, + std::size_t bytes_transferred) + { + boost::system::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_handle_read_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + if (owner) + { + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_HANDLE_EOF) + ec = boost::asio::error::eof; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + MutableBufferSequence buffers_; + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP diff --git a/boost/asio/detail/win_iocp_handle_service.hpp b/boost/asio/detail/win_iocp_handle_service.hpp new file mode 100644 index 0000000..92aa8e8 --- /dev/null +++ b/boost/asio/detail/win_iocp_handle_service.hpp @@ -0,0 +1,337 @@ +// +// detail/win_iocp_handle_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class win_iocp_handle_service : + public execution_context_service_base +{ +public: + // The native type of a stream handle. + typedef HANDLE native_handle_type; + + // The implementation type of the stream handle. + class implementation_type + { + public: + // Default constructor. + implementation_type() + : handle_(INVALID_HANDLE_VALUE), + safe_cancellation_thread_id_(0), + next_(0), + prev_(0) + { + } + + private: + // Only this service will have access to the internal values. + friend class win_iocp_handle_service; + + // The native stream handle representation. + native_handle_type handle_; + + // The ID of the thread from which it is safe to cancel asynchronous + // operations. 0 means no asynchronous operations have been started yet. + // ~0 means asynchronous operations have been started from more than one + // thread, and cancellation is not supported for the handle. + DWORD safe_cancellation_thread_id_; + + // Pointers to adjacent handle implementations in linked list. + implementation_type* next_; + implementation_type* prev_; + }; + + BOOST_ASIO_DECL win_iocp_handle_service(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown(); + + // Construct a new handle implementation. + BOOST_ASIO_DECL void construct(implementation_type& impl); + + // Move-construct a new handle implementation. + BOOST_ASIO_DECL void move_construct(implementation_type& impl, + implementation_type& other_impl); + + // Move-assign from another handle implementation. + BOOST_ASIO_DECL void move_assign(implementation_type& impl, + win_iocp_handle_service& other_service, + implementation_type& other_impl); + + // Destroy a handle implementation. + BOOST_ASIO_DECL void destroy(implementation_type& impl); + + // Assign a native handle to a handle implementation. + BOOST_ASIO_DECL boost::system::error_code assign(implementation_type& impl, + const native_handle_type& handle, boost::system::error_code& ec); + + // Determine whether the handle is open. + bool is_open(const implementation_type& impl) const + { + return impl.handle_ != INVALID_HANDLE_VALUE; + } + + // Destroy a handle implementation. + BOOST_ASIO_DECL boost::system::error_code close(implementation_type& impl, + boost::system::error_code& ec); + + // Get the native handle representation. + native_handle_type native_handle(const implementation_type& impl) const + { + return impl.handle_; + } + + // Cancel all operations associated with the handle. + BOOST_ASIO_DECL boost::system::error_code cancel(implementation_type& impl, + boost::system::error_code& ec); + + // Write the given data. Returns the number of bytes written. + template + size_t write_some(implementation_type& impl, + const ConstBufferSequence& buffers, boost::system::error_code& ec) + { + return write_some_at(impl, 0, buffers, ec); + } + + // Write the given data at the specified offset. Returns the number of bytes + // written. + template + size_t write_some_at(implementation_type& impl, uint64_t offset, + const ConstBufferSequence& buffers, boost::system::error_code& ec) + { + boost::asio::const_buffer buffer = + buffer_sequence_adapter::first(buffers); + + return do_write(impl, offset, buffer, ec); + } + + // Start an asynchronous write. The data being written must be valid for the + // lifetime of the asynchronous operation. + template + void async_write_some(implementation_type& impl, + const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_handle_write_op< + ConstBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(buffers, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, + reinterpret_cast(impl.handle_), "async_write_some")); + + start_write_op(impl, 0, + buffer_sequence_adapter::first(buffers), p.p); + p.v = p.p = 0; + } + + // Start an asynchronous write at a specified offset. The data being written + // must be valid for the lifetime of the asynchronous operation. + template + void async_write_some_at(implementation_type& impl, + uint64_t offset, const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_handle_write_op< + ConstBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(buffers, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, + reinterpret_cast(impl.handle_), "async_write_some_at")); + + start_write_op(impl, offset, + buffer_sequence_adapter::first(buffers), p.p); + p.v = p.p = 0; + } + + // Read some data. Returns the number of bytes received. + template + size_t read_some(implementation_type& impl, + const MutableBufferSequence& buffers, boost::system::error_code& ec) + { + return read_some_at(impl, 0, buffers, ec); + } + + // Read some data at a specified offset. Returns the number of bytes received. + template + size_t read_some_at(implementation_type& impl, uint64_t offset, + const MutableBufferSequence& buffers, boost::system::error_code& ec) + { + boost::asio::mutable_buffer buffer = + buffer_sequence_adapter::first(buffers); + + return do_read(impl, offset, buffer, ec); + } + + // Start an asynchronous read. The buffer for the data being received must be + // valid for the lifetime of the asynchronous operation. + template + void async_read_some(implementation_type& impl, + const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_handle_read_op< + MutableBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(buffers, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, + reinterpret_cast(impl.handle_), "async_read_some")); + + start_read_op(impl, 0, + buffer_sequence_adapter::first(buffers), p.p); + p.v = p.p = 0; + } + + // Start an asynchronous read at a specified offset. The buffer for the data + // being received must be valid for the lifetime of the asynchronous + // operation. + template + void async_read_some_at(implementation_type& impl, + uint64_t offset, const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_handle_read_op< + MutableBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(buffers, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((iocp_service_.context(), *p.p, "handle", &impl, + reinterpret_cast(impl.handle_), "async_read_some_at")); + + start_read_op(impl, offset, + buffer_sequence_adapter::first(buffers), p.p); + p.v = p.p = 0; + } + +private: + // Prevent the use of the null_buffers type with this service. + size_t write_some(implementation_type& impl, + const null_buffers& buffers, boost::system::error_code& ec); + size_t write_some_at(implementation_type& impl, uint64_t offset, + const null_buffers& buffers, boost::system::error_code& ec); + template + void async_write_some(implementation_type& impl, + const null_buffers& buffers, Handler& handler, + const IoExecutor& io_ex); + template + void async_write_some_at(implementation_type& impl, uint64_t offset, + const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex); + size_t read_some(implementation_type& impl, + const null_buffers& buffers, boost::system::error_code& ec); + size_t read_some_at(implementation_type& impl, uint64_t offset, + const null_buffers& buffers, boost::system::error_code& ec); + template + void async_read_some(implementation_type& impl, + const null_buffers& buffers, Handler& handler, + const IoExecutor& io_ex); + template + void async_read_some_at(implementation_type& impl, uint64_t offset, + const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex); + + // Helper class for waiting for synchronous operations to complete. + class overlapped_wrapper; + + // Helper function to perform a synchronous write operation. + BOOST_ASIO_DECL size_t do_write(implementation_type& impl, + uint64_t offset, const boost::asio::const_buffer& buffer, + boost::system::error_code& ec); + + // Helper function to start a write operation. + BOOST_ASIO_DECL void start_write_op(implementation_type& impl, + uint64_t offset, const boost::asio::const_buffer& buffer, + operation* op); + + // Helper function to perform a synchronous write operation. + BOOST_ASIO_DECL size_t do_read(implementation_type& impl, + uint64_t offset, const boost::asio::mutable_buffer& buffer, + boost::system::error_code& ec); + + // Helper function to start a read operation. + BOOST_ASIO_DECL void start_read_op(implementation_type& impl, + uint64_t offset, const boost::asio::mutable_buffer& buffer, + operation* op); + + // Update the ID of the thread from which cancellation is safe. + BOOST_ASIO_DECL void update_cancellation_thread_id(implementation_type& impl); + + // Helper function to close a handle when the associated object is being + // destroyed. + BOOST_ASIO_DECL void close_for_destruction(implementation_type& impl); + + // The IOCP service used for running asynchronous operations and dispatching + // handlers. + win_iocp_io_context& iocp_service_; + + // Mutex to protect access to the linked list of implementations. + mutex mutex_; + + // The head of a linked list of all implementations. + implementation_type* impl_list_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP diff --git a/boost/asio/detail/win_iocp_handle_write_op.hpp b/boost/asio/detail/win_iocp_handle_write_op.hpp new file mode 100644 index 0000000..7e81eb8 --- /dev/null +++ b/boost/asio/detail/win_iocp_handle_write_op.hpp @@ -0,0 +1,108 @@ +// +// detail/win_iocp_handle_write_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_handle_write_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_handle_write_op); + + win_iocp_handle_write_op(const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + : operation(&win_iocp_handle_write_op::do_complete), + buffers_(buffers), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_handle_write_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + if (owner) + { + // Check whether buffers are still valid. + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + ConstBufferSequence buffers_; + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP diff --git a/boost/asio/detail/win_iocp_io_context.hpp b/boost/asio/detail/win_iocp_io_context.hpp new file mode 100644 index 0000000..d551b9b --- /dev/null +++ b/boost/asio/detail/win_iocp_io_context.hpp @@ -0,0 +1,340 @@ +// +// detail/win_iocp_io_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class wait_op; + +class win_iocp_io_context + : public execution_context_service_base, + public thread_context +{ +public: + // Constructor. Specifies a concurrency hint that is passed through to the + // underlying I/O completion port. + BOOST_ASIO_DECL win_iocp_io_context(boost::asio::execution_context& ctx, + int concurrency_hint = -1, bool own_thread = true); + + // Destructor. + BOOST_ASIO_DECL ~win_iocp_io_context(); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown(); + + // Initialise the task. Nothing to do here. + void init_task() + { + } + + // Register a handle with the IO completion port. + BOOST_ASIO_DECL boost::system::error_code register_handle( + HANDLE handle, boost::system::error_code& ec); + + // Run the event loop until stopped or no more work. + BOOST_ASIO_DECL size_t run(boost::system::error_code& ec); + + // Run until stopped or one operation is performed. + BOOST_ASIO_DECL size_t run_one(boost::system::error_code& ec); + + // Run until timeout, interrupted, or one operation is performed. + BOOST_ASIO_DECL size_t wait_one(long usec, boost::system::error_code& ec); + + // Poll for operations without blocking. + BOOST_ASIO_DECL size_t poll(boost::system::error_code& ec); + + // Poll for one operation without blocking. + BOOST_ASIO_DECL size_t poll_one(boost::system::error_code& ec); + + // Stop the event processing loop. + BOOST_ASIO_DECL void stop(); + + // Determine whether the io_context is stopped. + bool stopped() const + { + return ::InterlockedExchangeAdd(&stopped_, 0) != 0; + } + + // Restart in preparation for a subsequent run invocation. + void restart() + { + ::InterlockedExchange(&stopped_, 0); + } + + // Notify that some work has started. + void work_started() + { + ::InterlockedIncrement(&outstanding_work_); + } + + // Notify that some work has finished. + void work_finished() + { + if (::InterlockedDecrement(&outstanding_work_) == 0) + stop(); + } + + // Return whether a handler can be dispatched immediately. + bool can_dispatch() + { + return thread_call_stack::contains(this) != 0; + } + + // Request invocation of the given operation and return immediately. Assumes + // that work_started() has not yet been called for the operation. + void post_immediate_completion(win_iocp_operation* op, bool) + { + work_started(); + post_deferred_completion(op); + } + + // Request invocation of the given operation and return immediately. Assumes + // that work_started() was previously called for the operation. + BOOST_ASIO_DECL void post_deferred_completion(win_iocp_operation* op); + + // Request invocation of the given operation and return immediately. Assumes + // that work_started() was previously called for the operations. + BOOST_ASIO_DECL void post_deferred_completions( + op_queue& ops); + + // Request invocation of the given operation using the thread-private queue + // and return immediately. Assumes that work_started() has not yet been + // called for the operation. + void post_private_immediate_completion(win_iocp_operation* op) + { + post_immediate_completion(op, false); + } + + // Request invocation of the given operation using the thread-private queue + // and return immediately. Assumes that work_started() was previously called + // for the operation. + void post_private_deferred_completion(win_iocp_operation* op) + { + post_deferred_completion(op); + } + + // Enqueue the given operation following a failed attempt to dispatch the + // operation for immediate invocation. + void do_dispatch(operation* op) + { + post_immediate_completion(op, false); + } + + // Process unfinished operations as part of a shutdown operation. Assumes + // that work_started() was previously called for the operations. + BOOST_ASIO_DECL void abandon_operations(op_queue& ops); + + // Called after starting an overlapped I/O operation that did not complete + // immediately. The caller must have already called work_started() prior to + // starting the operation. + BOOST_ASIO_DECL void on_pending(win_iocp_operation* op); + + // Called after starting an overlapped I/O operation that completed + // immediately. The caller must have already called work_started() prior to + // starting the operation. + BOOST_ASIO_DECL void on_completion(win_iocp_operation* op, + DWORD last_error = 0, DWORD bytes_transferred = 0); + + // Called after starting an overlapped I/O operation that completed + // immediately. The caller must have already called work_started() prior to + // starting the operation. + BOOST_ASIO_DECL void on_completion(win_iocp_operation* op, + const boost::system::error_code& ec, DWORD bytes_transferred = 0); + + // Add a new timer queue to the service. + template + void add_timer_queue(timer_queue& timer_queue); + + // Remove a timer queue from the service. + template + void remove_timer_queue(timer_queue& timer_queue); + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template + void schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op); + + // Cancel the timer associated with the given token. Returns the number of + // handlers that have been posted or dispatched. + template + std::size_t cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled = (std::numeric_limits::max)()); + + // Move the timer operations associated with the given timer. + template + void move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& to, + typename timer_queue::per_timer_data& from); + + // Get the concurrency hint that was used to initialise the io_context. + int concurrency_hint() const + { + return concurrency_hint_; + } + +private: +#if defined(WINVER) && (WINVER < 0x0500) + typedef DWORD dword_ptr_t; + typedef ULONG ulong_ptr_t; +#else // defined(WINVER) && (WINVER < 0x0500) + typedef DWORD_PTR dword_ptr_t; + typedef ULONG_PTR ulong_ptr_t; +#endif // defined(WINVER) && (WINVER < 0x0500) + + // Dequeues at most one operation from the I/O completion port, and then + // executes it. Returns the number of operations that were dequeued (i.e. + // either 0 or 1). + BOOST_ASIO_DECL size_t do_one(DWORD msec, boost::system::error_code& ec); + + // Helper to calculate the GetQueuedCompletionStatus timeout. + BOOST_ASIO_DECL static DWORD get_gqcs_timeout(); + + // Helper function to add a new timer queue. + BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // Called to recalculate and update the timeout. + BOOST_ASIO_DECL void update_timeout(); + + // Helper class to call work_finished() on block exit. + struct work_finished_on_block_exit; + + // Helper class for managing a HANDLE. + struct auto_handle + { + HANDLE handle; + auto_handle() : handle(0) {} + ~auto_handle() { if (handle) ::CloseHandle(handle); } + }; + + // The IO completion port used for queueing operations. + auto_handle iocp_; + + // The count of unfinished work. + long outstanding_work_; + + // Flag to indicate whether the event loop has been stopped. + mutable long stopped_; + + // Flag to indicate whether there is an in-flight stop event. Every event + // posted using PostQueuedCompletionStatus consumes non-paged pool, so to + // avoid exhausting this resouce we limit the number of outstanding events. + long stop_event_posted_; + + // Flag to indicate whether the service has been shut down. + long shutdown_; + + enum + { + // Timeout to use with GetQueuedCompletionStatus on older versions of + // Windows. Some versions of windows have a "bug" where a call to + // GetQueuedCompletionStatus can appear stuck even though there are events + // waiting on the queue. Using a timeout helps to work around the issue. + default_gqcs_timeout = 500, + + // Maximum waitable timer timeout, in milliseconds. + max_timeout_msec = 5 * 60 * 1000, + + // Maximum waitable timer timeout, in microseconds. + max_timeout_usec = max_timeout_msec * 1000, + + // Completion key value used to wake up a thread to dispatch timers or + // completed operations. + wake_for_dispatch = 1, + + // Completion key value to indicate that an operation has posted with the + // original last_error and bytes_transferred values stored in the fields of + // the OVERLAPPED structure. + overlapped_contains_result = 2 + }; + + // Timeout to use with GetQueuedCompletionStatus. + const DWORD gqcs_timeout_; + + // Helper class to run the scheduler in its own thread. + struct thread_function; + friend struct thread_function; + + // Function object for processing timeouts in a background thread. + struct timer_thread_function; + friend struct timer_thread_function; + + // Background thread used for processing timeouts. + scoped_ptr timer_thread_; + + // A waitable timer object used for waiting for timeouts. + auto_handle waitable_timer_; + + // Non-zero if timers or completed operations need to be dispatched. + long dispatch_required_; + + // Mutex for protecting access to the timer queues and completed operations. + mutex dispatch_mutex_; + + // The timer queues. + timer_queue_set timer_queues_; + + // The operations that are ready to dispatch. + op_queue completed_ops_; + + // The concurrency hint used to initialise the io_context. + const int concurrency_hint_; + + // The thread that is running the io_context. + scoped_ptr thread_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP diff --git a/boost/asio/detail/win_iocp_null_buffers_op.hpp b/boost/asio/detail/win_iocp_null_buffers_op.hpp new file mode 100644 index 0000000..c321639 --- /dev/null +++ b/boost/asio/detail/win_iocp_null_buffers_op.hpp @@ -0,0 +1,125 @@ +// +// detail/win_iocp_null_buffers_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_null_buffers_op : public reactor_op +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_null_buffers_op); + + win_iocp_null_buffers_op(socket_ops::weak_cancel_token_type cancel_token, + Handler& handler, const IoExecutor& io_ex) + : reactor_op(&win_iocp_null_buffers_op::do_perform, + &win_iocp_null_buffers_op::do_complete), + cancel_token_(cancel_token), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static status do_perform(reactor_op*) + { + return done; + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& result_ec, + std::size_t bytes_transferred) + { + boost::system::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_null_buffers_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // The reactor may have stored a result in the operation object. + if (o->ec_) + ec = o->ec_; + + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (o->cancel_token_.expired()) + ec = boost::asio::error::operation_aborted; + else + ec = boost::asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = boost::asio::error::connection_refused; + } + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP diff --git a/boost/asio/detail/win_iocp_operation.hpp b/boost/asio/detail/win_iocp_operation.hpp new file mode 100644 index 0000000..5cad6e3 --- /dev/null +++ b/boost/asio/detail/win_iocp_operation.hpp @@ -0,0 +1,98 @@ +// +// detail/win_iocp_operation.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_OPERATION_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_OPERATION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class win_iocp_io_context; + +// Base class for all operations. A function pointer is used instead of virtual +// functions to avoid the associated overhead. +class win_iocp_operation + : public OVERLAPPED + BOOST_ASIO_ALSO_INHERIT_TRACKED_HANDLER +{ +public: + typedef win_iocp_operation operation_type; + + void complete(void* owner, const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + func_(owner, this, ec, bytes_transferred); + } + + void destroy() + { + func_(0, this, boost::system::error_code(), 0); + } + +protected: + typedef void (*func_type)( + void*, win_iocp_operation*, + const boost::system::error_code&, std::size_t); + + win_iocp_operation(func_type func) + : next_(0), + func_(func) + { + reset(); + } + + // Prevents deletion through this type. + ~win_iocp_operation() + { + } + + void reset() + { + Internal = 0; + InternalHigh = 0; + Offset = 0; + OffsetHigh = 0; + hEvent = 0; + ready_ = 0; + } + +private: + friend class op_queue_access; + friend class win_iocp_io_context; + win_iocp_operation* next_; + func_type func_; + long ready_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_OPERATION_HPP diff --git a/boost/asio/detail/win_iocp_overlapped_op.hpp b/boost/asio/detail/win_iocp_overlapped_op.hpp new file mode 100644 index 0000000..c36e764 --- /dev/null +++ b/boost/asio/detail/win_iocp_overlapped_op.hpp @@ -0,0 +1,94 @@ +// +// detail/win_iocp_overlapped_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_overlapped_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_overlapped_op); + + win_iocp_overlapped_op(Handler& handler, const IoExecutor& io_ex) + : operation(&win_iocp_overlapped_op::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& ec, std::size_t bytes_transferred) + { + // Take ownership of the operation object. + win_iocp_overlapped_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP diff --git a/boost/asio/detail/win_iocp_overlapped_ptr.hpp b/boost/asio/detail/win_iocp_overlapped_ptr.hpp new file mode 100644 index 0000000..d1ed1cb --- /dev/null +++ b/boost/asio/detail/win_iocp_overlapped_ptr.hpp @@ -0,0 +1,161 @@ +// +// detail/win_iocp_overlapped_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Wraps a handler to create an OVERLAPPED object for use with overlapped I/O. +class win_iocp_overlapped_ptr + : private noncopyable +{ +public: + // Construct an empty win_iocp_overlapped_ptr. + win_iocp_overlapped_ptr() + : ptr_(0), + iocp_service_(0) + { + } + + // Construct an win_iocp_overlapped_ptr to contain the specified handler. + template + explicit win_iocp_overlapped_ptr(const Executor& ex, + BOOST_ASIO_MOVE_ARG(Handler) handler) + : ptr_(0), + iocp_service_(0) + { + this->reset(ex, BOOST_ASIO_MOVE_CAST(Handler)(handler)); + } + + // Destructor automatically frees the OVERLAPPED object unless released. + ~win_iocp_overlapped_ptr() + { + reset(); + } + + // Reset to empty. + void reset() + { + if (ptr_) + { + ptr_->destroy(); + ptr_ = 0; + iocp_service_->work_finished(); + iocp_service_ = 0; + } + } + + // Reset to contain the specified handler, freeing any current OVERLAPPED + // object. + template + void reset(const Executor& ex, Handler handler) + { + const bool native = is_same::value; + win_iocp_io_context* iocp_service = this->get_iocp_service(ex); + + typedef win_iocp_overlapped_op > op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_object_executor(ex, native)); + + BOOST_ASIO_HANDLER_CREATION((ex.context(), *p.p, + "iocp_service", iocp_service, 0, "overlapped")); + + iocp_service->work_started(); + reset(); + ptr_ = p.p; + p.v = p.p = 0; + iocp_service_ = iocp_service; + } + + // Get the contained OVERLAPPED object. + OVERLAPPED* get() + { + return ptr_; + } + + // Get the contained OVERLAPPED object. + const OVERLAPPED* get() const + { + return ptr_; + } + + // Release ownership of the OVERLAPPED object. + OVERLAPPED* release() + { + if (ptr_) + iocp_service_->on_pending(ptr_); + + OVERLAPPED* tmp = ptr_; + ptr_ = 0; + iocp_service_ = 0; + return tmp; + } + + // Post completion notification for overlapped operation. Releases ownership. + void complete(const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + if (ptr_) + { + iocp_service_->on_completion(ptr_, ec, + static_cast(bytes_transferred)); + ptr_ = 0; + iocp_service_ = 0; + } + } + +private: + template + static win_iocp_io_context* get_iocp_service(const Executor& ex) + { + return &use_service(ex.context()); + } + + static win_iocp_io_context* get_iocp_service( + const io_context::executor_type& ex) + { + return &ex.context().impl_; + } + + win_iocp_operation* ptr_; + win_iocp_io_context* iocp_service_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP diff --git a/boost/asio/detail/win_iocp_serial_port_service.hpp b/boost/asio/detail/win_iocp_serial_port_service.hpp new file mode 100644 index 0000000..6f05d92 --- /dev/null +++ b/boost/asio/detail/win_iocp_serial_port_service.hpp @@ -0,0 +1,234 @@ +// +// detail/win_iocp_serial_port_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) && defined(BOOST_ASIO_HAS_SERIAL_PORT) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Extend win_iocp_handle_service to provide serial port support. +class win_iocp_serial_port_service : + public execution_context_service_base +{ +public: + // The native type of a serial port. + typedef win_iocp_handle_service::native_handle_type native_handle_type; + + // The implementation type of the serial port. + typedef win_iocp_handle_service::implementation_type implementation_type; + + // Constructor. + BOOST_ASIO_DECL win_iocp_serial_port_service(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown(); + + // Construct a new serial port implementation. + void construct(implementation_type& impl) + { + handle_service_.construct(impl); + } + + // Move-construct a new serial port implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + handle_service_.move_construct(impl, other_impl); + } + + // Move-assign from another serial port implementation. + void move_assign(implementation_type& impl, + win_iocp_serial_port_service& other_service, + implementation_type& other_impl) + { + handle_service_.move_assign(impl, + other_service.handle_service_, other_impl); + } + + // Destroy a serial port implementation. + void destroy(implementation_type& impl) + { + handle_service_.destroy(impl); + } + + // Open the serial port using the specified device name. + BOOST_ASIO_DECL boost::system::error_code open(implementation_type& impl, + const std::string& device, boost::system::error_code& ec); + + // Assign a native handle to a serial port implementation. + boost::system::error_code assign(implementation_type& impl, + const native_handle_type& handle, boost::system::error_code& ec) + { + return handle_service_.assign(impl, handle, ec); + } + + // Determine whether the serial port is open. + bool is_open(const implementation_type& impl) const + { + return handle_service_.is_open(impl); + } + + // Destroy a serial port implementation. + boost::system::error_code close(implementation_type& impl, + boost::system::error_code& ec) + { + return handle_service_.close(impl, ec); + } + + // Get the native serial port representation. + native_handle_type native_handle(implementation_type& impl) + { + return handle_service_.native_handle(impl); + } + + // Cancel all operations associated with the handle. + boost::system::error_code cancel(implementation_type& impl, + boost::system::error_code& ec) + { + return handle_service_.cancel(impl, ec); + } + + // Set an option on the serial port. + template + boost::system::error_code set_option(implementation_type& impl, + const SettableSerialPortOption& option, boost::system::error_code& ec) + { + return do_set_option(impl, + &win_iocp_serial_port_service::store_option, + &option, ec); + } + + // Get an option from the serial port. + template + boost::system::error_code get_option(const implementation_type& impl, + GettableSerialPortOption& option, boost::system::error_code& ec) const + { + return do_get_option(impl, + &win_iocp_serial_port_service::load_option, + &option, ec); + } + + // Send a break sequence to the serial port. + boost::system::error_code send_break(implementation_type&, + boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return ec; + } + + // Write the given data. Returns the number of bytes sent. + template + size_t write_some(implementation_type& impl, + const ConstBufferSequence& buffers, boost::system::error_code& ec) + { + return handle_service_.write_some(impl, buffers, ec); + } + + // Start an asynchronous write. The data being written must be valid for the + // lifetime of the asynchronous operation. + template + void async_write_some(implementation_type& impl, + const ConstBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + handle_service_.async_write_some(impl, buffers, handler, io_ex); + } + + // Read some data. Returns the number of bytes received. + template + size_t read_some(implementation_type& impl, + const MutableBufferSequence& buffers, boost::system::error_code& ec) + { + return handle_service_.read_some(impl, buffers, ec); + } + + // Start an asynchronous read. The buffer for the data being received must be + // valid for the lifetime of the asynchronous operation. + template + void async_read_some(implementation_type& impl, + const MutableBufferSequence& buffers, + Handler& handler, const IoExecutor& io_ex) + { + handle_service_.async_read_some(impl, buffers, handler, io_ex); + } + +private: + // Function pointer type for storing a serial port option. + typedef boost::system::error_code (*store_function_type)( + const void*, ::DCB&, boost::system::error_code&); + + // Helper function template to store a serial port option. + template + static boost::system::error_code store_option(const void* option, + ::DCB& storage, boost::system::error_code& ec) + { + static_cast(option)->store(storage, ec); + return ec; + } + + // Helper function to set a serial port option. + BOOST_ASIO_DECL boost::system::error_code do_set_option( + implementation_type& impl, store_function_type store, + const void* option, boost::system::error_code& ec); + + // Function pointer type for loading a serial port option. + typedef boost::system::error_code (*load_function_type)( + void*, const ::DCB&, boost::system::error_code&); + + // Helper function template to load a serial port option. + template + static boost::system::error_code load_option(void* option, + const ::DCB& storage, boost::system::error_code& ec) + { + static_cast(option)->load(storage, ec); + return ec; + } + + // Helper function to get a serial port option. + BOOST_ASIO_DECL boost::system::error_code do_get_option( + const implementation_type& impl, load_function_type load, + void* option, boost::system::error_code& ec) const; + + // The implementation used for initiating asynchronous operations. + win_iocp_handle_service handle_service_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_IOCP) && defined(BOOST_ASIO_HAS_SERIAL_PORT) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SERIAL_PORT_SERVICE_HPP diff --git a/boost/asio/detail/win_iocp_socket_accept_op.hpp b/boost/asio/detail/win_iocp_socket_accept_op.hpp new file mode 100644 index 0000000..75dadc2 --- /dev/null +++ b/boost/asio/detail/win_iocp_socket_accept_op.hpp @@ -0,0 +1,308 @@ +// +// detail/win_iocp_socket_accept_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_socket_accept_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_accept_op); + + win_iocp_socket_accept_op(win_iocp_socket_service_base& socket_service, + socket_type socket, Socket& peer, const Protocol& protocol, + typename Protocol::endpoint* peer_endpoint, + bool enable_connection_aborted, Handler& handler, const IoExecutor& io_ex) + : operation(&win_iocp_socket_accept_op::do_complete), + socket_service_(socket_service), + socket_(socket), + peer_(peer), + protocol_(protocol), + peer_endpoint_(peer_endpoint), + enable_connection_aborted_(enable_connection_aborted), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + socket_holder& new_socket() + { + return new_socket_; + } + + void* output_buffer() + { + return output_buffer_; + } + + DWORD address_length() + { + return sizeof(sockaddr_storage_type) + 16; + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& result_ec, + std::size_t /*bytes_transferred*/) + { + boost::system::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_accept_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + if (owner) + { + typename Protocol::endpoint peer_endpoint; + std::size_t addr_len = peer_endpoint.capacity(); + socket_ops::complete_iocp_accept(o->socket_, + o->output_buffer(), o->address_length(), + peer_endpoint.data(), &addr_len, + o->new_socket_.get(), ec); + + // Restart the accept operation if we got the connection_aborted error + // and the enable_connection_aborted socket option is not set. + if (ec == boost::asio::error::connection_aborted + && !o->enable_connection_aborted_) + { + o->reset(); + o->socket_service_.restart_accept_op(o->socket_, + o->new_socket_, o->protocol_.family(), + o->protocol_.type(), o->protocol_.protocol(), + o->output_buffer(), o->address_length(), o); + p.v = p.p = 0; + return; + } + + // If the socket was successfully accepted, transfer ownership of the + // socket to the peer object. + if (!ec) + { + o->peer_.assign(o->protocol_, + typename Socket::native_handle_type( + o->new_socket_.get(), peer_endpoint), ec); + if (!ec) + o->new_socket_.release(); + } + + // Pass endpoint back to caller. + if (o->peer_endpoint_) + *o->peer_endpoint_ = peer_endpoint; + } + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1 + handler(o->handler_, ec); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + win_iocp_socket_service_base& socket_service_; + socket_type socket_; + socket_holder new_socket_; + Socket& peer_; + Protocol protocol_; + typename Protocol::endpoint* peer_endpoint_; + unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; + bool enable_connection_aborted_; + Handler handler_; + IoExecutor io_executor_; +}; + +#if defined(BOOST_ASIO_HAS_MOVE) + +template +class win_iocp_socket_move_accept_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_move_accept_op); + + win_iocp_socket_move_accept_op( + win_iocp_socket_service_base& socket_service, socket_type socket, + const Protocol& protocol, const PeerIoExecutor& peer_io_ex, + typename Protocol::endpoint* peer_endpoint, + bool enable_connection_aborted, Handler& handler, const IoExecutor& io_ex) + : operation(&win_iocp_socket_move_accept_op::do_complete), + socket_service_(socket_service), + socket_(socket), + peer_(peer_io_ex), + protocol_(protocol), + peer_endpoint_(peer_endpoint), + enable_connection_aborted_(enable_connection_aborted), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + socket_holder& new_socket() + { + return new_socket_; + } + + void* output_buffer() + { + return output_buffer_; + } + + DWORD address_length() + { + return sizeof(sockaddr_storage_type) + 16; + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& result_ec, + std::size_t /*bytes_transferred*/) + { + boost::system::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_move_accept_op* o( + static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + if (owner) + { + typename Protocol::endpoint peer_endpoint; + std::size_t addr_len = peer_endpoint.capacity(); + socket_ops::complete_iocp_accept(o->socket_, + o->output_buffer(), o->address_length(), + peer_endpoint.data(), &addr_len, + o->new_socket_.get(), ec); + + // Restart the accept operation if we got the connection_aborted error + // and the enable_connection_aborted socket option is not set. + if (ec == boost::asio::error::connection_aborted + && !o->enable_connection_aborted_) + { + o->reset(); + o->socket_service_.restart_accept_op(o->socket_, + o->new_socket_, o->protocol_.family(), + o->protocol_.type(), o->protocol_.protocol(), + o->output_buffer(), o->address_length(), o); + p.v = p.p = 0; + return; + } + + // If the socket was successfully accepted, transfer ownership of the + // socket to the peer object. + if (!ec) + { + o->peer_.assign(o->protocol_, + typename Protocol::socket::native_handle_type( + o->new_socket_.get(), peer_endpoint), ec); + if (!ec) + o->new_socket_.release(); + } + + // Pass endpoint back to caller. + if (o->peer_endpoint_) + *o->peer_endpoint_ = peer_endpoint; + } + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::move_binder2 + handler(0, BOOST_ASIO_MOVE_CAST(Handler)(o->handler_), ec, + BOOST_ASIO_MOVE_CAST(peer_socket_type)(o->peer_)); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + typedef typename Protocol::socket::template + rebind_executor::other peer_socket_type; + + win_iocp_socket_service_base& socket_service_; + socket_type socket_; + socket_holder new_socket_; + peer_socket_type peer_; + Protocol protocol_; + typename Protocol::endpoint* peer_endpoint_; + unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; + bool enable_connection_aborted_; + Handler handler_; + IoExecutor io_executor_; +}; + +#endif // defined(BOOST_ASIO_HAS_MOVE) + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP diff --git a/boost/asio/detail/win_iocp_socket_connect_op.hpp b/boost/asio/detail/win_iocp_socket_connect_op.hpp new file mode 100644 index 0000000..0041a05 --- /dev/null +++ b/boost/asio/detail/win_iocp_socket_connect_op.hpp @@ -0,0 +1,132 @@ +// +// detail/win_iocp_socket_connect_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_CONNECT_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_CONNECT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class win_iocp_socket_connect_op_base : public reactor_op +{ +public: + win_iocp_socket_connect_op_base(socket_type socket, func_type complete_func) + : reactor_op(&win_iocp_socket_connect_op_base::do_perform, complete_func), + socket_(socket), + connect_ex_(false) + { + } + + static status do_perform(reactor_op* base) + { + win_iocp_socket_connect_op_base* o( + static_cast(base)); + + return socket_ops::non_blocking_connect( + o->socket_, o->ec_) ? done : not_done; + } + + socket_type socket_; + bool connect_ex_; +}; + +template +class win_iocp_socket_connect_op : public win_iocp_socket_connect_op_base +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_connect_op); + + win_iocp_socket_connect_op(socket_type socket, + Handler& handler, const IoExecutor& io_ex) + : win_iocp_socket_connect_op_base(socket, + &win_iocp_socket_connect_op::do_complete), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& result_ec, + std::size_t /*bytes_transferred*/) + { + boost::system::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_connect_op* o( + static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + if (owner) + { + if (o->connect_ex_) + socket_ops::complete_iocp_connect(o->socket_, ec); + else + ec = o->ec_; + } + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1 + handler(o->handler_, ec); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_CONNECT_OP_HPP diff --git a/boost/asio/detail/win_iocp_socket_recv_op.hpp b/boost/asio/detail/win_iocp_socket_recv_op.hpp new file mode 100644 index 0000000..daa3ca2 --- /dev/null +++ b/boost/asio/detail/win_iocp_socket_recv_op.hpp @@ -0,0 +1,122 @@ +// +// detail/win_iocp_socket_recv_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_socket_recv_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recv_op); + + win_iocp_socket_recv_op(socket_ops::state_type state, + socket_ops::weak_cancel_token_type cancel_token, + const MutableBufferSequence& buffers, Handler& handler, + const IoExecutor& io_ex) + : operation(&win_iocp_socket_recv_op::do_complete), + state_(state), + cancel_token_(cancel_token), + buffers_(buffers), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& result_ec, + std::size_t bytes_transferred) + { + boost::system::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_recv_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_recv(o->state_, o->cancel_token_, + buffer_sequence_adapter::all_empty(o->buffers_), + ec, bytes_transferred); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + socket_ops::state_type state_; + socket_ops::weak_cancel_token_type cancel_token_; + MutableBufferSequence buffers_; + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP diff --git a/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp b/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp new file mode 100644 index 0000000..bfd469a --- /dev/null +++ b/boost/asio/detail/win_iocp_socket_recvfrom_op.hpp @@ -0,0 +1,131 @@ +// +// detail/win_iocp_socket_recvfrom_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_socket_recvfrom_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recvfrom_op); + + win_iocp_socket_recvfrom_op(Endpoint& endpoint, + socket_ops::weak_cancel_token_type cancel_token, + const MutableBufferSequence& buffers, Handler& handler, + const IoExecutor& io_ex) + : operation(&win_iocp_socket_recvfrom_op::do_complete), + endpoint_(endpoint), + endpoint_size_(static_cast(endpoint.capacity())), + cancel_token_(cancel_token), + buffers_(buffers), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + int& endpoint_size() + { + return endpoint_size_; + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& result_ec, + std::size_t bytes_transferred) + { + boost::system::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_recvfrom_op* o( + static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_recvfrom(o->cancel_token_, ec); + + // Record the size of the endpoint returned by the operation. + o->endpoint_.resize(o->endpoint_size_); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + Endpoint& endpoint_; + int endpoint_size_; + socket_ops::weak_cancel_token_type cancel_token_; + MutableBufferSequence buffers_; + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP diff --git a/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp b/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp new file mode 100644 index 0000000..73127dc --- /dev/null +++ b/boost/asio/detail/win_iocp_socket_recvmsg_op.hpp @@ -0,0 +1,123 @@ +// +// detail/win_iocp_socket_recvmsg_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECVMSG_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECVMSG_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_socket_recvmsg_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_recvmsg_op); + + win_iocp_socket_recvmsg_op( + socket_ops::weak_cancel_token_type cancel_token, + const MutableBufferSequence& buffers, + socket_base::message_flags& out_flags, + Handler& handler, const IoExecutor& io_ex) + : operation(&win_iocp_socket_recvmsg_op::do_complete), + cancel_token_(cancel_token), + buffers_(buffers), + out_flags_(out_flags), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& result_ec, + std::size_t bytes_transferred) + { + boost::system::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_recvmsg_op* o( + static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_recvmsg(o->cancel_token_, ec); + o->out_flags_ = 0; + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + MutableBufferSequence buffers_; + socket_base::message_flags& out_flags_; + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECVMSG_OP_HPP diff --git a/boost/asio/detail/win_iocp_socket_send_op.hpp b/boost/asio/detail/win_iocp_socket_send_op.hpp new file mode 100644 index 0000000..5f1fc4a --- /dev/null +++ b/boost/asio/detail/win_iocp_socket_send_op.hpp @@ -0,0 +1,116 @@ +// +// detail/win_iocp_socket_send_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_socket_send_op : public operation +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_socket_send_op); + + win_iocp_socket_send_op(socket_ops::weak_cancel_token_type cancel_token, + const ConstBufferSequence& buffers, Handler& handler, + const IoExecutor& io_ex) + : operation(&win_iocp_socket_send_op::do_complete), + cancel_token_(cancel_token), + buffers_(buffers), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& result_ec, + std::size_t bytes_transferred) + { + boost::system::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_socket_send_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + +#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + if (owner) + { + buffer_sequence_adapter::validate(o->buffers_); + } +#endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) + + socket_ops::complete_iocp_send(o->cancel_token_, ec); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, ec, bytes_transferred); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, handler.arg2_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + ConstBufferSequence buffers_; + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP diff --git a/boost/asio/detail/win_iocp_socket_service.hpp b/boost/asio/detail/win_iocp_socket_service.hpp new file mode 100644 index 0000000..df2292a --- /dev/null +++ b/boost/asio/detail/win_iocp_socket_service.hpp @@ -0,0 +1,583 @@ +// +// detail/win_iocp_socket_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_socket_service : + public execution_context_service_base >, + public win_iocp_socket_service_base +{ +public: + // The protocol type. + typedef Protocol protocol_type; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The native type of a socket. + class native_handle_type + { + public: + native_handle_type(socket_type s) + : socket_(s), + have_remote_endpoint_(false) + { + } + + native_handle_type(socket_type s, const endpoint_type& ep) + : socket_(s), + have_remote_endpoint_(true), + remote_endpoint_(ep) + { + } + + void operator=(socket_type s) + { + socket_ = s; + have_remote_endpoint_ = false; + remote_endpoint_ = endpoint_type(); + } + + operator socket_type() const + { + return socket_; + } + + bool have_remote_endpoint() const + { + return have_remote_endpoint_; + } + + endpoint_type remote_endpoint() const + { + return remote_endpoint_; + } + + private: + socket_type socket_; + bool have_remote_endpoint_; + endpoint_type remote_endpoint_; + }; + + // The implementation type of the socket. + struct implementation_type : + win_iocp_socket_service_base::base_implementation_type + { + // Default constructor. + implementation_type() + : protocol_(endpoint_type().protocol()), + have_remote_endpoint_(false), + remote_endpoint_() + { + } + + // The protocol associated with the socket. + protocol_type protocol_; + + // Whether we have a cached remote endpoint. + bool have_remote_endpoint_; + + // A cached remote endpoint. + endpoint_type remote_endpoint_; + }; + + // Constructor. + win_iocp_socket_service(execution_context& context) + : execution_context_service_base< + win_iocp_socket_service >(context), + win_iocp_socket_service_base(context) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + this->base_shutdown(); + } + + // Move-construct a new socket implementation. + void move_construct(implementation_type& impl, + implementation_type& other_impl) + { + this->base_move_construct(impl, other_impl); + + impl.protocol_ = other_impl.protocol_; + other_impl.protocol_ = endpoint_type().protocol(); + + impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_; + other_impl.have_remote_endpoint_ = false; + + impl.remote_endpoint_ = other_impl.remote_endpoint_; + other_impl.remote_endpoint_ = endpoint_type(); + } + + // Move-assign from another socket implementation. + void move_assign(implementation_type& impl, + win_iocp_socket_service_base& other_service, + implementation_type& other_impl) + { + this->base_move_assign(impl, other_service, other_impl); + + impl.protocol_ = other_impl.protocol_; + other_impl.protocol_ = endpoint_type().protocol(); + + impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_; + other_impl.have_remote_endpoint_ = false; + + impl.remote_endpoint_ = other_impl.remote_endpoint_; + other_impl.remote_endpoint_ = endpoint_type(); + } + + // Move-construct a new socket implementation from another protocol type. + template + void converting_move_construct(implementation_type& impl, + win_iocp_socket_service&, + typename win_iocp_socket_service< + Protocol1>::implementation_type& other_impl) + { + this->base_move_construct(impl, other_impl); + + impl.protocol_ = protocol_type(other_impl.protocol_); + other_impl.protocol_ = typename Protocol1::endpoint().protocol(); + + impl.have_remote_endpoint_ = other_impl.have_remote_endpoint_; + other_impl.have_remote_endpoint_ = false; + + impl.remote_endpoint_ = other_impl.remote_endpoint_; + other_impl.remote_endpoint_ = typename Protocol1::endpoint(); + } + + // Open a new socket implementation. + boost::system::error_code open(implementation_type& impl, + const protocol_type& protocol, boost::system::error_code& ec) + { + if (!do_open(impl, protocol.family(), + protocol.type(), protocol.protocol(), ec)) + { + impl.protocol_ = protocol; + impl.have_remote_endpoint_ = false; + impl.remote_endpoint_ = endpoint_type(); + } + return ec; + } + + // Assign a native socket to a socket implementation. + boost::system::error_code assign(implementation_type& impl, + const protocol_type& protocol, const native_handle_type& native_socket, + boost::system::error_code& ec) + { + if (!do_assign(impl, protocol.type(), native_socket, ec)) + { + impl.protocol_ = protocol; + impl.have_remote_endpoint_ = native_socket.have_remote_endpoint(); + impl.remote_endpoint_ = native_socket.remote_endpoint(); + } + return ec; + } + + // Get the native socket representation. + native_handle_type native_handle(implementation_type& impl) + { + if (impl.have_remote_endpoint_) + return native_handle_type(impl.socket_, impl.remote_endpoint_); + return native_handle_type(impl.socket_); + } + + // Bind the socket to the specified local endpoint. + boost::system::error_code bind(implementation_type& impl, + const endpoint_type& endpoint, boost::system::error_code& ec) + { + socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); + return ec; + } + + // Set a socket option. + template + boost::system::error_code set_option(implementation_type& impl, + const Option& option, boost::system::error_code& ec) + { + socket_ops::setsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), option.size(impl.protocol_), ec); + return ec; + } + + // Set a socket option. + template + boost::system::error_code get_option(const implementation_type& impl, + Option& option, boost::system::error_code& ec) const + { + std::size_t size = option.size(impl.protocol_); + socket_ops::getsockopt(impl.socket_, impl.state_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), &size, ec); + if (!ec) + option.resize(impl.protocol_, size); + return ec; + } + + // Get the local endpoint. + endpoint_type local_endpoint(const implementation_type& impl, + boost::system::error_code& ec) const + { + endpoint_type endpoint; + std::size_t addr_len = endpoint.capacity(); + if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) + return endpoint_type(); + endpoint.resize(addr_len); + return endpoint; + } + + // Get the remote endpoint. + endpoint_type remote_endpoint(const implementation_type& impl, + boost::system::error_code& ec) const + { + endpoint_type endpoint = impl.remote_endpoint_; + std::size_t addr_len = endpoint.capacity(); + if (socket_ops::getpeername(impl.socket_, endpoint.data(), + &addr_len, impl.have_remote_endpoint_, ec)) + return endpoint_type(); + endpoint.resize(addr_len); + return endpoint; + } + + // Disable sends or receives on the socket. + boost::system::error_code shutdown(base_implementation_type& impl, + socket_base::shutdown_type what, boost::system::error_code& ec) + { + socket_ops::shutdown(impl.socket_, what, ec); + return ec; + } + + // Send a datagram to the specified endpoint. Returns the number of bytes + // sent. + template + size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers, + const endpoint_type& destination, socket_base::message_flags flags, + boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_sendto(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, + destination.data(), destination.size(), ec); + } + + // Wait until data can be sent without blocking. + size_t send_to(implementation_type& impl, const null_buffers&, + const endpoint_type&, socket_base::message_flags, + boost::system::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send_to(implementation_type& impl, + const ConstBufferSequence& buffers, const endpoint_type& destination, + socket_base::message_flags flags, Handler& handler, + const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_send_op< + ConstBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, buffers, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_send_to")); + + buffer_sequence_adapter bufs(buffers); + + start_send_to_op(impl, bufs.buffers(), bufs.count(), + destination.data(), static_cast(destination.size()), + flags, p.p); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template + void async_send_to(implementation_type& impl, const null_buffers&, + const endpoint_type&, socket_base::message_flags, Handler& handler, + const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_send_to(null_buffers)")); + + start_reactor_op(impl, select_reactor::write_op, p.p); + p.v = p.p = 0; + } + + // Receive a datagram with the endpoint of the sender. Returns the number of + // bytes received. + template + size_t receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + std::size_t addr_len = sender_endpoint.capacity(); + std::size_t bytes_recvd = socket_ops::sync_recvfrom( + impl.socket_, impl.state_, bufs.buffers(), bufs.count(), + flags, sender_endpoint.data(), &addr_len, ec); + + if (!ec) + sender_endpoint.resize(addr_len); + + return bytes_recvd; + } + + // Wait until data can be received without blocking. + size_t receive_from(implementation_type& impl, + const null_buffers&, endpoint_type& sender_endpoint, + socket_base::message_flags, boost::system::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + // Reset endpoint since it can be given no sensible value at this time. + sender_endpoint = endpoint_type(); + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received and + // the sender_endpoint object must both be valid for the lifetime of the + // asynchronous operation. + template + void async_receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, endpoint_type& sender_endp, + socket_base::message_flags flags, Handler& handler, + const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_recvfrom_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(sender_endp, impl.cancel_token_, + buffers, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_receive_from")); + + buffer_sequence_adapter bufs(buffers); + + start_receive_from_op(impl, bufs.buffers(), bufs.count(), + sender_endp.data(), flags, &p.p->endpoint_size(), p.p); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template + void async_receive_from(implementation_type& impl, const null_buffers&, + endpoint_type& sender_endpoint, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_receive_from(null_buffers)")); + + // Reset endpoint since it can be given no sensible value at this time. + sender_endpoint = endpoint_type(); + + start_null_buffers_receive_op(impl, flags, p.p); + p.v = p.p = 0; + } + + // Accept a new connection. + template + boost::system::error_code accept(implementation_type& impl, Socket& peer, + endpoint_type* peer_endpoint, boost::system::error_code& ec) + { + // We cannot accept a socket that is already open. + if (peer.is_open()) + { + ec = boost::asio::error::already_open; + return ec; + } + + std::size_t addr_len = peer_endpoint ? peer_endpoint->capacity() : 0; + socket_holder new_socket(socket_ops::sync_accept(impl.socket_, + impl.state_, peer_endpoint ? peer_endpoint->data() : 0, + peer_endpoint ? &addr_len : 0, ec)); + + // On success, assign new connection to peer socket object. + if (new_socket.get() != invalid_socket) + { + if (peer_endpoint) + peer_endpoint->resize(addr_len); + peer.assign(impl.protocol_, new_socket.get(), ec); + if (!ec) + new_socket.release(); + } + + return ec; + } + + // Start an asynchronous accept. The peer and peer_endpoint objects + // must be valid until the accept's handler is invoked. + template + void async_accept(implementation_type& impl, Socket& peer, + endpoint_type* peer_endpoint, Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_accept_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + bool enable_connection_aborted = + (impl.state_ & socket_ops::enable_connection_aborted) != 0; + p.p = new (p.v) op(*this, impl.socket_, peer, impl.protocol_, + peer_endpoint, enable_connection_aborted, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_accept")); + + start_accept_op(impl, peer.is_open(), p.p->new_socket(), + impl.protocol_.family(), impl.protocol_.type(), + impl.protocol_.protocol(), p.p->output_buffer(), + p.p->address_length(), p.p); + p.v = p.p = 0; + } + +#if defined(BOOST_ASIO_HAS_MOVE) + // Start an asynchronous accept. The peer and peer_endpoint objects + // must be valid until the accept's handler is invoked. + template + void async_move_accept(implementation_type& impl, + const PeerIoExecutor& peer_io_ex, endpoint_type* peer_endpoint, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_move_accept_op< + protocol_type, PeerIoExecutor, Handler, IoExecutor> op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + bool enable_connection_aborted = + (impl.state_ & socket_ops::enable_connection_aborted) != 0; + p.p = new (p.v) op(*this, impl.socket_, impl.protocol_, + peer_io_ex, peer_endpoint, enable_connection_aborted, + handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_accept")); + + start_accept_op(impl, false, p.p->new_socket(), + impl.protocol_.family(), impl.protocol_.type(), + impl.protocol_.protocol(), p.p->output_buffer(), + p.p->address_length(), p.p); + p.v = p.p = 0; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + // Connect the socket to the specified endpoint. + boost::system::error_code connect(implementation_type& impl, + const endpoint_type& peer_endpoint, boost::system::error_code& ec) + { + socket_ops::sync_connect(impl.socket_, + peer_endpoint.data(), peer_endpoint.size(), ec); + return ec; + } + + // Start an asynchronous connect. + template + void async_connect(implementation_type& impl, + const endpoint_type& peer_endpoint, Handler& handler, + const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_connect_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.socket_, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_connect")); + + start_connect_op(impl, impl.protocol_.family(), impl.protocol_.type(), + peer_endpoint.data(), static_cast(peer_endpoint.size()), p.p); + p.v = p.p = 0; + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP diff --git a/boost/asio/detail/win_iocp_socket_service_base.hpp b/boost/asio/detail/win_iocp_socket_service_base.hpp new file mode 100644 index 0000000..7a7c900 --- /dev/null +++ b/boost/asio/detail/win_iocp_socket_service_base.hpp @@ -0,0 +1,602 @@ +// +// detail/win_iocp_socket_service_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class win_iocp_socket_service_base +{ +public: + // The implementation type of the socket. + struct base_implementation_type + { + // The native socket representation. + socket_type socket_; + + // The current state of the socket. + socket_ops::state_type state_; + + // We use a shared pointer as a cancellation token here to work around the + // broken Windows support for cancellation. MSDN says that when you call + // closesocket any outstanding WSARecv or WSASend operations will complete + // with the error ERROR_OPERATION_ABORTED. In practice they complete with + // ERROR_NETNAME_DELETED, which means you can't tell the difference between + // a local cancellation and the socket being hard-closed by the peer. + socket_ops::shared_cancel_token_type cancel_token_; + + // Per-descriptor data used by the reactor. + select_reactor::per_descriptor_data reactor_data_; + +#if defined(BOOST_ASIO_ENABLE_CANCELIO) + // The ID of the thread from which it is safe to cancel asynchronous + // operations. 0 means no asynchronous operations have been started yet. + // ~0 means asynchronous operations have been started from more than one + // thread, and cancellation is not supported for the socket. + DWORD safe_cancellation_thread_id_; +#endif // defined(BOOST_ASIO_ENABLE_CANCELIO) + + // Pointers to adjacent socket implementations in linked list. + base_implementation_type* next_; + base_implementation_type* prev_; + }; + + // Constructor. + BOOST_ASIO_DECL win_iocp_socket_service_base(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void base_shutdown(); + + // Construct a new socket implementation. + BOOST_ASIO_DECL void construct(base_implementation_type& impl); + + // Move-construct a new socket implementation. + BOOST_ASIO_DECL void base_move_construct(base_implementation_type& impl, + base_implementation_type& other_impl); + + // Move-assign from another socket implementation. + BOOST_ASIO_DECL void base_move_assign(base_implementation_type& impl, + win_iocp_socket_service_base& other_service, + base_implementation_type& other_impl); + + // Destroy a socket implementation. + BOOST_ASIO_DECL void destroy(base_implementation_type& impl); + + // Determine whether the socket is open. + bool is_open(const base_implementation_type& impl) const + { + return impl.socket_ != invalid_socket; + } + + // Destroy a socket implementation. + BOOST_ASIO_DECL boost::system::error_code close( + base_implementation_type& impl, boost::system::error_code& ec); + + // Release ownership of the socket. + BOOST_ASIO_DECL socket_type release( + base_implementation_type& impl, boost::system::error_code& ec); + + // Cancel all operations associated with the socket. + BOOST_ASIO_DECL boost::system::error_code cancel( + base_implementation_type& impl, boost::system::error_code& ec); + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const base_implementation_type& impl, + boost::system::error_code& ec) const + { + return socket_ops::sockatmark(impl.socket_, ec); + } + + // Determine the number of bytes available for reading. + std::size_t available(const base_implementation_type& impl, + boost::system::error_code& ec) const + { + return socket_ops::available(impl.socket_, ec); + } + + // Place the socket into the state where it will listen for new connections. + boost::system::error_code listen(base_implementation_type& impl, + int backlog, boost::system::error_code& ec) + { + socket_ops::listen(impl.socket_, backlog, ec); + return ec; + } + + // Perform an IO control command on the socket. + template + boost::system::error_code io_control(base_implementation_type& impl, + IO_Control_Command& command, boost::system::error_code& ec) + { + socket_ops::ioctl(impl.socket_, impl.state_, command.name(), + static_cast(command.data()), ec); + return ec; + } + + // Gets the non-blocking mode of the socket. + bool non_blocking(const base_implementation_type& impl) const + { + return (impl.state_ & socket_ops::user_set_non_blocking) != 0; + } + + // Sets the non-blocking mode of the socket. + boost::system::error_code non_blocking(base_implementation_type& impl, + bool mode, boost::system::error_code& ec) + { + socket_ops::set_user_non_blocking(impl.socket_, impl.state_, mode, ec); + return ec; + } + + // Gets the non-blocking mode of the native socket implementation. + bool native_non_blocking(const base_implementation_type& impl) const + { + return (impl.state_ & socket_ops::internal_non_blocking) != 0; + } + + // Sets the non-blocking mode of the native socket implementation. + boost::system::error_code native_non_blocking(base_implementation_type& impl, + bool mode, boost::system::error_code& ec) + { + socket_ops::set_internal_non_blocking(impl.socket_, impl.state_, mode, ec); + return ec; + } + + // Wait for the socket to become ready to read, ready to write, or to have + // pending error conditions. + boost::system::error_code wait(base_implementation_type& impl, + socket_base::wait_type w, boost::system::error_code& ec) + { + switch (w) + { + case socket_base::wait_read: + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + break; + case socket_base::wait_write: + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + break; + case socket_base::wait_error: + socket_ops::poll_error(impl.socket_, impl.state_, -1, ec); + break; + default: + ec = boost::asio::error::invalid_argument; + break; + } + + return ec; + } + + // Asynchronously wait for the socket to become ready to read, ready to + // write, or to have pending error conditions. + template + void async_wait(base_implementation_type& impl, + socket_base::wait_type w, Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_wait_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_wait")); + + switch (w) + { + case socket_base::wait_read: + start_null_buffers_receive_op(impl, 0, p.p); + break; + case socket_base::wait_write: + start_reactor_op(impl, select_reactor::write_op, p.p); + break; + case socket_base::wait_error: + start_reactor_op(impl, select_reactor::except_op, p.p); + break; + default: + p.p->ec_ = boost::asio::error::invalid_argument; + iocp_service_.post_immediate_completion(p.p, is_continuation); + break; + } + + p.v = p.p = 0; + } + + // Send the given data to the peer. Returns the number of bytes sent. + template + size_t send(base_implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_send(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be sent without blocking. + size_t send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, boost::system::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_write(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous send. The data being sent must be valid for the + // lifetime of the asynchronous operation. + template + void async_send(base_implementation_type& impl, + const ConstBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_send_op< + ConstBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, buffers, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_send")); + + buffer_sequence_adapter bufs(buffers); + + start_send_op(impl, bufs.buffers(), bufs.count(), flags, + (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(), + p.p); + p.v = p.p = 0; + } + + // Start an asynchronous wait until data can be sent without blocking. + template + void async_send(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_send(null_buffers)")); + + start_reactor_op(impl, select_reactor::write_op, p.p); + p.v = p.p = 0; + } + + // Receive some data from the peer. Returns the number of bytes received. + template + size_t receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_recv(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), flags, bufs.all_empty(), ec); + } + + // Wait until data can be received without blocking. + size_t receive(base_implementation_type& impl, const null_buffers&, + socket_base::message_flags, boost::system::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template + void async_receive(base_implementation_type& impl, + const MutableBufferSequence& buffers, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_recv_op< + MutableBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.state_, impl.cancel_token_, + buffers, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_receive")); + + buffer_sequence_adapter bufs(buffers); + + start_receive_op(impl, bufs.buffers(), bufs.count(), flags, + (impl.state_ & socket_ops::stream_oriented) != 0 && bufs.all_empty(), + p.p); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template + void async_receive(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags flags, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_receive(null_buffers)")); + + start_null_buffers_receive_op(impl, flags, p.p); + p.v = p.p = 0; + } + + // Receive some data with associated flags. Returns the number of bytes + // received. + template + size_t receive_with_flags(base_implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, boost::system::error_code& ec) + { + buffer_sequence_adapter bufs(buffers); + + return socket_ops::sync_recvmsg(impl.socket_, impl.state_, + bufs.buffers(), bufs.count(), in_flags, out_flags, ec); + } + + // Wait until data can be received without blocking. + size_t receive_with_flags(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags, + socket_base::message_flags& out_flags, boost::system::error_code& ec) + { + // Wait for socket to become ready. + socket_ops::poll_read(impl.socket_, impl.state_, -1, ec); + + // Clear out_flags, since we cannot give it any other sensible value when + // performing a null_buffers operation. + out_flags = 0; + + return 0; + } + + // Start an asynchronous receive. The buffer for the data being received + // must be valid for the lifetime of the asynchronous operation. + template + void async_receive_with_flags(base_implementation_type& impl, + const MutableBufferSequence& buffers, socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, Handler& handler, + const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_socket_recvmsg_op< + MutableBufferSequence, Handler, IoExecutor> op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, + buffers, out_flags, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_receive_with_flags")); + + buffer_sequence_adapter bufs(buffers); + + start_receive_op(impl, bufs.buffers(), bufs.count(), in_flags, false, p.p); + p.v = p.p = 0; + } + + // Wait until data can be received without blocking. + template + void async_receive_with_flags(base_implementation_type& impl, + const null_buffers&, socket_base::message_flags in_flags, + socket_base::message_flags& out_flags, Handler& handler, + const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef win_iocp_null_buffers_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(impl.cancel_token_, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((context_, *p.p, "socket", + &impl, impl.socket_, "async_receive_with_flags(null_buffers)")); + + // Reset out_flags since it can be given no sensible value at this time. + out_flags = 0; + + start_null_buffers_receive_op(impl, in_flags, p.p); + p.v = p.p = 0; + } + + // Helper function to restart an asynchronous accept operation. + BOOST_ASIO_DECL void restart_accept_op(socket_type s, + socket_holder& new_socket, int family, int type, int protocol, + void* output_buffer, DWORD address_length, operation* op); + +protected: + // Open a new socket implementation. + BOOST_ASIO_DECL boost::system::error_code do_open( + base_implementation_type& impl, int family, int type, + int protocol, boost::system::error_code& ec); + + // Assign a native socket to a socket implementation. + BOOST_ASIO_DECL boost::system::error_code do_assign( + base_implementation_type& impl, int type, + socket_type native_socket, boost::system::error_code& ec); + + // Helper function to start an asynchronous send operation. + BOOST_ASIO_DECL void start_send_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op); + + // Helper function to start an asynchronous send_to operation. + BOOST_ASIO_DECL void start_send_to_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + const socket_addr_type* addr, int addrlen, + socket_base::message_flags flags, operation* op); + + // Helper function to start an asynchronous receive operation. + BOOST_ASIO_DECL void start_receive_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, + socket_base::message_flags flags, bool noop, operation* op); + + // Helper function to start an asynchronous null_buffers receive operation. + BOOST_ASIO_DECL void start_null_buffers_receive_op( + base_implementation_type& impl, + socket_base::message_flags flags, reactor_op* op); + + // Helper function to start an asynchronous receive_from operation. + BOOST_ASIO_DECL void start_receive_from_op(base_implementation_type& impl, + WSABUF* buffers, std::size_t buffer_count, socket_addr_type* addr, + socket_base::message_flags flags, int* addrlen, operation* op); + + // Helper function to start an asynchronous accept operation. + BOOST_ASIO_DECL void start_accept_op(base_implementation_type& impl, + bool peer_is_open, socket_holder& new_socket, int family, int type, + int protocol, void* output_buffer, DWORD address_length, operation* op); + + // Start an asynchronous read or write operation using the reactor. + BOOST_ASIO_DECL void start_reactor_op(base_implementation_type& impl, + int op_type, reactor_op* op); + + // Start the asynchronous connect operation using the reactor. + BOOST_ASIO_DECL void start_connect_op(base_implementation_type& impl, + int family, int type, const socket_addr_type* remote_addr, + std::size_t remote_addrlen, win_iocp_socket_connect_op_base* op); + + // Helper function to close a socket when the associated object is being + // destroyed. + BOOST_ASIO_DECL void close_for_destruction(base_implementation_type& impl); + + // Update the ID of the thread from which cancellation is safe. + BOOST_ASIO_DECL void update_cancellation_thread_id( + base_implementation_type& impl); + + // Helper function to get the reactor. If no reactor has been created yet, a + // new one is obtained from the execution context and a pointer to it is + // cached in this service. + BOOST_ASIO_DECL select_reactor& get_reactor(); + + // The type of a ConnectEx function pointer, as old SDKs may not provide it. + typedef BOOL (PASCAL *connect_ex_fn)(SOCKET, + const socket_addr_type*, int, void*, DWORD, DWORD*, OVERLAPPED*); + + // Helper function to get the ConnectEx pointer. If no ConnectEx pointer has + // been obtained yet, one is obtained using WSAIoctl and the pointer is + // cached. Returns a null pointer if ConnectEx is not available. + BOOST_ASIO_DECL connect_ex_fn get_connect_ex( + base_implementation_type& impl, int type); + + // The type of a NtSetInformationFile function pointer. + typedef LONG (NTAPI *nt_set_info_fn)(HANDLE, ULONG_PTR*, void*, ULONG, ULONG); + + // Helper function to get the NtSetInformationFile function pointer. If no + // NtSetInformationFile pointer has been obtained yet, one is obtained using + // GetProcAddress and the pointer is cached. Returns a null pointer if + // NtSetInformationFile is not available. + BOOST_ASIO_DECL nt_set_info_fn get_nt_set_info(); + + // Helper function to emulate InterlockedCompareExchangePointer functionality + // for: + // - very old Platform SDKs; and + // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. + BOOST_ASIO_DECL void* interlocked_compare_exchange_pointer( + void** dest, void* exch, void* cmp); + + // Helper function to emulate InterlockedExchangePointer functionality for: + // - very old Platform SDKs; and + // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. + BOOST_ASIO_DECL void* interlocked_exchange_pointer(void** dest, void* val); + + // The execution context used to obtain the reactor, if required. + execution_context& context_; + + // The IOCP service used for running asynchronous operations and dispatching + // handlers. + win_iocp_io_context& iocp_service_; + + // The reactor used for performing connect operations. This object is created + // only if needed. + select_reactor* reactor_; + + // Pointer to ConnectEx implementation. + void* connect_ex_; + + // Pointer to NtSetInformationFile implementation. + void* nt_set_info_; + + // Mutex to protect access to the linked list of implementations. + boost::asio::detail::mutex mutex_; + + // The head of a linked list of all implementations. + base_implementation_type* impl_list_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP diff --git a/boost/asio/detail/win_iocp_thread_info.hpp b/boost/asio/detail/win_iocp_thread_info.hpp new file mode 100644 index 0000000..c681982 --- /dev/null +++ b/boost/asio/detail/win_iocp_thread_info.hpp @@ -0,0 +1,36 @@ +// +// detail/win_iocp_thread_info.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct win_iocp_thread_info : public thread_info_base +{ +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP diff --git a/boost/asio/detail/win_iocp_wait_op.hpp b/boost/asio/detail/win_iocp_wait_op.hpp new file mode 100644 index 0000000..1f0929f --- /dev/null +++ b/boost/asio/detail/win_iocp_wait_op.hpp @@ -0,0 +1,125 @@ +// +// detail/win_iocp_wait_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP +#define BOOST_ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class win_iocp_wait_op : public reactor_op +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(win_iocp_wait_op); + + win_iocp_wait_op(socket_ops::weak_cancel_token_type cancel_token, + Handler& handler, const IoExecutor& io_ex) + : reactor_op(&win_iocp_wait_op::do_perform, + &win_iocp_wait_op::do_complete), + cancel_token_(cancel_token), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static status do_perform(reactor_op*) + { + return done; + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code& result_ec, + std::size_t /*bytes_transferred*/) + { + boost::system::error_code ec(result_ec); + + // Take ownership of the operation object. + win_iocp_wait_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + // The reactor may have stored a result in the operation object. + if (o->ec_) + ec = o->ec_; + + // Map non-portable errors to their portable counterparts. + if (ec.value() == ERROR_NETNAME_DELETED) + { + if (o->cancel_token_.expired()) + ec = boost::asio::error::operation_aborted; + else + ec = boost::asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = boost::asio::error::connection_refused; + } + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder1 + handler(o->handler_, ec); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_)); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + socket_ops::weak_cancel_token_type cancel_token_; + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#endif // BOOST_ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP diff --git a/boost/asio/detail/win_mutex.hpp b/boost/asio/detail/win_mutex.hpp new file mode 100644 index 0000000..7509131 --- /dev/null +++ b/boost/asio/detail/win_mutex.hpp @@ -0,0 +1,80 @@ +// +// detail/win_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_MUTEX_HPP +#define BOOST_ASIO_DETAIL_WIN_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +class win_mutex + : private noncopyable +{ +public: + typedef boost::asio::detail::scoped_lock scoped_lock; + + // Constructor. + BOOST_ASIO_DECL win_mutex(); + + // Destructor. + ~win_mutex() + { + ::DeleteCriticalSection(&crit_section_); + } + + // Lock the mutex. + void lock() + { + ::EnterCriticalSection(&crit_section_); + } + + // Unlock the mutex. + void unlock() + { + ::LeaveCriticalSection(&crit_section_); + } + +private: + // Initialisation must be performed in a separate function to the constructor + // since the compiler does not support the use of structured exceptions and + // C++ exceptions in the same function. + BOOST_ASIO_DECL int do_init(); + + ::CRITICAL_SECTION crit_section_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_WINDOWS) + +#endif // BOOST_ASIO_DETAIL_WIN_MUTEX_HPP diff --git a/boost/asio/detail/win_object_handle_service.hpp b/boost/asio/detail/win_object_handle_service.hpp new file mode 100644 index 0000000..4203222 --- /dev/null +++ b/boost/asio/detail/win_object_handle_service.hpp @@ -0,0 +1,197 @@ +// +// detail/win_object_handle_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2011 Boris Schaeling (boris@highscore.de) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_OBJECT_HANDLE_SERVICE_HPP +#define BOOST_ASIO_DETAIL_WIN_OBJECT_HANDLE_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) + +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#else // defined(BOOST_ASIO_HAS_IOCP) +# include +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#include + +namespace boost { +namespace asio { +namespace detail { + +class win_object_handle_service : + public execution_context_service_base +{ +public: + // The native type of an object handle. + typedef HANDLE native_handle_type; + + // The implementation type of the object handle. + class implementation_type + { + public: + // Default constructor. + implementation_type() + : handle_(INVALID_HANDLE_VALUE), + wait_handle_(INVALID_HANDLE_VALUE), + owner_(0), + next_(0), + prev_(0) + { + } + + private: + // Only this service will have access to the internal values. + friend class win_object_handle_service; + + // The native object handle representation. May be accessed or modified + // without locking the mutex. + native_handle_type handle_; + + // The handle used to unregister the wait operation. The mutex must be + // locked when accessing or modifying this member. + HANDLE wait_handle_; + + // The operations waiting on the object handle. If there is a registered + // wait then the mutex must be locked when accessing or modifying this + // member + op_queue op_queue_; + + // The service instance that owns the object handle implementation. + win_object_handle_service* owner_; + + // Pointers to adjacent handle implementations in linked list. The mutex + // must be locked when accessing or modifying these members. + implementation_type* next_; + implementation_type* prev_; + }; + + // Constructor. + BOOST_ASIO_DECL win_object_handle_service(execution_context& context); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown(); + + // Construct a new handle implementation. + BOOST_ASIO_DECL void construct(implementation_type& impl); + + // Move-construct a new handle implementation. + BOOST_ASIO_DECL void move_construct(implementation_type& impl, + implementation_type& other_impl); + + // Move-assign from another handle implementation. + BOOST_ASIO_DECL void move_assign(implementation_type& impl, + win_object_handle_service& other_service, + implementation_type& other_impl); + + // Destroy a handle implementation. + BOOST_ASIO_DECL void destroy(implementation_type& impl); + + // Assign a native handle to a handle implementation. + BOOST_ASIO_DECL boost::system::error_code assign(implementation_type& impl, + const native_handle_type& handle, boost::system::error_code& ec); + + // Determine whether the handle is open. + bool is_open(const implementation_type& impl) const + { + return impl.handle_ != INVALID_HANDLE_VALUE && impl.handle_ != 0; + } + + // Destroy a handle implementation. + BOOST_ASIO_DECL boost::system::error_code close(implementation_type& impl, + boost::system::error_code& ec); + + // Get the native handle representation. + native_handle_type native_handle(const implementation_type& impl) const + { + return impl.handle_; + } + + // Cancel all operations associated with the handle. + BOOST_ASIO_DECL boost::system::error_code cancel(implementation_type& impl, + boost::system::error_code& ec); + + // Perform a synchronous wait for the object to enter a signalled state. + BOOST_ASIO_DECL void wait(implementation_type& impl, + boost::system::error_code& ec); + + /// Start an asynchronous wait. + template + void async_wait(implementation_type& impl, + Handler& handler, const IoExecutor& io_ex) + { + // Allocate and construct an operation to wrap the handler. + typedef wait_handler op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((scheduler_.context(), *p.p, "object_handle", + &impl, reinterpret_cast(impl.wait_handle_), "async_wait")); + + start_wait_op(impl, p.p); + p.v = p.p = 0; + } + +private: + // Helper function to start an asynchronous wait operation. + BOOST_ASIO_DECL void start_wait_op(implementation_type& impl, wait_op* op); + + // Helper function to register a wait operation. + BOOST_ASIO_DECL void register_wait_callback( + implementation_type& impl, mutex::scoped_lock& lock); + + // Callback function invoked when the registered wait completes. + static BOOST_ASIO_DECL VOID CALLBACK wait_callback( + PVOID param, BOOLEAN timeout); + + // The scheduler used to post completions. +#if defined(BOOST_ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; + + // Mutex to protect access to internal state. + mutex mutex_; + + // The head of a linked list of all implementations. + implementation_type* impl_list_; + + // Flag to indicate that the dispatcher has been shut down. + bool shutdown_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) + +#endif // BOOST_ASIO_DETAIL_WIN_OBJECT_HANDLE_SERVICE_HPP diff --git a/boost/asio/detail/win_static_mutex.hpp b/boost/asio/detail/win_static_mutex.hpp new file mode 100644 index 0000000..c310d31 --- /dev/null +++ b/boost/asio/detail/win_static_mutex.hpp @@ -0,0 +1,76 @@ +// +// detail/win_static_mutex.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_STATIC_MUTEX_HPP +#define BOOST_ASIO_DETAIL_WIN_STATIC_MUTEX_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS) + +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct win_static_mutex +{ + typedef boost::asio::detail::scoped_lock scoped_lock; + + // Initialise the mutex. + BOOST_ASIO_DECL void init(); + + // Initialisation must be performed in a separate function to the "public" + // init() function since the compiler does not support the use of structured + // exceptions and C++ exceptions in the same function. + BOOST_ASIO_DECL int do_init(); + + // Lock the mutex. + void lock() + { + ::EnterCriticalSection(&crit_section_); + } + + // Unlock the mutex. + void unlock() + { + ::LeaveCriticalSection(&crit_section_); + } + + bool initialised_; + ::CRITICAL_SECTION crit_section_; +}; + +#if defined(UNDER_CE) +# define BOOST_ASIO_WIN_STATIC_MUTEX_INIT { false, { 0, 0, 0, 0, 0 } } +#else // defined(UNDER_CE) +# define BOOST_ASIO_WIN_STATIC_MUTEX_INIT { false, { 0, 0, 0, 0, 0, 0 } } +#endif // defined(UNDER_CE) + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_WINDOWS) + +#endif // BOOST_ASIO_DETAIL_WIN_STATIC_MUTEX_HPP diff --git a/boost/asio/detail/win_thread.hpp b/boost/asio/detail/win_thread.hpp new file mode 100644 index 0000000..ef86744 --- /dev/null +++ b/boost/asio/detail/win_thread.hpp @@ -0,0 +1,149 @@ +// +// detail/win_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_THREAD_HPP +#define BOOST_ASIO_DETAIL_WIN_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS) \ + && !defined(BOOST_ASIO_WINDOWS_APP) \ + && !defined(UNDER_CE) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +BOOST_ASIO_DECL unsigned int __stdcall win_thread_function(void* arg); + +#if defined(WINVER) && (WINVER < 0x0500) +BOOST_ASIO_DECL void __stdcall apc_function(ULONG data); +#else +BOOST_ASIO_DECL void __stdcall apc_function(ULONG_PTR data); +#endif + +template +class win_thread_base +{ +public: + static bool terminate_threads() + { + return ::InterlockedExchangeAdd(&terminate_threads_, 0) != 0; + } + + static void set_terminate_threads(bool b) + { + ::InterlockedExchange(&terminate_threads_, b ? 1 : 0); + } + +private: + static long terminate_threads_; +}; + +template +long win_thread_base::terminate_threads_ = 0; + +class win_thread + : private noncopyable, + public win_thread_base +{ +public: + // Constructor. + template + win_thread(Function f, unsigned int stack_size = 0) + : thread_(0), + exit_event_(0) + { + start_thread(new func(f), stack_size); + } + + // Destructor. + BOOST_ASIO_DECL ~win_thread(); + + // Wait for the thread to exit. + BOOST_ASIO_DECL void join(); + + // Get number of CPUs. + BOOST_ASIO_DECL static std::size_t hardware_concurrency(); + +private: + friend BOOST_ASIO_DECL unsigned int __stdcall win_thread_function(void* arg); + +#if defined(WINVER) && (WINVER < 0x0500) + friend BOOST_ASIO_DECL void __stdcall apc_function(ULONG); +#else + friend BOOST_ASIO_DECL void __stdcall apc_function(ULONG_PTR); +#endif + + class func_base + { + public: + virtual ~func_base() {} + virtual void run() = 0; + ::HANDLE entry_event_; + ::HANDLE exit_event_; + }; + + struct auto_func_base_ptr + { + func_base* ptr; + ~auto_func_base_ptr() { delete ptr; } + }; + + template + class func + : public func_base + { + public: + func(Function f) + : f_(f) + { + } + + virtual void run() + { + f_(); + } + + private: + Function f_; + }; + + BOOST_ASIO_DECL void start_thread(func_base* arg, unsigned int stack_size); + + ::HANDLE thread_; + ::HANDLE exit_event_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_WINDOWS) + // && !defined(BOOST_ASIO_WINDOWS_APP) + // && !defined(UNDER_CE) + +#endif // BOOST_ASIO_DETAIL_WIN_THREAD_HPP diff --git a/boost/asio/detail/win_tss_ptr.hpp b/boost/asio/detail/win_tss_ptr.hpp new file mode 100644 index 0000000..102b41a --- /dev/null +++ b/boost/asio/detail/win_tss_ptr.hpp @@ -0,0 +1,81 @@ +// +// detail/win_tss_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WIN_TSS_PTR_HPP +#define BOOST_ASIO_DETAIL_WIN_TSS_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Helper function to create thread-specific storage. +BOOST_ASIO_DECL DWORD win_tss_ptr_create(); + +template +class win_tss_ptr + : private noncopyable +{ +public: + // Constructor. + win_tss_ptr() + : tss_key_(win_tss_ptr_create()) + { + } + + // Destructor. + ~win_tss_ptr() + { + ::TlsFree(tss_key_); + } + + // Get the value. + operator T*() const + { + return static_cast(::TlsGetValue(tss_key_)); + } + + // Set the value. + void operator=(T* value) + { + ::TlsSetValue(tss_key_, value); + } + +private: + // Thread-specific storage to allow unlocked access to determine whether a + // thread is a member of the pool. + DWORD tss_key_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_WINDOWS) + +#endif // BOOST_ASIO_DETAIL_WIN_TSS_PTR_HPP diff --git a/boost/asio/detail/winapp_thread.hpp b/boost/asio/detail/winapp_thread.hpp new file mode 100644 index 0000000..b92c7f5 --- /dev/null +++ b/boost/asio/detail/winapp_thread.hpp @@ -0,0 +1,126 @@ +// +// detail/winapp_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WINAPP_THREAD_HPP +#define BOOST_ASIO_DETAIL_WINAPP_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS) && defined(BOOST_ASIO_WINDOWS_APP) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +DWORD WINAPI winapp_thread_function(LPVOID arg); + +class winapp_thread + : private noncopyable +{ +public: + // Constructor. + template + winapp_thread(Function f, unsigned int = 0) + { + scoped_ptr arg(new func(f)); + DWORD thread_id = 0; + thread_ = ::CreateThread(0, 0, winapp_thread_function, + arg.get(), 0, &thread_id); + if (!thread_) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "thread"); + } + arg.release(); + } + + // Destructor. + ~winapp_thread() + { + ::CloseHandle(thread_); + } + + // Wait for the thread to exit. + void join() + { + ::WaitForSingleObjectEx(thread_, INFINITE, false); + } + + // Get number of CPUs. + static std::size_t hardware_concurrency() + { + SYSTEM_INFO system_info; + ::GetNativeSystemInfo(&system_info); + return system_info.dwNumberOfProcessors; + } + +private: + friend DWORD WINAPI winapp_thread_function(LPVOID arg); + + class func_base + { + public: + virtual ~func_base() {} + virtual void run() = 0; + }; + + template + class func + : public func_base + { + public: + func(Function f) + : f_(f) + { + } + + virtual void run() + { + f_(); + } + + private: + Function f_; + }; + + ::HANDLE thread_; +}; + +inline DWORD WINAPI winapp_thread_function(LPVOID arg) +{ + scoped_ptr func( + static_cast(arg)); + func->run(); + return 0; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS) && defined(BOOST_ASIO_WINDOWS_APP) + +#endif // BOOST_ASIO_DETAIL_WINAPP_THREAD_HPP diff --git a/boost/asio/detail/wince_thread.hpp b/boost/asio/detail/wince_thread.hpp new file mode 100644 index 0000000..492a37c --- /dev/null +++ b/boost/asio/detail/wince_thread.hpp @@ -0,0 +1,126 @@ +// +// detail/wince_thread.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WINCE_THREAD_HPP +#define BOOST_ASIO_DETAIL_WINCE_THREAD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +DWORD WINAPI wince_thread_function(LPVOID arg); + +class wince_thread + : private noncopyable +{ +public: + // Constructor. + template + wince_thread(Function f, unsigned int = 0) + { + scoped_ptr arg(new func(f)); + DWORD thread_id = 0; + thread_ = ::CreateThread(0, 0, wince_thread_function, + arg.get(), 0, &thread_id); + if (!thread_) + { + DWORD last_error = ::GetLastError(); + boost::system::error_code ec(last_error, + boost::asio::error::get_system_category()); + boost::asio::detail::throw_error(ec, "thread"); + } + arg.release(); + } + + // Destructor. + ~wince_thread() + { + ::CloseHandle(thread_); + } + + // Wait for the thread to exit. + void join() + { + ::WaitForSingleObject(thread_, INFINITE); + } + + // Get number of CPUs. + static std::size_t hardware_concurrency() + { + SYSTEM_INFO system_info; + ::GetSystemInfo(&system_info); + return system_info.dwNumberOfProcessors; + } + +private: + friend DWORD WINAPI wince_thread_function(LPVOID arg); + + class func_base + { + public: + virtual ~func_base() {} + virtual void run() = 0; + }; + + template + class func + : public func_base + { + public: + func(Function f) + : f_(f) + { + } + + virtual void run() + { + f_(); + } + + private: + Function f_; + }; + + ::HANDLE thread_; +}; + +inline DWORD WINAPI wince_thread_function(LPVOID arg) +{ + scoped_ptr func( + static_cast(arg)); + func->run(); + return 0; +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + +#endif // BOOST_ASIO_DETAIL_WINCE_THREAD_HPP diff --git a/boost/asio/detail/winrt_async_manager.hpp b/boost/asio/detail/winrt_async_manager.hpp new file mode 100644 index 0000000..e9dc6cb --- /dev/null +++ b/boost/asio/detail/winrt_async_manager.hpp @@ -0,0 +1,307 @@ +// +// detail/winrt_async_manager.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP +#define BOOST_ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#else // defined(BOOST_ASIO_HAS_IOCP) +# include +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#include + +namespace boost { +namespace asio { +namespace detail { + +class winrt_async_manager + : public execution_context_service_base +{ +public: + // Constructor. + winrt_async_manager(execution_context& context) + : execution_context_service_base(context), + scheduler_(use_service(context)), + outstanding_ops_(1) + { + } + + // Destructor. + ~winrt_async_manager() + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + if (--outstanding_ops_ > 0) + { + // Block until last operation is complete. + std::future f = promise_.get_future(); + f.wait(); + } + } + + void sync(Windows::Foundation::IAsyncAction^ action, + boost::system::error_code& ec) + { + using namespace Windows::Foundation; + using Windows::Foundation::AsyncStatus; + + auto promise = std::make_shared>(); + auto future = promise->get_future(); + + action->Completed = ref new AsyncActionCompletedHandler( + [promise](IAsyncAction^ action, AsyncStatus status) + { + switch (status) + { + case AsyncStatus::Canceled: + promise->set_value(boost::asio::error::operation_aborted); + break; + case AsyncStatus::Error: + case AsyncStatus::Completed: + default: + boost::system::error_code ec( + action->ErrorCode.Value, + boost::system::system_category()); + promise->set_value(ec); + break; + } + }); + + ec = future.get(); + } + + template + TResult sync(Windows::Foundation::IAsyncOperation^ operation, + boost::system::error_code& ec) + { + using namespace Windows::Foundation; + using Windows::Foundation::AsyncStatus; + + auto promise = std::make_shared>(); + auto future = promise->get_future(); + + operation->Completed = ref new AsyncOperationCompletedHandler( + [promise](IAsyncOperation^ operation, AsyncStatus status) + { + switch (status) + { + case AsyncStatus::Canceled: + promise->set_value(boost::asio::error::operation_aborted); + break; + case AsyncStatus::Error: + case AsyncStatus::Completed: + default: + boost::system::error_code ec( + operation->ErrorCode.Value, + boost::system::system_category()); + promise->set_value(ec); + break; + } + }); + + ec = future.get(); + return operation->GetResults(); + } + + template + TResult sync( + Windows::Foundation::IAsyncOperationWithProgress< + TResult, TProgress>^ operation, + boost::system::error_code& ec) + { + using namespace Windows::Foundation; + using Windows::Foundation::AsyncStatus; + + auto promise = std::make_shared>(); + auto future = promise->get_future(); + + operation->Completed + = ref new AsyncOperationWithProgressCompletedHandler( + [promise](IAsyncOperationWithProgress^ operation, + AsyncStatus status) + { + switch (status) + { + case AsyncStatus::Canceled: + promise->set_value(boost::asio::error::operation_aborted); + break; + case AsyncStatus::Started: + break; + case AsyncStatus::Error: + case AsyncStatus::Completed: + default: + boost::system::error_code ec( + operation->ErrorCode.Value, + boost::system::system_category()); + promise->set_value(ec); + break; + } + }); + + ec = future.get(); + return operation->GetResults(); + } + + void async(Windows::Foundation::IAsyncAction^ action, + winrt_async_op* handler) + { + using namespace Windows::Foundation; + using Windows::Foundation::AsyncStatus; + + auto on_completed = ref new AsyncActionCompletedHandler( + [this, handler](IAsyncAction^ action, AsyncStatus status) + { + switch (status) + { + case AsyncStatus::Canceled: + handler->ec_ = boost::asio::error::operation_aborted; + break; + case AsyncStatus::Started: + return; + case AsyncStatus::Completed: + case AsyncStatus::Error: + default: + handler->ec_ = boost::system::error_code( + action->ErrorCode.Value, + boost::system::system_category()); + break; + } + scheduler_.post_deferred_completion(handler); + if (--outstanding_ops_ == 0) + promise_.set_value(); + }); + + scheduler_.work_started(); + ++outstanding_ops_; + action->Completed = on_completed; + } + + template + void async(Windows::Foundation::IAsyncOperation^ operation, + winrt_async_op* handler) + { + using namespace Windows::Foundation; + using Windows::Foundation::AsyncStatus; + + auto on_completed = ref new AsyncOperationCompletedHandler( + [this, handler](IAsyncOperation^ operation, AsyncStatus status) + { + switch (status) + { + case AsyncStatus::Canceled: + handler->ec_ = boost::asio::error::operation_aborted; + break; + case AsyncStatus::Started: + return; + case AsyncStatus::Completed: + handler->result_ = operation->GetResults(); + // Fall through. + case AsyncStatus::Error: + default: + handler->ec_ = boost::system::error_code( + operation->ErrorCode.Value, + boost::system::system_category()); + break; + } + scheduler_.post_deferred_completion(handler); + if (--outstanding_ops_ == 0) + promise_.set_value(); + }); + + scheduler_.work_started(); + ++outstanding_ops_; + operation->Completed = on_completed; + } + + template + void async( + Windows::Foundation::IAsyncOperationWithProgress< + TResult, TProgress>^ operation, + winrt_async_op* handler) + { + using namespace Windows::Foundation; + using Windows::Foundation::AsyncStatus; + + auto on_completed + = ref new AsyncOperationWithProgressCompletedHandler( + [this, handler](IAsyncOperationWithProgress< + TResult, TProgress>^ operation, AsyncStatus status) + { + switch (status) + { + case AsyncStatus::Canceled: + handler->ec_ = boost::asio::error::operation_aborted; + break; + case AsyncStatus::Started: + return; + case AsyncStatus::Completed: + handler->result_ = operation->GetResults(); + // Fall through. + case AsyncStatus::Error: + default: + handler->ec_ = boost::system::error_code( + operation->ErrorCode.Value, + boost::system::system_category()); + break; + } + scheduler_.post_deferred_completion(handler); + if (--outstanding_ops_ == 0) + promise_.set_value(); + }); + + scheduler_.work_started(); + ++outstanding_ops_; + operation->Completed = on_completed; + } + +private: + // The scheduler implementation used to post completed handlers. +#if defined(BOOST_ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; + + // Count of outstanding operations. + atomic_count outstanding_ops_; + + // Used to keep wait for outstanding operations to complete. + std::promise promise_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#endif // BOOST_ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP diff --git a/boost/asio/detail/winrt_async_op.hpp b/boost/asio/detail/winrt_async_op.hpp new file mode 100644 index 0000000..251dd87 --- /dev/null +++ b/boost/asio/detail/winrt_async_op.hpp @@ -0,0 +1,67 @@ +// +// detail/winrt_async_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WINRT_ASYNC_OP_HPP +#define BOOST_ASIO_DETAIL_WINRT_ASYNC_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class winrt_async_op + : public operation +{ +public: + // The error code to be passed to the completion handler. + boost::system::error_code ec_; + + // The result of the operation, to be passed to the completion handler. + TResult result_; + +protected: + winrt_async_op(func_type complete_func) + : operation(complete_func), + result_() + { + } +}; + +template <> +class winrt_async_op + : public operation +{ +public: + // The error code to be passed to the completion handler. + boost::system::error_code ec_; + +protected: + winrt_async_op(func_type complete_func) + : operation(complete_func) + { + } +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_WINRT_ASYNC_OP_HPP diff --git a/boost/asio/detail/winrt_resolve_op.hpp b/boost/asio/detail/winrt_resolve_op.hpp new file mode 100644 index 0000000..f7faa29 --- /dev/null +++ b/boost/asio/detail/winrt_resolve_op.hpp @@ -0,0 +1,123 @@ +// +// detail/winrt_resolve_op.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WINRT_RESOLVE_OP_HPP +#define BOOST_ASIO_DETAIL_WINRT_RESOLVE_OP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class winrt_resolve_op : + public winrt_async_op< + Windows::Foundation::Collections::IVectorView< + Windows::Networking::EndpointPair^>^> +{ +public: + BOOST_ASIO_DEFINE_HANDLER_PTR(winrt_resolve_op); + + typedef typename Protocol::endpoint endpoint_type; + typedef boost::asio::ip::basic_resolver_query query_type; + typedef boost::asio::ip::basic_resolver_results results_type; + + winrt_resolve_op(const query_type& query, + Handler& handler, const IoExecutor& io_ex) + : winrt_async_op< + Windows::Foundation::Collections::IVectorView< + Windows::Networking::EndpointPair^>^>( + &winrt_resolve_op::do_complete), + query_(query), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + io_executor_(io_ex) + { + handler_work::start(handler_, io_executor_); + } + + static void do_complete(void* owner, operation* base, + const boost::system::error_code&, std::size_t) + { + // Take ownership of the operation object. + winrt_resolve_op* o(static_cast(base)); + ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; + handler_work w(o->handler_, o->io_executor_); + + BOOST_ASIO_HANDLER_COMPLETION((*o)); + + results_type results = results_type(); + if (!o->ec_) + { + try + { + results = results_type::create(o->result_, o->query_.hints(), + o->query_.host_name(), o->query_.service_name()); + } + catch (Platform::Exception^ e) + { + o->ec_ = boost::system::error_code(e->HResult, + boost::system::system_category()); + } + } + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. Even if we're not about to make an upcall, a + // sub-object of the handler may be the true owner of the memory associated + // with the handler. Consequently, a local copy of the handler is required + // to ensure that any owning sub-object remains valid until after we have + // deallocated the memory here. + detail::binder2 + handler(o->handler_, o->ec_, results); + p.h = boost::asio::detail::addressof(handler.handler_); + p.reset(); + + // Make the upcall if required. + if (owner) + { + fenced_block b(fenced_block::half); + BOOST_ASIO_HANDLER_INVOCATION_BEGIN((handler.arg1_, "...")); + w.complete(handler, handler.handler_); + BOOST_ASIO_HANDLER_INVOCATION_END; + } + } + +private: + query_type query_; + Handler handler_; + IoExecutor io_executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#endif // BOOST_ASIO_DETAIL_WINRT_RESOLVE_OP_HPP diff --git a/boost/asio/detail/winrt_resolver_service.hpp b/boost/asio/detail/winrt_resolver_service.hpp new file mode 100644 index 0000000..054b6ab --- /dev/null +++ b/boost/asio/detail/winrt_resolver_service.hpp @@ -0,0 +1,214 @@ +// +// detail/winrt_resolver_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP +#define BOOST_ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#else // defined(BOOST_ASIO_HAS_IOCP) +# include +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class winrt_resolver_service : + public execution_context_service_base > +{ +public: + // The implementation type of the resolver. A cancellation token is used to + // indicate to the asynchronous operation that the operation has been + // cancelled. + typedef socket_ops::shared_cancel_token_type implementation_type; + + // The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + // The query type. + typedef boost::asio::ip::basic_resolver_query query_type; + + // The results type. + typedef boost::asio::ip::basic_resolver_results results_type; + + // Constructor. + winrt_resolver_service(execution_context& context) + : execution_context_service_base< + winrt_resolver_service >(context), + scheduler_(use_service(context)), + async_manager_(use_service(context)) + { + } + + // Destructor. + ~winrt_resolver_service() + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown() + { + } + + // Perform any fork-related housekeeping. + void notify_fork(execution_context::fork_event) + { + } + + // Construct a new resolver implementation. + void construct(implementation_type&) + { + } + + // Move-construct a new resolver implementation. + void move_construct(implementation_type&, + implementation_type&) + { + } + + // Move-assign from another resolver implementation. + void move_assign(implementation_type&, + winrt_resolver_service&, implementation_type&) + { + } + + // Destroy a resolver implementation. + void destroy(implementation_type&) + { + } + + // Cancel pending asynchronous operations. + void cancel(implementation_type&) + { + } + + // Resolve a query to a list of entries. + results_type resolve(implementation_type&, + const query_type& query, boost::system::error_code& ec) + { + try + { + using namespace Windows::Networking::Sockets; + auto endpoint_pairs = async_manager_.sync( + DatagramSocket::GetEndpointPairsAsync( + winrt_utils::host_name(query.host_name()), + winrt_utils::string(query.service_name())), ec); + + if (ec) + return results_type(); + + return results_type::create( + endpoint_pairs, query.hints(), + query.host_name(), query.service_name()); + } + catch (Platform::Exception^ e) + { + ec = boost::system::error_code(e->HResult, + boost::system::system_category()); + return results_type(); + } + } + + // Asynchronously resolve a query to a list of entries. + template + void async_resolve(implementation_type& impl, const query_type& query, + Handler& handler, const IoExecutor& io_ex) + { + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler); + + // Allocate and construct an operation to wrap the handler. + typedef winrt_resolve_op op; + typename op::ptr p = { boost::asio::detail::addressof(handler), + op::ptr::allocate(handler), 0 }; + p.p = new (p.v) op(query, handler, io_ex); + + BOOST_ASIO_HANDLER_CREATION((scheduler_.context(), + *p.p, "resolver", &impl, 0, "async_resolve")); + (void)impl; + + try + { + using namespace Windows::Networking::Sockets; + async_manager_.async(DatagramSocket::GetEndpointPairsAsync( + winrt_utils::host_name(query.host_name()), + winrt_utils::string(query.service_name())), p.p); + p.v = p.p = 0; + } + catch (Platform::Exception^ e) + { + p.p->ec_ = boost::system::error_code( + e->HResult, boost::system::system_category()); + scheduler_.post_immediate_completion(p.p, is_continuation); + p.v = p.p = 0; + } + } + + // Resolve an endpoint to a list of entries. + results_type resolve(implementation_type&, + const endpoint_type&, boost::system::error_code& ec) + { + ec = boost::asio::error::operation_not_supported; + return results_type(); + } + + // Asynchronously resolve an endpoint to a list of entries. + template + void async_resolve(implementation_type&, const endpoint_type&, + Handler& handler, const IoExecutor& io_ex) + { + boost::system::error_code ec = boost::asio::error::operation_not_supported; + const results_type results; + boost::asio::post(io_ex, detail::bind_handler(handler, ec, results)); + } + +private: + // The scheduler implementation used for delivering completions. +#if defined(BOOST_ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; + + winrt_async_manager& async_manager_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#endif // BOOST_ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP diff --git a/boost/asio/detail/winrt_timer_scheduler.hpp b/boost/asio/detail/winrt_timer_scheduler.hpp new file mode 100644 index 0000000..d48ed2c --- /dev/null +++ b/boost/asio/detail/winrt_timer_scheduler.hpp @@ -0,0 +1,149 @@ +// +// detail/winrt_timer_scheduler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WINRT_TIMER_SCHEDULER_HPP +#define BOOST_ASIO_DETAIL_WINRT_TIMER_SCHEDULER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#else // defined(BOOST_ASIO_HAS_IOCP) +# include +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#endif // defined(BOOST_ASIO_HAS_IOCP) + +#include + +namespace boost { +namespace asio { +namespace detail { + +class winrt_timer_scheduler + : public execution_context_service_base +{ +public: + // Constructor. + BOOST_ASIO_DECL winrt_timer_scheduler(execution_context& context); + + // Destructor. + BOOST_ASIO_DECL ~winrt_timer_scheduler(); + + // Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL void shutdown(); + + // Recreate internal descriptors following a fork. + BOOST_ASIO_DECL void notify_fork(execution_context::fork_event fork_ev); + + // Initialise the task. No effect as this class uses its own thread. + BOOST_ASIO_DECL void init_task(); + + // Add a new timer queue to the reactor. + template + void add_timer_queue(timer_queue& queue); + + // Remove a timer queue from the reactor. + template + void remove_timer_queue(timer_queue& queue); + + // Schedule a new operation in the given timer queue to expire at the + // specified absolute time. + template + void schedule_timer(timer_queue& queue, + const typename Time_Traits::time_type& time, + typename timer_queue::per_timer_data& timer, wait_op* op); + + // Cancel the timer operations associated with the given token. Returns the + // number of operations that have been posted or dispatched. + template + std::size_t cancel_timer(timer_queue& queue, + typename timer_queue::per_timer_data& timer, + std::size_t max_cancelled = (std::numeric_limits::max)()); + + // Move the timer operations associated with the given timer. + template + void move_timer(timer_queue& queue, + typename timer_queue::per_timer_data& to, + typename timer_queue::per_timer_data& from); + +private: + // Run the select loop in the thread. + BOOST_ASIO_DECL void run_thread(); + + // Entry point for the select loop thread. + BOOST_ASIO_DECL static void call_run_thread(winrt_timer_scheduler* reactor); + + // Helper function to add a new timer queue. + BOOST_ASIO_DECL void do_add_timer_queue(timer_queue_base& queue); + + // Helper function to remove a timer queue. + BOOST_ASIO_DECL void do_remove_timer_queue(timer_queue_base& queue); + + // The scheduler implementation used to post completions. +#if defined(BOOST_ASIO_HAS_IOCP) + typedef class win_iocp_io_context scheduler_impl; +#else + typedef class scheduler scheduler_impl; +#endif + scheduler_impl& scheduler_; + + // Mutex used to protect internal variables. + boost::asio::detail::mutex mutex_; + + // Event used to wake up background thread. + boost::asio::detail::event event_; + + // The timer queues. + timer_queue_set timer_queues_; + + // The background thread that is waiting for timers to expire. + boost::asio::detail::thread* thread_; + + // Does the background thread need to stop. + bool stop_thread_; + + // Whether the service has been shut down. + bool shutdown_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#endif // BOOST_ASIO_DETAIL_WINRT_TIMER_SCHEDULER_HPP diff --git a/boost/asio/detail/winrt_utils.hpp b/boost/asio/detail/winrt_utils.hpp new file mode 100644 index 0000000..bc765ae --- /dev/null +++ b/boost/asio/detail/winrt_utils.hpp @@ -0,0 +1,108 @@ +// +// detail/winrt_utils.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WINRT_UTILS_HPP +#define BOOST_ASIO_DETAIL_WINRT_UTILS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { +namespace winrt_utils { + +inline Platform::String^ string(const char* from) +{ + std::wstring tmp(from, from + std::strlen(from)); + return ref new Platform::String(tmp.c_str()); +} + +inline Platform::String^ string(const std::string& from) +{ + std::wstring tmp(from.begin(), from.end()); + return ref new Platform::String(tmp.c_str()); +} + +inline std::string string(Platform::String^ from) +{ + std::wstring_convert> converter; + return converter.to_bytes(from->Data()); +} + +inline Platform::String^ string(unsigned short from) +{ + return string(std::to_string(from)); +} + +template +inline Platform::String^ string(const T& from) +{ + return string(from.to_string()); +} + +inline int integer(Platform::String^ from) +{ + return _wtoi(from->Data()); +} + +template +inline Windows::Networking::HostName^ host_name(const T& from) +{ + return ref new Windows::Networking::HostName((string)(from)); +} + +template +inline Windows::Storage::Streams::IBuffer^ buffer_dup( + const ConstBufferSequence& buffers) +{ + using Microsoft::WRL::ComPtr; + using boost::asio::buffer_size; + std::size_t size = buffer_size(buffers); + auto b = ref new Windows::Storage::Streams::Buffer(size); + ComPtr insp = reinterpret_cast(b); + ComPtr bacc; + insp.As(&bacc); + byte* bytes = nullptr; + bacc->Buffer(&bytes); + boost::asio::buffer_copy(boost::asio::buffer(bytes, size), buffers); + b->Length = size; + return b; +} + +} // namespace winrt_utils +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#endif // BOOST_ASIO_DETAIL_WINRT_UTILS_HPP diff --git a/boost/asio/detail/winsock_init.hpp b/boost/asio/detail/winsock_init.hpp new file mode 100644 index 0000000..dfda010 --- /dev/null +++ b/boost/asio/detail/winsock_init.hpp @@ -0,0 +1,130 @@ +// +// detail/winsock_init.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WINSOCK_INIT_HPP +#define BOOST_ASIO_DETAIL_WINSOCK_INIT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +#include + +namespace boost { +namespace asio { +namespace detail { + +class winsock_init_base +{ +protected: + // Structure to track result of initialisation and number of uses. POD is used + // to ensure that the values are zero-initialised prior to any code being run. + struct data + { + long init_count_; + long result_; + }; + + BOOST_ASIO_DECL static void startup(data& d, + unsigned char major, unsigned char minor); + + BOOST_ASIO_DECL static void manual_startup(data& d); + + BOOST_ASIO_DECL static void cleanup(data& d); + + BOOST_ASIO_DECL static void manual_cleanup(data& d); + + BOOST_ASIO_DECL static void throw_on_error(data& d); +}; + +template +class winsock_init : private winsock_init_base +{ +public: + winsock_init(bool allow_throw = true) + { + startup(data_, Major, Minor); + if (allow_throw) + throw_on_error(data_); + } + + winsock_init(const winsock_init&) + { + startup(data_, Major, Minor); + throw_on_error(data_); + } + + ~winsock_init() + { + cleanup(data_); + } + + // This class may be used to indicate that user code will manage Winsock + // initialisation and cleanup. This may be required in the case of a DLL, for + // example, where it is not safe to initialise Winsock from global object + // constructors. + // + // To prevent asio from initialising Winsock, the object must be constructed + // before any Asio's own global objects. With MSVC, this may be accomplished + // by adding the following code to the DLL: + // + // #pragma warning(push) + // #pragma warning(disable:4073) + // #pragma init_seg(lib) + // boost::asio::detail::winsock_init<>::manual manual_winsock_init; + // #pragma warning(pop) + class manual + { + public: + manual() + { + manual_startup(data_); + } + + manual(const manual&) + { + manual_startup(data_); + } + + ~manual() + { + manual_cleanup(data_); + } + }; + +private: + friend class manual; + static data data_; +}; + +template +winsock_init_base::data winsock_init::data_; + +// Static variable to ensure that winsock is initialised before main, and +// therefore before any other threads can get started. +static const winsock_init<>& winsock_init_instance = winsock_init<>(false); + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + +#endif // BOOST_ASIO_DETAIL_WINSOCK_INIT_HPP diff --git a/boost/asio/detail/work_dispatcher.hpp b/boost/asio/detail/work_dispatcher.hpp new file mode 100644 index 0000000..9a92c45 --- /dev/null +++ b/boost/asio/detail/work_dispatcher.hpp @@ -0,0 +1,75 @@ +// +// detail/work_dispatcher.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WORK_DISPATCHER_HPP +#define BOOST_ASIO_DETAIL_WORK_DISPATCHER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class work_dispatcher +{ +public: + template + explicit work_dispatcher(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) + : work_((get_associated_executor)(handler)), + handler_(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + work_dispatcher(const work_dispatcher& other) + : work_(other.work_), + handler_(other.handler_) + { + } + + work_dispatcher(work_dispatcher&& other) + : work_(BOOST_ASIO_MOVE_CAST(executor_work_guard< + typename associated_executor::type>)(other.work_)), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()() + { + typename associated_allocator::type alloc( + (get_associated_allocator)(handler_)); + work_.get_executor().dispatch( + BOOST_ASIO_MOVE_CAST(Handler)(handler_), alloc); + work_.reset(); + } + +private: + executor_work_guard::type> work_; + Handler handler_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_WORK_DISPATCHER_HPP diff --git a/boost/asio/detail/wrapped_handler.hpp b/boost/asio/detail/wrapped_handler.hpp new file mode 100644 index 0000000..8496168 --- /dev/null +++ b/boost/asio/detail/wrapped_handler.hpp @@ -0,0 +1,293 @@ +// +// detail/wrapped_handler.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DETAIL_WRAPPED_HANDLER_HPP +#define BOOST_ASIO_DETAIL_WRAPPED_HANDLER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct is_continuation_delegated +{ + template + bool operator()(Dispatcher&, Handler& handler) const + { + return boost_asio_handler_cont_helpers::is_continuation(handler); + } +}; + +struct is_continuation_if_running +{ + template + bool operator()(Dispatcher& dispatcher, Handler&) const + { + return dispatcher.running_in_this_thread(); + } +}; + +template +class wrapped_handler +{ +public: + typedef void result_type; + + wrapped_handler(Dispatcher dispatcher, Handler& handler) + : dispatcher_(dispatcher), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + wrapped_handler(const wrapped_handler& other) + : dispatcher_(other.dispatcher_), + handler_(other.handler_) + { + } + + wrapped_handler(wrapped_handler&& other) + : dispatcher_(other.dispatcher_), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()() + { + dispatcher_.dispatch(BOOST_ASIO_MOVE_CAST(Handler)(handler_)); + } + + void operator()() const + { + dispatcher_.dispatch(handler_); + } + + template + void operator()(const Arg1& arg1) + { + dispatcher_.dispatch(detail::bind_handler(handler_, arg1)); + } + + template + void operator()(const Arg1& arg1) const + { + dispatcher_.dispatch(detail::bind_handler(handler_, arg1)); + } + + template + void operator()(const Arg1& arg1, const Arg2& arg2) + { + dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2)); + } + + template + void operator()(const Arg1& arg1, const Arg2& arg2) const + { + dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2)); + } + + template + void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) + { + dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3)); + } + + template + void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) const + { + dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3)); + } + + template + void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4) + { + dispatcher_.dispatch( + detail::bind_handler(handler_, arg1, arg2, arg3, arg4)); + } + + template + void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4) const + { + dispatcher_.dispatch( + detail::bind_handler(handler_, arg1, arg2, arg3, arg4)); + } + + template + void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4, const Arg5& arg5) + { + dispatcher_.dispatch( + detail::bind_handler(handler_, arg1, arg2, arg3, arg4, arg5)); + } + + template + void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4, const Arg5& arg5) const + { + dispatcher_.dispatch( + detail::bind_handler(handler_, arg1, arg2, arg3, arg4, arg5)); + } + +//private: + Dispatcher dispatcher_; + Handler handler_; +}; + +template +class rewrapped_handler +{ +public: + explicit rewrapped_handler(Handler& handler, const Context& context) + : context_(context), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) + { + } + + explicit rewrapped_handler(const Handler& handler, const Context& context) + : context_(context), + handler_(handler) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + rewrapped_handler(const rewrapped_handler& other) + : context_(other.context_), + handler_(other.handler_) + { + } + + rewrapped_handler(rewrapped_handler&& other) + : context_(BOOST_ASIO_MOVE_CAST(Context)(other.context_)), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()() + { + handler_(); + } + + void operator()() const + { + handler_(); + } + +//private: + Context context_; + Handler handler_; +}; + +template +inline void* asio_handler_allocate(std::size_t size, + wrapped_handler* this_handler) +{ + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + wrapped_handler* this_handler) +{ + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template +inline bool asio_handler_is_continuation( + wrapped_handler* this_handler) +{ + return IsContinuation()(this_handler->dispatcher_, this_handler->handler_); +} + +template +inline void asio_handler_invoke(Function& function, + wrapped_handler* this_handler) +{ + this_handler->dispatcher_.dispatch( + rewrapped_handler( + function, this_handler->handler_)); +} + +template +inline void asio_handler_invoke(const Function& function, + wrapped_handler* this_handler) +{ + this_handler->dispatcher_.dispatch( + rewrapped_handler( + function, this_handler->handler_)); +} + +template +inline void* asio_handler_allocate(std::size_t size, + rewrapped_handler* this_handler) +{ + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->context_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + rewrapped_handler* this_handler) +{ + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->context_); +} + +template +inline bool asio_handler_is_continuation( + rewrapped_handler* this_handler) +{ + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->context_); +} + +template +inline void asio_handler_invoke(Function& function, + rewrapped_handler* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->context_); +} + +template +inline void asio_handler_invoke(const Function& function, + rewrapped_handler* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->context_); +} + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_DETAIL_WRAPPED_HANDLER_HPP diff --git a/boost/asio/dispatch.hpp b/boost/asio/dispatch.hpp new file mode 100644 index 0000000..578608c --- /dev/null +++ b/boost/asio/dispatch.hpp @@ -0,0 +1,110 @@ +// +// dispatch.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_DISPATCH_HPP +#define BOOST_ASIO_DISPATCH_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +/// Submits a completion token or function object for execution. +/** + * This function submits an object for execution using the object's associated + * executor. The function object may be called from the current thread prior to + * returning from dispatch(). Otherwise, it is queued for execution. + * + * This function has the following effects: + * + * @li Constructs a function object handler of type @c Handler, initialized + * with handler(forward(token)). + * + * @li Constructs an object @c result of type async_result, + * initializing the object as result(handler). + * + * @li Obtains the handler's associated executor object @c ex by performing + * get_associated_executor(handler). + * + * @li Obtains the handler's associated allocator object @c alloc by performing + * get_associated_allocator(handler). + * + * @li Performs ex.dispatch(std::move(handler), alloc). + * + * @li Returns result.get(). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( + BOOST_ASIO_MOVE_ARG(CompletionToken) token); + +/// Submits a completion token or function object for execution. +/** + * This function submits an object for execution using the specified executor. + * The function object may be called from the current thread prior to returning + * from dispatch(). Otherwise, it is queued for execution. + * + * This function has the following effects: + * + * @li Constructs a function object handler of type @c Handler, initialized + * with handler(forward(token)). + * + * @li Constructs an object @c result of type async_result, + * initializing the object as result(handler). + * + * @li Obtains the handler's associated executor object @c ex1 by performing + * get_associated_executor(handler). + * + * @li Creates a work object @c w by performing make_work(ex1). + * + * @li Obtains the handler's associated allocator object @c alloc by performing + * get_associated_allocator(handler). + * + * @li Constructs a function object @c f with a function call operator that + * performs ex1.dispatch(std::move(handler), alloc) followed by + * w.reset(). + * + * @li Performs Executor(ex).dispatch(std::move(f), alloc). + * + * @li Returns result.get(). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( + const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if::value>::type* = 0); + +/// Submits a completion token or function object for execution. +/** + * @returns dispatch(ctx.get_executor(), + * forward(token)). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( + ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if::value>::type* = 0); + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // BOOST_ASIO_DISPATCH_HPP diff --git a/boost/asio/error.hpp b/boost/asio/error.hpp new file mode 100644 index 0000000..448d9ae --- /dev/null +++ b/boost/asio/error.hpp @@ -0,0 +1,361 @@ +// +// error.hpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_ERROR_HPP +#define BOOST_ASIO_ERROR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#if defined(BOOST_ASIO_WINDOWS) \ + || defined(__CYGWIN__) \ + || defined(BOOST_ASIO_WINDOWS_RUNTIME) +# include +#else +# include +# include +#endif + +#if defined(GENERATING_DOCUMENTATION) +/// INTERNAL ONLY. +# define BOOST_ASIO_NATIVE_ERROR(e) implementation_defined +/// INTERNAL ONLY. +# define BOOST_ASIO_SOCKET_ERROR(e) implementation_defined +/// INTERNAL ONLY. +# define BOOST_ASIO_NETDB_ERROR(e) implementation_defined +/// INTERNAL ONLY. +# define BOOST_ASIO_GETADDRINFO_ERROR(e) implementation_defined +/// INTERNAL ONLY. +# define BOOST_ASIO_WIN_OR_POSIX(e_win, e_posix) implementation_defined +#elif defined(BOOST_ASIO_WINDOWS_RUNTIME) +# define BOOST_ASIO_NATIVE_ERROR(e) __HRESULT_FROM_WIN32(e) +# define BOOST_ASIO_SOCKET_ERROR(e) __HRESULT_FROM_WIN32(WSA ## e) +# define BOOST_ASIO_NETDB_ERROR(e) __HRESULT_FROM_WIN32(WSA ## e) +# define BOOST_ASIO_GETADDRINFO_ERROR(e) __HRESULT_FROM_WIN32(WSA ## e) +# define BOOST_ASIO_WIN_OR_POSIX(e_win, e_posix) e_win +#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# define BOOST_ASIO_NATIVE_ERROR(e) e +# define BOOST_ASIO_SOCKET_ERROR(e) WSA ## e +# define BOOST_ASIO_NETDB_ERROR(e) WSA ## e +# define BOOST_ASIO_GETADDRINFO_ERROR(e) WSA ## e +# define BOOST_ASIO_WIN_OR_POSIX(e_win, e_posix) e_win +#else +# define BOOST_ASIO_NATIVE_ERROR(e) e +# define BOOST_ASIO_SOCKET_ERROR(e) e +# define BOOST_ASIO_NETDB_ERROR(e) e +# define BOOST_ASIO_GETADDRINFO_ERROR(e) e +# define BOOST_ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix +#endif + +#include + +namespace boost { +namespace asio { +namespace error { + +enum basic_errors +{ + /// Permission denied. + access_denied = BOOST_ASIO_SOCKET_ERROR(EACCES), + + /// Address family not supported by protocol. + address_family_not_supported = BOOST_ASIO_SOCKET_ERROR(EAFNOSUPPORT), + + /// Address already in use. + address_in_use = BOOST_ASIO_SOCKET_ERROR(EADDRINUSE), + + /// Transport endpoint is already connected. + already_connected = BOOST_ASIO_SOCKET_ERROR(EISCONN), + + /// Operation already in progress. + already_started = BOOST_ASIO_SOCKET_ERROR(EALREADY), + + /// Broken pipe. + broken_pipe = BOOST_ASIO_WIN_OR_POSIX( + BOOST_ASIO_NATIVE_ERROR(ERROR_BROKEN_PIPE), + BOOST_ASIO_NATIVE_ERROR(EPIPE)), + + /// A connection has been aborted. + connection_aborted = BOOST_ASIO_SOCKET_ERROR(ECONNABORTED), + + /// Connection refused. + connection_refused = BOOST_ASIO_SOCKET_ERROR(ECONNREFUSED), + + /// Connection reset by peer. + connection_reset = BOOST_ASIO_SOCKET_ERROR(ECONNRESET), + + /// Bad file descriptor. + bad_descriptor = BOOST_ASIO_SOCKET_ERROR(EBADF), + + /// Bad address. + fault = BOOST_ASIO_SOCKET_ERROR(EFAULT), + + /// No route to host. + host_unreachable = BOOST_ASIO_SOCKET_ERROR(EHOSTUNREACH), + + /// Operation now in progress. + in_progress = BOOST_ASIO_SOCKET_ERROR(EINPROGRESS), + + /// Interrupted system call. + interrupted = BOOST_ASIO_SOCKET_ERROR(EINTR), + + /// Invalid argument. + invalid_argument = BOOST_ASIO_SOCKET_ERROR(EINVAL), + + /// Message too long. + message_size = BOOST_ASIO_SOCKET_ERROR(EMSGSIZE), + + /// The name was too long. + name_too_long = BOOST_ASIO_SOCKET_ERROR(ENAMETOOLONG), + + /// Network is down. + network_down = BOOST_ASIO_SOCKET_ERROR(ENETDOWN), + + /// Network dropped connection on reset. + network_reset = BOOST_ASIO_SOCKET_ERROR(ENETRESET), + + /// Network is unreachable. + network_unreachable = BOOST_ASIO_SOCKET_ERROR(ENETUNREACH), + + /// Too many open files. + no_descriptors = BOOST_ASIO_SOCKET_ERROR(EMFILE), + + /// No buffer space available. + no_buffer_space = BOOST_ASIO_SOCKET_ERROR(ENOBUFS), + + /// Cannot allocate memory. + no_memory = BOOST_ASIO_WIN_OR_POSIX( + BOOST_ASIO_NATIVE_ERROR(ERROR_OUTOFMEMORY), + BOOST_ASIO_NATIVE_ERROR(ENOMEM)), + + /// Operation not permitted. + no_permission = BOOST_ASIO_WIN_OR_POSIX( + BOOST_ASIO_NATIVE_ERROR(ERROR_ACCESS_DENIED), + BOOST_ASIO_NATIVE_ERROR(EPERM)), + + /// Protocol not available. + no_protocol_option = BOOST_ASIO_SOCKET_ERROR(ENOPROTOOPT), + + /// No such device. + no_such_device = BOOST_ASIO_WIN_OR_POSIX( + BOOST_ASIO_NATIVE_ERROR(ERROR_BAD_UNIT), + BOOST_ASIO_NATIVE_ERROR(ENODEV)), + + /// Transport endpoint is not connected. + not_connected = BOOST_ASIO_SOCKET_ERROR(ENOTCONN), + + /// Socket operation on non-socket. + not_socket = BOOST_ASIO_SOCKET_ERROR(ENOTSOCK), + + /// Operation cancelled. + operation_aborted = BOOST_ASIO_WIN_OR_POSIX( + BOOST_ASIO_NATIVE_ERROR(ERROR_OPERATION_ABORTED), + BOOST_ASIO_NATIVE_ERROR(ECANCELED)), + + /// Operation not supported. + operation_not_supported = BOOST_ASIO_SOCKET_ERROR(EOPNOTSUPP), + + /// Cannot send after transport endpoint shutdown. + shut_down = BOOST_ASIO_SOCKET_ERROR(ESHUTDOWN), + + /// Connection timed out. + timed_out = BOOST_ASIO_SOCKET_ERROR(ETIMEDOUT), + + /// Resource temporarily unavailable. + try_again = BOOST_ASIO_WIN_OR_POSIX( + BOOST_ASIO_NATIVE_ERROR(ERROR_RETRY), + BOOST_ASIO_NATIVE_ERROR(EAGAIN)), + + /// The socket is marked non-blocking and the requested operation would block. + would_block = BOOST_ASIO_SOCKET_ERROR(EWOULDBLOCK) +}; + +enum netdb_errors +{ + /// Host not found (authoritative). + host_not_found = BOOST_ASIO_NETDB_ERROR(HOST_NOT_FOUND), + + /// Host not found (non-authoritative). + host_not_found_try_again = BOOST_ASIO_NETDB_ERROR(TRY_AGAIN), + + /// The query is valid but does not have associated address data. + no_data = BOOST_ASIO_NETDB_ERROR(NO_DATA), + + /// A non-recoverable error occurred. + no_recovery = BOOST_ASIO_NETDB_ERROR(NO_RECOVERY) +}; + +enum addrinfo_errors +{ + /// The service is not supported for the given socket type. + service_not_found = BOOST_ASIO_WIN_OR_POSIX( + BOOST_ASIO_NATIVE_ERROR(WSATYPE_NOT_FOUND), + BOOST_ASIO_GETADDRINFO_ERROR(EAI_SERVICE)), + + /// The socket type is not supported. + socket_type_not_supported = BOOST_ASIO_WIN_OR_POSIX( + BOOST_ASIO_NATIVE_ERROR(WSAESOCKTNOSUPPORT), + BOOST_ASIO_GETADDRINFO_ERROR(EAI_SOCKTYPE)) +}; + +enum misc_errors +{ + /// Already open. + already_open = 1, + + /// End of file or stream. + eof, + + /// Element not found. + not_found, + + /// The descriptor cannot fit into the select system call's fd_set. + fd_set_failure +}; + +inline const boost::system::error_category& get_system_category() +{ + return boost::system::system_category(); +} + +#if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + +extern BOOST_ASIO_DECL +const boost::system::error_category& get_netdb_category(); + +extern BOOST_ASIO_DECL +const boost::system::error_category& get_addrinfo_category(); + +#else // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + +inline const boost::system::error_category& get_netdb_category() +{ + return get_system_category(); +} + +inline const boost::system::error_category& get_addrinfo_category() +{ + return get_system_category(); +} + +#endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + +extern BOOST_ASIO_DECL +const boost::system::error_category& get_misc_category(); + +static const boost::system::error_category& + system_category BOOST_ASIO_UNUSED_VARIABLE + = boost::asio::error::get_system_category(); +static const boost::system::error_category& + netdb_category BOOST_ASIO_UNUSED_VARIABLE + = boost::asio::error::get_netdb_category(); +static const boost::system::error_category& + addrinfo_category BOOST_ASIO_UNUSED_VARIABLE + = boost::asio::error::get_addrinfo_category(); +static const boost::system::error_category& + misc_category BOOST_ASIO_UNUSED_VARIABLE + = boost::asio::error::get_misc_category(); + +} // namespace error +} // namespace asio +} // namespace boost + +namespace boost { +namespace system { + +template<> struct is_error_code_enum +{ + static const bool value = true; +}; + +template<> struct is_error_code_enum +{ + static const bool value = true; +}; + +template<> struct is_error_code_enum +{ + static const bool value = true; +}; + +template<> struct is_error_code_enum +{ + static const bool value = true; +}; + +} // namespace system +} // namespace boost + +namespace boost { +namespace asio { +namespace error { + +inline boost::system::error_code make_error_code(basic_errors e) +{ + return boost::system::error_code( + static_cast(e), get_system_category()); +} + +inline boost::system::error_code make_error_code(netdb_errors e) +{ + return boost::system::error_code( + static_cast(e), get_netdb_category()); +} + +inline boost::system::error_code make_error_code(addrinfo_errors e) +{ + return boost::system::error_code( + static_cast(e), get_addrinfo_category()); +} + +inline boost::system::error_code make_error_code(misc_errors e) +{ + return boost::system::error_code( + static_cast(e), get_misc_category()); +} + +} // namespace error +namespace stream_errc { + // Simulates the proposed stream_errc scoped enum. + using error::eof; + using error::not_found; +} // namespace stream_errc +namespace socket_errc { + // Simulates the proposed socket_errc scoped enum. + using error::already_open; + using error::not_found; +} // namespace socket_errc +namespace resolver_errc { + // Simulates the proposed resolver_errc scoped enum. + using error::host_not_found; + const error::netdb_errors try_again = error::host_not_found_try_again; + using error::service_not_found; +} // namespace resolver_errc +} // namespace asio +} // namespace boost + +#include + +#undef BOOST_ASIO_NATIVE_ERROR +#undef BOOST_ASIO_SOCKET_ERROR +#undef BOOST_ASIO_NETDB_ERROR +#undef BOOST_ASIO_GETADDRINFO_ERROR +#undef BOOST_ASIO_WIN_OR_POSIX + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_ERROR_HPP diff --git a/boost/asio/execution_context.hpp b/boost/asio/execution_context.hpp new file mode 100644 index 0000000..f89fb4c --- /dev/null +++ b/boost/asio/execution_context.hpp @@ -0,0 +1,414 @@ +// +// execution_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTION_CONTEXT_HPP +#define BOOST_ASIO_EXECUTION_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +class execution_context; +class io_context; + +#if !defined(GENERATING_DOCUMENTATION) +template Service& use_service(execution_context&); +template Service& use_service(io_context&); +template void add_service(execution_context&, Service*); +template bool has_service(execution_context&); +#endif // !defined(GENERATING_DOCUMENTATION) + +namespace detail { class service_registry; } + +/// A context for function object execution. +/** + * An execution context represents a place where function objects will be + * executed. An @c io_context is an example of an execution context. + * + * @par The execution_context class and services + * + * Class execution_context implements an extensible, type-safe, polymorphic set + * of services, indexed by service type. + * + * Services exist to manage the resources that are shared across an execution + * context. For example, timers may be implemented in terms of a single timer + * queue, and this queue would be stored in a service. + * + * Access to the services of an execution_context is via three function + * templates, use_service(), add_service() and has_service(). + * + * In a call to @c use_service(), the type argument chooses a service, + * making available all members of the named type. If @c Service is not present + * in an execution_context, an object of type @c Service is created and added + * to the execution_context. A C++ program can check if an execution_context + * implements a particular service with the function template @c + * has_service(). + * + * Service objects may be explicitly added to an execution_context using the + * function template @c add_service(). If the @c Service is already + * present, the service_already_exists exception is thrown. If the owner of the + * service is not the same object as the execution_context parameter, the + * invalid_service_owner exception is thrown. + * + * Once a service reference is obtained from an execution_context object by + * calling use_service(), that reference remains usable as long as the owning + * execution_context object exists. + * + * All service implementations have execution_context::service as a public base + * class. Custom services may be implemented by deriving from this class and + * then added to an execution_context using the facilities described above. + * + * @par The execution_context as a base class + * + * Class execution_context may be used only as a base class for concrete + * execution context types. The @c io_context is an example of such a derived + * type. + * + * On destruction, a class that is derived from execution_context must perform + * execution_context::shutdown() followed by + * execution_context::destroy(). + * + * This destruction sequence permits programs to simplify their resource + * management by using @c shared_ptr<>. Where an object's lifetime is tied to + * the lifetime of a connection (or some other sequence of asynchronous + * operations), a @c shared_ptr to the object would be bound into the handlers + * for all asynchronous operations associated with it. This works as follows: + * + * @li When a single connection ends, all associated asynchronous operations + * complete. The corresponding handler objects are destroyed, and all @c + * shared_ptr references to the objects are destroyed. + * + * @li To shut down the whole program, the io_context function stop() is called + * to terminate any run() calls as soon as possible. The io_context destructor + * calls @c shutdown() and @c destroy() to destroy all pending handlers, + * causing all @c shared_ptr references to all connection objects to be + * destroyed. + */ +class execution_context + : private noncopyable +{ +public: + class id; + class service; + +public: + /// Constructor. + BOOST_ASIO_DECL execution_context(); + + /// Destructor. + BOOST_ASIO_DECL ~execution_context(); + +protected: + /// Shuts down all services in the context. + /** + * This function is implemented as follows: + * + * @li For each service object @c svc in the execution_context set, in + * reverse order of the beginning of service object lifetime, performs @c + * svc->shutdown(). + */ + BOOST_ASIO_DECL void shutdown(); + + /// Destroys all services in the context. + /** + * This function is implemented as follows: + * + * @li For each service object @c svc in the execution_context set, in + * reverse order * of the beginning of service object lifetime, performs + * delete static_cast(svc). + */ + BOOST_ASIO_DECL void destroy(); + +public: + /// Fork-related event notifications. + enum fork_event + { + /// Notify the context that the process is about to fork. + fork_prepare, + + /// Notify the context that the process has forked and is the parent. + fork_parent, + + /// Notify the context that the process has forked and is the child. + fork_child + }; + + /// Notify the execution_context of a fork-related event. + /** + * This function is used to inform the execution_context that the process is + * about to fork, or has just forked. This allows the execution_context, and + * the services it contains, to perform any necessary housekeeping to ensure + * correct operation following a fork. + * + * This function must not be called while any other execution_context + * function, or any function associated with the execution_context's derived + * class, is being called in another thread. It is, however, safe to call + * this function from within a completion handler, provided no other thread + * is accessing the execution_context or its derived class. + * + * @param event A fork-related event. + * + * @throws boost::system::system_error Thrown on failure. If the notification + * fails the execution_context object should no longer be used and should be + * destroyed. + * + * @par Example + * The following code illustrates how to incorporate the notify_fork() + * function: + * @code my_execution_context.notify_fork(execution_context::fork_prepare); + * if (fork() == 0) + * { + * // This is the child process. + * my_execution_context.notify_fork(execution_context::fork_child); + * } + * else + * { + * // This is the parent process. + * my_execution_context.notify_fork(execution_context::fork_parent); + * } @endcode + * + * @note For each service object @c svc in the execution_context set, + * performs svc->notify_fork();. When processing the fork_prepare + * event, services are visited in reverse order of the beginning of service + * object lifetime. Otherwise, services are visited in order of the beginning + * of service object lifetime. + */ + BOOST_ASIO_DECL void notify_fork(fork_event event); + + /// Obtain the service object corresponding to the given type. + /** + * This function is used to locate a service object that corresponds to the + * given service type. If there is no existing implementation of the service, + * then the execution_context will create a new instance of the service. + * + * @param e The execution_context object that owns the service. + * + * @return The service interface implementing the specified service type. + * Ownership of the service interface is not transferred to the caller. + */ + template + friend Service& use_service(execution_context& e); + + /// Obtain the service object corresponding to the given type. + /** + * This function is used to locate a service object that corresponds to the + * given service type. If there is no existing implementation of the service, + * then the io_context will create a new instance of the service. + * + * @param ioc The io_context object that owns the service. + * + * @return The service interface implementing the specified service type. + * Ownership of the service interface is not transferred to the caller. + * + * @note This overload is preserved for backwards compatibility with services + * that inherit from io_context::service. + */ + template + friend Service& use_service(io_context& ioc); + +#if defined(GENERATING_DOCUMENTATION) + + /// Creates a service object and adds it to the execution_context. + /** + * This function is used to add a service to the execution_context. + * + * @param e The execution_context object that owns the service. + * + * @param args Zero or more arguments to be passed to the service + * constructor. + * + * @throws boost::asio::service_already_exists Thrown if a service of the + * given type is already present in the execution_context. + */ + template + friend Service& make_service(execution_context& e, Args&&... args); + +#elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + friend Service& make_service(execution_context& e, + BOOST_ASIO_MOVE_ARG(Args)... args); + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + friend Service& make_service(execution_context& e); + +#define BOOST_ASIO_PRIVATE_MAKE_SERVICE_DEF(n) \ + template \ + friend Service& make_service(execution_context& e, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)); \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_MAKE_SERVICE_DEF) +#undef BOOST_ASIO_PRIVATE_MAKE_SERVICE_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + /// (Deprecated: Use make_service().) Add a service object to the + /// execution_context. + /** + * This function is used to add a service to the execution_context. + * + * @param e The execution_context object that owns the service. + * + * @param svc The service object. On success, ownership of the service object + * is transferred to the execution_context. When the execution_context object + * is destroyed, it will destroy the service object by performing: @code + * delete static_cast(svc) @endcode + * + * @throws boost::asio::service_already_exists Thrown if a service of the + * given type is already present in the execution_context. + * + * @throws boost::asio::invalid_service_owner Thrown if the service's owning + * execution_context is not the execution_context object specified by the + * @c e parameter. + */ + template + friend void add_service(execution_context& e, Service* svc); + + /// Determine if an execution_context contains a specified service type. + /** + * This function is used to determine whether the execution_context contains a + * service object corresponding to the given service type. + * + * @param e The execution_context object that owns the service. + * + * @return A boolean indicating whether the execution_context contains the + * service. + */ + template + friend bool has_service(execution_context& e); + +private: + // The service registry. + boost::asio::detail::service_registry* service_registry_; +}; + +/// Class used to uniquely identify a service. +class execution_context::id + : private noncopyable +{ +public: + /// Constructor. + id() {} +}; + +/// Base class for all io_context services. +class execution_context::service + : private noncopyable +{ +public: + /// Get the context object that owns the service. + execution_context& context(); + +protected: + /// Constructor. + /** + * @param owner The execution_context object that owns the service. + */ + BOOST_ASIO_DECL service(execution_context& owner); + + /// Destructor. + BOOST_ASIO_DECL virtual ~service(); + +private: + /// Destroy all user-defined handler objects owned by the service. + virtual void shutdown() = 0; + + /// Handle notification of a fork-related event to perform any necessary + /// housekeeping. + /** + * This function is not a pure virtual so that services only have to + * implement it if necessary. The default implementation does nothing. + */ + BOOST_ASIO_DECL virtual void notify_fork( + execution_context::fork_event event); + + friend class boost::asio::detail::service_registry; + struct key + { + key() : type_info_(0), id_(0) {} + const std::type_info* type_info_; + const execution_context::id* id_; + } key_; + + execution_context& owner_; + service* next_; +}; + +/// Exception thrown when trying to add a duplicate service to an +/// execution_context. +class service_already_exists + : public std::logic_error +{ +public: + BOOST_ASIO_DECL service_already_exists(); +}; + +/// Exception thrown when trying to add a service object to an +/// execution_context where the service has a different owner. +class invalid_service_owner + : public std::logic_error +{ +public: + BOOST_ASIO_DECL invalid_service_owner(); +}; + +namespace detail { + +// Special derived service id type to keep classes header-file only. +template +class service_id + : public execution_context::id +{ +}; + +// Special service base class to keep classes header-file only. +template +class execution_context_service_base + : public execution_context::service +{ +public: + static service_id id; + + // Constructor. + execution_context_service_base(execution_context& e) + : execution_context::service(e) + { + } +}; + +template +service_id execution_context_service_base::id; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_EXECUTION_CONTEXT_HPP diff --git a/boost/asio/executor.hpp b/boost/asio/executor.hpp new file mode 100644 index 0000000..7c6a353 --- /dev/null +++ b/boost/asio/executor.hpp @@ -0,0 +1,343 @@ +// +// executor.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTOR_HPP +#define BOOST_ASIO_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +/// Exception thrown when trying to access an empty polymorphic executor. +class bad_executor + : public std::exception +{ +public: + /// Constructor. + BOOST_ASIO_DECL bad_executor() BOOST_ASIO_NOEXCEPT; + + /// Obtain message associated with exception. + BOOST_ASIO_DECL virtual const char* what() const + BOOST_ASIO_NOEXCEPT_OR_NOTHROW; +}; + +/// Polymorphic wrapper for executors. +class executor +{ +public: + /// Default constructor. + executor() BOOST_ASIO_NOEXCEPT + : impl_(0) + { + } + + /// Construct from nullptr. + executor(nullptr_t) BOOST_ASIO_NOEXCEPT + : impl_(0) + { + } + + /// Copy constructor. + executor(const executor& other) BOOST_ASIO_NOEXCEPT + : impl_(other.clone()) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move constructor. + executor(executor&& other) BOOST_ASIO_NOEXCEPT + : impl_(other.impl_) + { + other.impl_ = 0; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Construct a polymorphic wrapper for the specified executor. + template + executor(Executor e); + + /// Allocator-aware constructor to create a polymorphic wrapper for the + /// specified executor. + template + executor(allocator_arg_t, const Allocator& a, Executor e); + + /// Destructor. + ~executor() + { + destroy(); + } + + /// Assignment operator. + executor& operator=(const executor& other) BOOST_ASIO_NOEXCEPT + { + destroy(); + impl_ = other.clone(); + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + // Move assignment operator. + executor& operator=(executor&& other) BOOST_ASIO_NOEXCEPT + { + destroy(); + impl_ = other.impl_; + other.impl_ = 0; + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Assignment operator for nullptr_t. + executor& operator=(nullptr_t) BOOST_ASIO_NOEXCEPT + { + destroy(); + impl_ = 0; + return *this; + } + + /// Assignment operator to create a polymorphic wrapper for the specified + /// executor. + template + executor& operator=(BOOST_ASIO_MOVE_ARG(Executor) e) BOOST_ASIO_NOEXCEPT + { + executor tmp(BOOST_ASIO_MOVE_CAST(Executor)(e)); + destroy(); + impl_ = tmp.impl_; + tmp.impl_ = 0; + return *this; + } + + /// Obtain the underlying execution context. + execution_context& context() const BOOST_ASIO_NOEXCEPT + { + return get_impl()->context(); + } + + /// Inform the executor that it has some outstanding work to do. + void on_work_started() const BOOST_ASIO_NOEXCEPT + { + get_impl()->on_work_started(); + } + + /// Inform the executor that some work is no longer outstanding. + void on_work_finished() const BOOST_ASIO_NOEXCEPT + { + get_impl()->on_work_finished(); + } + + /// Request the executor to invoke the given function object. + /** + * This function is used to ask the executor to execute the given function + * object. The function object is executed according to the rules of the + * target executor object. + * + * @param f The function object to be called. The executor will make a copy + * of the handler object as required. The function signature of the function + * object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template + void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Request the executor to invoke the given function object. + /** + * This function is used to ask the executor to execute the given function + * object. The function object is executed according to the rules of the + * target executor object. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template + void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Request the executor to invoke the given function object. + /** + * This function is used to ask the executor to execute the given function + * object. The function object is executed according to the rules of the + * target executor object. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template + void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + struct unspecified_bool_type_t {}; + typedef void (*unspecified_bool_type)(unspecified_bool_type_t); + static void unspecified_bool_true(unspecified_bool_type_t) {} + + /// Operator to test if the executor contains a valid target. + operator unspecified_bool_type() const BOOST_ASIO_NOEXCEPT + { + return impl_ ? &executor::unspecified_bool_true : 0; + } + + /// Obtain type information for the target executor object. + /** + * @returns If @c *this has a target type of type @c T, typeid(T); + * otherwise, typeid(void). + */ +#if !defined(BOOST_ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION) + const std::type_info& target_type() const BOOST_ASIO_NOEXCEPT + { + return impl_ ? impl_->target_type() : typeid(void); + } +#else // !defined(BOOST_ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION) + const void* target_type() const BOOST_ASIO_NOEXCEPT + { + return impl_ ? impl_->target_type() : 0; + } +#endif // !defined(BOOST_ASIO_NO_TYPEID) || defined(GENERATING_DOCUMENTATION) + + /// Obtain a pointer to the target executor object. + /** + * @returns If target_type() == typeid(T), a pointer to the stored + * executor target; otherwise, a null pointer. + */ + template + Executor* target() BOOST_ASIO_NOEXCEPT; + + /// Obtain a pointer to the target executor object. + /** + * @returns If target_type() == typeid(T), a pointer to the stored + * executor target; otherwise, a null pointer. + */ + template + const Executor* target() const BOOST_ASIO_NOEXCEPT; + + /// Compare two executors for equality. + friend bool operator==(const executor& a, + const executor& b) BOOST_ASIO_NOEXCEPT + { + if (a.impl_ == b.impl_) + return true; + if (!a.impl_ || !b.impl_) + return false; + return a.impl_->equals(b.impl_); + } + + /// Compare two executors for inequality. + friend bool operator!=(const executor& a, + const executor& b) BOOST_ASIO_NOEXCEPT + { + return !(a == b); + } + +private: +#if !defined(GENERATING_DOCUMENTATION) + class function; + template class impl; + +#if !defined(BOOST_ASIO_NO_TYPEID) + typedef const std::type_info& type_id_result_type; +#else // !defined(BOOST_ASIO_NO_TYPEID) + typedef const void* type_id_result_type; +#endif // !defined(BOOST_ASIO_NO_TYPEID) + + template + static type_id_result_type type_id() + { +#if !defined(BOOST_ASIO_NO_TYPEID) + return typeid(T); +#else // !defined(BOOST_ASIO_NO_TYPEID) + static int unique_id; + return &unique_id; +#endif // !defined(BOOST_ASIO_NO_TYPEID) + } + + // Base class for all polymorphic executor implementations. + class impl_base + { + public: + virtual impl_base* clone() const BOOST_ASIO_NOEXCEPT = 0; + virtual void destroy() BOOST_ASIO_NOEXCEPT = 0; + virtual execution_context& context() BOOST_ASIO_NOEXCEPT = 0; + virtual void on_work_started() BOOST_ASIO_NOEXCEPT = 0; + virtual void on_work_finished() BOOST_ASIO_NOEXCEPT = 0; + virtual void dispatch(BOOST_ASIO_MOVE_ARG(function)) = 0; + virtual void post(BOOST_ASIO_MOVE_ARG(function)) = 0; + virtual void defer(BOOST_ASIO_MOVE_ARG(function)) = 0; + virtual type_id_result_type target_type() const BOOST_ASIO_NOEXCEPT = 0; + virtual void* target() BOOST_ASIO_NOEXCEPT = 0; + virtual const void* target() const BOOST_ASIO_NOEXCEPT = 0; + virtual bool equals(const impl_base* e) const BOOST_ASIO_NOEXCEPT = 0; + + protected: + impl_base(bool fast_dispatch) : fast_dispatch_(fast_dispatch) {} + virtual ~impl_base() {} + + private: + friend class executor; + const bool fast_dispatch_; + }; + + // Helper function to check and return the implementation pointer. + impl_base* get_impl() const + { + if (!impl_) + { + bad_executor ex; + boost::asio::detail::throw_exception(ex); + } + return impl_; + } + + // Helper function to clone another implementation. + impl_base* clone() const BOOST_ASIO_NOEXCEPT + { + return impl_ ? impl_->clone() : 0; + } + + // Helper function to destroy an implementation. + void destroy() BOOST_ASIO_NOEXCEPT + { + if (impl_) + impl_->destroy(); + } + + impl_base* impl_; +#endif // !defined(GENERATING_DOCUMENTATION) +}; + +} // namespace asio +} // namespace boost + +BOOST_ASIO_USES_ALLOCATOR(boost::asio::executor) + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_EXECUTOR_HPP diff --git a/boost/asio/executor_work_guard.hpp b/boost/asio/executor_work_guard.hpp new file mode 100644 index 0000000..546f7ef --- /dev/null +++ b/boost/asio/executor_work_guard.hpp @@ -0,0 +1,172 @@ +// +// executor_work_guard.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_EXECUTOR_WORK_GUARD_HPP +#define BOOST_ASIO_EXECUTOR_WORK_GUARD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +/// An object of type @c executor_work_guard controls ownership of executor work +/// within a scope. +template +class executor_work_guard +{ +public: + /// The underlying executor type. + typedef Executor executor_type; + + /// Constructs a @c executor_work_guard object for the specified executor. + /** + * Stores a copy of @c e and calls on_work_started() on it. + */ + explicit executor_work_guard(const executor_type& e) BOOST_ASIO_NOEXCEPT + : executor_(e), + owns_(true) + { + executor_.on_work_started(); + } + + /// Copy constructor. + executor_work_guard(const executor_work_guard& other) BOOST_ASIO_NOEXCEPT + : executor_(other.executor_), + owns_(other.owns_) + { + if (owns_) + executor_.on_work_started(); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move constructor. + executor_work_guard(executor_work_guard&& other) BOOST_ASIO_NOEXCEPT + : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)), + owns_(other.owns_) + { + other.owns_ = false; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destructor. + /** + * Unless the object has already been reset, or is in a moved-from state, + * calls on_work_finished() on the stored executor. + */ + ~executor_work_guard() + { + if (owns_) + executor_.on_work_finished(); + } + + /// Obtain the associated executor. + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return executor_; + } + + /// Whether the executor_work_guard object owns some outstanding work. + bool owns_work() const BOOST_ASIO_NOEXCEPT + { + return owns_; + } + + /// Indicate that the work is no longer outstanding. + /* + * Unless the object has already been reset, or is in a moved-from state, + * calls on_work_finished() on the stored executor. + */ + void reset() BOOST_ASIO_NOEXCEPT + { + if (owns_) + { + executor_.on_work_finished(); + owns_ = false; + } + } + +private: + // Disallow assignment. + executor_work_guard& operator=(const executor_work_guard&); + + executor_type executor_; + bool owns_; +}; + +/// Create an @ref executor_work_guard object. +template +inline executor_work_guard make_work_guard(const Executor& ex, + typename enable_if::value>::type* = 0) +{ + return executor_work_guard(ex); +} + +/// Create an @ref executor_work_guard object. +template +inline executor_work_guard +make_work_guard(ExecutionContext& ctx, + typename enable_if< + is_convertible::value>::type* = 0) +{ + return executor_work_guard( + ctx.get_executor()); +} + +/// Create an @ref executor_work_guard object. +template +inline executor_work_guard::type> +make_work_guard(const T& t, + typename enable_if::value && + !is_convertible::value>::type* = 0) +{ + return executor_work_guard::type>( + associated_executor::get(t)); +} + +/// Create an @ref executor_work_guard object. +template +inline executor_work_guard::type> +make_work_guard(const T& t, const Executor& ex, + typename enable_if::value>::type* = 0) +{ + return executor_work_guard::type>( + associated_executor::get(t, ex)); +} + +/// Create an @ref executor_work_guard object. +template +inline executor_work_guard::type> +make_work_guard(const T& t, ExecutionContext& ctx, + typename enable_if::value && + !is_convertible::value && + is_convertible::value>::type* = 0) +{ + return executor_work_guard::type>( + associated_executor::get( + t, ctx.get_executor())); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_EXECUTOR_WORK_GUARD_HPP diff --git a/boost/asio/generic/basic_endpoint.hpp b/boost/asio/generic/basic_endpoint.hpp new file mode 100644 index 0000000..048a960 --- /dev/null +++ b/boost/asio/generic/basic_endpoint.hpp @@ -0,0 +1,195 @@ +// +// generic/basic_endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_GENERIC_BASIC_ENDPOINT_HPP +#define BOOST_ASIO_GENERIC_BASIC_ENDPOINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace generic { + +/// Describes an endpoint for any socket type. +/** + * The boost::asio::generic::basic_endpoint class template describes an endpoint + * that may be associated with any socket type. + * + * @note The socket types sockaddr type must be able to fit into a + * @c sockaddr_storage structure. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Concepts: + * Endpoint. + */ +template +class basic_endpoint +{ +public: + /// The protocol type associated with the endpoint. + typedef Protocol protocol_type; + + /// The type of the endpoint structure. This type is dependent on the + /// underlying implementation of the socket layer. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined data_type; +#else + typedef boost::asio::detail::socket_addr_type data_type; +#endif + + /// Default constructor. + basic_endpoint() + { + } + + /// Construct an endpoint from the specified socket address. + basic_endpoint(const void* socket_address, + std::size_t socket_address_size, int socket_protocol = 0) + : impl_(socket_address, socket_address_size, socket_protocol) + { + } + + /// Construct an endpoint from the specific endpoint type. + template + basic_endpoint(const Endpoint& endpoint) + : impl_(endpoint.data(), endpoint.size(), endpoint.protocol().protocol()) + { + } + + /// Copy constructor. + basic_endpoint(const basic_endpoint& other) + : impl_(other.impl_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move constructor. + basic_endpoint(basic_endpoint&& other) + : impl_(other.impl_) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Assign from another endpoint. + basic_endpoint& operator=(const basic_endpoint& other) + { + impl_ = other.impl_; + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move-assign from another endpoint. + basic_endpoint& operator=(basic_endpoint&& other) + { + impl_ = other.impl_; + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// The protocol associated with the endpoint. + protocol_type protocol() const + { + return protocol_type(impl_.family(), impl_.protocol()); + } + + /// Get the underlying endpoint in the native type. + data_type* data() + { + return impl_.data(); + } + + /// Get the underlying endpoint in the native type. + const data_type* data() const + { + return impl_.data(); + } + + /// Get the underlying size of the endpoint in the native type. + std::size_t size() const + { + return impl_.size(); + } + + /// Set the underlying size of the endpoint in the native type. + void resize(std::size_t new_size) + { + impl_.resize(new_size); + } + + /// Get the capacity of the endpoint in the native type. + std::size_t capacity() const + { + return impl_.capacity(); + } + + /// Compare two endpoints for equality. + friend bool operator==(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return e1.impl_ == e2.impl_; + } + + /// Compare two endpoints for inequality. + friend bool operator!=(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return !(e1.impl_ == e2.impl_); + } + + /// Compare endpoints for ordering. + friend bool operator<(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return e1.impl_ < e2.impl_; + } + + /// Compare endpoints for ordering. + friend bool operator>(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return e2.impl_ < e1.impl_; + } + + /// Compare endpoints for ordering. + friend bool operator<=(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return !(e2 < e1); + } + + /// Compare endpoints for ordering. + friend bool operator>=(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return !(e1 < e2); + } + +private: + // The underlying generic endpoint. + boost::asio::generic::detail::endpoint impl_; +}; + +} // namespace generic +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_GENERIC_BASIC_ENDPOINT_HPP diff --git a/boost/asio/generic/datagram_protocol.hpp b/boost/asio/generic/datagram_protocol.hpp new file mode 100644 index 0000000..51e95b5 --- /dev/null +++ b/boost/asio/generic/datagram_protocol.hpp @@ -0,0 +1,125 @@ +// +// generic/datagram_protocol.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_GENERIC_DATAGRAM_PROTOCOL_HPP +#define BOOST_ASIO_GENERIC_DATAGRAM_PROTOCOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace generic { + +/// Encapsulates the flags needed for a generic datagram-oriented socket. +/** + * The boost::asio::generic::datagram_protocol class contains flags necessary + * for datagram-oriented sockets of any address family and protocol. + * + * @par Examples + * Constructing using a native address family and socket protocol: + * @code datagram_protocol p(AF_INET, IPPROTO_UDP); @endcode + * Constructing from a specific protocol type: + * @code datagram_protocol p(boost::asio::ip::udp::v4()); @endcode + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Safe. + * + * @par Concepts: + * Protocol. + */ +class datagram_protocol +{ +public: + /// Construct a protocol object for a specific address family and protocol. + datagram_protocol(int address_family, int socket_protocol) + : family_(address_family), + protocol_(socket_protocol) + { + } + + /// Construct a generic protocol object from a specific protocol. + /** + * @throws @c bad_cast Thrown if the source protocol is not datagram-oriented. + */ + template + datagram_protocol(const Protocol& source_protocol) + : family_(source_protocol.family()), + protocol_(source_protocol.protocol()) + { + if (source_protocol.type() != type()) + { + std::bad_cast ex; + boost::asio::detail::throw_exception(ex); + } + } + + /// Obtain an identifier for the type of the protocol. + int type() const + { + return BOOST_ASIO_OS_DEF(SOCK_DGRAM); + } + + /// Obtain an identifier for the protocol. + int protocol() const + { + return protocol_; + } + + /// Obtain an identifier for the protocol family. + int family() const + { + return family_; + } + + /// Compare two protocols for equality. + friend bool operator==(const datagram_protocol& p1, + const datagram_protocol& p2) + { + return p1.family_ == p2.family_ && p1.protocol_ == p2.protocol_; + } + + /// Compare two protocols for inequality. + friend bool operator!=(const datagram_protocol& p1, + const datagram_protocol& p2) + { + return !(p1 == p2); + } + + /// The type of an endpoint. + typedef basic_endpoint endpoint; + + /// The generic socket type. + typedef basic_datagram_socket socket; + +private: + int family_; + int protocol_; +}; + +} // namespace generic +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_GENERIC_DATAGRAM_PROTOCOL_HPP diff --git a/boost/asio/generic/detail/endpoint.hpp b/boost/asio/generic/detail/endpoint.hpp new file mode 100644 index 0000000..84d320e --- /dev/null +++ b/boost/asio/generic/detail/endpoint.hpp @@ -0,0 +1,135 @@ +// +// generic/detail/endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_GENERIC_DETAIL_ENDPOINT_HPP +#define BOOST_ASIO_GENERIC_DETAIL_ENDPOINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace generic { +namespace detail { + +// Helper class for implementing a generic socket endpoint. +class endpoint +{ +public: + // Default constructor. + BOOST_ASIO_DECL endpoint(); + + // Construct an endpoint from the specified raw bytes. + BOOST_ASIO_DECL endpoint(const void* sock_addr, + std::size_t sock_addr_size, int sock_protocol); + + // Copy constructor. + endpoint(const endpoint& other) + : data_(other.data_), + size_(other.size_), + protocol_(other.protocol_) + { + } + + // Assign from another endpoint. + endpoint& operator=(const endpoint& other) + { + data_ = other.data_; + size_ = other.size_; + protocol_ = other.protocol_; + return *this; + } + + // Get the address family associated with the endpoint. + int family() const + { + return data_.base.sa_family; + } + + // Get the socket protocol associated with the endpoint. + int protocol() const + { + return protocol_; + } + + // Get the underlying endpoint in the native type. + boost::asio::detail::socket_addr_type* data() + { + return &data_.base; + } + + // Get the underlying endpoint in the native type. + const boost::asio::detail::socket_addr_type* data() const + { + return &data_.base; + } + + // Get the underlying size of the endpoint in the native type. + std::size_t size() const + { + return size_; + } + + // Set the underlying size of the endpoint in the native type. + BOOST_ASIO_DECL void resize(std::size_t size); + + // Get the capacity of the endpoint in the native type. + std::size_t capacity() const + { + return sizeof(boost::asio::detail::sockaddr_storage_type); + } + + // Compare two endpoints for equality. + BOOST_ASIO_DECL friend bool operator==( + const endpoint& e1, const endpoint& e2); + + // Compare endpoints for ordering. + BOOST_ASIO_DECL friend bool operator<( + const endpoint& e1, const endpoint& e2); + +private: + // The underlying socket address. + union data_union + { + boost::asio::detail::socket_addr_type base; + boost::asio::detail::sockaddr_storage_type generic; + } data_; + + // The length of the socket address stored in the endpoint. + std::size_t size_; + + // The socket protocol associated with the endpoint. + int protocol_; + + // Initialise with a specified memory. + BOOST_ASIO_DECL void init(const void* sock_addr, + std::size_t sock_addr_size, int sock_protocol); +}; + +} // namespace detail +} // namespace generic +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_GENERIC_DETAIL_ENDPOINT_HPP diff --git a/boost/asio/generic/detail/impl/endpoint.ipp b/boost/asio/generic/detail/impl/endpoint.ipp new file mode 100644 index 0000000..aee0377 --- /dev/null +++ b/boost/asio/generic/detail/impl/endpoint.ipp @@ -0,0 +1,112 @@ +// +// generic/detail/impl/endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_GENERIC_DETAIL_IMPL_ENDPOINT_IPP +#define BOOST_ASIO_GENERIC_DETAIL_IMPL_ENDPOINT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace generic { +namespace detail { + +endpoint::endpoint() +{ + init(0, 0, 0); +} + +endpoint::endpoint(const void* sock_addr, + std::size_t sock_addr_size, int sock_protocol) +{ + init(sock_addr, sock_addr_size, sock_protocol); +} + +void endpoint::resize(std::size_t new_size) +{ + if (new_size > sizeof(boost::asio::detail::sockaddr_storage_type)) + { + boost::system::error_code ec(boost::asio::error::invalid_argument); + boost::asio::detail::throw_error(ec); + } + else + { + size_ = new_size; + protocol_ = 0; + } +} + +bool operator==(const endpoint& e1, const endpoint& e2) +{ + using namespace std; // For memcmp. + return e1.size() == e2.size() && memcmp(e1.data(), e2.data(), e1.size()) == 0; +} + +bool operator<(const endpoint& e1, const endpoint& e2) +{ + if (e1.protocol() < e2.protocol()) + return true; + + if (e1.protocol() > e2.protocol()) + return false; + + using namespace std; // For memcmp. + std::size_t compare_size = e1.size() < e2.size() ? e1.size() : e2.size(); + int compare_result = memcmp(e1.data(), e2.data(), compare_size); + + if (compare_result < 0) + return true; + + if (compare_result > 0) + return false; + + return e1.size() < e2.size(); +} + +void endpoint::init(const void* sock_addr, + std::size_t sock_addr_size, int sock_protocol) +{ + if (sock_addr_size > sizeof(boost::asio::detail::sockaddr_storage_type)) + { + boost::system::error_code ec(boost::asio::error::invalid_argument); + boost::asio::detail::throw_error(ec); + } + + using namespace std; // For memset and memcpy. + memset(&data_.generic, 0, sizeof(boost::asio::detail::sockaddr_storage_type)); + if (sock_addr_size > 0) + memcpy(&data_.generic, sock_addr, sock_addr_size); + + size_ = sock_addr_size; + protocol_ = sock_protocol; +} + +} // namespace detail +} // namespace generic +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_GENERIC_DETAIL_IMPL_ENDPOINT_IPP diff --git a/boost/asio/generic/raw_protocol.hpp b/boost/asio/generic/raw_protocol.hpp new file mode 100644 index 0000000..ae28faf --- /dev/null +++ b/boost/asio/generic/raw_protocol.hpp @@ -0,0 +1,123 @@ +// +// generic/raw_protocol.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_GENERIC_RAW_PROTOCOL_HPP +#define BOOST_ASIO_GENERIC_RAW_PROTOCOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace generic { + +/// Encapsulates the flags needed for a generic raw socket. +/** + * The boost::asio::generic::raw_protocol class contains flags necessary for + * raw sockets of any address family and protocol. + * + * @par Examples + * Constructing using a native address family and socket protocol: + * @code raw_protocol p(AF_INET, IPPROTO_ICMP); @endcode + * Constructing from a specific protocol type: + * @code raw_protocol p(boost::asio::ip::icmp::v4()); @endcode + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Safe. + * + * @par Concepts: + * Protocol. + */ +class raw_protocol +{ +public: + /// Construct a protocol object for a specific address family and protocol. + raw_protocol(int address_family, int socket_protocol) + : family_(address_family), + protocol_(socket_protocol) + { + } + + /// Construct a generic protocol object from a specific protocol. + /** + * @throws @c bad_cast Thrown if the source protocol is not raw-oriented. + */ + template + raw_protocol(const Protocol& source_protocol) + : family_(source_protocol.family()), + protocol_(source_protocol.protocol()) + { + if (source_protocol.type() != type()) + { + std::bad_cast ex; + boost::asio::detail::throw_exception(ex); + } + } + + /// Obtain an identifier for the type of the protocol. + int type() const + { + return BOOST_ASIO_OS_DEF(SOCK_RAW); + } + + /// Obtain an identifier for the protocol. + int protocol() const + { + return protocol_; + } + + /// Obtain an identifier for the protocol family. + int family() const + { + return family_; + } + + /// Compare two protocols for equality. + friend bool operator==(const raw_protocol& p1, const raw_protocol& p2) + { + return p1.family_ == p2.family_ && p1.protocol_ == p2.protocol_; + } + + /// Compare two protocols for inequality. + friend bool operator!=(const raw_protocol& p1, const raw_protocol& p2) + { + return !(p1 == p2); + } + + /// The type of an endpoint. + typedef basic_endpoint endpoint; + + /// The generic socket type. + typedef basic_raw_socket socket; + +private: + int family_; + int protocol_; +}; + +} // namespace generic +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_GENERIC_RAW_PROTOCOL_HPP diff --git a/boost/asio/generic/seq_packet_protocol.hpp b/boost/asio/generic/seq_packet_protocol.hpp new file mode 100644 index 0000000..d9b719f --- /dev/null +++ b/boost/asio/generic/seq_packet_protocol.hpp @@ -0,0 +1,124 @@ +// +// generic/seq_packet_protocol.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_GENERIC_SEQ_PACKET_PROTOCOL_HPP +#define BOOST_ASIO_GENERIC_SEQ_PACKET_PROTOCOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace generic { + +/// Encapsulates the flags needed for a generic sequenced packet socket. +/** + * The boost::asio::generic::seq_packet_protocol class contains flags necessary + * for seq_packet-oriented sockets of any address family and protocol. + * + * @par Examples + * Constructing using a native address family and socket protocol: + * @code seq_packet_protocol p(AF_INET, IPPROTO_SCTP); @endcode + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Safe. + * + * @par Concepts: + * Protocol. + */ +class seq_packet_protocol +{ +public: + /// Construct a protocol object for a specific address family and protocol. + seq_packet_protocol(int address_family, int socket_protocol) + : family_(address_family), + protocol_(socket_protocol) + { + } + + /// Construct a generic protocol object from a specific protocol. + /** + * @throws @c bad_cast Thrown if the source protocol is not based around + * sequenced packets. + */ + template + seq_packet_protocol(const Protocol& source_protocol) + : family_(source_protocol.family()), + protocol_(source_protocol.protocol()) + { + if (source_protocol.type() != type()) + { + std::bad_cast ex; + boost::asio::detail::throw_exception(ex); + } + } + + /// Obtain an identifier for the type of the protocol. + int type() const + { + return BOOST_ASIO_OS_DEF(SOCK_SEQPACKET); + } + + /// Obtain an identifier for the protocol. + int protocol() const + { + return protocol_; + } + + /// Obtain an identifier for the protocol family. + int family() const + { + return family_; + } + + /// Compare two protocols for equality. + friend bool operator==(const seq_packet_protocol& p1, + const seq_packet_protocol& p2) + { + return p1.family_ == p2.family_ && p1.protocol_ == p2.protocol_; + } + + /// Compare two protocols for inequality. + friend bool operator!=(const seq_packet_protocol& p1, + const seq_packet_protocol& p2) + { + return !(p1 == p2); + } + + /// The type of an endpoint. + typedef basic_endpoint endpoint; + + /// The generic socket type. + typedef basic_seq_packet_socket socket; + +private: + int family_; + int protocol_; +}; + +} // namespace generic +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_GENERIC_SEQ_PACKET_PROTOCOL_HPP diff --git a/boost/asio/generic/stream_protocol.hpp b/boost/asio/generic/stream_protocol.hpp new file mode 100644 index 0000000..ca5fbb2 --- /dev/null +++ b/boost/asio/generic/stream_protocol.hpp @@ -0,0 +1,129 @@ +// +// generic/stream_protocol.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_GENERIC_STREAM_PROTOCOL_HPP +#define BOOST_ASIO_GENERIC_STREAM_PROTOCOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace generic { + +/// Encapsulates the flags needed for a generic stream-oriented socket. +/** + * The boost::asio::generic::stream_protocol class contains flags necessary for + * stream-oriented sockets of any address family and protocol. + * + * @par Examples + * Constructing using a native address family and socket protocol: + * @code stream_protocol p(AF_INET, IPPROTO_TCP); @endcode + * Constructing from a specific protocol type: + * @code stream_protocol p(boost::asio::ip::tcp::v4()); @endcode + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Safe. + * + * @par Concepts: + * Protocol. + */ +class stream_protocol +{ +public: + /// Construct a protocol object for a specific address family and protocol. + stream_protocol(int address_family, int socket_protocol) + : family_(address_family), + protocol_(socket_protocol) + { + } + + /// Construct a generic protocol object from a specific protocol. + /** + * @throws @c bad_cast Thrown if the source protocol is not stream-oriented. + */ + template + stream_protocol(const Protocol& source_protocol) + : family_(source_protocol.family()), + protocol_(source_protocol.protocol()) + { + if (source_protocol.type() != type()) + { + std::bad_cast ex; + boost::asio::detail::throw_exception(ex); + } + } + + /// Obtain an identifier for the type of the protocol. + int type() const + { + return BOOST_ASIO_OS_DEF(SOCK_STREAM); + } + + /// Obtain an identifier for the protocol. + int protocol() const + { + return protocol_; + } + + /// Obtain an identifier for the protocol family. + int family() const + { + return family_; + } + + /// Compare two protocols for equality. + friend bool operator==(const stream_protocol& p1, const stream_protocol& p2) + { + return p1.family_ == p2.family_ && p1.protocol_ == p2.protocol_; + } + + /// Compare two protocols for inequality. + friend bool operator!=(const stream_protocol& p1, const stream_protocol& p2) + { + return !(p1 == p2); + } + + /// The type of an endpoint. + typedef basic_endpoint endpoint; + + /// The generic socket type. + typedef basic_stream_socket socket; + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + /// The generic socket iostream type. + typedef basic_socket_iostream iostream; +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +private: + int family_; + int protocol_; +}; + +} // namespace generic +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_GENERIC_STREAM_PROTOCOL_HPP diff --git a/boost/asio/handler_alloc_hook.hpp b/boost/asio/handler_alloc_hook.hpp new file mode 100644 index 0000000..595e36b --- /dev/null +++ b/boost/asio/handler_alloc_hook.hpp @@ -0,0 +1,83 @@ +// +// handler_alloc_hook.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_HANDLER_ALLOC_HOOK_HPP +#define BOOST_ASIO_HANDLER_ALLOC_HOOK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { + +/// Default allocation function for handlers. +/** + * Asynchronous operations may need to allocate temporary objects. Since + * asynchronous operations have a handler function object, these temporary + * objects can be said to be associated with the handler. + * + * Implement asio_handler_allocate and asio_handler_deallocate for your own + * handlers to provide custom allocation for these temporary objects. + * + * The default implementation of these allocation hooks uses ::operator + * new and ::operator delete. + * + * @note All temporary objects associated with a handler will be deallocated + * before the upcall to the handler is performed. This allows the same memory to + * be reused for a subsequent asynchronous operation initiated by the handler. + * + * @par Example + * @code + * class my_handler; + * + * void* asio_handler_allocate(std::size_t size, my_handler* context) + * { + * return ::operator new(size); + * } + * + * void asio_handler_deallocate(void* pointer, std::size_t size, + * my_handler* context) + * { + * ::operator delete(pointer); + * } + * @endcode + */ +BOOST_ASIO_DECL void* asio_handler_allocate( + std::size_t size, ...); + +/// Default deallocation function for handlers. +/** + * Implement asio_handler_allocate and asio_handler_deallocate for your own + * handlers to provide custom allocation for the associated temporary objects. + * + * The default implementation of these allocation hooks uses ::operator + * new and ::operator delete. + * + * @sa asio_handler_allocate. + */ +BOOST_ASIO_DECL void asio_handler_deallocate( + void* pointer, std::size_t size, ...); + +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_HANDLER_ALLOC_HOOK_HPP diff --git a/boost/asio/handler_continuation_hook.hpp b/boost/asio/handler_continuation_hook.hpp new file mode 100644 index 0000000..05645cf --- /dev/null +++ b/boost/asio/handler_continuation_hook.hpp @@ -0,0 +1,56 @@ +// +// handler_continuation_hook.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_HANDLER_CONTINUATION_HOOK_HPP +#define BOOST_ASIO_HANDLER_CONTINUATION_HOOK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { + +/// Default continuation function for handlers. +/** + * Asynchronous operations may represent a continuation of the asynchronous + * control flow associated with the current handler. The implementation can use + * this knowledge to optimise scheduling of the handler. + * + * Implement asio_handler_is_continuation for your own handlers to indicate + * when a handler represents a continuation. + * + * The default implementation of the continuation hook returns false. + * + * @par Example + * @code + * class my_handler; + * + * bool asio_handler_is_continuation(my_handler* context) + * { + * return true; + * } + * @endcode + */ +inline bool asio_handler_is_continuation(...) +{ + return false; +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_HANDLER_CONTINUATION_HOOK_HPP diff --git a/boost/asio/handler_invoke_hook.hpp b/boost/asio/handler_invoke_hook.hpp new file mode 100644 index 0000000..7d3f0fd --- /dev/null +++ b/boost/asio/handler_invoke_hook.hpp @@ -0,0 +1,87 @@ +// +// handler_invoke_hook.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_HANDLER_INVOKE_HOOK_HPP +#define BOOST_ASIO_HANDLER_INVOKE_HOOK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { + +/** @defgroup asio_handler_invoke boost::asio::asio_handler_invoke + * + * @brief Default invoke function for handlers. + * + * Completion handlers for asynchronous operations are invoked by the + * io_context associated with the corresponding object (e.g. a socket or + * deadline_timer). Certain guarantees are made on when the handler may be + * invoked, in particular that a handler can only be invoked from a thread that + * is currently calling @c run() on the corresponding io_context object. + * Handlers may subsequently be invoked through other objects (such as + * io_context::strand objects) that provide additional guarantees. + * + * When asynchronous operations are composed from other asynchronous + * operations, all intermediate handlers should be invoked using the same + * method as the final handler. This is required to ensure that user-defined + * objects are not accessed in a way that may violate the guarantees. This + * hooking function ensures that the invoked method used for the final handler + * is accessible at each intermediate step. + * + * Implement asio_handler_invoke for your own handlers to specify a custom + * invocation strategy. + * + * This default implementation invokes the function object like so: + * @code function(); @endcode + * If necessary, the default implementation makes a copy of the function object + * so that the non-const operator() can be used. + * + * @par Example + * @code + * class my_handler; + * + * template + * void asio_handler_invoke(Function function, my_handler* context) + * { + * context->strand_.dispatch(function); + * } + * @endcode + */ +/*@{*/ + +/// Default handler invocation hook used for non-const function objects. +template +inline void asio_handler_invoke(Function& function, ...) +{ + function(); +} + +/// Default handler invocation hook used for const function objects. +template +inline void asio_handler_invoke(const Function& function, ...) +{ + Function tmp(function); + tmp(); +} + +/*@}*/ + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_HANDLER_INVOKE_HOOK_HPP diff --git a/boost/asio/high_resolution_timer.hpp b/boost/asio/high_resolution_timer.hpp new file mode 100644 index 0000000..6050405 --- /dev/null +++ b/boost/asio/high_resolution_timer.hpp @@ -0,0 +1,46 @@ +// +// high_resolution_timer.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_HIGH_RESOLUTION_TIMER_HPP +#define BOOST_ASIO_HIGH_RESOLUTION_TIMER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) + +#include +#include + +namespace boost { +namespace asio { + +/// Typedef for a timer based on the high resolution clock. +/** + * This typedef uses the C++11 @c <chrono> standard library facility, if + * available. Otherwise, it may use the Boost.Chrono library. To explicitly + * utilise Boost.Chrono, use the basic_waitable_timer template directly: + * @code + * typedef basic_waitable_timer timer; + * @endcode + */ +typedef basic_waitable_timer< + chrono::high_resolution_clock> + high_resolution_timer; + +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_HIGH_RESOLUTION_TIMER_HPP diff --git a/boost/asio/impl/awaitable.hpp b/boost/asio/impl/awaitable.hpp new file mode 100644 index 0000000..b8cf537 --- /dev/null +++ b/boost/asio/impl/awaitable.hpp @@ -0,0 +1,424 @@ +// +// impl/awaitable.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_AWAITABLE_HPP +#define BOOST_ASIO_IMPL_AWAITABLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// An awaitable_thread represents a thread-of-execution that is composed of one +// or more "stack frames", with each frame represented by an awaitable_frame. +// All execution occurs in the context of the awaitable_thread's executor. An +// awaitable_thread continues to "pump" the stack frames by repeatedly resuming +// the top stack frame until the stack is empty, or until ownership of the +// stack is transferred to another awaitable_thread object. +// +// +------------------------------------+ +// | top_of_stack_ | +// | V +// +--------------+---+ +-----------------+ +// | | | | +// | awaitable_thread |<---------------------------+ awaitable_frame | +// | | attached_thread_ | | +// +--------------+---+ (Set only when +---+-------------+ +// | frames are being | +// | actively pumped | caller_ +// | by a thread, and | +// | then only for V +// | the top frame.) +-----------------+ +// | | | +// | | awaitable_frame | +// | | | +// | +---+-------------+ +// | | +// | | caller_ +// | : +// | : +// | | +// | V +// | +-----------------+ +// | bottom_of_stack_ | | +// +------------------------------->| awaitable_frame | +// | | +// +-----------------+ + +template +class awaitable_frame_base +{ +public: +#if !defined(BOOST_ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING) + void* operator new(std::size_t size) + { + return boost::asio::detail::thread_info_base::allocate( + boost::asio::detail::thread_info_base::awaitable_frame_tag(), + boost::asio::detail::thread_context::thread_call_stack::top(), + size); + } + + void operator delete(void* pointer, std::size_t size) + { + boost::asio::detail::thread_info_base::deallocate( + boost::asio::detail::thread_info_base::awaitable_frame_tag(), + boost::asio::detail::thread_context::thread_call_stack::top(), + pointer, size); + } +#endif // !defined(BOOST_ASIO_DISABLE_AWAITABLE_FRAME_RECYCLING) + + // The frame starts in a suspended state until the awaitable_thread object + // pumps the stack. + auto initial_suspend() noexcept + { + return suspend_always(); + } + + // On final suspension the frame is popped from the top of the stack. + auto final_suspend() noexcept + { + struct result + { + awaitable_frame_base* this_; + + bool await_ready() const noexcept + { + return false; + } + + void await_suspend(coroutine_handle) noexcept + { + this_->pop_frame(); + } + + void await_resume() const noexcept + { + } + }; + + return result{this}; + } + + void set_except(std::exception_ptr e) noexcept + { + pending_exception_ = e; + } + + void set_error(const boost::system::error_code& ec) + { + this->set_except(std::make_exception_ptr(boost::system::system_error(ec))); + } + + void unhandled_exception() + { + set_except(std::current_exception()); + } + + void rethrow_exception() + { + if (pending_exception_) + { + std::exception_ptr ex = std::exchange(pending_exception_, nullptr); + std::rethrow_exception(ex); + } + } + + template + auto await_transform(awaitable a) const + { + return a; + } + + // This await transformation obtains the associated executor of the thread of + // execution. + auto await_transform(this_coro::executor_t) noexcept + { + struct result + { + awaitable_frame_base* this_; + + bool await_ready() const noexcept + { + return true; + } + + void await_suspend(coroutine_handle) noexcept + { + } + + auto await_resume() const noexcept + { + return this_->attached_thread_->get_executor(); + } + }; + + return result{this}; + } + + // This await transformation is used to run an async operation's initiation + // function object after the coroutine has been suspended. This ensures that + // immediate resumption of the coroutine in another thread does not cause a + // race condition. + template + auto await_transform(Function f, + typename enable_if< + is_convertible< + typename result_of::type, + awaitable_thread* + >::value + >::type* = 0) + { + struct result + { + Function function_; + awaitable_frame_base* this_; + + bool await_ready() const noexcept + { + return false; + } + + void await_suspend(coroutine_handle) noexcept + { + function_(this_); + } + + void await_resume() const noexcept + { + } + }; + + return result{std::move(f), this}; + } + + void attach_thread(awaitable_thread* handler) noexcept + { + attached_thread_ = handler; + } + + awaitable_thread* detach_thread() noexcept + { + return std::exchange(attached_thread_, nullptr); + } + + void push_frame(awaitable_frame_base* caller) noexcept + { + caller_ = caller; + attached_thread_ = caller_->attached_thread_; + attached_thread_->top_of_stack_ = this; + caller_->attached_thread_ = nullptr; + } + + void pop_frame() noexcept + { + if (caller_) + caller_->attached_thread_ = attached_thread_; + attached_thread_->top_of_stack_ = caller_; + attached_thread_ = nullptr; + caller_ = nullptr; + } + + void resume() + { + coro_.resume(); + } + + void destroy() + { + coro_.destroy(); + } + +protected: + coroutine_handle coro_ = nullptr; + awaitable_thread* attached_thread_ = nullptr; + awaitable_frame_base* caller_ = nullptr; + std::exception_ptr pending_exception_ = nullptr; +}; + +template +class awaitable_frame + : public awaitable_frame_base +{ +public: + awaitable_frame() noexcept + { + } + + awaitable_frame(awaitable_frame&& other) noexcept + : awaitable_frame_base(std::move(other)) + { + } + + ~awaitable_frame() + { + if (has_result_) + static_cast(static_cast(result_))->~T(); + } + + awaitable get_return_object() noexcept + { + this->coro_ = coroutine_handle::from_promise(*this); + return awaitable(this); + }; + + template + void return_value(U&& u) + { + new (&result_) T(std::forward(u)); + has_result_ = true; + } + + template + void return_values(Us&&... us) + { + this->return_value(std::forward_as_tuple(std::forward(us)...)); + } + + T get() + { + this->caller_ = nullptr; + this->rethrow_exception(); + return std::move(*static_cast(static_cast(result_))); + } + +private: + alignas(T) unsigned char result_[sizeof(T)]; + bool has_result_ = false; +}; + +template +class awaitable_frame + : public awaitable_frame_base +{ +public: + awaitable get_return_object() + { + this->coro_ = coroutine_handle::from_promise(*this); + return awaitable(this); + }; + + void return_void() + { + } + + void get() + { + this->caller_ = nullptr; + this->rethrow_exception(); + } +}; + +template +class awaitable_thread +{ +public: + typedef Executor executor_type; + + // Construct from the entry point of a new thread of execution. + awaitable_thread(awaitable p, const Executor& ex) + : bottom_of_stack_(std::move(p)), + top_of_stack_(bottom_of_stack_.frame_), + executor_(ex) + { + } + + // Transfer ownership from another awaitable_thread. + awaitable_thread(awaitable_thread&& other) noexcept + : bottom_of_stack_(std::move(other.bottom_of_stack_)), + top_of_stack_(std::exchange(other.top_of_stack_, nullptr)), + executor_(std::move(other.executor_)) + { + } + + // Clean up with a last ditch effort to ensure the thread is unwound within + // the context of the executor. + ~awaitable_thread() + { + if (bottom_of_stack_.valid()) + { + // Coroutine "stack unwinding" must be performed through the executor. + (post)(executor_, + [a = std::move(bottom_of_stack_)]() mutable + { + awaitable(std::move(a)); + }); + } + } + + executor_type get_executor() const noexcept + { + return executor_; + } + + // Launch a new thread of execution. + void launch() + { + top_of_stack_->attach_thread(this); + pump(); + } + +protected: + template friend class awaitable_frame_base; + + // Repeatedly resume the top stack frame until the stack is empty or until it + // has been transferred to another resumable_thread object. + void pump() + { + do top_of_stack_->resume(); while (top_of_stack_); + if (bottom_of_stack_.valid()) + { + awaitable a(std::move(bottom_of_stack_)); + a.frame_->rethrow_exception(); + } + } + + awaitable bottom_of_stack_; + awaitable_frame_base* top_of_stack_; + executor_type executor_; +}; + +} // namespace detail +} // namespace asio +} // namespace boost + +#if !defined(GENERATING_DOCUMENTATION) + +namespace std { namespace experimental { + +template +struct coroutine_traits, Args...> +{ + typedef boost::asio::detail::awaitable_frame promise_type; +}; + +}} // namespace std::experimental + +#endif // !defined(GENERATING_DOCUMENTATION) + +#include + +#endif // BOOST_ASIO_IMPL_AWAITABLE_HPP diff --git a/boost/asio/impl/buffered_read_stream.hpp b/boost/asio/impl/buffered_read_stream.hpp new file mode 100644 index 0000000..6a51d8e --- /dev/null +++ b/boost/asio/impl/buffered_read_stream.hpp @@ -0,0 +1,450 @@ +// +// impl/buffered_read_stream.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_BUFFERED_READ_STREAM_HPP +#define BOOST_ASIO_IMPL_BUFFERED_READ_STREAM_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +template +std::size_t buffered_read_stream::fill() +{ + detail::buffer_resize_guard + resize_guard(storage_); + std::size_t previous_size = storage_.size(); + storage_.resize(storage_.capacity()); + storage_.resize(previous_size + next_layer_.read_some(buffer( + storage_.data() + previous_size, + storage_.size() - previous_size))); + resize_guard.commit(); + return storage_.size() - previous_size; +} + +template +std::size_t buffered_read_stream::fill(boost::system::error_code& ec) +{ + detail::buffer_resize_guard + resize_guard(storage_); + std::size_t previous_size = storage_.size(); + storage_.resize(storage_.capacity()); + storage_.resize(previous_size + next_layer_.read_some(buffer( + storage_.data() + previous_size, + storage_.size() - previous_size), + ec)); + resize_guard.commit(); + return storage_.size() - previous_size; +} + +namespace detail +{ + template + class buffered_fill_handler + { + public: + buffered_fill_handler(detail::buffered_stream_storage& storage, + std::size_t previous_size, ReadHandler& handler) + : storage_(storage), + previous_size_(previous_size), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + buffered_fill_handler(const buffered_fill_handler& other) + : storage_(other.storage_), + previous_size_(other.previous_size_), + handler_(other.handler_) + { + } + + buffered_fill_handler(buffered_fill_handler&& other) + : storage_(other.storage_), + previous_size_(other.previous_size_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + const std::size_t bytes_transferred) + { + storage_.resize(previous_size_ + bytes_transferred); + handler_(ec, bytes_transferred); + } + + //private: + detail::buffered_stream_storage& storage_; + std::size_t previous_size_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + buffered_fill_handler* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + buffered_fill_handler* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + buffered_fill_handler* this_handler) + { + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + buffered_fill_handler* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + buffered_fill_handler* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_buffered_fill + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + buffered_stream_storage* storage, Stream* next_layer) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue handler2(handler); + std::size_t previous_size = storage->size(); + storage->resize(storage->capacity()); + next_layer->async_read_some( + buffer( + storage->data() + previous_size, + storage->size() - previous_size), + buffered_fill_handler::type>( + *storage, previous_size, handler2.value)); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::buffered_fill_handler, Allocator> +{ + typedef typename associated_allocator::type type; + + static type get(const detail::buffered_fill_handler& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::buffered_fill_handler, Executor> +{ + typedef typename associated_executor::type type; + + static type get(const detail::buffered_fill_handler& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +buffered_read_stream::async_fill( + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_initiate( + detail::initiate_async_buffered_fill(), handler, &storage_, &next_layer_); +} + +template +template +std::size_t buffered_read_stream::read_some( + const MutableBufferSequence& buffers) +{ + using boost::asio::buffer_size; + if (buffer_size(buffers) == 0) + return 0; + + if (storage_.empty()) + this->fill(); + + return this->copy(buffers); +} + +template +template +std::size_t buffered_read_stream::read_some( + const MutableBufferSequence& buffers, boost::system::error_code& ec) +{ + ec = boost::system::error_code(); + + using boost::asio::buffer_size; + if (buffer_size(buffers) == 0) + return 0; + + if (storage_.empty() && !this->fill(ec)) + return 0; + + return this->copy(buffers); +} + +namespace detail +{ + template + class buffered_read_some_handler + { + public: + buffered_read_some_handler(detail::buffered_stream_storage& storage, + const MutableBufferSequence& buffers, ReadHandler& handler) + : storage_(storage), + buffers_(buffers), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + buffered_read_some_handler(const buffered_read_some_handler& other) + : storage_(other.storage_), + buffers_(other.buffers_), + handler_(other.handler_) + { + } + + buffered_read_some_handler(buffered_read_some_handler&& other) + : storage_(other.storage_), + buffers_(other.buffers_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, std::size_t) + { + if (ec || storage_.empty()) + { + const std::size_t length = 0; + handler_(ec, length); + } + else + { + const std::size_t bytes_copied = boost::asio::buffer_copy( + buffers_, storage_.data(), storage_.size()); + storage_.consume(bytes_copied); + handler_(ec, bytes_copied); + } + } + + //private: + detail::buffered_stream_storage& storage_; + MutableBufferSequence buffers_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + buffered_read_some_handler< + MutableBufferSequence, ReadHandler>* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + buffered_read_some_handler< + MutableBufferSequence, ReadHandler>* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + buffered_read_some_handler< + MutableBufferSequence, ReadHandler>* this_handler) + { + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + buffered_read_some_handler< + MutableBufferSequence, ReadHandler>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + buffered_read_some_handler< + MutableBufferSequence, ReadHandler>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_buffered_read_some + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + buffered_stream_storage* storage, Stream* next_layer, + const MutableBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + using boost::asio::buffer_size; + non_const_lvalue handler2(handler); + if (buffer_size(buffers) == 0 || !storage->empty()) + { + next_layer->async_read_some(BOOST_ASIO_MUTABLE_BUFFER(0, 0), + buffered_read_some_handler::type>( + *storage, buffers, handler2.value)); + } + else + { + initiate_async_buffered_fill()( + buffered_read_some_handler::type>( + *storage, buffers, handler2.value), + storage, next_layer); + } + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::buffered_read_some_handler, + Allocator> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::buffered_read_some_handler< + MutableBufferSequence, ReadHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::buffered_read_some_handler, + Executor> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::buffered_read_some_handler< + MutableBufferSequence, ReadHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +buffered_read_stream::async_read_some( + const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_initiate( + detail::initiate_async_buffered_read_some(), + handler, &storage_, &next_layer_, buffers); +} + +template +template +std::size_t buffered_read_stream::peek( + const MutableBufferSequence& buffers) +{ + if (storage_.empty()) + this->fill(); + return this->peek_copy(buffers); +} + +template +template +std::size_t buffered_read_stream::peek( + const MutableBufferSequence& buffers, boost::system::error_code& ec) +{ + ec = boost::system::error_code(); + if (storage_.empty() && !this->fill(ec)) + return 0; + return this->peek_copy(buffers); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_BUFFERED_READ_STREAM_HPP diff --git a/boost/asio/impl/buffered_write_stream.hpp b/boost/asio/impl/buffered_write_stream.hpp new file mode 100644 index 0000000..05d4406 --- /dev/null +++ b/boost/asio/impl/buffered_write_stream.hpp @@ -0,0 +1,432 @@ +// +// impl/buffered_write_stream.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP +#define BOOST_ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +template +std::size_t buffered_write_stream::flush() +{ + std::size_t bytes_written = write(next_layer_, + buffer(storage_.data(), storage_.size())); + storage_.consume(bytes_written); + return bytes_written; +} + +template +std::size_t buffered_write_stream::flush(boost::system::error_code& ec) +{ + std::size_t bytes_written = write(next_layer_, + buffer(storage_.data(), storage_.size()), + transfer_all(), ec); + storage_.consume(bytes_written); + return bytes_written; +} + +namespace detail +{ + template + class buffered_flush_handler + { + public: + buffered_flush_handler(detail::buffered_stream_storage& storage, + WriteHandler& handler) + : storage_(storage), + handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + buffered_flush_handler(const buffered_flush_handler& other) + : storage_(other.storage_), + handler_(other.handler_) + { + } + + buffered_flush_handler(buffered_flush_handler&& other) + : storage_(other.storage_), + handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + const std::size_t bytes_written) + { + storage_.consume(bytes_written); + handler_(ec, bytes_written); + } + + //private: + detail::buffered_stream_storage& storage_; + WriteHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + buffered_flush_handler* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + buffered_flush_handler* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + buffered_flush_handler* this_handler) + { + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + buffered_flush_handler* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + buffered_flush_handler* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_buffered_flush + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + buffered_stream_storage* storage, Stream* next_layer) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + non_const_lvalue handler2(handler); + async_write(*next_layer, buffer(storage->data(), storage->size()), + buffered_flush_handler::type>( + *storage, handler2.value)); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::buffered_flush_handler, Allocator> +{ + typedef typename associated_allocator::type type; + + static type get(const detail::buffered_flush_handler& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::buffered_flush_handler, Executor> +{ + typedef typename associated_executor::type type; + + static type get(const detail::buffered_flush_handler& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +template +BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +buffered_write_stream::async_flush( + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) +{ + return async_initiate( + detail::initiate_async_buffered_flush(), + handler, &storage_, &next_layer_); +} + +template +template +std::size_t buffered_write_stream::write_some( + const ConstBufferSequence& buffers) +{ + using boost::asio::buffer_size; + if (buffer_size(buffers) == 0) + return 0; + + if (storage_.size() == storage_.capacity()) + this->flush(); + + return this->copy(buffers); +} + +template +template +std::size_t buffered_write_stream::write_some( + const ConstBufferSequence& buffers, boost::system::error_code& ec) +{ + ec = boost::system::error_code(); + + using boost::asio::buffer_size; + if (buffer_size(buffers) == 0) + return 0; + + if (storage_.size() == storage_.capacity() && !flush(ec)) + return 0; + + return this->copy(buffers); +} + +namespace detail +{ + template + class buffered_write_some_handler + { + public: + buffered_write_some_handler(detail::buffered_stream_storage& storage, + const ConstBufferSequence& buffers, WriteHandler& handler) + : storage_(storage), + buffers_(buffers), + handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + buffered_write_some_handler(const buffered_write_some_handler& other) + : storage_(other.storage_), + buffers_(other.buffers_), + handler_(other.handler_) + { + } + + buffered_write_some_handler(buffered_write_some_handler&& other) + : storage_(other.storage_), + buffers_(other.buffers_), + handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, std::size_t) + { + if (ec) + { + const std::size_t length = 0; + handler_(ec, length); + } + else + { + using boost::asio::buffer_size; + std::size_t orig_size = storage_.size(); + std::size_t space_avail = storage_.capacity() - orig_size; + std::size_t bytes_avail = buffer_size(buffers_); + std::size_t length = bytes_avail < space_avail + ? bytes_avail : space_avail; + storage_.resize(orig_size + length); + const std::size_t bytes_copied = boost::asio::buffer_copy( + storage_.data() + orig_size, buffers_, length); + handler_(ec, bytes_copied); + } + } + + //private: + detail::buffered_stream_storage& storage_; + ConstBufferSequence buffers_; + WriteHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + buffered_write_some_handler< + ConstBufferSequence, WriteHandler>* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + buffered_write_some_handler< + ConstBufferSequence, WriteHandler>* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + buffered_write_some_handler< + ConstBufferSequence, WriteHandler>* this_handler) + { + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + buffered_write_some_handler< + ConstBufferSequence, WriteHandler>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + buffered_write_some_handler< + ConstBufferSequence, WriteHandler>* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_buffered_write_some + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + buffered_stream_storage* storage, Stream* next_layer, + const ConstBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + using boost::asio::buffer_size; + non_const_lvalue handler2(handler); + if (buffer_size(buffers) == 0 || storage->size() < storage->capacity()) + { + next_layer->async_write_some(BOOST_ASIO_CONST_BUFFER(0, 0), + buffered_write_some_handler::type>( + *storage, buffers, handler2.value)); + } + else + { + initiate_async_buffered_flush()( + buffered_write_some_handler::type>( + *storage, buffers, handler2.value), + storage, next_layer); + } + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::buffered_write_some_handler, + Allocator> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::buffered_write_some_handler< + ConstBufferSequence, WriteHandler>& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::buffered_write_some_handler, + Executor> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::buffered_write_some_handler< + ConstBufferSequence, WriteHandler>& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +template +BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +buffered_write_stream::async_write_some( + const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) +{ + return async_initiate( + detail::initiate_async_buffered_write_some(), + handler, &storage_, &next_layer_, buffers); +} + +template +template +std::size_t buffered_write_stream::copy( + const ConstBufferSequence& buffers) +{ + using boost::asio::buffer_size; + std::size_t orig_size = storage_.size(); + std::size_t space_avail = storage_.capacity() - orig_size; + std::size_t bytes_avail = buffer_size(buffers); + std::size_t length = bytes_avail < space_avail ? bytes_avail : space_avail; + storage_.resize(orig_size + length); + return boost::asio::buffer_copy( + storage_.data() + orig_size, buffers, length); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP diff --git a/boost/asio/impl/co_spawn.hpp b/boost/asio/impl/co_spawn.hpp new file mode 100644 index 0000000..19770cd --- /dev/null +++ b/boost/asio/impl/co_spawn.hpp @@ -0,0 +1,140 @@ +// +// impl/co_spawn.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_CO_SPAWN_HPP +#define BOOST_ASIO_IMPL_CO_SPAWN_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +awaitable co_spawn_entry_point( + awaitable*, Executor ex, F f, Handler handler) +{ + auto spawn_work = make_work_guard(ex); + auto handler_work = make_work_guard(handler, ex); + + (void) co_await (post)(spawn_work.get_executor(), + use_awaitable_t{}); + + bool done = false; + try + { + T t = co_await f(); + + done = true; + + (dispatch)(handler_work.get_executor(), + [handler = std::move(handler), t = std::move(t)]() mutable + { + handler(std::exception_ptr(), std::move(t)); + }); + } + catch (...) + { + if (done) + throw; + + (dispatch)(handler_work.get_executor(), + [handler = std::move(handler), e = std::current_exception()]() mutable + { + handler(e, T()); + }); + } +} + +template +awaitable co_spawn_entry_point( + awaitable*, Executor ex, F f, Handler handler) +{ + auto spawn_work = make_work_guard(ex); + auto handler_work = make_work_guard(handler, ex); + + (void) co_await (post)(spawn_work.get_executor(), + use_awaitable_t{}); + + std::exception_ptr e = nullptr; + try + { + co_await f(); + } + catch (...) + { + e = std::current_exception(); + } + + (dispatch)(handler_work.get_executor(), + [handler = std::move(handler), e]() mutable + { + handler(e); + }); +} + +struct initiate_co_spawn +{ + template + void operator()(Handler&& handler, const Executor& ex, F&& f) const + { + typedef typename result_of::type awaitable_type; + typedef typename awaitable_type::executor_type executor_type; + + executor_type ex2(ex); + auto a = (co_spawn_entry_point)(static_cast(nullptr), + ex2, std::forward(f), std::forward(handler)); + awaitable_handler(std::move(a), ex2).launch(); + } +}; + +} // namespace detail + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, + typename detail::awaitable_signature::type>::type) +co_spawn(const Executor& ex, F&& f, CompletionToken&& token, + typename enable_if< + is_executor::value + >::type*) +{ + return async_initiate::type>>( + detail::initiate_co_spawn(), token, ex, std::forward(f)); +} + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, + typename detail::awaitable_signature::type>::type) +co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token, + typename enable_if< + is_convertible::value + >::type*) +{ + return (co_spawn)(ctx.get_executor(), std::forward(f), + std::forward(token)); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_CO_SPAWN_HPP diff --git a/boost/asio/impl/compose.hpp b/boost/asio/impl/compose.hpp new file mode 100644 index 0000000..76fe54d --- /dev/null +++ b/boost/asio/impl/compose.hpp @@ -0,0 +1,421 @@ +// +// impl/compose.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_COMPOSE_HPP +#define BOOST_ASIO_IMPL_COMPOSE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +namespace detail +{ + template + struct composed_work; + + template <> + struct composed_work + { + composed_work() BOOST_ASIO_NOEXCEPT + : head_(system_executor()) + { + } + + void reset() + { + head_.reset(); + } + + typedef system_executor head_type; + executor_work_guard head_; + }; + + inline composed_work make_composed_work() + { + return composed_work(); + } + + template + struct composed_work + { + explicit composed_work(const Head& ex) BOOST_ASIO_NOEXCEPT + : head_(ex) + { + } + + void reset() + { + head_.reset(); + } + + typedef Head head_type; + executor_work_guard head_; + }; + + template + inline composed_work make_composed_work(const Head& head) + { + return composed_work(head); + } + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + struct composed_work + { + explicit composed_work(const Head& head, + const Tail&... tail) BOOST_ASIO_NOEXCEPT + : head_(head), + tail_(tail...) + { + } + + void reset() + { + head_.reset(); + tail_.reset(); + } + + typedef Head head_type; + executor_work_guard head_; + composed_work tail_; + }; + + template + inline composed_work + make_composed_work(const Head& head, const Tail&... tail) + { + return composed_work(head, tail...); + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#define BOOST_ASIO_PRIVATE_COMPOSED_WORK_DEF(n) \ + template \ + struct composed_work \ + { \ + explicit composed_work(const Head& head, \ + BOOST_ASIO_VARIADIC_CONSTREF_PARAMS(n)) BOOST_ASIO_NOEXCEPT \ + : head_(head), \ + tail_(BOOST_ASIO_VARIADIC_BYVAL_ARGS(n)) \ + { \ + } \ + \ + void reset() \ + { \ + head_.reset(); \ + tail_.reset(); \ + } \ + \ + typedef Head head_type; \ + executor_work_guard head_; \ + composed_work tail_; \ + }; \ + \ + template \ + inline composed_work \ + make_composed_work(const Head& head, BOOST_ASIO_VARIADIC_CONSTREF_PARAMS(n)) \ + { \ + return composed_work< \ + void(Head, BOOST_ASIO_VARIADIC_TARGS(n))>( \ + head, BOOST_ASIO_VARIADIC_BYVAL_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_COMPOSED_WORK_DEF) +#undef BOOST_ASIO_PRIVATE_COMPOSED_WORK_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + template + class composed_op; + + template + class composed_op +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + template + class composed_op +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + { + public: + composed_op(BOOST_ASIO_MOVE_ARG(Impl) impl, + BOOST_ASIO_MOVE_ARG(Work) work, + BOOST_ASIO_MOVE_ARG(Handler) handler) + : impl_(BOOST_ASIO_MOVE_CAST(Impl)(impl)), + work_(BOOST_ASIO_MOVE_CAST(Work)(work)), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), + invocations_(0) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + composed_op(composed_op&& other) + : impl_(BOOST_ASIO_MOVE_CAST(Impl)(other.impl_)), + work_(BOOST_ASIO_MOVE_CAST(Work)(other.work_)), + handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)), + invocations_(other.invocations_) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + typedef typename associated_executor::type executor_type; + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return (get_associated_executor)(handler_, work_.head_.get_executor()); + } + + typedef typename associated_allocator >::type allocator_type; + + allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT + { + return (get_associated_allocator)(handler_, std::allocator()); + } + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + void operator()(BOOST_ASIO_MOVE_ARG(T)... t) + { + if (invocations_ < ~unsigned(0)) + ++invocations_; + impl_(*this, BOOST_ASIO_MOVE_CAST(T)(t)...); + } + + void complete(Args... args) + { + this->work_.reset(); + this->handler_(BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + void operator()() + { + if (invocations_ < ~unsigned(0)) + ++invocations_; + impl_(*this); + } + + void complete() + { + this->work_.reset(); + this->handler_(); + } + +#define BOOST_ASIO_PRIVATE_COMPOSED_OP_DEF(n) \ + template \ + void operator()(BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + if (invocations_ < ~unsigned(0)) \ + ++invocations_; \ + impl_(*this, BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + \ + template \ + void complete(BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + this->work_.reset(); \ + this->handler_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_COMPOSED_OP_DEF) +#undef BOOST_ASIO_PRIVATE_COMPOSED_OP_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + //private: + Impl impl_; + Work work_; + Handler handler_; + unsigned invocations_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + composed_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + composed_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + composed_op* this_handler) + { + return this_handler->invocations_ > 1 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + composed_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + composed_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + struct initiate_composed_op + { + template + void operator()(BOOST_ASIO_MOVE_ARG(Handler) handler, + BOOST_ASIO_MOVE_ARG(Impl) impl, + BOOST_ASIO_MOVE_ARG(Work) work) const + { + composed_op::type, typename decay::type, + typename decay::type, Signature>( + BOOST_ASIO_MOVE_CAST(Impl)(impl), BOOST_ASIO_MOVE_CAST(Work)(work), + BOOST_ASIO_MOVE_CAST(Handler)(handler))(); + } + }; + + template + inline typename IoObject::executor_type + get_composed_io_executor(IoObject& io_object) + { + return io_object.get_executor(); + } + + template + inline const Executor& get_composed_io_executor(const Executor& ex, + typename enable_if::value>::type* = 0) + { + return ex; + } +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature) +async_compose(BOOST_ASIO_MOVE_ARG(Implementation) implementation, + BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, + BOOST_ASIO_MOVE_ARG(IoObjectsOrExecutors)... io_objects_or_executors) +{ + return async_initiate( + detail::initiate_composed_op(), token, + BOOST_ASIO_MOVE_CAST(Implementation)(implementation), + detail::make_composed_work( + detail::get_composed_io_executor( + BOOST_ASIO_MOVE_CAST(IoObjectsOrExecutors)( + io_objects_or_executors))...)); +} + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature) +async_compose(BOOST_ASIO_MOVE_ARG(Implementation) implementation, + BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token) +{ + return async_initiate( + detail::initiate_composed_op(), token, + BOOST_ASIO_MOVE_CAST(Implementation)(implementation), + detail::make_composed_work()); +} + +# define BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR(n) \ + BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_##n + +# define BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_1 \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T1)(x1)) +# define BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_2 \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T1)(x1)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T2)(x2)) +# define BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_3 \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T1)(x1)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T2)(x2)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T3)(x3)) +# define BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_4 \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T1)(x1)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T2)(x2)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T3)(x3)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T4)(x4)) +# define BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_5 \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T1)(x1)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T2)(x2)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T3)(x3)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T4)(x4)), \ + detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T5)(x5)) + +#define BOOST_ASIO_PRIVATE_ASYNC_COMPOSE_DEF(n) \ + template \ + BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, Signature) \ + async_compose(BOOST_ASIO_MOVE_ARG(Implementation) implementation, \ + BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + return async_initiate( \ + detail::initiate_composed_op(), token, \ + BOOST_ASIO_MOVE_CAST(Implementation)(implementation), \ + detail::make_composed_work( \ + BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR(n))); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_ASYNC_COMPOSE_DEF) +#undef BOOST_ASIO_PRIVATE_ASYNC_COMPOSE_DEF + +#undef BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR +#undef BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_1 +#undef BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_2 +#undef BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_3 +#undef BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_4 +#undef BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_5 + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_COMPOSE_HPP diff --git a/boost/asio/impl/connect.hpp b/boost/asio/impl/connect.hpp new file mode 100644 index 0000000..7089316 --- /dev/null +++ b/boost/asio/impl/connect.hpp @@ -0,0 +1,830 @@ +// +// impl/connect.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_CONNECT_HPP +#define BOOST_ASIO_IMPL_CONNECT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +namespace detail +{ + struct default_connect_condition + { + template + bool operator()(const boost::system::error_code&, const Endpoint&) + { + return true; + } + }; + + template + inline typename Protocol::endpoint deref_connect_result( + Iterator iter, boost::system::error_code& ec) + { + return ec ? typename Protocol::endpoint() : *iter; + } + + template + struct legacy_connect_condition_helper : T + { + typedef char (*fallback_func_type)(...); + operator fallback_func_type() const; + }; + + template + struct legacy_connect_condition_helper + { + R operator()(Arg1, Arg2) const; + char operator()(...) const; + }; + + template + struct is_legacy_connect_condition + { + static char asio_connect_condition_check(char); + static char (&asio_connect_condition_check(Iterator))[2]; + + static const bool value = + sizeof(asio_connect_condition_check( + (*static_cast*>(0))( + *static_cast(0), + *static_cast(0)))) != 1; + }; + + template + inline Iterator call_connect_condition(ConnectCondition& connect_condition, + const boost::system::error_code& ec, Iterator next, Iterator end, + typename enable_if::value>::type* = 0) + { + if (next != end) + return connect_condition(ec, next); + return end; + } + + template + inline Iterator call_connect_condition(ConnectCondition& connect_condition, + const boost::system::error_code& ec, Iterator next, Iterator end, + typename enable_if::value>::type* = 0) + { + for (;next != end; ++next) + if (connect_condition(ec, *next)) + return next; + return end; + } +} + +template +typename Protocol::endpoint connect(basic_socket& s, + const EndpointSequence& endpoints, + typename enable_if::value>::type*) +{ + boost::system::error_code ec; + typename Protocol::endpoint result = connect(s, endpoints, ec); + boost::asio::detail::throw_error(ec, "connect"); + return result; +} + +template +typename Protocol::endpoint connect(basic_socket& s, + const EndpointSequence& endpoints, boost::system::error_code& ec, + typename enable_if::value>::type*) +{ + return detail::deref_connect_result( + connect(s, endpoints.begin(), endpoints.end(), + detail::default_connect_condition(), ec), ec); +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +template +Iterator connect(basic_socket& s, Iterator begin, + typename enable_if::value>::type*) +{ + boost::system::error_code ec; + Iterator result = connect(s, begin, ec); + boost::asio::detail::throw_error(ec, "connect"); + return result; +} + +template +inline Iterator connect(basic_socket& s, + Iterator begin, boost::system::error_code& ec, + typename enable_if::value>::type*) +{ + return connect(s, begin, Iterator(), detail::default_connect_condition(), ec); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +template +Iterator connect(basic_socket& s, + Iterator begin, Iterator end) +{ + boost::system::error_code ec; + Iterator result = connect(s, begin, end, ec); + boost::asio::detail::throw_error(ec, "connect"); + return result; +} + +template +inline Iterator connect(basic_socket& s, + Iterator begin, Iterator end, boost::system::error_code& ec) +{ + return connect(s, begin, end, detail::default_connect_condition(), ec); +} + +template +typename Protocol::endpoint connect(basic_socket& s, + const EndpointSequence& endpoints, ConnectCondition connect_condition, + typename enable_if::value>::type*) +{ + boost::system::error_code ec; + typename Protocol::endpoint result = connect( + s, endpoints, connect_condition, ec); + boost::asio::detail::throw_error(ec, "connect"); + return result; +} + +template +typename Protocol::endpoint connect(basic_socket& s, + const EndpointSequence& endpoints, ConnectCondition connect_condition, + boost::system::error_code& ec, + typename enable_if::value>::type*) +{ + return detail::deref_connect_result( + connect(s, endpoints.begin(), endpoints.end(), + connect_condition, ec), ec); +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +template +Iterator connect(basic_socket& s, + Iterator begin, ConnectCondition connect_condition, + typename enable_if::value>::type*) +{ + boost::system::error_code ec; + Iterator result = connect(s, begin, connect_condition, ec); + boost::asio::detail::throw_error(ec, "connect"); + return result; +} + +template +inline Iterator connect(basic_socket& s, + Iterator begin, ConnectCondition connect_condition, + boost::system::error_code& ec, + typename enable_if::value>::type*) +{ + return connect(s, begin, Iterator(), connect_condition, ec); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +template +Iterator connect(basic_socket& s, Iterator begin, + Iterator end, ConnectCondition connect_condition) +{ + boost::system::error_code ec; + Iterator result = connect(s, begin, end, connect_condition, ec); + boost::asio::detail::throw_error(ec, "connect"); + return result; +} + +template +Iterator connect(basic_socket& s, Iterator begin, + Iterator end, ConnectCondition connect_condition, + boost::system::error_code& ec) +{ + ec = boost::system::error_code(); + + for (Iterator iter = begin; iter != end; ++iter) + { + iter = (detail::call_connect_condition(connect_condition, ec, iter, end)); + if (iter != end) + { + s.close(ec); + s.connect(*iter, ec); + if (!ec) + return iter; + } + else + break; + } + + if (!ec) + ec = boost::asio::error::not_found; + + return end; +} + +namespace detail +{ + // Enable the empty base class optimisation for the connect condition. + template + class base_from_connect_condition + { + protected: + explicit base_from_connect_condition( + const ConnectCondition& connect_condition) + : connect_condition_(connect_condition) + { + } + + template + void check_condition(const boost::system::error_code& ec, + Iterator& iter, Iterator& end) + { + iter = detail::call_connect_condition(connect_condition_, ec, iter, end); + } + + private: + ConnectCondition connect_condition_; + }; + + // The default_connect_condition implementation is essentially a no-op. This + // template specialisation lets us eliminate all costs associated with it. + template <> + class base_from_connect_condition + { + protected: + explicit base_from_connect_condition(const default_connect_condition&) + { + } + + template + void check_condition(const boost::system::error_code&, Iterator&, Iterator&) + { + } + }; + + template + class range_connect_op : base_from_connect_condition + { + public: + range_connect_op(basic_socket& sock, + const EndpointSequence& endpoints, + const ConnectCondition& connect_condition, + RangeConnectHandler& handler) + : base_from_connect_condition(connect_condition), + socket_(sock), + endpoints_(endpoints), + index_(0), + start_(0), + handler_(BOOST_ASIO_MOVE_CAST(RangeConnectHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + range_connect_op(const range_connect_op& other) + : base_from_connect_condition(other), + socket_(other.socket_), + endpoints_(other.endpoints_), + index_(other.index_), + start_(other.start_), + handler_(other.handler_) + { + } + + range_connect_op(range_connect_op&& other) + : base_from_connect_condition(other), + socket_(other.socket_), + endpoints_(other.endpoints_), + index_(other.index_), + start_(other.start_), + handler_(BOOST_ASIO_MOVE_CAST(RangeConnectHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(boost::system::error_code ec, int start = 0) + { + this->process(ec, start, + const_cast(endpoints_).begin(), + const_cast(endpoints_).end()); + } + + //private: + template + void process(boost::system::error_code ec, + int start, Iterator begin, Iterator end) + { + Iterator iter = begin; + std::advance(iter, index_); + + switch (start_ = start) + { + case 1: + for (;;) + { + this->check_condition(ec, iter, end); + index_ = std::distance(begin, iter); + + if (iter != end) + { + socket_.close(ec); + socket_.async_connect(*iter, + BOOST_ASIO_MOVE_CAST(range_connect_op)(*this)); + return; + } + + if (start) + { + ec = boost::asio::error::not_found; + boost::asio::post(socket_.get_executor(), + detail::bind_handler( + BOOST_ASIO_MOVE_CAST(range_connect_op)(*this), ec)); + return; + } + + /* fall-through */ default: + + if (iter == end) + break; + + if (!socket_.is_open()) + { + ec = boost::asio::error::operation_aborted; + break; + } + + if (!ec) + break; + + ++iter; + ++index_; + } + + handler_(static_cast(ec), + static_cast( + ec || iter == end ? typename Protocol::endpoint() : *iter)); + } + } + + basic_socket& socket_; + EndpointSequence endpoints_; + std::size_t index_; + int start_; + RangeConnectHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + range_connect_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + range_connect_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + range_connect_op* this_handler) + { + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + range_connect_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + range_connect_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_range_connect + { + template + void operator()(BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler, + basic_socket* s, const EndpointSequence& endpoints, + const ConnectCondition& connect_condition) const + { + // If you get an error on the following line it means that your + // handler does not meet the documented type requirements for an + // RangeConnectHandler. + BOOST_ASIO_RANGE_CONNECT_HANDLER_CHECK(RangeConnectHandler, + handler, typename Protocol::endpoint) type_check; + + non_const_lvalue handler2(handler); + range_connect_op::type>(*s, endpoints, + connect_condition, handler2.value)(boost::system::error_code(), 1); + } + }; + + template + class iterator_connect_op : base_from_connect_condition + { + public: + iterator_connect_op(basic_socket& sock, + const Iterator& begin, const Iterator& end, + const ConnectCondition& connect_condition, + IteratorConnectHandler& handler) + : base_from_connect_condition(connect_condition), + socket_(sock), + iter_(begin), + end_(end), + start_(0), + handler_(BOOST_ASIO_MOVE_CAST(IteratorConnectHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + iterator_connect_op(const iterator_connect_op& other) + : base_from_connect_condition(other), + socket_(other.socket_), + iter_(other.iter_), + end_(other.end_), + start_(other.start_), + handler_(other.handler_) + { + } + + iterator_connect_op(iterator_connect_op&& other) + : base_from_connect_condition(other), + socket_(other.socket_), + iter_(other.iter_), + end_(other.end_), + start_(other.start_), + handler_(BOOST_ASIO_MOVE_CAST(IteratorConnectHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(boost::system::error_code ec, int start = 0) + { + switch (start_ = start) + { + case 1: + for (;;) + { + this->check_condition(ec, iter_, end_); + + if (iter_ != end_) + { + socket_.close(ec); + socket_.async_connect(*iter_, + BOOST_ASIO_MOVE_CAST(iterator_connect_op)(*this)); + return; + } + + if (start) + { + ec = boost::asio::error::not_found; + boost::asio::post(socket_.get_executor(), + detail::bind_handler( + BOOST_ASIO_MOVE_CAST(iterator_connect_op)(*this), ec)); + return; + } + + /* fall-through */ default: + + if (iter_ == end_) + break; + + if (!socket_.is_open()) + { + ec = boost::asio::error::operation_aborted; + break; + } + + if (!ec) + break; + + ++iter_; + } + + handler_(static_cast(ec), + static_cast(iter_)); + } + } + + //private: + basic_socket& socket_; + Iterator iter_; + Iterator end_; + int start_; + IteratorConnectHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + iterator_connect_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + iterator_connect_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + iterator_connect_op* this_handler) + { + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + iterator_connect_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + iterator_connect_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_iterator_connect + { + template + void operator()(BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, + basic_socket* s, Iterator begin, + Iterator end, const ConnectCondition& connect_condition) const + { + // If you get an error on the following line it means that your + // handler does not meet the documented type requirements for an + // IteratorConnectHandler. + BOOST_ASIO_ITERATOR_CONNECT_HANDLER_CHECK( + IteratorConnectHandler, handler, Iterator) type_check; + + non_const_lvalue handler2(handler); + iterator_connect_op::type>(*s, begin, end, + connect_condition, handler2.value)(boost::system::error_code(), 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::range_connect_op, Allocator> +{ + typedef typename associated_allocator< + RangeConnectHandler, Allocator>::type type; + + static type get( + const detail::range_connect_op& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::range_connect_op, Executor1> +{ + typedef typename associated_executor< + RangeConnectHandler, Executor1>::type type; + + static type get( + const detail::range_connect_op& h, + const Executor1& ex = Executor1()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +template +struct associated_allocator< + detail::iterator_connect_op, + Allocator> +{ + typedef typename associated_allocator< + IteratorConnectHandler, Allocator>::type type; + + static type get( + const detail::iterator_connect_op& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::iterator_connect_op, + Executor1> +{ + typedef typename associated_executor< + IteratorConnectHandler, Executor1>::type type; + + static type get( + const detail::iterator_connect_op& h, + const Executor1& ex = Executor1()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, + void (boost::system::error_code, typename Protocol::endpoint)) +async_connect(basic_socket& s, + const EndpointSequence& endpoints, + BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler, + typename enable_if::value>::type*) +{ + return async_initiate( + detail::initiate_async_range_connect(), handler, + &s, endpoints, detail::default_connect_condition()); +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, + void (boost::system::error_code, Iterator)) +async_connect(basic_socket& s, Iterator begin, + BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, + typename enable_if::value>::type*) +{ + return async_initiate( + detail::initiate_async_iterator_connect(), handler, + &s, begin, Iterator(), detail::default_connect_condition()); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, + void (boost::system::error_code, Iterator)) +async_connect(basic_socket& s, Iterator begin, Iterator end, + BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler) +{ + return async_initiate( + detail::initiate_async_iterator_connect(), handler, + &s, begin, end, detail::default_connect_condition()); +} + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler, + void (boost::system::error_code, typename Protocol::endpoint)) +async_connect(basic_socket& s, + const EndpointSequence& endpoints, ConnectCondition connect_condition, + BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler, + typename enable_if::value>::type*) +{ + return async_initiate( + detail::initiate_async_range_connect(), + handler, &s, endpoints, connect_condition); +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, + void (boost::system::error_code, Iterator)) +async_connect(basic_socket& s, Iterator begin, + ConnectCondition connect_condition, + BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, + typename enable_if::value>::type*) +{ + return async_initiate( + detail::initiate_async_iterator_connect(), + handler, &s, begin, Iterator(), connect_condition); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler, + void (boost::system::error_code, Iterator)) +async_connect(basic_socket& s, Iterator begin, + Iterator end, ConnectCondition connect_condition, + BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler) +{ + return async_initiate( + detail::initiate_async_iterator_connect(), + handler, &s, begin, end, connect_condition); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_CONNECT_HPP diff --git a/boost/asio/impl/defer.hpp b/boost/asio/impl/defer.hpp new file mode 100644 index 0000000..856a33c --- /dev/null +++ b/boost/asio/impl/defer.hpp @@ -0,0 +1,93 @@ +// +// impl/defer.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_DEFER_HPP +#define BOOST_ASIO_IMPL_DEFER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct initiate_defer +{ + template + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) const + { + typedef typename decay::type DecayedHandler; + + typename associated_executor::type ex( + (get_associated_executor)(handler)); + + typename associated_allocator::type alloc( + (get_associated_allocator)(handler)); + + ex.defer(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); + } + + template + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + BOOST_ASIO_MOVE_ARG(Executor) ex) const + { + typedef typename decay::type DecayedHandler; + + typename associated_allocator::type alloc( + (get_associated_allocator)(handler)); + + ex.defer(detail::work_dispatcher( + BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)), alloc); + } +}; + +} // namespace detail + +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( + BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + return async_initiate( + detail::initiate_defer(), token); +} + +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( + const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if::value>::type*) +{ + return async_initiate( + detail::initiate_defer(), token, ex); +} + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) defer( + ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if::value>::type*) +{ + return (defer)(ctx.get_executor(), + BOOST_ASIO_MOVE_CAST(CompletionToken)(token)); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_DEFER_HPP diff --git a/boost/asio/impl/detached.hpp b/boost/asio/impl/detached.hpp new file mode 100644 index 0000000..ae2c882 --- /dev/null +++ b/boost/asio/impl/detached.hpp @@ -0,0 +1,132 @@ +// +// impl/detached.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_DETACHED_HPP +#define BOOST_ASIO_IMPL_DETACHED_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + + // Class to adapt a detached_t as a completion handler. + class detached_handler + { + public: + typedef void result_type; + + detached_handler(detached_t) + { + } + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + void operator()(Args...) + { + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + void operator()() + { + } + +#define BOOST_ASIO_PRIVATE_DETACHED_DEF(n) \ + template \ + void operator()(BOOST_ASIO_VARIADIC_TARGS(n)) \ + { \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_DETACHED_DEF) +#undef BOOST_ASIO_PRIVATE_DETACHED_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + }; + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct async_result +{ + typedef boost::asio::detail::detached_handler completion_handler_type; + + typedef void return_type; + + explicit async_result(completion_handler_type&) + { + } + + void get() + { + } + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + static return_type initiate( + BOOST_ASIO_MOVE_ARG(Initiation) initiation, + BOOST_ASIO_MOVE_ARG(RawCompletionToken), + BOOST_ASIO_MOVE_ARG(Args)... args) + { + BOOST_ASIO_MOVE_CAST(Initiation)(initiation)( + detail::detached_handler(detached_t()), + BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + static return_type initiate( + BOOST_ASIO_MOVE_ARG(Initiation) initiation, + BOOST_ASIO_MOVE_ARG(RawCompletionToken)) + { + BOOST_ASIO_MOVE_CAST(Initiation)(initiation)( + detail::detached_handler(detached_t())); + } + +#define BOOST_ASIO_PRIVATE_INITIATE_DEF(n) \ + template \ + static return_type initiate( \ + BOOST_ASIO_MOVE_ARG(Initiation) initiation, \ + BOOST_ASIO_MOVE_ARG(RawCompletionToken), \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + BOOST_ASIO_MOVE_CAST(Initiation)(initiation)( \ + detail::detached_handler(detached_t()), \ + BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_INITIATE_DEF) +#undef BOOST_ASIO_PRIVATE_INITIATE_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_DETACHED_HPP diff --git a/boost/asio/impl/dispatch.hpp b/boost/asio/impl/dispatch.hpp new file mode 100644 index 0000000..bcba2ee --- /dev/null +++ b/boost/asio/impl/dispatch.hpp @@ -0,0 +1,93 @@ +// +// impl/dispatch.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_DISPATCH_HPP +#define BOOST_ASIO_IMPL_DISPATCH_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct initiate_dispatch +{ + template + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) const + { + typedef typename decay::type DecayedHandler; + + typename associated_executor::type ex( + (get_associated_executor)(handler)); + + typename associated_allocator::type alloc( + (get_associated_allocator)(handler)); + + ex.dispatch(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); + } + + template + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + BOOST_ASIO_MOVE_ARG(Executor) ex) const + { + typedef typename decay::type DecayedHandler; + + typename associated_allocator::type alloc( + (get_associated_allocator)(handler)); + + ex.dispatch(detail::work_dispatcher( + BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)), alloc); + } +}; + +} // namespace detail + +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( + BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + return async_initiate( + detail::initiate_dispatch(), token); +} + +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( + const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if::value>::type*) +{ + return async_initiate( + detail::initiate_dispatch(), token, ex); +} + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) dispatch( + ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if::value>::type*) +{ + return (dispatch)(ctx.get_executor(), + BOOST_ASIO_MOVE_CAST(CompletionToken)(token)); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_DISPATCH_HPP diff --git a/boost/asio/impl/error.ipp b/boost/asio/impl/error.ipp new file mode 100644 index 0000000..0dcb125 --- /dev/null +++ b/boost/asio/impl/error.ipp @@ -0,0 +1,130 @@ +// +// impl/error.ipp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_ERROR_IPP +#define BOOST_ASIO_IMPL_ERROR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace error { + +#if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + +namespace detail { + +class netdb_category : public boost::system::error_category +{ +public: + const char* name() const BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT + { + return "asio.netdb"; + } + + std::string message(int value) const + { + if (value == error::host_not_found) + return "Host not found (authoritative)"; + if (value == error::host_not_found_try_again) + return "Host not found (non-authoritative), try again later"; + if (value == error::no_data) + return "The query is valid, but it does not have associated data"; + if (value == error::no_recovery) + return "A non-recoverable error occurred during database lookup"; + return "asio.netdb error"; + } +}; + +} // namespace detail + +const boost::system::error_category& get_netdb_category() +{ + static detail::netdb_category instance; + return instance; +} + +namespace detail { + +class addrinfo_category : public boost::system::error_category +{ +public: + const char* name() const BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT + { + return "asio.addrinfo"; + } + + std::string message(int value) const + { + if (value == error::service_not_found) + return "Service not found"; + if (value == error::socket_type_not_supported) + return "Socket type not supported"; + return "asio.addrinfo error"; + } +}; + +} // namespace detail + +const boost::system::error_category& get_addrinfo_category() +{ + static detail::addrinfo_category instance; + return instance; +} + +#endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + +namespace detail { + +class misc_category : public boost::system::error_category +{ +public: + const char* name() const BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT + { + return "asio.misc"; + } + + std::string message(int value) const + { + if (value == error::already_open) + return "Already open"; + if (value == error::eof) + return "End of file"; + if (value == error::not_found) + return "Element not found"; + if (value == error::fd_set_failure) + return "The descriptor does not fit into the select call's fd_set"; + return "asio.misc error"; + } +}; + +} // namespace detail + +const boost::system::error_category& get_misc_category() +{ + static detail::misc_category instance; + return instance; +} + +} // namespace error +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_ERROR_IPP diff --git a/boost/asio/impl/execution_context.hpp b/boost/asio/impl/execution_context.hpp new file mode 100644 index 0000000..a1617f8 --- /dev/null +++ b/boost/asio/impl/execution_context.hpp @@ -0,0 +1,111 @@ +// +// impl/execution_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_EXECUTION_CONTEXT_HPP +#define BOOST_ASIO_IMPL_EXECUTION_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +#if !defined(GENERATING_DOCUMENTATION) + +template +inline Service& use_service(execution_context& e) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast(static_cast(0)); + + return e.service_registry_->template use_service(); +} + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +Service& make_service(execution_context& e, BOOST_ASIO_MOVE_ARG(Args)... args) +{ + detail::scoped_ptr svc( + new Service(e, BOOST_ASIO_MOVE_CAST(Args)(args)...)); + e.service_registry_->template add_service(svc.get()); + Service& result = *svc; + svc.release(); + return result; +} + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +Service& make_service(execution_context& e) +{ + detail::scoped_ptr svc(new Service(e)); + e.service_registry_->template add_service(svc.get()); + Service& result = *svc; + svc.release(); + return result; +} + +#define BOOST_ASIO_PRIVATE_MAKE_SERVICE_DEF(n) \ + template \ + Service& make_service(execution_context& e, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + detail::scoped_ptr svc( \ + new Service(e, BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \ + e.service_registry_->template add_service(svc.get()); \ + Service& result = *svc; \ + svc.release(); \ + return result; \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_MAKE_SERVICE_DEF) +#undef BOOST_ASIO_PRIVATE_MAKE_SERVICE_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +inline void add_service(execution_context& e, Service* svc) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast(static_cast(0)); + + e.service_registry_->template add_service(svc); +} + +template +inline bool has_service(execution_context& e) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast(static_cast(0)); + + return e.service_registry_->template has_service(); +} + +#endif // !defined(GENERATING_DOCUMENTATION) + +inline execution_context& execution_context::service::context() +{ + return owner_; +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_EXECUTION_CONTEXT_HPP diff --git a/boost/asio/impl/execution_context.ipp b/boost/asio/impl/execution_context.ipp new file mode 100644 index 0000000..30e7bb9 --- /dev/null +++ b/boost/asio/impl/execution_context.ipp @@ -0,0 +1,84 @@ +// +// impl/execution_context.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_EXECUTION_CONTEXT_IPP +#define BOOST_ASIO_IMPL_EXECUTION_CONTEXT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +execution_context::execution_context() + : service_registry_(new boost::asio::detail::service_registry(*this)) +{ +} + +execution_context::~execution_context() +{ + shutdown(); + destroy(); + delete service_registry_; +} + +void execution_context::shutdown() +{ + service_registry_->shutdown_services(); +} + +void execution_context::destroy() +{ + service_registry_->destroy_services(); +} + +void execution_context::notify_fork( + boost::asio::execution_context::fork_event event) +{ + service_registry_->notify_fork(event); +} + +execution_context::service::service(execution_context& owner) + : owner_(owner), + next_(0) +{ +} + +execution_context::service::~service() +{ +} + +void execution_context::service::notify_fork(execution_context::fork_event) +{ +} + +service_already_exists::service_already_exists() + : std::logic_error("Service already exists.") +{ +} + +invalid_service_owner::invalid_service_owner() + : std::logic_error("Invalid service owner.") +{ +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_EXECUTION_CONTEXT_IPP diff --git a/boost/asio/impl/executor.hpp b/boost/asio/impl/executor.hpp new file mode 100644 index 0000000..b1c6cd7 --- /dev/null +++ b/boost/asio/impl/executor.hpp @@ -0,0 +1,389 @@ +// +// impl/executor.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_EXECUTOR_HPP +#define BOOST_ASIO_IMPL_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +#if !defined(GENERATING_DOCUMENTATION) + +#if defined(BOOST_ASIO_HAS_MOVE) + +// Lightweight, move-only function object wrapper. +class executor::function +{ +public: + template + explicit function(F f, const Alloc& a) + { + // Allocate and construct an operation to wrap the function. + typedef detail::executor_function func_type; + typename func_type::ptr p = { + detail::addressof(a), func_type::ptr::allocate(a), 0 }; + func_ = new (p.v) func_type(BOOST_ASIO_MOVE_CAST(F)(f), a); + p.v = 0; + } + + function(function&& other) BOOST_ASIO_NOEXCEPT + : func_(other.func_) + { + other.func_ = 0; + } + + ~function() + { + if (func_) + func_->destroy(); + } + + void operator()() + { + if (func_) + { + detail::executor_function_base* func = func_; + func_ = 0; + func->complete(); + } + } + +private: + detail::executor_function_base* func_; +}; + +#else // defined(BOOST_ASIO_HAS_MOVE) + +// Not so lightweight, copyable function object wrapper. +class executor::function +{ +public: + template + explicit function(const F& f, const Alloc&) + : impl_(new impl(f)) + { + } + + void operator()() + { + impl_->invoke_(impl_.get()); + } + +private: + // Base class for polymorphic function implementations. + struct impl_base + { + void (*invoke_)(impl_base*); + }; + + // Polymorphic function implementation. + template + struct impl : impl_base + { + impl(const F& f) + : function_(f) + { + invoke_ = &function::invoke; + } + + F function_; + }; + + // Helper to invoke a function. + template + static void invoke(impl_base* i) + { + static_cast*>(i)->function_(); + } + + detail::shared_ptr impl_; +}; + +#endif // defined(BOOST_ASIO_HAS_MOVE) + +// Default polymorphic allocator implementation. +template +class executor::impl + : public executor::impl_base +{ +public: + typedef BOOST_ASIO_REBIND_ALLOC(Allocator, impl) allocator_type; + + static impl_base* create(const Executor& e, Allocator a = Allocator()) + { + raw_mem mem(a); + impl* p = new (mem.ptr_) impl(e, a); + mem.ptr_ = 0; + return p; + } + + impl(const Executor& e, const Allocator& a) BOOST_ASIO_NOEXCEPT + : impl_base(false), + ref_count_(1), + executor_(e), + allocator_(a) + { + } + + impl_base* clone() const BOOST_ASIO_NOEXCEPT + { + ++ref_count_; + return const_cast(static_cast(this)); + } + + void destroy() BOOST_ASIO_NOEXCEPT + { + if (--ref_count_ == 0) + { + allocator_type alloc(allocator_); + impl* p = this; + p->~impl(); + alloc.deallocate(p, 1); + } + } + + void on_work_started() BOOST_ASIO_NOEXCEPT + { + executor_.on_work_started(); + } + + void on_work_finished() BOOST_ASIO_NOEXCEPT + { + executor_.on_work_finished(); + } + + execution_context& context() BOOST_ASIO_NOEXCEPT + { + return executor_.context(); + } + + void dispatch(BOOST_ASIO_MOVE_ARG(function) f) + { + executor_.dispatch(BOOST_ASIO_MOVE_CAST(function)(f), allocator_); + } + + void post(BOOST_ASIO_MOVE_ARG(function) f) + { + executor_.post(BOOST_ASIO_MOVE_CAST(function)(f), allocator_); + } + + void defer(BOOST_ASIO_MOVE_ARG(function) f) + { + executor_.defer(BOOST_ASIO_MOVE_CAST(function)(f), allocator_); + } + + type_id_result_type target_type() const BOOST_ASIO_NOEXCEPT + { + return type_id(); + } + + void* target() BOOST_ASIO_NOEXCEPT + { + return &executor_; + } + + const void* target() const BOOST_ASIO_NOEXCEPT + { + return &executor_; + } + + bool equals(const impl_base* e) const BOOST_ASIO_NOEXCEPT + { + if (this == e) + return true; + if (target_type() != e->target_type()) + return false; + return executor_ == *static_cast(e->target()); + } + +private: + mutable detail::atomic_count ref_count_; + Executor executor_; + Allocator allocator_; + + struct raw_mem + { + allocator_type allocator_; + impl* ptr_; + + explicit raw_mem(const Allocator& a) + : allocator_(a), + ptr_(allocator_.allocate(1)) + { + } + + ~raw_mem() + { + if (ptr_) + allocator_.deallocate(ptr_, 1); + } + + private: + // Disallow copying and assignment. + raw_mem(const raw_mem&); + raw_mem operator=(const raw_mem&); + }; +}; + +// Polymorphic allocator specialisation for system_executor. +template +class executor::impl + : public executor::impl_base +{ +public: + static impl_base* create(const system_executor&, + const Allocator& = Allocator()) + { + return &detail::global > >(); + } + + impl() + : impl_base(true) + { + } + + impl_base* clone() const BOOST_ASIO_NOEXCEPT + { + return const_cast(static_cast(this)); + } + + void destroy() BOOST_ASIO_NOEXCEPT + { + } + + void on_work_started() BOOST_ASIO_NOEXCEPT + { + executor_.on_work_started(); + } + + void on_work_finished() BOOST_ASIO_NOEXCEPT + { + executor_.on_work_finished(); + } + + execution_context& context() BOOST_ASIO_NOEXCEPT + { + return executor_.context(); + } + + void dispatch(BOOST_ASIO_MOVE_ARG(function) f) + { + executor_.dispatch(BOOST_ASIO_MOVE_CAST(function)(f), allocator_); + } + + void post(BOOST_ASIO_MOVE_ARG(function) f) + { + executor_.post(BOOST_ASIO_MOVE_CAST(function)(f), allocator_); + } + + void defer(BOOST_ASIO_MOVE_ARG(function) f) + { + executor_.defer(BOOST_ASIO_MOVE_CAST(function)(f), allocator_); + } + + type_id_result_type target_type() const BOOST_ASIO_NOEXCEPT + { + return type_id(); + } + + void* target() BOOST_ASIO_NOEXCEPT + { + return &executor_; + } + + const void* target() const BOOST_ASIO_NOEXCEPT + { + return &executor_; + } + + bool equals(const impl_base* e) const BOOST_ASIO_NOEXCEPT + { + return this == e; + } + +private: + system_executor executor_; + Allocator allocator_; +}; + +template +executor::executor(Executor e) + : impl_(impl >::create(e)) +{ +} + +template +executor::executor(allocator_arg_t, const Allocator& a, Executor e) + : impl_(impl::create(e, a)) +{ +} + +template +void executor::dispatch(BOOST_ASIO_MOVE_ARG(Function) f, + const Allocator& a) const +{ + impl_base* i = get_impl(); + if (i->fast_dispatch_) + system_executor().dispatch(BOOST_ASIO_MOVE_CAST(Function)(f), a); + else + i->dispatch(function(BOOST_ASIO_MOVE_CAST(Function)(f), a)); +} + +template +void executor::post(BOOST_ASIO_MOVE_ARG(Function) f, + const Allocator& a) const +{ + get_impl()->post(function(BOOST_ASIO_MOVE_CAST(Function)(f), a)); +} + +template +void executor::defer(BOOST_ASIO_MOVE_ARG(Function) f, + const Allocator& a) const +{ + get_impl()->defer(function(BOOST_ASIO_MOVE_CAST(Function)(f), a)); +} + +template +Executor* executor::target() BOOST_ASIO_NOEXCEPT +{ + return impl_ && impl_->target_type() == type_id() + ? static_cast(impl_->target()) : 0; +} + +template +const Executor* executor::target() const BOOST_ASIO_NOEXCEPT +{ + return impl_ && impl_->target_type() == type_id() + ? static_cast(impl_->target()) : 0; +} + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_EXECUTOR_HPP diff --git a/boost/asio/impl/executor.ipp b/boost/asio/impl/executor.ipp new file mode 100644 index 0000000..289265d --- /dev/null +++ b/boost/asio/impl/executor.ipp @@ -0,0 +1,40 @@ +// +// impl/executor.ipp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_EXECUTOR_IPP +#define BOOST_ASIO_IMPL_EXECUTOR_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { + +bad_executor::bad_executor() BOOST_ASIO_NOEXCEPT +{ +} + +const char* bad_executor::what() const BOOST_ASIO_NOEXCEPT_OR_NOTHROW +{ + return "bad executor"; +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_EXECUTOR_IPP diff --git a/boost/asio/impl/handler_alloc_hook.ipp b/boost/asio/impl/handler_alloc_hook.ipp new file mode 100644 index 0000000..a580f71 --- /dev/null +++ b/boost/asio/impl/handler_alloc_hook.ipp @@ -0,0 +1,54 @@ +// +// impl/handler_alloc_hook.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_HANDLER_ALLOC_HOOK_IPP +#define BOOST_ASIO_IMPL_HANDLER_ALLOC_HOOK_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +void* asio_handler_allocate(std::size_t size, ...) +{ +#if !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + return detail::thread_info_base::allocate( + detail::thread_context::thread_call_stack::top(), size); +#else // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + return ::operator new(size); +#endif // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) +} + +void asio_handler_deallocate(void* pointer, std::size_t size, ...) +{ +#if !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + detail::thread_info_base::deallocate( + detail::thread_context::thread_call_stack::top(), pointer, size); +#else // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) + (void)size; + ::operator delete(pointer); +#endif // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_HANDLER_ALLOC_HOOK_IPP diff --git a/boost/asio/impl/io_context.hpp b/boost/asio/impl/io_context.hpp new file mode 100644 index 0000000..2cf8c4b --- /dev/null +++ b/boost/asio/impl/io_context.hpp @@ -0,0 +1,357 @@ +// +// impl/io_context.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_IO_CONTEXT_HPP +#define BOOST_ASIO_IMPL_IO_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if !defined(GENERATING_DOCUMENTATION) + +namespace boost { +namespace asio { + +template +inline Service& use_service(io_context& ioc) +{ + // Check that Service meets the necessary type requirements. + (void)static_cast(static_cast(0)); + (void)static_cast(&Service::id); + + return ioc.service_registry_->template use_service(ioc); +} + +template <> +inline detail::io_context_impl& use_service( + io_context& ioc) +{ + return ioc.impl_; +} + +} // namespace asio +} // namespace boost + +#endif // !defined(GENERATING_DOCUMENTATION) + +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#else +# include +#endif + +#include + +namespace boost { +namespace asio { + +inline io_context::executor_type +io_context::get_executor() BOOST_ASIO_NOEXCEPT +{ + return executor_type(*this); +} + +#if defined(BOOST_ASIO_HAS_CHRONO) + +template +std::size_t io_context::run_for( + const chrono::duration& rel_time) +{ + return this->run_until(chrono::steady_clock::now() + rel_time); +} + +template +std::size_t io_context::run_until( + const chrono::time_point& abs_time) +{ + std::size_t n = 0; + while (this->run_one_until(abs_time)) + if (n != (std::numeric_limits::max)()) + ++n; + return n; +} + +template +std::size_t io_context::run_one_for( + const chrono::duration& rel_time) +{ + return this->run_one_until(chrono::steady_clock::now() + rel_time); +} + +template +std::size_t io_context::run_one_until( + const chrono::time_point& abs_time) +{ + typename Clock::time_point now = Clock::now(); + while (now < abs_time) + { + typename Clock::duration rel_time = abs_time - now; + if (rel_time > chrono::seconds(1)) + rel_time = chrono::seconds(1); + + boost::system::error_code ec; + std::size_t s = impl_.wait_one( + static_cast(chrono::duration_cast< + chrono::microseconds>(rel_time).count()), ec); + boost::asio::detail::throw_error(ec); + + if (s || impl_.stopped()) + return s; + + now = Clock::now(); + } + + return 0; +} + +#endif // defined(BOOST_ASIO_HAS_CHRONO) + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + +inline void io_context::reset() +{ + restart(); +} + +struct io_context::initiate_dispatch +{ + template + void operator()(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler, + io_context* self) const + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a LegacyCompletionHandler. + BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( + LegacyCompletionHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + if (self->impl_.can_dispatch()) + { + detail::fenced_block b(detail::fenced_block::full); + boost_asio_handler_invoke_helpers::invoke( + handler2.value, handler2.value); + } + else + { + // Allocate and construct an operation to wrap the handler. + typedef detail::completion_handler< + typename decay::type> op; + typename op::ptr p = { detail::addressof(handler2.value), + op::ptr::allocate(handler2.value), 0 }; + p.p = new (p.v) op(handler2.value); + + BOOST_ASIO_HANDLER_CREATION((*self, *p.p, + "io_context", self, 0, "dispatch")); + + self->impl_.do_dispatch(p.p); + p.v = p.p = 0; + } + } +}; + +template +BOOST_ASIO_INITFN_RESULT_TYPE(LegacyCompletionHandler, void ()) +io_context::dispatch(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler) +{ + return async_initiate( + initiate_dispatch(), handler, this); +} + +struct io_context::initiate_post +{ + template + void operator()(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler, + io_context* self) const + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a LegacyCompletionHandler. + BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( + LegacyCompletionHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + + bool is_continuation = + boost_asio_handler_cont_helpers::is_continuation(handler2.value); + + // Allocate and construct an operation to wrap the handler. + typedef detail::completion_handler< + typename decay::type> op; + typename op::ptr p = { detail::addressof(handler2.value), + op::ptr::allocate(handler2.value), 0 }; + p.p = new (p.v) op(handler2.value); + + BOOST_ASIO_HANDLER_CREATION((*self, *p.p, + "io_context", self, 0, "post")); + + self->impl_.post_immediate_completion(p.p, is_continuation); + p.v = p.p = 0; + } +}; + +template +BOOST_ASIO_INITFN_RESULT_TYPE(LegacyCompletionHandler, void ()) +io_context::post(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler) +{ + return async_initiate( + initiate_post(), handler, this); +} + +template +#if defined(GENERATING_DOCUMENTATION) +unspecified +#else +inline detail::wrapped_handler +#endif +io_context::wrap(Handler handler) +{ + return detail::wrapped_handler(*this, handler); +} + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +inline io_context& +io_context::executor_type::context() const BOOST_ASIO_NOEXCEPT +{ + return io_context_; +} + +inline void +io_context::executor_type::on_work_started() const BOOST_ASIO_NOEXCEPT +{ + io_context_.impl_.work_started(); +} + +inline void +io_context::executor_type::on_work_finished() const BOOST_ASIO_NOEXCEPT +{ + io_context_.impl_.work_finished(); +} + +template +void io_context::executor_type::dispatch( + BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay::type function_type; + + // Invoke immediately if we are already inside the thread pool. + if (io_context_.impl_.can_dispatch()) + { + // Make a local, non-const copy of the function. + function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); + + detail::fenced_block b(detail::fenced_block::full); + boost_asio_handler_invoke_helpers::invoke(tmp, tmp); + return; + } + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); + + BOOST_ASIO_HANDLER_CREATION((this->context(), *p.p, + "io_context", &this->context(), 0, "dispatch")); + + io_context_.impl_.post_immediate_completion(p.p, false); + p.v = p.p = 0; +} + +template +void io_context::executor_type::post( + BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); + + BOOST_ASIO_HANDLER_CREATION((this->context(), *p.p, + "io_context", &this->context(), 0, "post")); + + io_context_.impl_.post_immediate_completion(p.p, false); + p.v = p.p = 0; +} + +template +void io_context::executor_type::defer( + BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); + + BOOST_ASIO_HANDLER_CREATION((this->context(), *p.p, + "io_context", &this->context(), 0, "defer")); + + io_context_.impl_.post_immediate_completion(p.p, true); + p.v = p.p = 0; +} + +inline bool +io_context::executor_type::running_in_this_thread() const BOOST_ASIO_NOEXCEPT +{ + return io_context_.impl_.can_dispatch(); +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +inline io_context::work::work(boost::asio::io_context& io_context) + : io_context_impl_(io_context.impl_) +{ + io_context_impl_.work_started(); +} + +inline io_context::work::work(const work& other) + : io_context_impl_(other.io_context_impl_) +{ + io_context_impl_.work_started(); +} + +inline io_context::work::~work() +{ + io_context_impl_.work_finished(); +} + +inline boost::asio::io_context& io_context::work::get_io_context() +{ + return static_cast(io_context_impl_.context()); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +inline boost::asio::io_context& io_context::service::get_io_context() +{ + return static_cast(context()); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_IO_CONTEXT_HPP diff --git a/boost/asio/impl/io_context.ipp b/boost/asio/impl/io_context.ipp new file mode 100644 index 0000000..5de0718 --- /dev/null +++ b/boost/asio/impl/io_context.ipp @@ -0,0 +1,177 @@ +// +// impl/io_context.ipp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_IO_CONTEXT_IPP +#define BOOST_ASIO_IMPL_IO_CONTEXT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_IOCP) +# include +#else +# include +#endif + +#include + +namespace boost { +namespace asio { + +io_context::io_context() + : impl_(add_impl(new impl_type(*this, + BOOST_ASIO_CONCURRENCY_HINT_DEFAULT, false))) +{ +} + +io_context::io_context(int concurrency_hint) + : impl_(add_impl(new impl_type(*this, concurrency_hint == 1 + ? BOOST_ASIO_CONCURRENCY_HINT_1 : concurrency_hint, false))) +{ +} + +io_context::impl_type& io_context::add_impl(io_context::impl_type* impl) +{ + boost::asio::detail::scoped_ptr scoped_impl(impl); + boost::asio::add_service(*this, scoped_impl.get()); + return *scoped_impl.release(); +} + +io_context::~io_context() +{ +} + +io_context::count_type io_context::run() +{ + boost::system::error_code ec; + count_type s = impl_.run(ec); + boost::asio::detail::throw_error(ec); + return s; +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +io_context::count_type io_context::run(boost::system::error_code& ec) +{ + return impl_.run(ec); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +io_context::count_type io_context::run_one() +{ + boost::system::error_code ec; + count_type s = impl_.run_one(ec); + boost::asio::detail::throw_error(ec); + return s; +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +io_context::count_type io_context::run_one(boost::system::error_code& ec) +{ + return impl_.run_one(ec); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +io_context::count_type io_context::poll() +{ + boost::system::error_code ec; + count_type s = impl_.poll(ec); + boost::asio::detail::throw_error(ec); + return s; +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +io_context::count_type io_context::poll(boost::system::error_code& ec) +{ + return impl_.poll(ec); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +io_context::count_type io_context::poll_one() +{ + boost::system::error_code ec; + count_type s = impl_.poll_one(ec); + boost::asio::detail::throw_error(ec); + return s; +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +io_context::count_type io_context::poll_one(boost::system::error_code& ec) +{ + return impl_.poll_one(ec); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +void io_context::stop() +{ + impl_.stop(); +} + +bool io_context::stopped() const +{ + return impl_.stopped(); +} + +void io_context::restart() +{ + impl_.restart(); +} + +io_context::service::service(boost::asio::io_context& owner) + : execution_context::service(owner) +{ +} + +io_context::service::~service() +{ +} + +void io_context::service::shutdown() +{ +#if !defined(BOOST_ASIO_NO_DEPRECATED) + shutdown_service(); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +void io_context::service::shutdown_service() +{ +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +void io_context::service::notify_fork(io_context::fork_event ev) +{ +#if !defined(BOOST_ASIO_NO_DEPRECATED) + fork_service(ev); +#else // !defined(BOOST_ASIO_NO_DEPRECATED) + (void)ev; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +void io_context::service::fork_service(io_context::fork_event) +{ +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_IO_CONTEXT_IPP diff --git a/boost/asio/impl/post.hpp b/boost/asio/impl/post.hpp new file mode 100644 index 0000000..ac0831e --- /dev/null +++ b/boost/asio/impl/post.hpp @@ -0,0 +1,93 @@ +// +// impl/post.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_POST_HPP +#define BOOST_ASIO_IMPL_POST_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +struct initiate_post +{ + template + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler) const + { + typedef typename decay::type DecayedHandler; + + typename associated_executor::type ex( + (get_associated_executor)(handler)); + + typename associated_allocator::type alloc( + (get_associated_allocator)(handler)); + + ex.post(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); + } + + template + void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, + BOOST_ASIO_MOVE_ARG(Executor) ex) const + { + typedef typename decay::type DecayedHandler; + + typename associated_allocator::type alloc( + (get_associated_allocator)(handler)); + + ex.post(detail::work_dispatcher( + BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)), alloc); + } +}; + +} // namespace detail + +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( + BOOST_ASIO_MOVE_ARG(CompletionToken) token) +{ + return async_initiate( + detail::initiate_post(), token); +} + +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( + const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if::value>::type*) +{ + return async_initiate( + detail::initiate_post(), token, ex); +} + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( + ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if::value>::type*) +{ + return (post)(ctx.get_executor(), + BOOST_ASIO_MOVE_CAST(CompletionToken)(token)); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_POST_HPP diff --git a/boost/asio/impl/read.hpp b/boost/asio/impl/read.hpp new file mode 100644 index 0000000..6eabf0f --- /dev/null +++ b/boost/asio/impl/read.hpp @@ -0,0 +1,1081 @@ +// +// impl/read.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_READ_HPP +#define BOOST_ASIO_IMPL_READ_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +namespace detail +{ + template + std::size_t read_buffer_sequence(SyncReadStream& s, + const MutableBufferSequence& buffers, const MutableBufferIterator&, + CompletionCondition completion_condition, boost::system::error_code& ec) + { + ec = boost::system::error_code(); + boost::asio::detail::consuming_buffers tmp(buffers); + while (!tmp.empty()) + { + if (std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, tmp.total_consumed()))) + tmp.consume(s.read_some(tmp.prepare(max_size), ec)); + else + break; + } + return tmp.total_consumed();; + } +} // namespace detail + +template +std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_mutable_buffer_sequence::value + >::type*) +{ + return detail::read_buffer_sequence(s, buffers, + boost::asio::buffer_sequence_begin(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); +} + +template +inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + typename enable_if< + is_mutable_buffer_sequence::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec); + boost::asio::detail::throw_error(ec, "read"); + return bytes_transferred; +} + +template +inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + boost::system::error_code& ec, + typename enable_if< + is_mutable_buffer_sequence::value + >::type*) +{ + return read(s, buffers, transfer_all(), ec); +} + +template +inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, + typename enable_if< + is_mutable_buffer_sequence::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read(s, buffers, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); + boost::asio::detail::throw_error(ec, "read"); + return bytes_transferred; +} + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +template +std::size_t read(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + typename decay::type b( + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers)); + + ec = boost::system::error_code(); + std::size_t total_transferred = 0; + std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + std::size_t bytes_available = std::min( + std::max(512, b.capacity() - b.size()), + std::min(max_size, b.max_size() - b.size())); + while (bytes_available > 0) + { + std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec); + b.commit(bytes_transferred); + total_transferred += bytes_transferred; + max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + bytes_available = std::min( + std::max(512, b.capacity() - b.size()), + std::min(max_size, b.max_size() - b.size())); + } + return total_transferred; +} + +template +inline std::size_t read(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), transfer_all(), ec); + boost::asio::detail::throw_error(ec, "read"); + return bytes_transferred; +} + +template +inline std::size_t read(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + return read(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + transfer_all(), ec); +} + +template +inline std::size_t read(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); + boost::asio::detail::throw_error(ec, "read"); + return bytes_transferred; +} + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +template +inline std::size_t read(SyncReadStream& s, + boost::asio::basic_streambuf& b, + CompletionCondition completion_condition, boost::system::error_code& ec) +{ + return read(s, basic_streambuf_ref(b), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); +} + +template +inline std::size_t read(SyncReadStream& s, + boost::asio::basic_streambuf& b) +{ + return read(s, basic_streambuf_ref(b)); +} + +template +inline std::size_t read(SyncReadStream& s, + boost::asio::basic_streambuf& b, + boost::system::error_code& ec) +{ + return read(s, basic_streambuf_ref(b), ec); +} + +template +inline std::size_t read(SyncReadStream& s, + boost::asio::basic_streambuf& b, + CompletionCondition completion_condition) +{ + return read(s, basic_streambuf_ref(b), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); +} + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +template +std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + DynamicBuffer_v2& b = buffers; + + ec = boost::system::error_code(); + std::size_t total_transferred = 0; + std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + std::size_t bytes_available = std::min( + std::max(512, b.capacity() - b.size()), + std::min(max_size, b.max_size() - b.size())); + while (bytes_available > 0) + { + std::size_t pos = b.size(); + b.grow(bytes_available); + std::size_t bytes_transferred = s.read_some( + b.data(pos, bytes_available), ec); + b.shrink(bytes_available - bytes_transferred); + total_transferred += bytes_transferred; + max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + bytes_available = std::min( + std::max(512, b.capacity() - b.size()), + std::min(max_size, b.max_size() - b.size())); + } + return total_transferred; +} + +template +inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), transfer_all(), ec); + boost::asio::detail::throw_error(ec, "read"); + return bytes_transferred; +} + +template +inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + return read(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + transfer_all(), ec); +} + +template +inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); + boost::asio::detail::throw_error(ec, "read"); + return bytes_transferred; +} + +namespace detail +{ + template + class read_op + : detail::base_from_completion_cond + { + public: + read_op(AsyncReadStream& stream, const MutableBufferSequence& buffers, + CompletionCondition& completion_condition, ReadHandler& handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), + buffers_(buffers), + start_(0), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + read_op(const read_op& other) + : detail::base_from_completion_cond(other), + stream_(other.stream_), + buffers_(other.buffers_), + start_(other.start_), + handler_(other.handler_) + { + } + + read_op(read_op&& other) + : detail::base_from_completion_cond( + BOOST_ASIO_MOVE_CAST(detail::base_from_completion_cond< + CompletionCondition>)(other)), + stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(buffers_type)(other.buffers_)), + start_(other.start_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t max_size; + switch (start_ = start) + { + case 1: + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + do + { + stream_.async_read_some(buffers_.prepare(max_size), + BOOST_ASIO_MOVE_CAST(read_op)(*this)); + return; default: + buffers_.consume(bytes_transferred); + if ((!ec && bytes_transferred == 0) || buffers_.empty()) + break; + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + } while (max_size > 0); + + handler_(ec, buffers_.total_consumed()); + } + } + + //private: + typedef boost::asio::detail::consuming_buffers buffers_type; + + AsyncReadStream& stream_; + buffers_type buffers_; + int start_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + read_op* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + read_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void start_read_buffer_sequence_op(AsyncReadStream& stream, + const MutableBufferSequence& buffers, const MutableBufferIterator&, + CompletionCondition& completion_condition, ReadHandler& handler) + { + detail::read_op( + stream, buffers, completion_condition, handler)( + boost::system::error_code(), 0, 1); + } + + struct initiate_async_read_buffer_sequence + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue handler2(handler); + non_const_lvalue completion_cond2(completion_cond); + start_read_buffer_sequence_op(*s, buffers, + boost::asio::buffer_sequence_begin(buffers), + completion_cond2.value, handler2.value); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::read_op, + Allocator> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::read_op& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::read_op, + Executor> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::read_op& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_mutable_buffer_sequence::value + >::type*) +{ + return async_initiate( + detail::initiate_async_read_buffer_sequence(), handler, &s, buffers, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); +} + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_mutable_buffer_sequence::value + >::type*) +{ + return async_initiate( + detail::initiate_async_read_buffer_sequence(), + handler, &s, buffers, transfer_all()); +} + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +namespace detail +{ + template + class read_dynbuf_v1_op + : detail::base_from_completion_cond + { + public: + template + read_dynbuf_v1_op(AsyncReadStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, + CompletionCondition& completion_condition, ReadHandler& handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), + start_(0), + total_transferred_(0), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + read_dynbuf_v1_op(const read_dynbuf_v1_op& other) + : detail::base_from_completion_cond(other), + stream_(other.stream_), + buffers_(other.buffers_), + start_(other.start_), + total_transferred_(other.total_transferred_), + handler_(other.handler_) + { + } + + read_dynbuf_v1_op(read_dynbuf_v1_op&& other) + : detail::base_from_completion_cond( + BOOST_ASIO_MOVE_CAST(detail::base_from_completion_cond< + CompletionCondition>)(other)), + stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)), + start_(other.start_), + total_transferred_(other.total_transferred_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t max_size, bytes_available; + switch (start_ = start) + { + case 1: + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available = std::min( + std::max(512, + buffers_.capacity() - buffers_.size()), + std::min(max_size, + buffers_.max_size() - buffers_.size())); + for (;;) + { + stream_.async_read_some(buffers_.prepare(bytes_available), + BOOST_ASIO_MOVE_CAST(read_dynbuf_v1_op)(*this)); + return; default: + total_transferred_ += bytes_transferred; + buffers_.commit(bytes_transferred); + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available = std::min( + std::max(512, + buffers_.capacity() - buffers_.size()), + std::min(max_size, + buffers_.max_size() - buffers_.size())); + if ((!ec && bytes_transferred == 0) || bytes_available == 0) + break; + } + + handler_(ec, static_cast(total_transferred_)); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v1 buffers_; + int start_; + std::size_t total_transferred_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_dynbuf_v1_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_dynbuf_v1_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + read_dynbuf_v1_op* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + read_dynbuf_v1_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_dynbuf_v1_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_read_dynbuf_v1 + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue handler2(handler); + non_const_lvalue completion_cond2(completion_cond); + read_dynbuf_v1_op::type, + CompletionCondition, typename decay::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + completion_cond2.value, handler2.value)( + boost::system::error_code(), 0, 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::read_dynbuf_v1_op, + Allocator> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::read_dynbuf_v1_op& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::read_dynbuf_v1_op, + Executor> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::read_dynbuf_v1_op& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + return async_read(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + transfer_all(), BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + return async_initiate( + detail::initiate_async_read_dynbuf_v1(), handler, &s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); +} + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, basic_streambuf& b, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_read(s, basic_streambuf_ref(b), + BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, basic_streambuf& b, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_read(s, basic_streambuf_ref(b), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), + BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +namespace detail +{ + template + class read_dynbuf_v2_op + : detail::base_from_completion_cond + { + public: + template + read_dynbuf_v2_op(AsyncReadStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, + CompletionCondition& completion_condition, ReadHandler& handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), + start_(0), + total_transferred_(0), + bytes_available_(0), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + read_dynbuf_v2_op(const read_dynbuf_v2_op& other) + : detail::base_from_completion_cond(other), + stream_(other.stream_), + buffers_(other.buffers_), + start_(other.start_), + total_transferred_(other.total_transferred_), + bytes_available_(other.bytes_available_), + handler_(other.handler_) + { + } + + read_dynbuf_v2_op(read_dynbuf_v2_op&& other) + : detail::base_from_completion_cond( + BOOST_ASIO_MOVE_CAST(detail::base_from_completion_cond< + CompletionCondition>)(other)), + stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)), + start_(other.start_), + total_transferred_(other.total_transferred_), + bytes_available_(other.bytes_available_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t max_size, pos; + switch (start_ = start) + { + case 1: + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available_ = std::min( + std::max(512, + buffers_.capacity() - buffers_.size()), + std::min(max_size, + buffers_.max_size() - buffers_.size())); + for (;;) + { + pos = buffers_.size(); + buffers_.grow(bytes_available_); + stream_.async_read_some(buffers_.data(pos, bytes_available_), + BOOST_ASIO_MOVE_CAST(read_dynbuf_v2_op)(*this)); + return; default: + total_transferred_ += bytes_transferred; + buffers_.shrink(bytes_available_ - bytes_transferred); + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available_ = std::min( + std::max(512, + buffers_.capacity() - buffers_.size()), + std::min(max_size, + buffers_.max_size() - buffers_.size())); + if ((!ec && bytes_transferred == 0) || bytes_available_ == 0) + break; + } + + handler_(ec, static_cast(total_transferred_)); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v2 buffers_; + int start_; + std::size_t total_transferred_; + std::size_t bytes_available_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_dynbuf_v2_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_dynbuf_v2_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + read_dynbuf_v2_op* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + read_dynbuf_v2_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_dynbuf_v2_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_read_dynbuf_v2 + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue handler2(handler); + non_const_lvalue completion_cond2(completion_cond); + read_dynbuf_v2_op::type, + CompletionCondition, typename decay::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + completion_cond2.value, handler2.value)( + boost::system::error_code(), 0, 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::read_dynbuf_v2_op, + Allocator> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::read_dynbuf_v2_op& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::read_dynbuf_v2_op, + Executor> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::read_dynbuf_v2_op& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + return async_read(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + transfer_all(), BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + return async_initiate( + detail::initiate_async_read_dynbuf_v2(), handler, &s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_READ_HPP diff --git a/boost/asio/impl/read_at.hpp b/boost/asio/impl/read_at.hpp new file mode 100644 index 0000000..8152ef9 --- /dev/null +++ b/boost/asio/impl/read_at.hpp @@ -0,0 +1,657 @@ +// +// impl/read_at.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_READ_AT_HPP +#define BOOST_ASIO_IMPL_READ_AT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +namespace detail +{ + template + std::size_t read_at_buffer_sequence(SyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, + const MutableBufferIterator&, CompletionCondition completion_condition, + boost::system::error_code& ec) + { + ec = boost::system::error_code(); + boost::asio::detail::consuming_buffers tmp(buffers); + while (!tmp.empty()) + { + if (std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, tmp.total_consumed()))) + { + tmp.consume(d.read_some_at(offset + tmp.total_consumed(), + tmp.prepare(max_size), ec)); + } + else + break; + } + return tmp.total_consumed();; + } +} // namespace detail + +template +std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, boost::system::error_code& ec) +{ + return detail::read_at_buffer_sequence(d, offset, buffers, + boost::asio::buffer_sequence_begin(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); +} + +template +inline std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_at( + d, offset, buffers, transfer_all(), ec); + boost::asio::detail::throw_error(ec, "read_at"); + return bytes_transferred; +} + +template +inline std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, + boost::system::error_code& ec) +{ + return read_at(d, offset, buffers, transfer_all(), ec); +} + +template +inline std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, + CompletionCondition completion_condition) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_at(d, offset, buffers, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); + boost::asio::detail::throw_error(ec, "read_at"); + return bytes_transferred; +} + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +template +std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, boost::asio::basic_streambuf& b, + CompletionCondition completion_condition, boost::system::error_code& ec) +{ + ec = boost::system::error_code(); + std::size_t total_transferred = 0; + std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + std::size_t bytes_available = read_size_helper(b, max_size); + while (bytes_available > 0) + { + std::size_t bytes_transferred = d.read_some_at( + offset + total_transferred, b.prepare(bytes_available), ec); + b.commit(bytes_transferred); + total_transferred += bytes_transferred; + max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + bytes_available = read_size_helper(b, max_size); + } + return total_transferred; +} + +template +inline std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, boost::asio::basic_streambuf& b) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_at( + d, offset, b, transfer_all(), ec); + boost::asio::detail::throw_error(ec, "read_at"); + return bytes_transferred; +} + +template +inline std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, boost::asio::basic_streambuf& b, + boost::system::error_code& ec) +{ + return read_at(d, offset, b, transfer_all(), ec); +} + +template +inline std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, boost::asio::basic_streambuf& b, + CompletionCondition completion_condition) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_at(d, offset, b, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); + boost::asio::detail::throw_error(ec, "read_at"); + return bytes_transferred; +} + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +namespace detail +{ + template + class read_at_op + : detail::base_from_completion_cond + { + public: + read_at_op(AsyncRandomAccessReadDevice& device, + uint64_t offset, const MutableBufferSequence& buffers, + CompletionCondition& completion_condition, ReadHandler& handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), + offset_(offset), + buffers_(buffers), + start_(0), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + read_at_op(const read_at_op& other) + : detail::base_from_completion_cond(other), + device_(other.device_), + offset_(other.offset_), + buffers_(other.buffers_), + start_(other.start_), + handler_(other.handler_) + { + } + + read_at_op(read_at_op&& other) + : detail::base_from_completion_cond( + BOOST_ASIO_MOVE_CAST(detail::base_from_completion_cond< + CompletionCondition>)(other)), + device_(other.device_), + offset_(other.offset_), + buffers_(BOOST_ASIO_MOVE_CAST(buffers_type)(other.buffers_)), + start_(other.start_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t max_size; + switch (start_ = start) + { + case 1: + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + do + { + device_.async_read_some_at( + offset_ + buffers_.total_consumed(), buffers_.prepare(max_size), + BOOST_ASIO_MOVE_CAST(read_at_op)(*this)); + return; default: + buffers_.consume(bytes_transferred); + if ((!ec && bytes_transferred == 0) || buffers_.empty()) + break; + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + } while (max_size > 0); + + handler_(ec, buffers_.total_consumed()); + } + } + + //private: + typedef boost::asio::detail::consuming_buffers buffers_type; + + AsyncRandomAccessReadDevice& device_; + uint64_t offset_; + buffers_type buffers_; + int start_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_at_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_at_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + read_at_op* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + read_at_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_at_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void start_read_at_buffer_sequence_op(AsyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, + const MutableBufferIterator&, CompletionCondition& completion_condition, + ReadHandler& handler) + { + detail::read_at_op( + d, offset, buffers, completion_condition, handler)( + boost::system::error_code(), 0, 1); + } + + struct initiate_async_read_at_buffer_sequence + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncRandomAccessReadDevice* d, uint64_t offset, + const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue handler2(handler); + non_const_lvalue completion_cond2(completion_cond); + start_read_at_buffer_sequence_op(*d, offset, buffers, + boost::asio::buffer_sequence_begin(buffers), + completion_cond2.value, handler2.value); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::read_at_op, + Allocator> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::read_at_op& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::read_at_op, + Executor> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::read_at_op& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_at(AsyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_initiate( + detail::initiate_async_read_at_buffer_sequence(), handler, &d, offset, + buffers, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); +} + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_at(AsyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_initiate( + detail::initiate_async_read_at_buffer_sequence(), + handler, &d, offset, buffers, transfer_all()); +} + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +namespace detail +{ + template + class read_at_streambuf_op + : detail::base_from_completion_cond + { + public: + read_at_streambuf_op(AsyncRandomAccessReadDevice& device, + uint64_t offset, basic_streambuf& streambuf, + CompletionCondition& completion_condition, ReadHandler& handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), + offset_(offset), + streambuf_(streambuf), + start_(0), + total_transferred_(0), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + read_at_streambuf_op(const read_at_streambuf_op& other) + : detail::base_from_completion_cond(other), + device_(other.device_), + offset_(other.offset_), + streambuf_(other.streambuf_), + start_(other.start_), + total_transferred_(other.total_transferred_), + handler_(other.handler_) + { + } + + read_at_streambuf_op(read_at_streambuf_op&& other) + : detail::base_from_completion_cond( + BOOST_ASIO_MOVE_CAST(detail::base_from_completion_cond< + CompletionCondition>)(other)), + device_(other.device_), + offset_(other.offset_), + streambuf_(other.streambuf_), + start_(other.start_), + total_transferred_(other.total_transferred_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t max_size, bytes_available; + switch (start_ = start) + { + case 1: + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available = read_size_helper(streambuf_, max_size); + for (;;) + { + device_.async_read_some_at(offset_ + total_transferred_, + streambuf_.prepare(bytes_available), + BOOST_ASIO_MOVE_CAST(read_at_streambuf_op)(*this)); + return; default: + total_transferred_ += bytes_transferred; + streambuf_.commit(bytes_transferred); + max_size = this->check_for_completion(ec, total_transferred_); + bytes_available = read_size_helper(streambuf_, max_size); + if ((!ec && bytes_transferred == 0) || bytes_available == 0) + break; + } + + handler_(ec, static_cast(total_transferred_)); + } + } + + //private: + AsyncRandomAccessReadDevice& device_; + uint64_t offset_; + boost::asio::basic_streambuf& streambuf_; + int start_; + std::size_t total_transferred_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_at_streambuf_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_at_streambuf_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + read_at_streambuf_op* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + read_at_streambuf_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_at_streambuf_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_read_at_streambuf + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncRandomAccessReadDevice* d, uint64_t offset, + basic_streambuf* b, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue handler2(handler); + non_const_lvalue completion_cond2(completion_cond); + read_at_streambuf_op::type>( + *d, offset, *b, completion_cond2.value, handler2.value)( + boost::system::error_code(), 0, 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::read_at_streambuf_op, + Allocator1> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::read_at_streambuf_op& h, + const Allocator1& a = Allocator1()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::read_at_streambuf_op, + Executor1> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::read_at_streambuf_op& h, + const Executor1& ex = Executor1()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_at(AsyncRandomAccessReadDevice& d, + uint64_t offset, boost::asio::basic_streambuf& b, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_initiate( + detail::initiate_async_read_at_streambuf(), handler, &d, offset, + &b, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); +} + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_at(AsyncRandomAccessReadDevice& d, + uint64_t offset, boost::asio::basic_streambuf& b, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_initiate( + detail::initiate_async_read_at_streambuf(), + handler, &d, offset, &b, transfer_all()); +} + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_READ_AT_HPP diff --git a/boost/asio/impl/read_until.hpp b/boost/asio/impl/read_until.hpp new file mode 100644 index 0000000..63b86f8 --- /dev/null +++ b/boost/asio/impl/read_until.hpp @@ -0,0 +1,3006 @@ +// +// impl/read_until.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_READ_UNTIL_HPP +#define BOOST_ASIO_IMPL_READ_UNTIL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +namespace detail +{ + // Algorithm that finds a subsequence of equal values in a sequence. Returns + // (iterator,true) if a full match was found, in which case the iterator + // points to the beginning of the match. Returns (iterator,false) if a + // partial match was found at the end of the first sequence, in which case + // the iterator points to the beginning of the partial match. Returns + // (last1,false) if no full or partial match was found. + template + std::pair partial_search( + Iterator1 first1, Iterator1 last1, Iterator2 first2, Iterator2 last2) + { + for (Iterator1 iter1 = first1; iter1 != last1; ++iter1) + { + Iterator1 test_iter1 = iter1; + Iterator2 test_iter2 = first2; + for (;; ++test_iter1, ++test_iter2) + { + if (test_iter2 == last2) + return std::make_pair(iter1, true); + if (test_iter1 == last1) + { + if (test_iter2 != first2) + return std::make_pair(iter1, false); + else + break; + } + if (*test_iter1 != *test_iter2) + break; + } + } + return std::make_pair(last1, false); + } +} // namespace detail + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +template +inline std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, char delim, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim, ec); + boost::asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + char delim, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + typename decay::type b( + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers)); + + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; + typedef buffers_iterator iterator; + buffers_type data_buffers = b.data(); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position; + iterator end = iterator::end(data_buffers); + + // Look for a match. + iterator iter = std::find(start_pos, end, delim); + if (iter != end) + { + // Found a match. We're done. + ec = boost::system::error_code(); + return iter - begin + 1; + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = std::min( + std::max(512, b.capacity() - b.size()), + std::min(65536, b.max_size() - b.size())); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +template +inline std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_STRING_VIEW_PARAM delim, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim, ec); + boost::asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + typename decay::type b( + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers)); + + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; + typedef buffers_iterator iterator; + buffers_type data_buffers = b.data(); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position; + iterator end = iterator::end(data_buffers); + + // Look for a match. + std::pair result = detail::partial_search( + start_pos, end, delim.begin(), delim.end()); + if (result.first != end) + { + if (result.second) + { + // Full match. We're done. + ec = boost::system::error_code(); + return result.first - begin + delim.length(); + } + else + { + // Partial match. Next search needs to start from beginning of match. + search_position = result.first - begin; + } + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = std::min( + std::max(512, b.capacity() - b.size()), + std::min(65536, b.max_size() - b.size())); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if defined(BOOST_ASIO_HAS_BOOST_REGEX) + +template +inline std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + const boost::regex& expr, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), expr, ec); + boost::asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + const boost::regex& expr, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + typename decay::type b( + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers)); + + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; + typedef buffers_iterator iterator; + buffers_type data_buffers = b.data(); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position; + iterator end = iterator::end(data_buffers); + + // Look for a match. + boost::match_results >::allocator_type> + match_results; + if (regex_search(start_pos, end, match_results, expr, + boost::match_default | boost::match_partial)) + { + if (match_results[0].matched) + { + // Full match. We're done. + ec = boost::system::error_code(); + return match_results[0].second - begin; + } + else + { + // Partial match. Next search needs to start from beginning of match. + search_position = match_results[0].first - begin; + } + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = std::min( + std::max(512, b.capacity() - b.size()), + std::min(65536, b.max_size() - b.size())); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) + +template +inline std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + MatchCondition match_condition, + typename enable_if< + is_match_condition::value + && is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + match_condition, ec); + boost::asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + MatchCondition match_condition, boost::system::error_code& ec, + typename enable_if< + is_match_condition::value + && is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + typename decay::type b( + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers)); + + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v1::const_buffers_type buffers_type; + typedef buffers_iterator iterator; + buffers_type data_buffers = b.data(); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position; + iterator end = iterator::end(data_buffers); + + // Look for a match. + std::pair result = match_condition(start_pos, end); + if (result.second) + { + // Full match. We're done. + ec = boost::system::error_code(); + return result.first - begin; + } + else if (result.first != end) + { + // Partial match. Next search needs to start from beginning of match. + search_position = result.first - begin; + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = std::min( + std::max(512, b.capacity() - b.size()), + std::min(65536, b.max_size() - b.size())); + b.commit(s.read_some(b.prepare(bytes_to_read), ec)); + if (ec) + return 0; + } +} + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +template +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, char delim) +{ + return read_until(s, basic_streambuf_ref(b), delim); +} + +template +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, char delim, + boost::system::error_code& ec) +{ + return read_until(s, basic_streambuf_ref(b), delim, ec); +} + +template +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, + BOOST_ASIO_STRING_VIEW_PARAM delim) +{ + return read_until(s, basic_streambuf_ref(b), delim); +} + +template +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, + BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec) +{ + return read_until(s, basic_streambuf_ref(b), delim, ec); +} + +#if defined(BOOST_ASIO_HAS_BOOST_REGEX) + +template +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, const boost::regex& expr) +{ + return read_until(s, basic_streambuf_ref(b), expr); +} + +template +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, const boost::regex& expr, + boost::system::error_code& ec) +{ + return read_until(s, basic_streambuf_ref(b), expr, ec); +} + +#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) + +template +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, MatchCondition match_condition, + typename enable_if::value>::type*) +{ + return read_until(s, basic_streambuf_ref(b), match_condition); +} + +template +inline std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, + MatchCondition match_condition, boost::system::error_code& ec, + typename enable_if::value>::type*) +{ + return read_until(s, basic_streambuf_ref(b), match_condition, ec); +} + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +template +inline std::size_t read_until(SyncReadStream& s, + DynamicBuffer_v2 buffers, char delim, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim, ec); + boost::asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + char delim, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + DynamicBuffer_v2& b = buffers; + + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type buffers_type; + typedef buffers_iterator iterator; + buffers_type data_buffers = + const_cast(b).data(0, b.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position; + iterator end = iterator::end(data_buffers); + + // Look for a match. + iterator iter = std::find(start_pos, end, delim); + if (iter != end) + { + // Found a match. We're done. + ec = boost::system::error_code(); + return iter - begin + 1; + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = std::min( + std::max(512, b.capacity() - b.size()), + std::min(65536, b.max_size() - b.size())); + std::size_t pos = b.size(); + b.grow(bytes_to_read); + std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec); + b.shrink(bytes_to_read - bytes_transferred); + if (ec) + return 0; + } +} + +template +inline std::size_t read_until(SyncReadStream& s, + DynamicBuffer_v2 buffers, BOOST_ASIO_STRING_VIEW_PARAM delim, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim, ec); + boost::asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + DynamicBuffer_v2& b = buffers; + + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type buffers_type; + typedef buffers_iterator iterator; + buffers_type data_buffers = + const_cast(b).data(0, b.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position; + iterator end = iterator::end(data_buffers); + + // Look for a match. + std::pair result = detail::partial_search( + start_pos, end, delim.begin(), delim.end()); + if (result.first != end) + { + if (result.second) + { + // Full match. We're done. + ec = boost::system::error_code(); + return result.first - begin + delim.length(); + } + else + { + // Partial match. Next search needs to start from beginning of match. + search_position = result.first - begin; + } + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = std::min( + std::max(512, b.capacity() - b.size()), + std::min(65536, b.max_size() - b.size())); + std::size_t pos = b.size(); + b.grow(bytes_to_read); + std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec); + b.shrink(bytes_to_read - bytes_transferred); + if (ec) + return 0; + } +} + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if defined(BOOST_ASIO_HAS_BOOST_REGEX) + +template +inline std::size_t read_until(SyncReadStream& s, + DynamicBuffer_v2 buffers, const boost::regex& expr, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), expr, ec); + boost::asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + const boost::regex& expr, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + DynamicBuffer_v2& b = buffers; + + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type buffers_type; + typedef buffers_iterator iterator; + buffers_type data_buffers = + const_cast(b).data(0, b.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position; + iterator end = iterator::end(data_buffers); + + // Look for a match. + boost::match_results >::allocator_type> + match_results; + if (regex_search(start_pos, end, match_results, expr, + boost::match_default | boost::match_partial)) + { + if (match_results[0].matched) + { + // Full match. We're done. + ec = boost::system::error_code(); + return match_results[0].second - begin; + } + else + { + // Partial match. Next search needs to start from beginning of match. + search_position = match_results[0].first - begin; + } + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = std::min( + std::max(512, b.capacity() - b.size()), + std::min(65536, b.max_size() - b.size())); + std::size_t pos = b.size(); + b.grow(bytes_to_read); + std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec); + b.shrink(bytes_to_read - bytes_transferred); + if (ec) + return 0; + } +} + +#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) + +template +inline std::size_t read_until(SyncReadStream& s, + DynamicBuffer_v2 buffers, MatchCondition match_condition, + typename enable_if< + is_match_condition::value + && is_dynamic_buffer_v2::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = read_until(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + match_condition, ec); + boost::asio::detail::throw_error(ec, "read_until"); + return bytes_transferred; +} + +template +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + MatchCondition match_condition, boost::system::error_code& ec, + typename enable_if< + is_match_condition::value + && is_dynamic_buffer_v2::value + >::type*) +{ + DynamicBuffer_v2& b = buffers; + + std::size_t search_position = 0; + for (;;) + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type buffers_type; + typedef buffers_iterator iterator; + buffers_type data_buffers = + const_cast(b).data(0, b.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position; + iterator end = iterator::end(data_buffers); + + // Look for a match. + std::pair result = match_condition(start_pos, end); + if (result.second) + { + // Full match. We're done. + ec = boost::system::error_code(); + return result.first - begin; + } + else if (result.first != end) + { + // Partial match. Next search needs to start from beginning of match. + search_position = result.first - begin; + } + else + { + // No match. Next search can start with the new data. + search_position = end - begin; + } + + // Check if buffer is full. + if (b.size() == b.max_size()) + { + ec = error::not_found; + return 0; + } + + // Need more data. + std::size_t bytes_to_read = std::min( + std::max(512, b.capacity() - b.size()), + std::min(65536, b.max_size() - b.size())); + std::size_t pos = b.size(); + b.grow(bytes_to_read); + std::size_t bytes_transferred = s.read_some(b.data(pos, bytes_to_read), ec); + b.shrink(bytes_to_read - bytes_transferred); + if (ec) + return 0; + } +} + +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +namespace detail +{ + template + class read_until_delim_op_v1 + { + public: + template + read_until_delim_op_v1(AsyncReadStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, + char delim, ReadHandler& handler) + : stream_(stream), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), + delim_(delim), + start_(0), + search_position_(0), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + read_until_delim_op_v1(const read_until_delim_op_v1& other) + : stream_(other.stream_), + buffers_(other.buffers_), + delim_(other.delim_), + start_(other.start_), + search_position_(other.search_position_), + handler_(other.handler_) + { + } + + read_until_delim_op_v1(read_until_delim_op_v1&& other) + : stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)), + delim_(other.delim_), + start_(other.start_), + search_position_(other.search_position_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits::max)(); + std::size_t bytes_to_read; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v1::const_buffers_type + buffers_type; + typedef buffers_iterator iterator; + buffers_type data_buffers = buffers_.data(); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position_; + iterator end = iterator::end(data_buffers); + + // Look for a match. + iterator iter = std::find(start_pos, end, delim_); + if (iter != end) + { + // Found a match. We're done. + search_position_ = iter - begin + 1; + bytes_to_read = 0; + } + + // No match yet. Check if buffer is full. + else if (buffers_.size() == buffers_.max_size()) + { + search_position_ = not_found; + bytes_to_read = 0; + } + + // Need to read some more data. + else + { + // Next search can start with the new data. + search_position_ = end - begin; + bytes_to_read = std::min( + std::max(512, + buffers_.capacity() - buffers_.size()), + std::min(65536, + buffers_.max_size() - buffers_.size())); + } + } + + // Check if we're done. + if (!start && bytes_to_read == 0) + break; + + // Start a new asynchronous read op_v1eration to obtain more data. + stream_.async_read_some(buffers_.prepare(bytes_to_read), + BOOST_ASIO_MOVE_CAST(read_until_delim_op_v1)(*this)); + return; default: + buffers_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const boost::system::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + handler_(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v1 buffers_; + char delim_; + int start_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_until_delim_op_v1* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_delim_op_v1* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + read_until_delim_op_v1* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + read_until_delim_op_v1* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_until_delim_op_v1* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_read_until_delim_v1 + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + char delim) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue handler2(handler); + read_until_delim_op_v1::type, + typename decay::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + delim, handler2.value)(boost::system::error_code(), 0, 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::read_until_delim_op_v1, + Allocator> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::read_until_delim_op_v1& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::read_until_delim_op_v1, + Executor> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::read_until_delim_op_v1& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + return async_initiate( + detail::initiate_async_read_until_delim_v1(), handler, + &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim); +} + +namespace detail +{ + template + class read_until_delim_string_op_v1 + { + public: + template + read_until_delim_string_op_v1(AsyncReadStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, + const std::string& delim, ReadHandler& handler) + : stream_(stream), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), + delim_(delim), + start_(0), + search_position_(0), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + read_until_delim_string_op_v1(const read_until_delim_string_op_v1& other) + : stream_(other.stream_), + buffers_(other.buffers_), + delim_(other.delim_), + start_(other.start_), + search_position_(other.search_position_), + handler_(other.handler_) + { + } + + read_until_delim_string_op_v1(read_until_delim_string_op_v1&& other) + : stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)), + delim_(BOOST_ASIO_MOVE_CAST(std::string)(other.delim_)), + start_(other.start_), + search_position_(other.search_position_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits::max)(); + std::size_t bytes_to_read; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v1::const_buffers_type + buffers_type; + typedef buffers_iterator iterator; + buffers_type data_buffers = buffers_.data(); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position_; + iterator end = iterator::end(data_buffers); + + // Look for a match. + std::pair result = detail::partial_search( + start_pos, end, delim_.begin(), delim_.end()); + if (result.first != end && result.second) + { + // Full match. We're done. + search_position_ = result.first - begin + delim_.length(); + bytes_to_read = 0; + } + + // No match yet. Check if buffer is full. + else if (buffers_.size() == buffers_.max_size()) + { + search_position_ = not_found; + bytes_to_read = 0; + } + + // Need to read some more data. + else + { + if (result.first != end) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = result.first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read = std::min( + std::max(512, + buffers_.capacity() - buffers_.size()), + std::min(65536, + buffers_.max_size() - buffers_.size())); + } + } + + // Check if we're done. + if (!start && bytes_to_read == 0) + break; + + // Start a new asynchronous read op_v1eration to obtain more data. + stream_.async_read_some(buffers_.prepare(bytes_to_read), + BOOST_ASIO_MOVE_CAST(read_until_delim_string_op_v1)(*this)); + return; default: + buffers_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const boost::system::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + handler_(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v1 buffers_; + std::string delim_; + int start_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_until_delim_string_op_v1* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_delim_string_op_v1* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + read_until_delim_string_op_v1* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + read_until_delim_string_op_v1* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_until_delim_string_op_v1* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_read_until_delim_string_v1 + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + const std::string& delim) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue handler2(handler); + read_until_delim_string_op_v1::type, + typename decay::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + delim, handler2.value)(boost::system::error_code(), 0, 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::read_until_delim_string_op_v1, + Allocator> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::read_until_delim_string_op_v1& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::read_until_delim_string_op_v1, + Executor> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::read_until_delim_string_op_v1& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_STRING_VIEW_PARAM delim, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + return async_initiate( + detail::initiate_async_read_until_delim_string_v1(), + handler, &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + static_cast(delim)); +} + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if defined(BOOST_ASIO_HAS_BOOST_REGEX) + +namespace detail +{ + template + class read_until_expr_op_v1 + { + public: + template + read_until_expr_op_v1(AsyncReadStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, + const boost::regex& expr, ReadHandler& handler) + : stream_(stream), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), + expr_(expr), + start_(0), + search_position_(0), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + read_until_expr_op_v1(const read_until_expr_op_v1& other) + : stream_(other.stream_), + buffers_(other.buffers_), + expr_(other.expr_), + start_(other.start_), + search_position_(other.search_position_), + handler_(other.handler_) + { + } + + read_until_expr_op_v1(read_until_expr_op_v1&& other) + : stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)), + expr_(other.expr_), + start_(other.start_), + search_position_(other.search_position_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits::max)(); + std::size_t bytes_to_read; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v1::const_buffers_type + buffers_type; + typedef buffers_iterator iterator; + buffers_type data_buffers = buffers_.data(); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position_; + iterator end = iterator::end(data_buffers); + + // Look for a match. + boost::match_results >::allocator_type> + match_results; + bool match = regex_search(start_pos, end, match_results, expr_, + boost::match_default | boost::match_partial); + if (match && match_results[0].matched) + { + // Full match. We're done. + search_position_ = match_results[0].second - begin; + bytes_to_read = 0; + } + + // No match yet. Check if buffer is full. + else if (buffers_.size() == buffers_.max_size()) + { + search_position_ = not_found; + bytes_to_read = 0; + } + + // Need to read some more data. + else + { + if (match) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = match_results[0].first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read = std::min( + std::max(512, + buffers_.capacity() - buffers_.size()), + std::min(65536, + buffers_.max_size() - buffers_.size())); + } + } + + // Check if we're done. + if (!start && bytes_to_read == 0) + break; + + // Start a new asynchronous read op_v1eration to obtain more data. + stream_.async_read_some(buffers_.prepare(bytes_to_read), + BOOST_ASIO_MOVE_CAST(read_until_expr_op_v1)(*this)); + return; default: + buffers_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const boost::system::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + handler_(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v1 buffers_; + RegEx expr_; + int start_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_until_expr_op_v1* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_expr_op_v1* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + read_until_expr_op_v1* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + read_until_expr_op_v1* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_until_expr_op_v1* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_read_until_expr_v1 + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + const RegEx& expr) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue handler2(handler); + read_until_expr_op_v1::type, + RegEx, typename decay::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + expr, handler2.value)(boost::system::error_code(), 0, 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::read_until_expr_op_v1, + Allocator> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::read_until_expr_op_v1& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::read_until_expr_op_v1, + Executor> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::read_until_expr_op_v1& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + const boost::regex& expr, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + return async_initiate( + detail::initiate_async_read_until_expr_v1(), handler, + &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), expr); +} + +#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) + +namespace detail +{ + template + class read_until_match_op_v1 + { + public: + template + read_until_match_op_v1(AsyncReadStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, + MatchCondition match_condition, ReadHandler& handler) + : stream_(stream), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), + match_condition_(match_condition), + start_(0), + search_position_(0), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + read_until_match_op_v1(const read_until_match_op_v1& other) + : stream_(other.stream_), + buffers_(other.buffers_), + match_condition_(other.match_condition_), + start_(other.start_), + search_position_(other.search_position_), + handler_(other.handler_) + { + } + + read_until_match_op_v1(read_until_match_op_v1&& other) + : stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)), + match_condition_(other.match_condition_), + start_(other.start_), + search_position_(other.search_position_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits::max)(); + std::size_t bytes_to_read; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v1::const_buffers_type + buffers_type; + typedef buffers_iterator iterator; + buffers_type data_buffers = buffers_.data(); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position_; + iterator end = iterator::end(data_buffers); + + // Look for a match. + std::pair result = match_condition_(start_pos, end); + if (result.second) + { + // Full match. We're done. + search_position_ = result.first - begin; + bytes_to_read = 0; + } + + // No match yet. Check if buffer is full. + else if (buffers_.size() == buffers_.max_size()) + { + search_position_ = not_found; + bytes_to_read = 0; + } + + // Need to read some more data. + else + { + if (result.first != end) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = result.first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read = std::min( + std::max(512, + buffers_.capacity() - buffers_.size()), + std::min(65536, + buffers_.max_size() - buffers_.size())); + } + } + + // Check if we're done. + if (!start && bytes_to_read == 0) + break; + + // Start a new asynchronous read op_v1eration to obtain more data. + stream_.async_read_some(buffers_.prepare(bytes_to_read), + BOOST_ASIO_MOVE_CAST(read_until_match_op_v1)(*this)); + return; default: + buffers_.commit(bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const boost::system::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + handler_(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v1 buffers_; + MatchCondition match_condition_; + int start_; + std::size_t search_position_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_until_match_op_v1* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_match_op_v1* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + read_until_match_op_v1* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + read_until_match_op_v1* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_until_match_op_v1* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_read_until_match_v1 + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + MatchCondition match_condition) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue handler2(handler); + read_until_match_op_v1::type, + MatchCondition, typename decay::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + match_condition, handler2.value)(boost::system::error_code(), 0, 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::read_until_match_op_v1, + Allocator> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::read_until_match_op_v1& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::read_until_match_op_v1, + Executor> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::read_until_match_op_v1& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_match_condition::value + && is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + return async_initiate( + detail::initiate_async_read_until_match_v1(), handler, + &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), match_condition); +} + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf& b, + char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_read_until(s, basic_streambuf_ref(b), + delim, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf& b, + BOOST_ASIO_STRING_VIEW_PARAM delim, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_read_until(s, basic_streambuf_ref(b), + delim, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +#if defined(BOOST_ASIO_HAS_BOOST_REGEX) + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf& b, const boost::regex& expr, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) +{ + return async_read_until(s, basic_streambuf_ref(b), + expr, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf& b, + MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if::value>::type*) +{ + return async_read_until(s, basic_streambuf_ref(b), + match_condition, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); +} + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +namespace detail +{ + template + class read_until_delim_op_v2 + { + public: + template + read_until_delim_op_v2(AsyncReadStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, + char delim, ReadHandler& handler) + : stream_(stream), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), + delim_(delim), + start_(0), + search_position_(0), + bytes_to_read_(0), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + read_until_delim_op_v2(const read_until_delim_op_v2& other) + : stream_(other.stream_), + buffers_(other.buffers_), + delim_(other.delim_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(other.handler_) + { + } + + read_until_delim_op_v2(read_until_delim_op_v2&& other) + : stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)), + delim_(other.delim_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits::max)(); + std::size_t pos; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type + buffers_type; + typedef buffers_iterator iterator; + buffers_type data_buffers = + const_cast(buffers_).data( + 0, buffers_.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position_; + iterator end = iterator::end(data_buffers); + + // Look for a match. + iterator iter = std::find(start_pos, end, delim_); + if (iter != end) + { + // Found a match. We're done. + search_position_ = iter - begin + 1; + bytes_to_read_ = 0; + } + + // No match yet. Check if buffer is full. + else if (buffers_.size() == buffers_.max_size()) + { + search_position_ = not_found; + bytes_to_read_ = 0; + } + + // Need to read some more data. + else + { + // Next search can start with the new data. + search_position_ = end - begin; + bytes_to_read_ = std::min( + std::max(512, + buffers_.capacity() - buffers_.size()), + std::min(65536, + buffers_.max_size() - buffers_.size())); + } + } + + // Check if we're done. + if (!start && bytes_to_read_ == 0) + break; + + // Start a new asynchronous read op_v2eration to obtain more data. + pos = buffers_.size(); + buffers_.grow(bytes_to_read_); + stream_.async_read_some(buffers_.data(pos, bytes_to_read_), + BOOST_ASIO_MOVE_CAST(read_until_delim_op_v2)(*this)); + return; default: + buffers_.shrink(bytes_to_read_ - bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const boost::system::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + handler_(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v2 buffers_; + char delim_; + int start_; + std::size_t search_position_; + std::size_t bytes_to_read_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_until_delim_op_v2* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_delim_op_v2* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + read_until_delim_op_v2* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + read_until_delim_op_v2* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_until_delim_op_v2* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_read_until_delim_v2 + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, + char delim) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue handler2(handler); + read_until_delim_op_v2::type, + typename decay::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + delim, handler2.value)(boost::system::error_code(), 0, 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::read_until_delim_op_v2, + Allocator> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::read_until_delim_op_v2& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::read_until_delim_op_v2, + Executor> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::read_until_delim_op_v2& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, + char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + return async_initiate( + detail::initiate_async_read_until_delim_v2(), handler, + &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim); +} + +namespace detail +{ + template + class read_until_delim_string_op_v2 + { + public: + template + read_until_delim_string_op_v2(AsyncReadStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, + const std::string& delim, ReadHandler& handler) + : stream_(stream), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), + delim_(delim), + start_(0), + search_position_(0), + bytes_to_read_(0), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + read_until_delim_string_op_v2(const read_until_delim_string_op_v2& other) + : stream_(other.stream_), + buffers_(other.buffers_), + delim_(other.delim_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(other.handler_) + { + } + + read_until_delim_string_op_v2(read_until_delim_string_op_v2&& other) + : stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)), + delim_(BOOST_ASIO_MOVE_CAST(std::string)(other.delim_)), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits::max)(); + std::size_t pos; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type + buffers_type; + typedef buffers_iterator iterator; + buffers_type data_buffers = + const_cast(buffers_).data( + 0, buffers_.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position_; + iterator end = iterator::end(data_buffers); + + // Look for a match. + std::pair result = detail::partial_search( + start_pos, end, delim_.begin(), delim_.end()); + if (result.first != end && result.second) + { + // Full match. We're done. + search_position_ = result.first - begin + delim_.length(); + bytes_to_read_ = 0; + } + + // No match yet. Check if buffer is full. + else if (buffers_.size() == buffers_.max_size()) + { + search_position_ = not_found; + bytes_to_read_ = 0; + } + + // Need to read some more data. + else + { + if (result.first != end) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = result.first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read_ = std::min( + std::max(512, + buffers_.capacity() - buffers_.size()), + std::min(65536, + buffers_.max_size() - buffers_.size())); + } + } + + // Check if we're done. + if (!start && bytes_to_read_ == 0) + break; + + // Start a new asynchronous read op_v2eration to obtain more data. + pos = buffers_.size(); + buffers_.grow(bytes_to_read_); + stream_.async_read_some(buffers_.data(pos, bytes_to_read_), + BOOST_ASIO_MOVE_CAST(read_until_delim_string_op_v2)(*this)); + return; default: + buffers_.shrink(bytes_to_read_ - bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const boost::system::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + handler_(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v2 buffers_; + std::string delim_; + int start_; + std::size_t search_position_; + std::size_t bytes_to_read_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_until_delim_string_op_v2* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_delim_string_op_v2* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + read_until_delim_string_op_v2* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + read_until_delim_string_op_v2* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_until_delim_string_op_v2* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_read_until_delim_string_v2 + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, + const std::string& delim) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue handler2(handler); + read_until_delim_string_op_v2::type, + typename decay::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + delim, handler2.value)(boost::system::error_code(), 0, 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::read_until_delim_string_op_v2, + Allocator> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::read_until_delim_string_op_v2& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::read_until_delim_string_op_v2, + Executor> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::read_until_delim_string_op_v2& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + DynamicBuffer_v2 buffers, BOOST_ASIO_STRING_VIEW_PARAM delim, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + return async_initiate( + detail::initiate_async_read_until_delim_string_v2(), + handler, &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + static_cast(delim)); +} + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if defined(BOOST_ASIO_HAS_BOOST_REGEX) + +namespace detail +{ + template + class read_until_expr_op_v2 + { + public: + template + read_until_expr_op_v2(AsyncReadStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, + const boost::regex& expr, ReadHandler& handler) + : stream_(stream), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), + expr_(expr), + start_(0), + search_position_(0), + bytes_to_read_(0), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + read_until_expr_op_v2(const read_until_expr_op_v2& other) + : stream_(other.stream_), + buffers_(other.buffers_), + expr_(other.expr_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(other.handler_) + { + } + + read_until_expr_op_v2(read_until_expr_op_v2&& other) + : stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)), + expr_(other.expr_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits::max)(); + std::size_t pos; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type + buffers_type; + typedef buffers_iterator iterator; + buffers_type data_buffers = + const_cast(buffers_).data( + 0, buffers_.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position_; + iterator end = iterator::end(data_buffers); + + // Look for a match. + boost::match_results >::allocator_type> + match_results; + bool match = regex_search(start_pos, end, match_results, expr_, + boost::match_default | boost::match_partial); + if (match && match_results[0].matched) + { + // Full match. We're done. + search_position_ = match_results[0].second - begin; + bytes_to_read_ = 0; + } + + // No match yet. Check if buffer is full. + else if (buffers_.size() == buffers_.max_size()) + { + search_position_ = not_found; + bytes_to_read_ = 0; + } + + // Need to read some more data. + else + { + if (match) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = match_results[0].first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read_ = std::min( + std::max(512, + buffers_.capacity() - buffers_.size()), + std::min(65536, + buffers_.max_size() - buffers_.size())); + } + } + + // Check if we're done. + if (!start && bytes_to_read_ == 0) + break; + + // Start a new asynchronous read op_v2eration to obtain more data. + pos = buffers_.size(); + buffers_.grow(bytes_to_read_); + stream_.async_read_some(buffers_.data(pos, bytes_to_read_), + BOOST_ASIO_MOVE_CAST(read_until_expr_op_v2)(*this)); + return; default: + buffers_.shrink(bytes_to_read_ - bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const boost::system::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + handler_(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v2 buffers_; + RegEx expr_; + int start_; + std::size_t search_position_; + std::size_t bytes_to_read_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_until_expr_op_v2* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_expr_op_v2* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + read_until_expr_op_v2* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + read_until_expr_op_v2* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_until_expr_op_v2* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_read_until_expr_v2 + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, + const RegEx& expr) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue handler2(handler); + read_until_expr_op_v2::type, + RegEx, typename decay::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + expr, handler2.value)(boost::system::error_code(), 0, 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::read_until_expr_op_v2, + Allocator> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::read_until_expr_op_v2& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::read_until_expr_op_v2, + Executor> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::read_until_expr_op_v2& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, + const boost::regex& expr, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + return async_initiate( + detail::initiate_async_read_until_expr_v2(), handler, + &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), expr); +} + +#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) + +namespace detail +{ + template + class read_until_match_op_v2 + { + public: + template + read_until_match_op_v2(AsyncReadStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, + MatchCondition match_condition, ReadHandler& handler) + : stream_(stream), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), + match_condition_(match_condition), + start_(0), + search_position_(0), + bytes_to_read_(0), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + read_until_match_op_v2(const read_until_match_op_v2& other) + : stream_(other.stream_), + buffers_(other.buffers_), + match_condition_(other.match_condition_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(other.handler_) + { + } + + read_until_match_op_v2(read_until_match_op_v2&& other) + : stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)), + match_condition_(other.match_condition_), + start_(other.start_), + search_position_(other.search_position_), + bytes_to_read_(other.bytes_to_read_), + handler_(BOOST_ASIO_MOVE_CAST(ReadHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + const std::size_t not_found = (std::numeric_limits::max)(); + std::size_t pos; + switch (start_ = start) + { + case 1: + for (;;) + { + { + // Determine the range of the data to be searched. + typedef typename DynamicBuffer_v2::const_buffers_type + buffers_type; + typedef buffers_iterator iterator; + buffers_type data_buffers = + const_cast(buffers_).data( + 0, buffers_.size()); + iterator begin = iterator::begin(data_buffers); + iterator start_pos = begin + search_position_; + iterator end = iterator::end(data_buffers); + + // Look for a match. + std::pair result = match_condition_(start_pos, end); + if (result.second) + { + // Full match. We're done. + search_position_ = result.first - begin; + bytes_to_read_ = 0; + } + + // No match yet. Check if buffer is full. + else if (buffers_.size() == buffers_.max_size()) + { + search_position_ = not_found; + bytes_to_read_ = 0; + } + + // Need to read some more data. + else + { + if (result.first != end) + { + // Partial match. Next search needs to start from beginning of + // match. + search_position_ = result.first - begin; + } + else + { + // Next search can start with the new data. + search_position_ = end - begin; + } + + bytes_to_read_ = std::min( + std::max(512, + buffers_.capacity() - buffers_.size()), + std::min(65536, + buffers_.max_size() - buffers_.size())); + } + } + + // Check if we're done. + if (!start && bytes_to_read_ == 0) + break; + + // Start a new asynchronous read op_v2eration to obtain more data. + pos = buffers_.size(); + buffers_.grow(bytes_to_read_); + stream_.async_read_some(buffers_.data(pos, bytes_to_read_), + BOOST_ASIO_MOVE_CAST(read_until_match_op_v2)(*this)); + return; default: + buffers_.shrink(bytes_to_read_ - bytes_transferred); + if (ec || bytes_transferred == 0) + break; + } + + const boost::system::error_code result_ec = + (search_position_ == not_found) + ? error::not_found : ec; + + const std::size_t result_n = + (ec || search_position_ == not_found) + ? 0 : search_position_; + + handler_(result_ec, result_n); + } + } + + //private: + AsyncReadStream& stream_; + DynamicBuffer_v2 buffers_; + MatchCondition match_condition_; + int start_; + std::size_t search_position_; + std::size_t bytes_to_read_; + ReadHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + read_until_match_op_v2* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + read_until_match_op_v2* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + read_until_match_op_v2* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + read_until_match_op_v2* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + read_until_match_op_v2* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_read_until_match_v2 + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + AsyncReadStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, + MatchCondition match_condition) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + non_const_lvalue handler2(handler); + read_until_match_op_v2::type, + MatchCondition, typename decay::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + match_condition, handler2.value)(boost::system::error_code(), 0, 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::read_until_match_op_v2, + Allocator> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::read_until_match_op_v2& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::read_until_match_op_v2, + Executor> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::read_until_match_op_v2& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, + MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_match_condition::value + && is_dynamic_buffer_v2::value + >::type*) +{ + return async_initiate( + detail::initiate_async_read_until_match_v2(), handler, + &s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), match_condition); +} + +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_READ_UNTIL_HPP diff --git a/boost/asio/impl/redirect_error.hpp b/boost/asio/impl/redirect_error.hpp new file mode 100644 index 0000000..eb0d829 --- /dev/null +++ b/boost/asio/impl/redirect_error.hpp @@ -0,0 +1,374 @@ + +// impl/redirect_error.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_REDIRECT_ERROR_HPP +#define BOOST_ASIO_IMPL_REDIRECT_ERROR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +// Class to adapt a redirect_error_t as a completion handler. +template +class redirect_error_handler +{ +public: + typedef void result_type; + + template + redirect_error_handler(redirect_error_t e) + : ec_(e.ec_), + handler_(BOOST_ASIO_MOVE_CAST(CompletionToken)(e.token_)) + { + } + + template + redirect_error_handler(boost::system::error_code& ec, + BOOST_ASIO_MOVE_ARG(RedirectedHandler) h) + : ec_(ec), + handler_(BOOST_ASIO_MOVE_CAST(RedirectedHandler)(h)) + { + } + + void operator()() + { + handler_(); + } + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + typename enable_if< + !is_same::type, boost::system::error_code>::value + >::type + operator()(BOOST_ASIO_MOVE_ARG(Arg) arg, BOOST_ASIO_MOVE_ARG(Args)... args) + { + handler_(BOOST_ASIO_MOVE_CAST(Arg)(arg), + BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + + template + void operator()(const boost::system::error_code& ec, + BOOST_ASIO_MOVE_ARG(Args)... args) + { + ec_ = ec; + handler_(BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + typename enable_if< + !is_same::type, boost::system::error_code>::value + >::type + operator()(BOOST_ASIO_MOVE_ARG(Arg) arg) + { + handler_(BOOST_ASIO_MOVE_CAST(Arg)(arg)); + } + + void operator()(const boost::system::error_code& ec) + { + ec_ = ec; + handler_(); + } + +#define BOOST_ASIO_PRIVATE_REDIRECT_ERROR_DEF(n) \ + template \ + typename enable_if< \ + !is_same::type, boost::system::error_code>::value \ + >::type \ + operator()(BOOST_ASIO_MOVE_ARG(Arg) arg, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + handler_(BOOST_ASIO_MOVE_CAST(Arg)(arg), \ + BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + \ + template \ + void operator()(const boost::system::error_code& ec, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + ec_ = ec; \ + handler_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_REDIRECT_ERROR_DEF) +#undef BOOST_ASIO_PRIVATE_REDIRECT_ERROR_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +//private: + boost::system::error_code& ec_; + Handler handler_; +}; + +template +inline void* asio_handler_allocate(std::size_t size, + redirect_error_handler* this_handler) +{ + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); +} + +template +inline void asio_handler_deallocate(void* pointer, std::size_t size, + redirect_error_handler* this_handler) +{ + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); +} + +template +inline bool asio_handler_is_continuation( + redirect_error_handler* this_handler) +{ + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); +} + +template +inline void asio_handler_invoke(Function& function, + redirect_error_handler* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template +inline void asio_handler_invoke(const Function& function, + redirect_error_handler* this_handler) +{ + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); +} + +template +struct redirect_error_signature +{ + typedef Signature type; +}; + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct redirect_error_signature +{ + typedef R type(Args...); +}; + +template +struct redirect_error_signature +{ + typedef R type(Args...); +}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +struct redirect_error_signature +{ + typedef R type(); +}; + +template +struct redirect_error_signature +{ + typedef R type(); +}; + +#define BOOST_ASIO_PRIVATE_REDIRECT_ERROR_DEF(n) \ + template \ + struct redirect_error_signature< \ + R(boost::system::error_code, BOOST_ASIO_VARIADIC_TARGS(n))> \ + { \ + typedef R type(BOOST_ASIO_VARIADIC_TARGS(n)); \ + }; \ + \ + template \ + struct redirect_error_signature< \ + R(const boost::system::error_code&, BOOST_ASIO_VARIADIC_TARGS(n))> \ + { \ + typedef R type(BOOST_ASIO_VARIADIC_TARGS(n)); \ + }; \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_REDIRECT_ERROR_DEF) +#undef BOOST_ASIO_PRIVATE_REDIRECT_ERROR_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct async_result, Signature> +{ + typedef typename async_result::type> + ::return_type return_type; + + template + struct init_wrapper + { + template + init_wrapper(boost::system::error_code& ec, BOOST_ASIO_MOVE_ARG(Init) init) + : ec_(ec), + initiation_(BOOST_ASIO_MOVE_CAST(Init)(init)) + { + } + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + void operator()( + BOOST_ASIO_MOVE_ARG(Handler) handler, + BOOST_ASIO_MOVE_ARG(Args)... args) + { + BOOST_ASIO_MOVE_CAST(Initiation)(initiation_)( + detail::redirect_error_handler< + typename decay::type>( + ec_, BOOST_ASIO_MOVE_CAST(Handler)(handler)), + BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + void operator()( + BOOST_ASIO_MOVE_ARG(Handler) handler) + { + BOOST_ASIO_MOVE_CAST(Initiation)(initiation_)( + detail::redirect_error_handler< + typename decay::type>( + ec_, BOOST_ASIO_MOVE_CAST(Handler)(handler))); + } + +#define BOOST_ASIO_PRIVATE_INIT_WRAPPER_DEF(n) \ + template \ + void operator()( \ + BOOST_ASIO_MOVE_ARG(Handler) handler, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + BOOST_ASIO_MOVE_CAST(Initiation)(initiation_)( \ + detail::redirect_error_handler< \ + typename decay::type>( \ + ec_, BOOST_ASIO_MOVE_CAST(Handler)(handler)), \ + BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_INIT_WRAPPER_DEF) +#undef BOOST_ASIO_PRIVATE_INIT_WRAPPER_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + boost::system::error_code& ec_; + Initiation initiation_; + }; + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + static return_type initiate( + BOOST_ASIO_MOVE_ARG(Initiation) initiation, + BOOST_ASIO_MOVE_ARG(RawCompletionToken) token, + BOOST_ASIO_MOVE_ARG(Args)... args) + { + return async_initiate::type>( + init_wrapper::type>( + token.ec_, BOOST_ASIO_MOVE_CAST(Initiation)(initiation)), + token.token_, BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + static return_type initiate( + BOOST_ASIO_MOVE_ARG(Initiation) initiation, + BOOST_ASIO_MOVE_ARG(RawCompletionToken) token) + { + return async_initiate::type>( + init_wrapper::type>( + token.ec_, BOOST_ASIO_MOVE_CAST(Initiation)(initiation)), + token.token_); + } + +#define BOOST_ASIO_PRIVATE_INITIATE_DEF(n) \ + template \ + static return_type initiate( \ + BOOST_ASIO_MOVE_ARG(Initiation) initiation, \ + BOOST_ASIO_MOVE_ARG(RawCompletionToken) token, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + return async_initiate::type>( \ + init_wrapper::type>( \ + token.ec_, BOOST_ASIO_MOVE_CAST(Initiation)(initiation)), \ + token.token_, BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_INITIATE_DEF) +#undef BOOST_ASIO_PRIVATE_INITIATE_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +}; + +template +struct associated_executor, Executor> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::redirect_error_handler& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +template +struct associated_allocator, Allocator> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::redirect_error_handler& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_REDIRECT_ERROR_HPP diff --git a/boost/asio/impl/serial_port_base.hpp b/boost/asio/impl/serial_port_base.hpp new file mode 100644 index 0000000..c456e30 --- /dev/null +++ b/boost/asio/impl/serial_port_base.hpp @@ -0,0 +1,61 @@ +// +// impl/serial_port_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_SERIAL_PORT_BASE_HPP +#define BOOST_ASIO_IMPL_SERIAL_PORT_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +namespace boost { +namespace asio { + +inline serial_port_base::baud_rate::baud_rate(unsigned int rate) + : value_(rate) +{ +} + +inline unsigned int serial_port_base::baud_rate::value() const +{ + return value_; +} + +inline serial_port_base::flow_control::type +serial_port_base::flow_control::value() const +{ + return value_; +} + +inline serial_port_base::parity::type serial_port_base::parity::value() const +{ + return value_; +} + +inline serial_port_base::stop_bits::type +serial_port_base::stop_bits::value() const +{ + return value_; +} + +inline unsigned int serial_port_base::character_size::value() const +{ + return value_; +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_SERIAL_PORT_BASE_HPP diff --git a/boost/asio/impl/serial_port_base.ipp b/boost/asio/impl/serial_port_base.ipp new file mode 100644 index 0000000..c7ff518 --- /dev/null +++ b/boost/asio/impl/serial_port_base.ipp @@ -0,0 +1,556 @@ +// +// impl/serial_port_base.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_SERIAL_PORT_BASE_IPP +#define BOOST_ASIO_IMPL_SERIAL_PORT_BASE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_SERIAL_PORT) + +#include +#include +#include +#include + +#if defined(GENERATING_DOCUMENTATION) +# define BOOST_ASIO_OPTION_STORAGE implementation_defined +#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# define BOOST_ASIO_OPTION_STORAGE DCB +#else +# define BOOST_ASIO_OPTION_STORAGE termios +#endif + +#include + +namespace boost { +namespace asio { + +BOOST_ASIO_SYNC_OP_VOID serial_port_base::baud_rate::store( + BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const +{ +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + storage.BaudRate = value_; +#else + speed_t baud; + switch (value_) + { + // Do POSIX-specified rates first. + case 0: baud = B0; break; + case 50: baud = B50; break; + case 75: baud = B75; break; + case 110: baud = B110; break; + case 134: baud = B134; break; + case 150: baud = B150; break; + case 200: baud = B200; break; + case 300: baud = B300; break; + case 600: baud = B600; break; + case 1200: baud = B1200; break; + case 1800: baud = B1800; break; + case 2400: baud = B2400; break; + case 4800: baud = B4800; break; + case 9600: baud = B9600; break; + case 19200: baud = B19200; break; + case 38400: baud = B38400; break; + // And now the extended ones conditionally. +# ifdef B7200 + case 7200: baud = B7200; break; +# endif +# ifdef B14400 + case 14400: baud = B14400; break; +# endif +# ifdef B57600 + case 57600: baud = B57600; break; +# endif +# ifdef B115200 + case 115200: baud = B115200; break; +# endif +# ifdef B230400 + case 230400: baud = B230400; break; +# endif +# ifdef B460800 + case 460800: baud = B460800; break; +# endif +# ifdef B500000 + case 500000: baud = B500000; break; +# endif +# ifdef B576000 + case 576000: baud = B576000; break; +# endif +# ifdef B921600 + case 921600: baud = B921600; break; +# endif +# ifdef B1000000 + case 1000000: baud = B1000000; break; +# endif +# ifdef B1152000 + case 1152000: baud = B1152000; break; +# endif +# ifdef B2000000 + case 2000000: baud = B2000000; break; +# endif +# ifdef B3000000 + case 3000000: baud = B3000000; break; +# endif +# ifdef B3500000 + case 3500000: baud = B3500000; break; +# endif +# ifdef B4000000 + case 4000000: baud = B4000000; break; +# endif + default: + ec = boost::asio::error::invalid_argument; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) + ::cfsetspeed(&storage, baud); +# else + ::cfsetispeed(&storage, baud); + ::cfsetospeed(&storage, baud); +# endif +#endif + ec = boost::system::error_code(); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); +} + +BOOST_ASIO_SYNC_OP_VOID serial_port_base::baud_rate::load( + const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) +{ +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + value_ = storage.BaudRate; +#else + speed_t baud = ::cfgetospeed(&storage); + switch (baud) + { + // First do those specified by POSIX. + case B0: value_ = 0; break; + case B50: value_ = 50; break; + case B75: value_ = 75; break; + case B110: value_ = 110; break; + case B134: value_ = 134; break; + case B150: value_ = 150; break; + case B200: value_ = 200; break; + case B300: value_ = 300; break; + case B600: value_ = 600; break; + case B1200: value_ = 1200; break; + case B1800: value_ = 1800; break; + case B2400: value_ = 2400; break; + case B4800: value_ = 4800; break; + case B9600: value_ = 9600; break; + case B19200: value_ = 19200; break; + case B38400: value_ = 38400; break; + // Now conditionally handle a bunch of extended rates. +# ifdef B7200 + case B7200: value_ = 7200; break; +# endif +# ifdef B14400 + case B14400: value_ = 14400; break; +# endif +# ifdef B57600 + case B57600: value_ = 57600; break; +# endif +# ifdef B115200 + case B115200: value_ = 115200; break; +# endif +# ifdef B230400 + case B230400: value_ = 230400; break; +# endif +# ifdef B460800 + case B460800: value_ = 460800; break; +# endif +# ifdef B500000 + case B500000: value_ = 500000; break; +# endif +# ifdef B576000 + case B576000: value_ = 576000; break; +# endif +# ifdef B921600 + case B921600: value_ = 921600; break; +# endif +# ifdef B1000000 + case B1000000: value_ = 1000000; break; +# endif +# ifdef B1152000 + case B1152000: value_ = 1152000; break; +# endif +# ifdef B2000000 + case B2000000: value_ = 2000000; break; +# endif +# ifdef B3000000 + case B3000000: value_ = 3000000; break; +# endif +# ifdef B3500000 + case B3500000: value_ = 3500000; break; +# endif +# ifdef B4000000 + case B4000000: value_ = 4000000; break; +# endif + default: + value_ = 0; + ec = boost::asio::error::invalid_argument; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } +#endif + ec = boost::system::error_code(); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); +} + +serial_port_base::flow_control::flow_control( + serial_port_base::flow_control::type t) + : value_(t) +{ + if (t != none && t != software && t != hardware) + { + std::out_of_range ex("invalid flow_control value"); + boost::asio::detail::throw_exception(ex); + } +} + +BOOST_ASIO_SYNC_OP_VOID serial_port_base::flow_control::store( + BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const +{ +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + storage.fOutxCtsFlow = FALSE; + storage.fOutxDsrFlow = FALSE; + storage.fTXContinueOnXoff = TRUE; + storage.fDtrControl = DTR_CONTROL_ENABLE; + storage.fDsrSensitivity = FALSE; + storage.fOutX = FALSE; + storage.fInX = FALSE; + storage.fRtsControl = RTS_CONTROL_ENABLE; + switch (value_) + { + case none: + break; + case software: + storage.fOutX = TRUE; + storage.fInX = TRUE; + break; + case hardware: + storage.fOutxCtsFlow = TRUE; + storage.fRtsControl = RTS_CONTROL_HANDSHAKE; + break; + default: + break; + } +#else + switch (value_) + { + case none: + storage.c_iflag &= ~(IXOFF | IXON); +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) + storage.c_cflag &= ~CRTSCTS; +# elif defined(__QNXNTO__) + storage.c_cflag &= ~(IHFLOW | OHFLOW); +# endif + break; + case software: + storage.c_iflag |= IXOFF | IXON; +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) + storage.c_cflag &= ~CRTSCTS; +# elif defined(__QNXNTO__) + storage.c_cflag &= ~(IHFLOW | OHFLOW); +# endif + break; + case hardware: +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) + storage.c_iflag &= ~(IXOFF | IXON); + storage.c_cflag |= CRTSCTS; + break; +# elif defined(__QNXNTO__) + storage.c_iflag &= ~(IXOFF | IXON); + storage.c_cflag |= (IHFLOW | OHFLOW); + break; +# else + ec = boost::asio::error::operation_not_supported; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); +# endif + default: + break; + } +#endif + ec = boost::system::error_code(); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); +} + +BOOST_ASIO_SYNC_OP_VOID serial_port_base::flow_control::load( + const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) +{ +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + if (storage.fOutX && storage.fInX) + { + value_ = software; + } + else if (storage.fOutxCtsFlow && storage.fRtsControl == RTS_CONTROL_HANDSHAKE) + { + value_ = hardware; + } + else + { + value_ = none; + } +#else + if (storage.c_iflag & (IXOFF | IXON)) + { + value_ = software; + } +# if defined(_BSD_SOURCE) || defined(_DEFAULT_SOURCE) + else if (storage.c_cflag & CRTSCTS) + { + value_ = hardware; + } +# elif defined(__QNXNTO__) + else if (storage.c_cflag & IHFLOW && storage.c_cflag & OHFLOW) + { + value_ = hardware; + } +# endif + else + { + value_ = none; + } +#endif + ec = boost::system::error_code(); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); +} + +serial_port_base::parity::parity(serial_port_base::parity::type t) + : value_(t) +{ + if (t != none && t != odd && t != even) + { + std::out_of_range ex("invalid parity value"); + boost::asio::detail::throw_exception(ex); + } +} + +BOOST_ASIO_SYNC_OP_VOID serial_port_base::parity::store( + BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const +{ +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + switch (value_) + { + case none: + storage.fParity = FALSE; + storage.Parity = NOPARITY; + break; + case odd: + storage.fParity = TRUE; + storage.Parity = ODDPARITY; + break; + case even: + storage.fParity = TRUE; + storage.Parity = EVENPARITY; + break; + default: + break; + } +#else + switch (value_) + { + case none: + storage.c_iflag |= IGNPAR; + storage.c_cflag &= ~(PARENB | PARODD); + break; + case even: + storage.c_iflag &= ~(IGNPAR | PARMRK); + storage.c_iflag |= INPCK; + storage.c_cflag |= PARENB; + storage.c_cflag &= ~PARODD; + break; + case odd: + storage.c_iflag &= ~(IGNPAR | PARMRK); + storage.c_iflag |= INPCK; + storage.c_cflag |= (PARENB | PARODD); + break; + default: + break; + } +#endif + ec = boost::system::error_code(); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); +} + +BOOST_ASIO_SYNC_OP_VOID serial_port_base::parity::load( + const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) +{ +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + if (storage.Parity == EVENPARITY) + { + value_ = even; + } + else if (storage.Parity == ODDPARITY) + { + value_ = odd; + } + else + { + value_ = none; + } +#else + if (storage.c_cflag & PARENB) + { + if (storage.c_cflag & PARODD) + { + value_ = odd; + } + else + { + value_ = even; + } + } + else + { + value_ = none; + } +#endif + ec = boost::system::error_code(); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); +} + +serial_port_base::stop_bits::stop_bits( + serial_port_base::stop_bits::type t) + : value_(t) +{ + if (t != one && t != onepointfive && t != two) + { + std::out_of_range ex("invalid stop_bits value"); + boost::asio::detail::throw_exception(ex); + } +} + +BOOST_ASIO_SYNC_OP_VOID serial_port_base::stop_bits::store( + BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const +{ +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + switch (value_) + { + case one: + storage.StopBits = ONESTOPBIT; + break; + case onepointfive: + storage.StopBits = ONE5STOPBITS; + break; + case two: + storage.StopBits = TWOSTOPBITS; + break; + default: + break; + } +#else + switch (value_) + { + case one: + storage.c_cflag &= ~CSTOPB; + break; + case two: + storage.c_cflag |= CSTOPB; + break; + default: + ec = boost::asio::error::operation_not_supported; + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } +#endif + ec = boost::system::error_code(); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); +} + +BOOST_ASIO_SYNC_OP_VOID serial_port_base::stop_bits::load( + const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) +{ +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + if (storage.StopBits == ONESTOPBIT) + { + value_ = one; + } + else if (storage.StopBits == ONE5STOPBITS) + { + value_ = onepointfive; + } + else if (storage.StopBits == TWOSTOPBITS) + { + value_ = two; + } + else + { + value_ = one; + } +#else + value_ = (storage.c_cflag & CSTOPB) ? two : one; +#endif + ec = boost::system::error_code(); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); +} + +serial_port_base::character_size::character_size(unsigned int t) + : value_(t) +{ + if (t < 5 || t > 8) + { + std::out_of_range ex("invalid character_size value"); + boost::asio::detail::throw_exception(ex); + } +} + +BOOST_ASIO_SYNC_OP_VOID serial_port_base::character_size::store( + BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) const +{ +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + storage.ByteSize = value_; +#else + storage.c_cflag &= ~CSIZE; + switch (value_) + { + case 5: storage.c_cflag |= CS5; break; + case 6: storage.c_cflag |= CS6; break; + case 7: storage.c_cflag |= CS7; break; + case 8: storage.c_cflag |= CS8; break; + default: break; + } +#endif + ec = boost::system::error_code(); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); +} + +BOOST_ASIO_SYNC_OP_VOID serial_port_base::character_size::load( + const BOOST_ASIO_OPTION_STORAGE& storage, boost::system::error_code& ec) +{ +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + value_ = storage.ByteSize; +#else + if ((storage.c_cflag & CSIZE) == CS5) { value_ = 5; } + else if ((storage.c_cflag & CSIZE) == CS6) { value_ = 6; } + else if ((storage.c_cflag & CSIZE) == CS7) { value_ = 7; } + else if ((storage.c_cflag & CSIZE) == CS8) { value_ = 8; } + else + { + // Hmmm, use 8 for now. + value_ = 8; + } +#endif + ec = boost::system::error_code(); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); +} + +} // namespace asio +} // namespace boost + +#include + +#undef BOOST_ASIO_OPTION_STORAGE + +#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) + +#endif // BOOST_ASIO_IMPL_SERIAL_PORT_BASE_IPP diff --git a/boost/asio/impl/system_context.hpp b/boost/asio/impl/system_context.hpp new file mode 100644 index 0000000..2a6b61f --- /dev/null +++ b/boost/asio/impl/system_context.hpp @@ -0,0 +1,36 @@ +// +// impl/system_context.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_SYSTEM_CONTEXT_HPP +#define BOOST_ASIO_IMPL_SYSTEM_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { + +inline system_context::executor_type +system_context::get_executor() BOOST_ASIO_NOEXCEPT +{ + return system_executor(); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_SYSTEM_CONTEXT_HPP diff --git a/boost/asio/impl/system_context.ipp b/boost/asio/impl/system_context.ipp new file mode 100644 index 0000000..0ec6fad --- /dev/null +++ b/boost/asio/impl/system_context.ipp @@ -0,0 +1,82 @@ +// +// impl/system_context.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_SYSTEM_CONTEXT_IPP +#define BOOST_ASIO_IMPL_SYSTEM_CONTEXT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { + +struct system_context::thread_function +{ + detail::scheduler* scheduler_; + + void operator()() + { + boost::system::error_code ec; + scheduler_->run(ec); + } +}; + +system_context::system_context() + : scheduler_(add_scheduler(new detail::scheduler(*this, 0, false))) +{ + scheduler_.work_started(); + + thread_function f = { &scheduler_ }; + std::size_t num_threads = detail::thread::hardware_concurrency() * 2; + threads_.create_threads(f, num_threads ? num_threads : 2); +} + +system_context::~system_context() +{ + scheduler_.work_finished(); + scheduler_.stop(); + threads_.join(); +} + +void system_context::stop() +{ + scheduler_.stop(); +} + +bool system_context::stopped() const BOOST_ASIO_NOEXCEPT +{ + return scheduler_.stopped(); +} + +void system_context::join() +{ + scheduler_.work_finished(); + threads_.join(); +} + +detail::scheduler& system_context::add_scheduler(detail::scheduler* s) +{ + detail::scoped_ptr scoped_impl(s); + boost::asio::add_service(*this, scoped_impl.get()); + return *scoped_impl.release(); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_SYSTEM_CONTEXT_IPP diff --git a/boost/asio/impl/system_executor.hpp b/boost/asio/impl/system_executor.hpp new file mode 100644 index 0000000..25c51a6 --- /dev/null +++ b/boost/asio/impl/system_executor.hpp @@ -0,0 +1,87 @@ +// +// impl/system_executor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_SYSTEM_EXECUTOR_HPP +#define BOOST_ASIO_IMPL_SYSTEM_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +inline system_context& system_executor::context() const BOOST_ASIO_NOEXCEPT +{ + return detail::global(); +} + +template +void system_executor::dispatch( + BOOST_ASIO_MOVE_ARG(Function) f, const Allocator&) const +{ + typename decay::type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); + boost_asio_handler_invoke_helpers::invoke(tmp, tmp); +} + +template +void system_executor::post( + BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay::type function_type; + + system_context& ctx = detail::global(); + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); + + BOOST_ASIO_HANDLER_CREATION((ctx, *p.p, + "system_executor", &this->context(), 0, "post")); + + ctx.scheduler_.post_immediate_completion(p.p, false); + p.v = p.p = 0; +} + +template +void system_executor::defer( + BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay::type function_type; + + system_context& ctx = detail::global(); + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); + + BOOST_ASIO_HANDLER_CREATION((ctx, *p.p, + "system_executor", &this->context(), 0, "defer")); + + ctx.scheduler_.post_immediate_completion(p.p, true); + p.v = p.p = 0; +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_SYSTEM_EXECUTOR_HPP diff --git a/boost/asio/impl/thread_pool.hpp b/boost/asio/impl/thread_pool.hpp new file mode 100644 index 0000000..31d8b37 --- /dev/null +++ b/boost/asio/impl/thread_pool.hpp @@ -0,0 +1,129 @@ +// +// impl/thread_pool.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_THREAD_POOL_HPP +#define BOOST_ASIO_IMPL_THREAD_POOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +inline thread_pool::executor_type +thread_pool::get_executor() BOOST_ASIO_NOEXCEPT +{ + return executor_type(*this); +} + +inline thread_pool& +thread_pool::executor_type::context() const BOOST_ASIO_NOEXCEPT +{ + return pool_; +} + +inline void +thread_pool::executor_type::on_work_started() const BOOST_ASIO_NOEXCEPT +{ + pool_.scheduler_.work_started(); +} + +inline void thread_pool::executor_type::on_work_finished() +const BOOST_ASIO_NOEXCEPT +{ + pool_.scheduler_.work_finished(); +} + +template +void thread_pool::executor_type::dispatch( + BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay::type function_type; + + // Invoke immediately if we are already inside the thread pool. + if (pool_.scheduler_.can_dispatch()) + { + // Make a local, non-const copy of the function. + function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); + + detail::fenced_block b(detail::fenced_block::full); + boost_asio_handler_invoke_helpers::invoke(tmp, tmp); + return; + } + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); + + BOOST_ASIO_HANDLER_CREATION((pool_, *p.p, + "thread_pool", &this->context(), 0, "dispatch")); + + pool_.scheduler_.post_immediate_completion(p.p, false); + p.v = p.p = 0; +} + +template +void thread_pool::executor_type::post( + BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); + + BOOST_ASIO_HANDLER_CREATION((pool_, *p.p, + "thread_pool", &this->context(), 0, "post")); + + pool_.scheduler_.post_immediate_completion(p.p, false); + p.v = p.p = 0; +} + +template +void thread_pool::executor_type::defer( + BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const +{ + typedef typename decay::type function_type; + + // Allocate and construct an operation to wrap the function. + typedef detail::executor_op op; + typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 }; + p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), a); + + BOOST_ASIO_HANDLER_CREATION((pool_, *p.p, + "thread_pool", &this->context(), 0, "defer")); + + pool_.scheduler_.post_immediate_completion(p.p, true); + p.v = p.p = 0; +} + +inline bool +thread_pool::executor_type::running_in_this_thread() const BOOST_ASIO_NOEXCEPT +{ + return pool_.scheduler_.can_dispatch(); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_THREAD_POOL_HPP diff --git a/boost/asio/impl/thread_pool.ipp b/boost/asio/impl/thread_pool.ipp new file mode 100644 index 0000000..d59b6ef --- /dev/null +++ b/boost/asio/impl/thread_pool.ipp @@ -0,0 +1,89 @@ +// +// impl/thread_pool.ipp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_THREAD_POOL_IPP +#define BOOST_ASIO_IMPL_THREAD_POOL_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { + +struct thread_pool::thread_function +{ + detail::scheduler* scheduler_; + + void operator()() + { + boost::system::error_code ec; + scheduler_->run(ec); + } +}; + +thread_pool::thread_pool() + : scheduler_(add_scheduler(new detail::scheduler(*this, 0, false))) +{ + scheduler_.work_started(); + + thread_function f = { &scheduler_ }; + std::size_t num_threads = detail::thread::hardware_concurrency() * 2; + threads_.create_threads(f, num_threads ? num_threads : 2); +} + +thread_pool::thread_pool(std::size_t num_threads) + : scheduler_(add_scheduler(new detail::scheduler( + *this, num_threads == 1 ? 1 : 0, false))) +{ + scheduler_.work_started(); + + thread_function f = { &scheduler_ }; + threads_.create_threads(f, num_threads); +} + +thread_pool::~thread_pool() +{ + stop(); + join(); +} + +void thread_pool::stop() +{ + scheduler_.stop(); +} + +void thread_pool::join() +{ + if (!threads_.empty()) + { + scheduler_.work_finished(); + threads_.join(); + } +} + +detail::scheduler& thread_pool::add_scheduler(detail::scheduler* s) +{ + detail::scoped_ptr scoped_impl(s); + boost::asio::add_service(*this, scoped_impl.get()); + return *scoped_impl.release(); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_THREAD_POOL_IPP diff --git a/boost/asio/impl/use_awaitable.hpp b/boost/asio/impl/use_awaitable.hpp new file mode 100644 index 0000000..0d7ad0a --- /dev/null +++ b/boost/asio/impl/use_awaitable.hpp @@ -0,0 +1,278 @@ +// +// impl/use_awaitable.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_USE_AWAITABLE_HPP +#define BOOST_ASIO_IMPL_USE_AWAITABLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class awaitable_handler_base + : public awaitable_thread +{ +public: + typedef void result_type; + typedef awaitable awaitable_type; + + // Construct from the entry point of a new thread of execution. + awaitable_handler_base(awaitable a, const Executor& ex) + : awaitable_thread(std::move(a), ex) + { + } + + // Transfer ownership from another awaitable_thread. + explicit awaitable_handler_base(awaitable_thread* h) + : awaitable_thread(std::move(*h)) + { + } + +protected: + awaitable_frame* frame() noexcept + { + return static_cast*>(this->top_of_stack_); + } +}; + +template +class awaitable_handler; + +template +class awaitable_handler + : public awaitable_handler_base +{ +public: + using awaitable_handler_base::awaitable_handler_base; + + void operator()() + { + this->frame()->attach_thread(this); + this->frame()->return_void(); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template +class awaitable_handler + : public awaitable_handler_base +{ +public: + using awaitable_handler_base::awaitable_handler_base; + + void operator()(const boost::system::error_code& ec) + { + this->frame()->attach_thread(this); + if (ec) + this->frame()->set_error(ec); + else + this->frame()->return_void(); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template +class awaitable_handler + : public awaitable_handler_base +{ +public: + using awaitable_handler_base::awaitable_handler_base; + + void operator()(std::exception_ptr ex) + { + this->frame()->attach_thread(this); + if (ex) + this->frame()->set_except(ex); + else + this->frame()->return_void(); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template +class awaitable_handler + : public awaitable_handler_base +{ +public: + using awaitable_handler_base::awaitable_handler_base; + + template + void operator()(Arg&& arg) + { + this->frame()->attach_thread(this); + this->frame()->return_value(std::forward(arg)); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template +class awaitable_handler + : public awaitable_handler_base +{ +public: + using awaitable_handler_base::awaitable_handler_base; + + template + void operator()(const boost::system::error_code& ec, Arg&& arg) + { + this->frame()->attach_thread(this); + if (ec) + this->frame()->set_error(ec); + else + this->frame()->return_value(std::forward(arg)); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template +class awaitable_handler + : public awaitable_handler_base +{ +public: + using awaitable_handler_base::awaitable_handler_base; + + template + void operator()(std::exception_ptr ex, Arg&& arg) + { + this->frame()->attach_thread(this); + if (ex) + this->frame()->set_except(ex); + else + this->frame()->return_value(std::forward(arg)); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template +class awaitable_handler + : public awaitable_handler_base> +{ +public: + using awaitable_handler_base>::awaitable_handler_base; + + template + void operator()(Args&&... args) + { + this->frame()->attach_thread(this); + this->frame()->return_values(std::forward(args)...); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template +class awaitable_handler + : public awaitable_handler_base> +{ +public: + using awaitable_handler_base>::awaitable_handler_base; + + template + void operator()(const boost::system::error_code& ec, Args&&... args) + { + this->frame()->attach_thread(this); + if (ec) + this->frame()->set_error(ec); + else + this->frame()->return_values(std::forward(args)...); + this->frame()->pop_frame(); + this->pump(); + } +}; + +template +class awaitable_handler + : public awaitable_handler_base> +{ +public: + using awaitable_handler_base>::awaitable_handler_base; + + template + void operator()(std::exception_ptr ex, Args&&... args) + { + this->frame()->attach_thread(this); + if (ex) + this->frame()->set_except(ex); + else + this->frame()->return_values(std::forward(args)...); + this->frame()->pop_frame(); + this->pump(); + } +}; + +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +class async_result, R(Args...)> +{ +public: + typedef typename detail::awaitable_handler< + Executor, typename decay::type...> handler_type; + typedef typename handler_type::awaitable_type return_type; + +#if defined(_MSC_VER) + template + static T dummy_return() + { + return std::move(*static_cast(nullptr)); + } + + template <> + static void dummy_return() + { + } +#endif // defined(_MSC_VER) + + template + static return_type initiate(Initiation initiation, + use_awaitable_t, InitArgs... args) + { + co_await [&](auto* frame) + { + handler_type handler(frame->detach_thread()); + std::move(initiation)(std::move(handler), std::move(args)...); + return static_cast(nullptr); + }; + + for (;;) {} // Never reached. +#if defined(_MSC_VER) + co_return dummy_return(); +#endif // defined(_MSC_VER) + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_USE_AWAITABLE_HPP diff --git a/boost/asio/impl/use_future.hpp b/boost/asio/impl/use_future.hpp new file mode 100644 index 0000000..83fb74a --- /dev/null +++ b/boost/asio/impl/use_future.hpp @@ -0,0 +1,889 @@ +// +// impl/use_future.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_USE_FUTURE_HPP +#define BOOST_ASIO_IMPL_USE_FUTURE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +inline void promise_invoke_and_set(std::promise& p, + F& f, BOOST_ASIO_MOVE_ARG(Args)... args) +{ +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + try +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) + { + p.set_value(f(BOOST_ASIO_MOVE_CAST(Args)(args)...)); + } +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + catch (...) + { + p.set_exception(std::current_exception()); + } +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) +} + +template +inline void promise_invoke_and_set(std::promise& p, + F& f, BOOST_ASIO_MOVE_ARG(Args)... args) +{ +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + try +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) + { + f(BOOST_ASIO_MOVE_CAST(Args)(args)...); + p.set_value(); + } +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + catch (...) + { + p.set_exception(std::current_exception()); + } +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) +} + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +inline void promise_invoke_and_set(std::promise& p, F& f) +{ +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + try +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) + { + p.set_value(f()); + } +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + catch (...) + { + p.set_exception(std::current_exception()); + } +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) +} + +template +inline void promise_invoke_and_set(std::promise& p, F& f) +{ +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + try +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) + { + f(); + p.set_value(); +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + } + catch (...) + { + p.set_exception(std::current_exception()); + } +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) +} + +#if defined(BOOST_ASIO_NO_EXCEPTIONS) + +#define BOOST_ASIO_PRIVATE_PROMISE_INVOKE_DEF(n) \ + template \ + inline void promise_invoke_and_set(std::promise& p, \ + F& f, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + p.set_value(f(BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \ + } \ + \ + template \ + inline void promise_invoke_and_set(std::promise& p, \ + F& f, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + f(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + p.set_value(); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_PROMISE_INVOKE_DEF) +#undef BOOST_ASIO_PRIVATE_PROMISE_INVOKE_DEF + +#else // defined(BOOST_ASIO_NO_EXCEPTIONS) + +#define BOOST_ASIO_PRIVATE_PROMISE_INVOKE_DEF(n) \ + template \ + inline void promise_invoke_and_set(std::promise& p, \ + F& f, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + try \ + { \ + p.set_value(f(BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \ + } \ + catch (...) \ + { \ + p.set_exception(std::current_exception()); \ + } \ + } \ + \ + template \ + inline void promise_invoke_and_set(std::promise& p, \ + F& f, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + { \ + try \ + { \ + f(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + p.set_value(); \ + } \ + catch (...) \ + { \ + p.set_exception(std::current_exception()); \ + } \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_PROMISE_INVOKE_DEF) +#undef BOOST_ASIO_PRIVATE_PROMISE_INVOKE_DEF + +#endif // defined(BOOST_ASIO_NO_EXCEPTIONS) + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +// A function object adapter to invoke a nullary function object and capture +// any exception thrown into a promise. +template +class promise_invoker +{ +public: + promise_invoker(const shared_ptr >& p, + BOOST_ASIO_MOVE_ARG(F) f) + : p_(p), f_(BOOST_ASIO_MOVE_CAST(F)(f)) + { + } + + void operator()() + { +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + try +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) + { + f_(); + } +#if !defined(BOOST_ASIO_NO_EXCEPTIONS) + catch (...) + { + p_->set_exception(std::current_exception()); + } +#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) + } + +private: + shared_ptr > p_; + typename decay::type f_; +}; + +// An executor that adapts the system_executor to capture any exeption thrown +// by a submitted function object and save it into a promise. +template +class promise_executor +{ +public: + explicit promise_executor(const shared_ptr >& p) + : p_(p) + { + } + + execution_context& context() const BOOST_ASIO_NOEXCEPT + { + return system_executor().context(); + } + + void on_work_started() const BOOST_ASIO_NOEXCEPT {} + void on_work_finished() const BOOST_ASIO_NOEXCEPT {} + + template + void dispatch(BOOST_ASIO_MOVE_ARG(F) f, const A&) const + { + promise_invoker(p_, BOOST_ASIO_MOVE_CAST(F)(f))(); + } + + template + void post(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const + { + system_executor().post( + promise_invoker(p_, BOOST_ASIO_MOVE_CAST(F)(f)), a); + } + + template + void defer(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const + { + system_executor().defer( + promise_invoker(p_, BOOST_ASIO_MOVE_CAST(F)(f)), a); + } + + friend bool operator==(const promise_executor& a, + const promise_executor& b) BOOST_ASIO_NOEXCEPT + { + return a.p_ == b.p_; + } + + friend bool operator!=(const promise_executor& a, + const promise_executor& b) BOOST_ASIO_NOEXCEPT + { + return a.p_ != b.p_; + } + +private: + shared_ptr > p_; +}; + +// The base class for all completion handlers that create promises. +template +class promise_creator +{ +public: + typedef promise_executor executor_type; + + executor_type get_executor() const BOOST_ASIO_NOEXCEPT + { + return executor_type(p_); + } + + typedef std::future future_type; + + future_type get_future() + { + return p_->get_future(); + } + +protected: + template + void create_promise(const Allocator& a) + { + BOOST_ASIO_REBIND_ALLOC(Allocator, char) b(a); + p_ = std::allocate_shared>(b, std::allocator_arg, b); + } + + shared_ptr > p_; +}; + +// For completion signature void(). +class promise_handler_0 + : public promise_creator +{ +public: + void operator()() + { + this->p_->set_value(); + } +}; + +// For completion signature void(error_code). +class promise_handler_ec_0 + : public promise_creator +{ +public: + void operator()(const boost::system::error_code& ec) + { + if (ec) + { + this->p_->set_exception( + std::make_exception_ptr( + boost::system::system_error(ec))); + } + else + { + this->p_->set_value(); + } + } +}; + +// For completion signature void(exception_ptr). +class promise_handler_ex_0 + : public promise_creator +{ +public: + void operator()(const std::exception_ptr& ex) + { + if (ex) + { + this->p_->set_exception(ex); + } + else + { + this->p_->set_value(); + } + } +}; + +// For completion signature void(T). +template +class promise_handler_1 + : public promise_creator +{ +public: + template + void operator()(BOOST_ASIO_MOVE_ARG(Arg) arg) + { + this->p_->set_value(BOOST_ASIO_MOVE_CAST(Arg)(arg)); + } +}; + +// For completion signature void(error_code, T). +template +class promise_handler_ec_1 + : public promise_creator +{ +public: + template + void operator()(const boost::system::error_code& ec, + BOOST_ASIO_MOVE_ARG(Arg) arg) + { + if (ec) + { + this->p_->set_exception( + std::make_exception_ptr( + boost::system::system_error(ec))); + } + else + this->p_->set_value(BOOST_ASIO_MOVE_CAST(Arg)(arg)); + } +}; + +// For completion signature void(exception_ptr, T). +template +class promise_handler_ex_1 + : public promise_creator +{ +public: + template + void operator()(const std::exception_ptr& ex, + BOOST_ASIO_MOVE_ARG(Arg) arg) + { + if (ex) + this->p_->set_exception(ex); + else + this->p_->set_value(BOOST_ASIO_MOVE_CAST(Arg)(arg)); + } +}; + +// For completion signature void(T1, ..., Tn); +template +class promise_handler_n + : public promise_creator +{ +public: +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + void operator()(BOOST_ASIO_MOVE_ARG(Args)... args) + { + this->p_->set_value( + std::forward_as_tuple( + BOOST_ASIO_MOVE_CAST(Args)(args)...)); + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#define BOOST_ASIO_PRIVATE_CALL_OP_DEF(n) \ + template \ + void operator()(BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + {\ + this->p_->set_value( \ + std::forward_as_tuple( \ + BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CALL_OP_DEF) +#undef BOOST_ASIO_PRIVATE_CALL_OP_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +}; + +// For completion signature void(error_code, T1, ..., Tn); +template +class promise_handler_ec_n + : public promise_creator +{ +public: +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + void operator()(const boost::system::error_code& ec, + BOOST_ASIO_MOVE_ARG(Args)... args) + { + if (ec) + { + this->p_->set_exception( + std::make_exception_ptr( + boost::system::system_error(ec))); + } + else + { + this->p_->set_value( + std::forward_as_tuple( + BOOST_ASIO_MOVE_CAST(Args)(args)...)); + } + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#define BOOST_ASIO_PRIVATE_CALL_OP_DEF(n) \ + template \ + void operator()(const boost::system::error_code& ec, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + {\ + if (ec) \ + { \ + this->p_->set_exception( \ + std::make_exception_ptr( \ + boost::system::system_error(ec))); \ + } \ + else \ + { \ + this->p_->set_value( \ + std::forward_as_tuple( \ + BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \ + } \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CALL_OP_DEF) +#undef BOOST_ASIO_PRIVATE_CALL_OP_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +}; + +// For completion signature void(exception_ptr, T1, ..., Tn); +template +class promise_handler_ex_n + : public promise_creator +{ +public: +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + void operator()(const std::exception_ptr& ex, + BOOST_ASIO_MOVE_ARG(Args)... args) + { + if (ex) + this->p_->set_exception(ex); + else + { + this->p_->set_value( + std::forward_as_tuple( + BOOST_ASIO_MOVE_CAST(Args)(args)...)); + } + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#define BOOST_ASIO_PRIVATE_CALL_OP_DEF(n) \ + template \ + void operator()(const std::exception_ptr& ex, \ + BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + {\ + if (ex) \ + this->p_->set_exception(ex); \ + else \ + { \ + this->p_->set_value( \ + std::forward_as_tuple( \ + BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \ + } \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CALL_OP_DEF) +#undef BOOST_ASIO_PRIVATE_CALL_OP_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) +}; + +// Helper template to choose the appropriate concrete promise handler +// implementation based on the supplied completion signature. +template class promise_handler_selector; + +template <> +class promise_handler_selector + : public promise_handler_0 {}; + +template <> +class promise_handler_selector + : public promise_handler_ec_0 {}; + +template <> +class promise_handler_selector + : public promise_handler_ex_0 {}; + +template +class promise_handler_selector + : public promise_handler_1 {}; + +template +class promise_handler_selector + : public promise_handler_ec_1 {}; + +template +class promise_handler_selector + : public promise_handler_ex_1 {}; + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +class promise_handler_selector + : public promise_handler_n > {}; + +template +class promise_handler_selector + : public promise_handler_ec_n > {}; + +template +class promise_handler_selector + : public promise_handler_ex_n > {}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#define BOOST_ASIO_PRIVATE_PROMISE_SELECTOR_DEF(n) \ + template \ + class promise_handler_selector< \ + void(Arg, BOOST_ASIO_VARIADIC_TARGS(n))> \ + : public promise_handler_n< \ + std::tuple > {}; \ + \ + template \ + class promise_handler_selector< \ + void(boost::system::error_code, Arg, BOOST_ASIO_VARIADIC_TARGS(n))> \ + : public promise_handler_ec_n< \ + std::tuple > {}; \ + \ + template \ + class promise_handler_selector< \ + void(std::exception_ptr, Arg, BOOST_ASIO_VARIADIC_TARGS(n))> \ + : public promise_handler_ex_n< \ + std::tuple > {}; \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_PROMISE_SELECTOR_DEF) +#undef BOOST_ASIO_PRIVATE_PROMISE_SELECTOR_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +// Completion handlers produced from the use_future completion token, when not +// using use_future::operator(). +template +class promise_handler + : public promise_handler_selector +{ +public: + typedef Allocator allocator_type; + typedef void result_type; + + promise_handler(use_future_t u) + : allocator_(u.get_allocator()) + { + this->create_promise(allocator_); + } + + allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT + { + return allocator_; + } + +private: + Allocator allocator_; +}; + +template +inline void asio_handler_invoke(Function& f, + promise_handler* h) +{ + typename promise_handler::executor_type + ex(h->get_executor()); + ex.dispatch(BOOST_ASIO_MOVE_CAST(Function)(f), std::allocator()); +} + +template +inline void asio_handler_invoke(const Function& f, + promise_handler* h) +{ + typename promise_handler::executor_type + ex(h->get_executor()); + ex.dispatch(f, std::allocator()); +} + +// Helper base class for async_result specialisation. +template +class promise_async_result +{ +public: + typedef promise_handler completion_handler_type; + typedef typename completion_handler_type::future_type return_type; + + explicit promise_async_result(completion_handler_type& h) + : future_(h.get_future()) + { + } + + return_type get() + { + return BOOST_ASIO_MOVE_CAST(return_type)(future_); + } + +private: + return_type future_; +}; + +// Return value from use_future::operator(). +template +class packaged_token +{ +public: + packaged_token(Function f, const Allocator& a) + : function_(BOOST_ASIO_MOVE_CAST(Function)(f)), + allocator_(a) + { + } + +//private: + Function function_; + Allocator allocator_; +}; + +// Completion handlers produced from the use_future completion token, when +// using use_future::operator(). +template +class packaged_handler + : public promise_creator +{ +public: + typedef Allocator allocator_type; + typedef void result_type; + + packaged_handler(packaged_token t) + : function_(BOOST_ASIO_MOVE_CAST(Function)(t.function_)), + allocator_(t.allocator_) + { + this->create_promise(allocator_); + } + + allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT + { + return allocator_; + } + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + template + void operator()(BOOST_ASIO_MOVE_ARG(Args)... args) + { + (promise_invoke_and_set)(*this->p_, + function_, BOOST_ASIO_MOVE_CAST(Args)(args)...); + } + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + + void operator()() + { + (promise_invoke_and_set)(*this->p_, function_); + } + +#define BOOST_ASIO_PRIVATE_CALL_OP_DEF(n) \ + template \ + void operator()(BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ + {\ + (promise_invoke_and_set)(*this->p_, \ + function_, BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ + } \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_CALL_OP_DEF) +#undef BOOST_ASIO_PRIVATE_CALL_OP_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +private: + Function function_; + Allocator allocator_; +}; + +template +inline void asio_handler_invoke(Function& f, + packaged_handler* h) +{ + typename packaged_handler::executor_type + ex(h->get_executor()); + ex.dispatch(BOOST_ASIO_MOVE_CAST(Function)(f), std::allocator()); +} + +template +inline void asio_handler_invoke(const Function& f, + packaged_handler* h) +{ + typename packaged_handler::executor_type + ex(h->get_executor()); + ex.dispatch(f, std::allocator()); +} + +// Helper base class for async_result specialisation. +template +class packaged_async_result +{ +public: + typedef packaged_handler completion_handler_type; + typedef typename completion_handler_type::future_type return_type; + + explicit packaged_async_result(completion_handler_type& h) + : future_(h.get_future()) + { + } + + return_type get() + { + return BOOST_ASIO_MOVE_CAST(return_type)(future_); + } + +private: + return_type future_; +}; + +} // namespace detail + +template template +inline detail::packaged_token::type, Allocator> +use_future_t::operator()(BOOST_ASIO_MOVE_ARG(Function) f) const +{ + return detail::packaged_token::type, Allocator>( + BOOST_ASIO_MOVE_CAST(Function)(f), allocator_); +} + +#if !defined(GENERATING_DOCUMENTATION) + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +class async_result, Result(Args...)> + : public detail::promise_async_result< + void(typename decay::type...), Allocator> +{ +public: + explicit async_result( + typename detail::promise_async_result::type...), + Allocator>::completion_handler_type& h) + : detail::promise_async_result< + void(typename decay::type...), Allocator>(h) + { + } +}; + +template +class async_result, Result(Args...)> + : public detail::packaged_async_result::type> +{ +public: + explicit async_result( + typename detail::packaged_async_result::type>::completion_handler_type& h) + : detail::packaged_async_result::type>(h) + { + } +}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +template +class async_result, Result()> + : public detail::promise_async_result +{ +public: + explicit async_result( + typename detail::promise_async_result< + void(), Allocator>::completion_handler_type& h) + : detail::promise_async_result(h) + { + } +}; + +template +class async_result, Result()> + : public detail::packaged_async_result::type> +{ +public: + explicit async_result( + typename detail::packaged_async_result::type>::completion_handler_type& h) + : detail::packaged_async_result::type>(h) + { + } +}; + +#define BOOST_ASIO_PRIVATE_ASYNC_RESULT_DEF(n) \ + template \ + class async_result, \ + Result(BOOST_ASIO_VARIADIC_TARGS(n))> \ + : public detail::promise_async_result< \ + void(BOOST_ASIO_VARIADIC_DECAY(n)), Allocator> \ + { \ + public: \ + explicit async_result( \ + typename detail::promise_async_result< \ + void(BOOST_ASIO_VARIADIC_DECAY(n)), \ + Allocator>::completion_handler_type& h) \ + : detail::promise_async_result< \ + void(BOOST_ASIO_VARIADIC_DECAY(n)), Allocator>(h) \ + { \ + } \ + }; \ + \ + template \ + class async_result, \ + Result(BOOST_ASIO_VARIADIC_TARGS(n))> \ + : public detail::packaged_async_result::type> \ + { \ + public: \ + explicit async_result( \ + typename detail::packaged_async_result::type \ + >::completion_handler_type& h) \ + : detail::packaged_async_result::type>(h) \ + { \ + } \ + }; \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_ASYNC_RESULT_DEF) +#undef BOOST_ASIO_PRIVATE_ASYNC_RESULT_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + +#endif // !defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_USE_FUTURE_HPP diff --git a/boost/asio/impl/write.hpp b/boost/asio/impl/write.hpp new file mode 100644 index 0000000..9624359 --- /dev/null +++ b/boost/asio/impl/write.hpp @@ -0,0 +1,980 @@ +// +// impl/write.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_WRITE_HPP +#define BOOST_ASIO_IMPL_WRITE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +namespace detail +{ + template + std::size_t write_buffer_sequence(SyncWriteStream& s, + const ConstBufferSequence& buffers, const ConstBufferIterator&, + CompletionCondition completion_condition, boost::system::error_code& ec) + { + ec = boost::system::error_code(); + boost::asio::detail::consuming_buffers tmp(buffers); + while (!tmp.empty()) + { + if (std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, tmp.total_consumed()))) + tmp.consume(s.write_some(tmp.prepare(max_size), ec)); + else + break; + } + return tmp.total_consumed();; + } +} // namespace detail + +template +inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_const_buffer_sequence::value + >::type*) +{ + return detail::write_buffer_sequence(s, buffers, + boost::asio::buffer_sequence_begin(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); +} + +template +inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + typename enable_if< + is_const_buffer_sequence::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = write(s, buffers, transfer_all(), ec); + boost::asio::detail::throw_error(ec, "write"); + return bytes_transferred; +} + +template +inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + boost::system::error_code& ec, + typename enable_if< + is_const_buffer_sequence::value + >::type*) +{ + return write(s, buffers, transfer_all(), ec); +} + +template +inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, + typename enable_if< + is_const_buffer_sequence::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = write(s, buffers, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); + boost::asio::detail::throw_error(ec, "write"); + return bytes_transferred; +} + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +template +std::size_t write(SyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + typename decay::type b( + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers)); + + std::size_t bytes_transferred = write(s, b.data(), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); + b.consume(bytes_transferred); + return bytes_transferred; +} + +template +inline std::size_t write(SyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = write(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + transfer_all(), ec); + boost::asio::detail::throw_error(ec, "write"); + return bytes_transferred; +} + +template +inline std::size_t write(SyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + return write(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + transfer_all(), ec); +} + +template +inline std::size_t write(SyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = write(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); + boost::asio::detail::throw_error(ec, "write"); + return bytes_transferred; +} + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +template +inline std::size_t write(SyncWriteStream& s, + boost::asio::basic_streambuf& b, + CompletionCondition completion_condition, boost::system::error_code& ec) +{ + return write(s, basic_streambuf_ref(b), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); +} + +template +inline std::size_t write(SyncWriteStream& s, + boost::asio::basic_streambuf& b) +{ + return write(s, basic_streambuf_ref(b)); +} + +template +inline std::size_t write(SyncWriteStream& s, + boost::asio::basic_streambuf& b, + boost::system::error_code& ec) +{ + return write(s, basic_streambuf_ref(b), ec); +} + +template +inline std::size_t write(SyncWriteStream& s, + boost::asio::basic_streambuf& b, + CompletionCondition completion_condition) +{ + return write(s, basic_streambuf_ref(b), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); +} + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +template +std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + std::size_t bytes_transferred = write(s, buffers.data(0, buffers.size()), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); + buffers.consume(bytes_transferred); + return bytes_transferred; +} + +template +inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = write(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + transfer_all(), ec); + boost::asio::detail::throw_error(ec, "write"); + return bytes_transferred; +} + +template +inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + return write(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + transfer_all(), ec); +} + +template +inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = write(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); + boost::asio::detail::throw_error(ec, "write"); + return bytes_transferred; +} + +namespace detail +{ + template + class write_op + : detail::base_from_completion_cond + { + public: + write_op(AsyncWriteStream& stream, const ConstBufferSequence& buffers, + CompletionCondition& completion_condition, WriteHandler& handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + stream_(stream), + buffers_(buffers), + start_(0), + handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + write_op(const write_op& other) + : detail::base_from_completion_cond(other), + stream_(other.stream_), + buffers_(other.buffers_), + start_(other.start_), + handler_(other.handler_) + { + } + + write_op(write_op&& other) + : detail::base_from_completion_cond( + BOOST_ASIO_MOVE_CAST(detail::base_from_completion_cond< + CompletionCondition>)(other)), + stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(buffers_type)(other.buffers_)), + start_(other.start_), + handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t max_size; + switch (start_ = start) + { + case 1: + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + do + { + stream_.async_write_some(buffers_.prepare(max_size), + BOOST_ASIO_MOVE_CAST(write_op)(*this)); + return; default: + buffers_.consume(bytes_transferred); + if ((!ec && bytes_transferred == 0) || buffers_.empty()) + break; + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + } while (max_size > 0); + + handler_(ec, buffers_.total_consumed()); + } + } + + //private: + typedef boost::asio::detail::consuming_buffers buffers_type; + + AsyncWriteStream& stream_; + buffers_type buffers_; + int start_; + WriteHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + write_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + write_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + write_op* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + write_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + write_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void start_write_buffer_sequence_op(AsyncWriteStream& stream, + const ConstBufferSequence& buffers, const ConstBufferIterator&, + CompletionCondition& completion_condition, WriteHandler& handler) + { + detail::write_op( + stream, buffers, completion_condition, handler)( + boost::system::error_code(), 0, 1); + } + + struct initiate_async_write_buffer_sequence + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + AsyncWriteStream* s, const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + non_const_lvalue handler2(handler); + non_const_lvalue completion_cond2(completion_cond); + start_write_buffer_sequence_op(*s, buffers, + boost::asio::buffer_sequence_begin(buffers), + completion_cond2.value, handler2.value); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::write_op, + Allocator> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::write_op& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::write_op, + Executor> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::write_op& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_const_buffer_sequence::value + >::type*) +{ + return async_initiate( + detail::initiate_async_write_buffer_sequence(), handler, &s, buffers, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); +} + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_const_buffer_sequence::value + >::type*) +{ + return async_initiate( + detail::initiate_async_write_buffer_sequence(), + handler, &s, buffers, transfer_all()); +} + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +namespace detail +{ + template + class write_dynbuf_v1_op + { + public: + template + write_dynbuf_v1_op(AsyncWriteStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, + CompletionCondition& completion_condition, WriteHandler& handler) + : stream_(stream), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), + completion_condition_( + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)), + handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + write_dynbuf_v1_op(const write_dynbuf_v1_op& other) + : stream_(other.stream_), + buffers_(other.buffers_), + completion_condition_(other.completion_condition_), + handler_(other.handler_) + { + } + + write_dynbuf_v1_op(write_dynbuf_v1_op&& other) + : stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(other.buffers_)), + completion_condition_( + BOOST_ASIO_MOVE_CAST(CompletionCondition)( + other.completion_condition_)), + handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + switch (start) + { + case 1: + async_write(stream_, buffers_.data(), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition_), + BOOST_ASIO_MOVE_CAST(write_dynbuf_v1_op)(*this)); + return; default: + buffers_.consume(bytes_transferred); + handler_(ec, static_cast(bytes_transferred)); + } + } + + //private: + AsyncWriteStream& stream_; + DynamicBuffer_v1 buffers_; + CompletionCondition completion_condition_; + WriteHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + write_dynbuf_v1_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + write_dynbuf_v1_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + write_dynbuf_v1_op* this_handler) + { + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + write_dynbuf_v1_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + write_dynbuf_v1_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_write_dynbuf_v1 + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + AsyncWriteStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + non_const_lvalue handler2(handler); + non_const_lvalue completion_cond2(completion_cond); + write_dynbuf_v1_op::type, + CompletionCondition, typename decay::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + completion_cond2.value, handler2.value)( + boost::system::error_code(), 0, 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::write_dynbuf_v1_op, + Allocator> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::write_dynbuf_v1_op& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::write_dynbuf_v1_op, + Executor> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::write_dynbuf_v1_op& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + return async_write(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + transfer_all(), BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); +} + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type*) +{ + return async_initiate( + detail::initiate_async_write_dynbuf_v1(), handler, &s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); +} + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, + boost::asio::basic_streambuf& b, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) +{ + return async_write(s, basic_streambuf_ref(b), + BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); +} + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, + boost::asio::basic_streambuf& b, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) +{ + return async_write(s, basic_streambuf_ref(b), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), + BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); +} + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +namespace detail +{ + template + class write_dynbuf_v2_op + { + public: + template + write_dynbuf_v2_op(AsyncWriteStream& stream, + BOOST_ASIO_MOVE_ARG(BufferSequence) buffers, + CompletionCondition& completion_condition, WriteHandler& handler) + : stream_(stream), + buffers_(BOOST_ASIO_MOVE_CAST(BufferSequence)(buffers)), + completion_condition_( + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)), + handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + write_dynbuf_v2_op(const write_dynbuf_v2_op& other) + : stream_(other.stream_), + buffers_(other.buffers_), + completion_condition_(other.completion_condition_), + handler_(other.handler_) + { + } + + write_dynbuf_v2_op(write_dynbuf_v2_op&& other) + : stream_(other.stream_), + buffers_(BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(other.buffers_)), + completion_condition_( + BOOST_ASIO_MOVE_CAST(CompletionCondition)( + other.completion_condition_)), + handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + switch (start) + { + case 1: + async_write(stream_, buffers_.data(0, buffers_.size()), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition_), + BOOST_ASIO_MOVE_CAST(write_dynbuf_v2_op)(*this)); + return; default: + buffers_.consume(bytes_transferred); + handler_(ec, static_cast(bytes_transferred)); + } + } + + //private: + AsyncWriteStream& stream_; + DynamicBuffer_v2 buffers_; + CompletionCondition completion_condition_; + WriteHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + write_dynbuf_v2_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + write_dynbuf_v2_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + write_dynbuf_v2_op* this_handler) + { + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + write_dynbuf_v2_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + write_dynbuf_v2_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_write_dynbuf_v2 + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + AsyncWriteStream* s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v2) buffers, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + non_const_lvalue handler2(handler); + non_const_lvalue completion_cond2(completion_cond); + write_dynbuf_v2_op::type, + CompletionCondition, typename decay::type>( + *s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + completion_cond2.value, handler2.value)( + boost::system::error_code(), 0, 1); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::write_dynbuf_v2_op, + Allocator> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::write_dynbuf_v2_op& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::write_dynbuf_v2_op, + Executor> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::write_dynbuf_v2_op& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + return async_write(s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + transfer_all(), BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); +} + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer_v2::value + >::type*) +{ + return async_initiate( + detail::initiate_async_write_dynbuf_v2(), handler, &s, + BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); +} + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_WRITE_HPP diff --git a/boost/asio/impl/write_at.hpp b/boost/asio/impl/write_at.hpp new file mode 100644 index 0000000..3cad9c5 --- /dev/null +++ b/boost/asio/impl/write_at.hpp @@ -0,0 +1,580 @@ +// +// impl/write_at.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IMPL_WRITE_AT_HPP +#define BOOST_ASIO_IMPL_WRITE_AT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +namespace detail +{ + template + std::size_t write_at_buffer_sequence(SyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, + const ConstBufferIterator&, CompletionCondition completion_condition, + boost::system::error_code& ec) + { + ec = boost::system::error_code(); + boost::asio::detail::consuming_buffers tmp(buffers); + while (!tmp.empty()) + { + if (std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, tmp.total_consumed()))) + { + tmp.consume(d.write_some_at(offset + tmp.total_consumed(), + tmp.prepare(max_size), ec)); + } + else + break; + } + return tmp.total_consumed();; + } +} // namespace detail + +template +std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, boost::system::error_code& ec) +{ + return detail::write_at_buffer_sequence(d, offset, buffers, + boost::asio::buffer_sequence_begin(buffers), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); +} + +template +inline std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = write_at( + d, offset, buffers, transfer_all(), ec); + boost::asio::detail::throw_error(ec, "write_at"); + return bytes_transferred; +} + +template +inline std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, + boost::system::error_code& ec) +{ + return write_at(d, offset, buffers, transfer_all(), ec); +} + +template +inline std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, + CompletionCondition completion_condition) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = write_at(d, offset, buffers, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); + boost::asio::detail::throw_error(ec, "write_at"); + return bytes_transferred; +} + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +template +std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, boost::asio::basic_streambuf& b, + CompletionCondition completion_condition, boost::system::error_code& ec) +{ + std::size_t bytes_transferred = write_at(d, offset, b.data(), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); + b.consume(bytes_transferred); + return bytes_transferred; +} + +template +inline std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, boost::asio::basic_streambuf& b) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = write_at(d, offset, b, transfer_all(), ec); + boost::asio::detail::throw_error(ec, "write_at"); + return bytes_transferred; +} + +template +inline std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, boost::asio::basic_streambuf& b, + boost::system::error_code& ec) +{ + return write_at(d, offset, b, transfer_all(), ec); +} + +template +inline std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, boost::asio::basic_streambuf& b, + CompletionCondition completion_condition) +{ + boost::system::error_code ec; + std::size_t bytes_transferred = write_at(d, offset, b, + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); + boost::asio::detail::throw_error(ec, "write_at"); + return bytes_transferred; +} + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +namespace detail +{ + template + class write_at_op + : detail::base_from_completion_cond + { + public: + write_at_op(AsyncRandomAccessWriteDevice& device, + uint64_t offset, const ConstBufferSequence& buffers, + CompletionCondition& completion_condition, WriteHandler& handler) + : detail::base_from_completion_cond< + CompletionCondition>(completion_condition), + device_(device), + offset_(offset), + buffers_(buffers), + start_(0), + handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + write_at_op(const write_at_op& other) + : detail::base_from_completion_cond(other), + device_(other.device_), + offset_(other.offset_), + buffers_(other.buffers_), + start_(other.start_), + handler_(other.handler_) + { + } + + write_at_op(write_at_op&& other) + : detail::base_from_completion_cond( + BOOST_ASIO_MOVE_CAST(detail::base_from_completion_cond< + CompletionCondition>)(other)), + device_(other.device_), + offset_(other.offset_), + buffers_(BOOST_ASIO_MOVE_CAST(buffers_type)(other.buffers_)), + start_(other.start_), + handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + std::size_t bytes_transferred, int start = 0) + { + std::size_t max_size; + switch (start_ = start) + { + case 1: + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + do + { + device_.async_write_some_at( + offset_ + buffers_.total_consumed(), buffers_.prepare(max_size), + BOOST_ASIO_MOVE_CAST(write_at_op)(*this)); + return; default: + buffers_.consume(bytes_transferred); + if ((!ec && bytes_transferred == 0) || buffers_.empty()) + break; + max_size = this->check_for_completion(ec, buffers_.total_consumed()); + } while (max_size > 0); + + handler_(ec, buffers_.total_consumed()); + } + } + + //private: + typedef boost::asio::detail::consuming_buffers buffers_type; + + AsyncRandomAccessWriteDevice& device_; + uint64_t offset_; + buffers_type buffers_; + int start_; + WriteHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + write_at_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + write_at_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + write_at_op* this_handler) + { + return this_handler->start_ == 0 ? true + : boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + write_at_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + write_at_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void start_write_at_buffer_sequence_op(AsyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, + const ConstBufferIterator&, CompletionCondition& completion_condition, + WriteHandler& handler) + { + detail::write_at_op( + d, offset, buffers, completion_condition, handler)( + boost::system::error_code(), 0, 1); + } + + struct initiate_async_write_at_buffer_sequence + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + AsyncRandomAccessWriteDevice* d, uint64_t offset, + const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_cond) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + non_const_lvalue handler2(handler); + non_const_lvalue completion_cond2(completion_cond); + start_write_at_buffer_sequence_op(*d, offset, buffers, + boost::asio::buffer_sequence_begin(buffers), + completion_cond2.value, handler2.value); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::write_at_op, + Allocator> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::write_at_op& h, + const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::write_at_op, + Executor> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::write_at_op& h, + const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write_at(AsyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) +{ + return async_initiate( + detail::initiate_async_write_at_buffer_sequence(), handler, &d, offset, + buffers, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); +} + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write_at(AsyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) +{ + return async_initiate( + detail::initiate_async_write_at_buffer_sequence(), + handler, &d, offset, buffers, transfer_all()); +} + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +namespace detail +{ + template + class write_at_streambuf_op + { + public: + write_at_streambuf_op( + boost::asio::basic_streambuf& streambuf, + WriteHandler& handler) + : streambuf_(streambuf), + handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + write_at_streambuf_op(const write_at_streambuf_op& other) + : streambuf_(other.streambuf_), + handler_(other.handler_) + { + } + + write_at_streambuf_op(write_at_streambuf_op&& other) + : streambuf_(other.streambuf_), + handler_(BOOST_ASIO_MOVE_CAST(WriteHandler)(other.handler_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + void operator()(const boost::system::error_code& ec, + const std::size_t bytes_transferred) + { + streambuf_.consume(bytes_transferred); + handler_(ec, bytes_transferred); + } + + //private: + boost::asio::basic_streambuf& streambuf_; + WriteHandler handler_; + }; + + template + inline void* asio_handler_allocate(std::size_t size, + write_at_streambuf_op* this_handler) + { + return boost_asio_handler_alloc_helpers::allocate( + size, this_handler->handler_); + } + + template + inline void asio_handler_deallocate(void* pointer, std::size_t size, + write_at_streambuf_op* this_handler) + { + boost_asio_handler_alloc_helpers::deallocate( + pointer, size, this_handler->handler_); + } + + template + inline bool asio_handler_is_continuation( + write_at_streambuf_op* this_handler) + { + return boost_asio_handler_cont_helpers::is_continuation( + this_handler->handler_); + } + + template + inline void asio_handler_invoke(Function& function, + write_at_streambuf_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + template + inline void asio_handler_invoke(const Function& function, + write_at_streambuf_op* this_handler) + { + boost_asio_handler_invoke_helpers::invoke( + function, this_handler->handler_); + } + + struct initiate_async_write_at_streambuf + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + AsyncRandomAccessWriteDevice* d, uint64_t offset, + basic_streambuf* b, + BOOST_ASIO_MOVE_ARG(CompletionCondition) completion_condition) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + non_const_lvalue handler2(handler); + async_write_at(*d, offset, b->data(), + BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), + write_at_streambuf_op::type>( + *b, handler2.value)); + } + }; +} // namespace detail + +#if !defined(GENERATING_DOCUMENTATION) + +template +struct associated_allocator< + detail::write_at_streambuf_op, + Allocator1> +{ + typedef typename associated_allocator::type type; + + static type get( + const detail::write_at_streambuf_op& h, + const Allocator1& a = Allocator1()) BOOST_ASIO_NOEXCEPT + { + return associated_allocator::get(h.handler_, a); + } +}; + +template +struct associated_executor< + detail::write_at_streambuf_op, + Executor1> +{ + typedef typename associated_executor::type type; + + static type get( + const detail::write_at_streambuf_op& h, + const Executor1& ex = Executor1()) BOOST_ASIO_NOEXCEPT + { + return associated_executor::get(h.handler_, ex); + } +}; + +#endif // !defined(GENERATING_DOCUMENTATION) + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write_at(AsyncRandomAccessWriteDevice& d, + uint64_t offset, boost::asio::basic_streambuf& b, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) +{ + return async_initiate( + detail::initiate_async_write_at_streambuf(), handler, &d, offset, + &b, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); +} + +template +inline BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write_at(AsyncRandomAccessWriteDevice& d, + uint64_t offset, boost::asio::basic_streambuf& b, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) +{ + return async_initiate( + detail::initiate_async_write_at_streambuf(), + handler, &d, offset, &b, transfer_all()); +} + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IMPL_WRITE_AT_HPP diff --git a/boost/asio/io_context.hpp b/boost/asio/io_context.hpp new file mode 100644 index 0000000..1fb3864 --- /dev/null +++ b/boost/asio/io_context.hpp @@ -0,0 +1,874 @@ +// +// io_context.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IO_CONTEXT_HPP +#define BOOST_ASIO_IO_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_CHRONO) +# include +#endif // defined(BOOST_ASIO_HAS_CHRONO) + +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# include +#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \ + || defined(__osf__) +# include +#endif + +#include + +namespace boost { +namespace asio { + +namespace detail { +#if defined(BOOST_ASIO_HAS_IOCP) + typedef class win_iocp_io_context io_context_impl; + class win_iocp_overlapped_ptr; +#else + typedef class scheduler io_context_impl; +#endif +} // namespace detail + +/// Provides core I/O functionality. +/** + * The io_context class provides the core I/O functionality for users of the + * asynchronous I/O objects, including: + * + * @li boost::asio::ip::tcp::socket + * @li boost::asio::ip::tcp::acceptor + * @li boost::asio::ip::udp::socket + * @li boost::asio::deadline_timer. + * + * The io_context class also includes facilities intended for developers of + * custom asynchronous services. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Safe, with the specific exceptions of the restart() + * and notify_fork() functions. Calling restart() while there are unfinished + * run(), run_one(), run_for(), run_until(), poll() or poll_one() calls results + * in undefined behaviour. The notify_fork() function should not be called + * while any io_context function, or any function on an I/O object that is + * associated with the io_context, is being called in another thread. + * + * @par Concepts: + * Dispatcher. + * + * @par Synchronous and asynchronous operations + * + * Synchronous operations on I/O objects implicitly run the io_context object + * for an individual operation. The io_context functions run(), run_one(), + * run_for(), run_until(), poll() or poll_one() must be called for the + * io_context to perform asynchronous operations on behalf of a C++ program. + * Notification that an asynchronous operation has completed is delivered by + * invocation of the associated handler. Handlers are invoked only by a thread + * that is currently calling any overload of run(), run_one(), run_for(), + * run_until(), poll() or poll_one() for the io_context. + * + * @par Effect of exceptions thrown from handlers + * + * If an exception is thrown from a handler, the exception is allowed to + * propagate through the throwing thread's invocation of run(), run_one(), + * run_for(), run_until(), poll() or poll_one(). No other threads that are + * calling any of these functions are affected. It is then the responsibility + * of the application to catch the exception. + * + * After the exception has been caught, the run(), run_one(), run_for(), + * run_until(), poll() or poll_one() call may be restarted @em without the need + * for an intervening call to restart(). This allows the thread to rejoin the + * io_context object's thread pool without impacting any other threads in the + * pool. + * + * For example: + * + * @code + * boost::asio::io_context io_context; + * ... + * for (;;) + * { + * try + * { + * io_context.run(); + * break; // run() exited normally + * } + * catch (my_exception& e) + * { + * // Deal with exception as appropriate. + * } + * } + * @endcode + * + * @par Submitting arbitrary tasks to the io_context + * + * To submit functions to the io_context, use the @ref boost::asio::dispatch, + * @ref boost::asio::post or @ref boost::asio::defer free functions. + * + * For example: + * + * @code void my_task() + * { + * ... + * } + * + * ... + * + * boost::asio::io_context io_context; + * + * // Submit a function to the io_context. + * boost::asio::post(io_context, my_task); + * + * // Submit a lambda object to the io_context. + * boost::asio::post(io_context, + * []() + * { + * ... + * }); + * + * // Run the io_context until it runs out of work. + * io_context.run(); @endcode + * + * @par Stopping the io_context from running out of work + * + * Some applications may need to prevent an io_context object's run() call from + * returning when there is no more work to do. For example, the io_context may + * be being run in a background thread that is launched prior to the + * application's asynchronous operations. The run() call may be kept running by + * creating an object of type + * boost::asio::executor_work_guard: + * + * @code boost::asio::io_context io_context; + * boost::asio::executor_work_guard + * = boost::asio::make_work_guard(io_context); + * ... @endcode + * + * To effect a shutdown, the application will then need to call the io_context + * object's stop() member function. This will cause the io_context run() call + * to return as soon as possible, abandoning unfinished operations and without + * permitting ready handlers to be dispatched. + * + * Alternatively, if the application requires that all operations and handlers + * be allowed to finish normally, the work object may be explicitly reset. + * + * @code boost::asio::io_context io_context; + * boost::asio::executor_work_guard + * = boost::asio::make_work_guard(io_context); + * ... + * work.reset(); // Allow run() to exit. @endcode + */ +class io_context + : public execution_context +{ +private: + typedef detail::io_context_impl impl_type; +#if defined(BOOST_ASIO_HAS_IOCP) + friend class detail::win_iocp_overlapped_ptr; +#endif + +public: + class executor_type; + friend class executor_type; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + class work; + friend class work; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + class service; + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) + class strand; +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + + /// The type used to count the number of handlers executed by the context. + typedef std::size_t count_type; + + /// Constructor. + BOOST_ASIO_DECL io_context(); + + /// Constructor. + /** + * Construct with a hint about the required level of concurrency. + * + * @param concurrency_hint A suggestion to the implementation on how many + * threads it should allow to run simultaneously. + */ + BOOST_ASIO_DECL explicit io_context(int concurrency_hint); + + /// Destructor. + /** + * On destruction, the io_context performs the following sequence of + * operations: + * + * @li For each service object @c svc in the io_context set, in reverse order + * of the beginning of service object lifetime, performs + * @c svc->shutdown(). + * + * @li Uninvoked handler objects that were scheduled for deferred invocation + * on the io_context, or any associated strand, are destroyed. + * + * @li For each service object @c svc in the io_context set, in reverse order + * of the beginning of service object lifetime, performs + * delete static_cast(svc). + * + * @note The destruction sequence described above permits programs to + * simplify their resource management by using @c shared_ptr<>. Where an + * object's lifetime is tied to the lifetime of a connection (or some other + * sequence of asynchronous operations), a @c shared_ptr to the object would + * be bound into the handlers for all asynchronous operations associated with + * it. This works as follows: + * + * @li When a single connection ends, all associated asynchronous operations + * complete. The corresponding handler objects are destroyed, and all + * @c shared_ptr references to the objects are destroyed. + * + * @li To shut down the whole program, the io_context function stop() is + * called to terminate any run() calls as soon as possible. The io_context + * destructor defined above destroys all handlers, causing all @c shared_ptr + * references to all connection objects to be destroyed. + */ + BOOST_ASIO_DECL ~io_context(); + + /// Obtains the executor associated with the io_context. + executor_type get_executor() BOOST_ASIO_NOEXCEPT; + + /// Run the io_context object's event processing loop. + /** + * The run() function blocks until all work has finished and there are no + * more handlers to be dispatched, or until the io_context has been stopped. + * + * Multiple threads may call the run() function to set up a pool of threads + * from which the io_context may execute handlers. All threads that are + * waiting in the pool are equivalent and the io_context may choose any one + * of them to invoke a handler. + * + * A normal exit from the run() function implies that the io_context object + * is stopped (the stopped() function returns @c true). Subsequent calls to + * run(), run_one(), poll() or poll_one() will return immediately unless there + * is a prior call to restart(). + * + * @return The number of handlers that were executed. + * + * @note Calling the run() function from a thread that is currently calling + * one of run(), run_one(), run_for(), run_until(), poll() or poll_one() on + * the same io_context object may introduce the potential for deadlock. It is + * the caller's reponsibility to avoid this. + * + * The poll() function may also be used to dispatch ready handlers, but + * without blocking. + */ + BOOST_ASIO_DECL count_type run(); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use non-error_code overload.) Run the io_context object's + /// event processing loop. + /** + * The run() function blocks until all work has finished and there are no + * more handlers to be dispatched, or until the io_context has been stopped. + * + * Multiple threads may call the run() function to set up a pool of threads + * from which the io_context may execute handlers. All threads that are + * waiting in the pool are equivalent and the io_context may choose any one + * of them to invoke a handler. + * + * A normal exit from the run() function implies that the io_context object + * is stopped (the stopped() function returns @c true). Subsequent calls to + * run(), run_one(), poll() or poll_one() will return immediately unless there + * is a prior call to restart(). + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of handlers that were executed. + * + * @note Calling the run() function from a thread that is currently calling + * one of run(), run_one(), run_for(), run_until(), poll() or poll_one() on + * the same io_context object may introduce the potential for deadlock. It is + * the caller's reponsibility to avoid this. + * + * The poll() function may also be used to dispatch ready handlers, but + * without blocking. + */ + BOOST_ASIO_DECL count_type run(boost::system::error_code& ec); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +#if defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) + /// Run the io_context object's event processing loop for a specified + /// duration. + /** + * The run_for() function blocks until all work has finished and there are no + * more handlers to be dispatched, until the io_context has been stopped, or + * until the specified duration has elapsed. + * + * @param rel_time The duration for which the call may block. + * + * @return The number of handlers that were executed. + */ + template + std::size_t run_for(const chrono::duration& rel_time); + + /// Run the io_context object's event processing loop until a specified time. + /** + * The run_until() function blocks until all work has finished and there are + * no more handlers to be dispatched, until the io_context has been stopped, + * or until the specified time has been reached. + * + * @param abs_time The time point until which the call may block. + * + * @return The number of handlers that were executed. + */ + template + std::size_t run_until(const chrono::time_point& abs_time); +#endif // defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) + + /// Run the io_context object's event processing loop to execute at most one + /// handler. + /** + * The run_one() function blocks until one handler has been dispatched, or + * until the io_context has been stopped. + * + * @return The number of handlers that were executed. A zero return value + * implies that the io_context object is stopped (the stopped() function + * returns @c true). Subsequent calls to run(), run_one(), poll() or + * poll_one() will return immediately unless there is a prior call to + * restart(). + * + * @note Calling the run_one() function from a thread that is currently + * calling one of run(), run_one(), run_for(), run_until(), poll() or + * poll_one() on the same io_context object may introduce the potential for + * deadlock. It is the caller's reponsibility to avoid this. + */ + BOOST_ASIO_DECL count_type run_one(); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use non-error_code overlaod.) Run the io_context object's + /// event processing loop to execute at most one handler. + /** + * The run_one() function blocks until one handler has been dispatched, or + * until the io_context has been stopped. + * + * @return The number of handlers that were executed. A zero return value + * implies that the io_context object is stopped (the stopped() function + * returns @c true). Subsequent calls to run(), run_one(), poll() or + * poll_one() will return immediately unless there is a prior call to + * restart(). + * + * @return The number of handlers that were executed. + * + * @note Calling the run_one() function from a thread that is currently + * calling one of run(), run_one(), run_for(), run_until(), poll() or + * poll_one() on the same io_context object may introduce the potential for + * deadlock. It is the caller's reponsibility to avoid this. + */ + BOOST_ASIO_DECL count_type run_one(boost::system::error_code& ec); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +#if defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) + /// Run the io_context object's event processing loop for a specified duration + /// to execute at most one handler. + /** + * The run_one_for() function blocks until one handler has been dispatched, + * until the io_context has been stopped, or until the specified duration has + * elapsed. + * + * @param rel_time The duration for which the call may block. + * + * @return The number of handlers that were executed. + */ + template + std::size_t run_one_for(const chrono::duration& rel_time); + + /// Run the io_context object's event processing loop until a specified time + /// to execute at most one handler. + /** + * The run_one_until() function blocks until one handler has been dispatched, + * until the io_context has been stopped, or until the specified time has + * been reached. + * + * @param abs_time The time point until which the call may block. + * + * @return The number of handlers that were executed. + */ + template + std::size_t run_one_until( + const chrono::time_point& abs_time); +#endif // defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) + + /// Run the io_context object's event processing loop to execute ready + /// handlers. + /** + * The poll() function runs handlers that are ready to run, without blocking, + * until the io_context has been stopped or there are no more ready handlers. + * + * @return The number of handlers that were executed. + */ + BOOST_ASIO_DECL count_type poll(); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use non-error_code overload.) Run the io_context object's + /// event processing loop to execute ready handlers. + /** + * The poll() function runs handlers that are ready to run, without blocking, + * until the io_context has been stopped or there are no more ready handlers. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of handlers that were executed. + */ + BOOST_ASIO_DECL count_type poll(boost::system::error_code& ec); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Run the io_context object's event processing loop to execute one ready + /// handler. + /** + * The poll_one() function runs at most one handler that is ready to run, + * without blocking. + * + * @return The number of handlers that were executed. + */ + BOOST_ASIO_DECL count_type poll_one(); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use non-error_code overload.) Run the io_context object's + /// event processing loop to execute one ready handler. + /** + * The poll_one() function runs at most one handler that is ready to run, + * without blocking. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of handlers that were executed. + */ + BOOST_ASIO_DECL count_type poll_one(boost::system::error_code& ec); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Stop the io_context object's event processing loop. + /** + * This function does not block, but instead simply signals the io_context to + * stop. All invocations of its run() or run_one() member functions should + * return as soon as possible. Subsequent calls to run(), run_one(), poll() + * or poll_one() will return immediately until restart() is called. + */ + BOOST_ASIO_DECL void stop(); + + /// Determine whether the io_context object has been stopped. + /** + * This function is used to determine whether an io_context object has been + * stopped, either through an explicit call to stop(), or due to running out + * of work. When an io_context object is stopped, calls to run(), run_one(), + * poll() or poll_one() will return immediately without invoking any + * handlers. + * + * @return @c true if the io_context object is stopped, otherwise @c false. + */ + BOOST_ASIO_DECL bool stopped() const; + + /// Restart the io_context in preparation for a subsequent run() invocation. + /** + * This function must be called prior to any second or later set of + * invocations of the run(), run_one(), poll() or poll_one() functions when a + * previous invocation of these functions returned due to the io_context + * being stopped or running out of work. After a call to restart(), the + * io_context object's stopped() function will return @c false. + * + * This function must not be called while there are any unfinished calls to + * the run(), run_one(), poll() or poll_one() functions. + */ + BOOST_ASIO_DECL void restart(); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use restart().) Reset the io_context in preparation for a + /// subsequent run() invocation. + /** + * This function must be called prior to any second or later set of + * invocations of the run(), run_one(), poll() or poll_one() functions when a + * previous invocation of these functions returned due to the io_context + * being stopped or running out of work. After a call to restart(), the + * io_context object's stopped() function will return @c false. + * + * This function must not be called while there are any unfinished calls to + * the run(), run_one(), poll() or poll_one() functions. + */ + void reset(); + + /// (Deprecated: Use boost::asio::dispatch().) Request the io_context to + /// invoke the given handler. + /** + * This function is used to ask the io_context to execute the given handler. + * + * The io_context guarantees that the handler will only be called in a thread + * in which the run(), run_one(), poll() or poll_one() member functions is + * currently being invoked. The handler may be executed inside this function + * if the guarantee can be met. + * + * @param handler The handler to be called. The io_context will make + * a copy of the handler object as required. The function signature of the + * handler must be: @code void handler(); @endcode + * + * @note This function throws an exception only if: + * + * @li the handler's @c asio_handler_allocate function; or + * + * @li the handler's copy constructor + * + * throws an exception. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(LegacyCompletionHandler, void ()) + dispatch(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler); + + /// (Deprecated: Use boost::asio::post().) Request the io_context to invoke + /// the given handler and return immediately. + /** + * This function is used to ask the io_context to execute the given handler, + * but without allowing the io_context to call the handler from inside this + * function. + * + * The io_context guarantees that the handler will only be called in a thread + * in which the run(), run_one(), poll() or poll_one() member functions is + * currently being invoked. + * + * @param handler The handler to be called. The io_context will make + * a copy of the handler object as required. The function signature of the + * handler must be: @code void handler(); @endcode + * + * @note This function throws an exception only if: + * + * @li the handler's @c asio_handler_allocate function; or + * + * @li the handler's copy constructor + * + * throws an exception. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(LegacyCompletionHandler, void ()) + post(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler); + + /// (Deprecated: Use boost::asio::bind_executor().) Create a new handler that + /// automatically dispatches the wrapped handler on the io_context. + /** + * This function is used to create a new handler function object that, when + * invoked, will automatically pass the wrapped handler to the io_context + * object's dispatch function. + * + * @param handler The handler to be wrapped. The io_context will make a copy + * of the handler object as required. The function signature of the handler + * must be: @code void handler(A1 a1, ... An an); @endcode + * + * @return A function object that, when invoked, passes the wrapped handler to + * the io_context object's dispatch function. Given a function object with the + * signature: + * @code R f(A1 a1, ... An an); @endcode + * If this function object is passed to the wrap function like so: + * @code io_context.wrap(f); @endcode + * then the return value is a function object with the signature + * @code void g(A1 a1, ... An an); @endcode + * that, when invoked, executes code equivalent to: + * @code io_context.dispatch(boost::bind(f, a1, ... an)); @endcode + */ + template +#if defined(GENERATING_DOCUMENTATION) + unspecified +#else + detail::wrapped_handler +#endif + wrap(Handler handler); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +private: +#if !defined(BOOST_ASIO_NO_DEPRECATED) + struct initiate_dispatch; + struct initiate_post; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + // Helper function to add the implementation. + BOOST_ASIO_DECL impl_type& add_impl(impl_type* impl); + + // Backwards compatible overload for use with services derived from + // io_context::service. + template + friend Service& use_service(io_context& ioc); + +#if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) + detail::winsock_init<> init_; +#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \ + || defined(__osf__) + detail::signal_init<> init_; +#endif + + // The implementation. + impl_type& impl_; +}; + +/// Executor used to submit functions to an io_context. +class io_context::executor_type +{ +public: + /// Obtain the underlying execution context. + io_context& context() const BOOST_ASIO_NOEXCEPT; + + /// Inform the io_context that it has some outstanding work to do. + /** + * This function is used to inform the io_context that some work has begun. + * This ensures that the io_context's run() and run_one() functions do not + * exit while the work is underway. + */ + void on_work_started() const BOOST_ASIO_NOEXCEPT; + + /// Inform the io_context that some work is no longer outstanding. + /** + * This function is used to inform the io_context that some work has + * finished. Once the count of unfinished work reaches zero, the io_context + * is stopped and the run() and run_one() functions may exit. + */ + void on_work_finished() const BOOST_ASIO_NOEXCEPT; + + /// Request the io_context to invoke the given function object. + /** + * This function is used to ask the io_context to execute the given function + * object. If the current thread is running the io_context, @c dispatch() + * executes the function before returning. Otherwise, the function will be + * scheduled to run on the io_context. + * + * @param f The function object to be called. The executor will make a copy + * of the handler object as required. The function signature of the function + * object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template + void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Request the io_context to invoke the given function object. + /** + * This function is used to ask the io_context to execute the given function + * object. The function object will never be executed inside @c post(). + * Instead, it will be scheduled to run on the io_context. + * + * @param f The function object to be called. The executor will make a copy + * of the handler object as required. The function signature of the function + * object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template + void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Request the io_context to invoke the given function object. + /** + * This function is used to ask the io_context to execute the given function + * object. The function object will never be executed inside @c defer(). + * Instead, it will be scheduled to run on the io_context. + * + * If the current thread belongs to the io_context, @c defer() will delay + * scheduling the function object until the current thread returns control to + * the pool. + * + * @param f The function object to be called. The executor will make a copy + * of the handler object as required. The function signature of the function + * object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template + void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Determine whether the io_context is running in the current thread. + /** + * @return @c true if the current thread is running the io_context. Otherwise + * returns @c false. + */ + bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT; + + /// Compare two executors for equality. + /** + * Two executors are equal if they refer to the same underlying io_context. + */ + friend bool operator==(const executor_type& a, + const executor_type& b) BOOST_ASIO_NOEXCEPT + { + return &a.io_context_ == &b.io_context_; + } + + /// Compare two executors for inequality. + /** + * Two executors are equal if they refer to the same underlying io_context. + */ + friend bool operator!=(const executor_type& a, + const executor_type& b) BOOST_ASIO_NOEXCEPT + { + return &a.io_context_ != &b.io_context_; + } + +private: + friend class io_context; + + // Constructor. + explicit executor_type(io_context& i) : io_context_(i) {} + + // The underlying io_context. + io_context& io_context_; +}; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +/// (Deprecated: Use executor_work_guard.) Class to inform the io_context when +/// it has work to do. +/** + * The work class is used to inform the io_context when work starts and + * finishes. This ensures that the io_context object's run() function will not + * exit while work is underway, and that it does exit when there is no + * unfinished work remaining. + * + * The work class is copy-constructible so that it may be used as a data member + * in a handler class. It is not assignable. + */ +class io_context::work +{ +public: + /// Constructor notifies the io_context that work is starting. + /** + * The constructor is used to inform the io_context that some work has begun. + * This ensures that the io_context object's run() function will not exit + * while the work is underway. + */ + explicit work(boost::asio::io_context& io_context); + + /// Copy constructor notifies the io_context that work is starting. + /** + * The constructor is used to inform the io_context that some work has begun. + * This ensures that the io_context object's run() function will not exit + * while the work is underway. + */ + work(const work& other); + + /// Destructor notifies the io_context that the work is complete. + /** + * The destructor is used to inform the io_context that some work has + * finished. Once the count of unfinished work reaches zero, the io_context + * object's run() function is permitted to exit. + */ + ~work(); + + /// Get the io_context associated with the work. + boost::asio::io_context& get_io_context(); + +private: + // Prevent assignment. + void operator=(const work& other); + + // The io_context implementation. + detail::io_context_impl& io_context_impl_; +}; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +/// Base class for all io_context services. +class io_context::service + : public execution_context::service +{ +public: + /// Get the io_context object that owns the service. + boost::asio::io_context& get_io_context(); + +private: + /// Destroy all user-defined handler objects owned by the service. + BOOST_ASIO_DECL virtual void shutdown(); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use shutdown().) Destroy all user-defined handler objects + /// owned by the service. + BOOST_ASIO_DECL virtual void shutdown_service(); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Handle notification of a fork-related event to perform any necessary + /// housekeeping. + /** + * This function is not a pure virtual so that services only have to + * implement it if necessary. The default implementation does nothing. + */ + BOOST_ASIO_DECL virtual void notify_fork( + execution_context::fork_event event); + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use notify_fork().) Handle notification of a fork-related + /// event to perform any necessary housekeeping. + /** + * This function is not a pure virtual so that services only have to + * implement it if necessary. The default implementation does nothing. + */ + BOOST_ASIO_DECL virtual void fork_service( + execution_context::fork_event event); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +protected: + /// Constructor. + /** + * @param owner The io_context object that owns the service. + */ + BOOST_ASIO_DECL service(boost::asio::io_context& owner); + + /// Destructor. + BOOST_ASIO_DECL virtual ~service(); +}; + +namespace detail { + +// Special service base class to keep classes header-file only. +template +class service_base + : public boost::asio::io_context::service +{ +public: + static boost::asio::detail::service_id id; + + // Constructor. + service_base(boost::asio::io_context& io_context) + : boost::asio::io_context::service(io_context) + { + } +}; + +template +boost::asio::detail::service_id service_base::id; + +} // namespace detail +} // namespace asio +} // namespace boost + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +// If both io_context.hpp and strand.hpp have been included, automatically +// include the header file needed for the io_context::strand class. +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +# if defined(BOOST_ASIO_STRAND_HPP) +# include +# endif // defined(BOOST_ASIO_STRAND_HPP) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +#endif // BOOST_ASIO_IO_CONTEXT_HPP diff --git a/boost/asio/io_context_strand.hpp b/boost/asio/io_context_strand.hpp new file mode 100644 index 0000000..a9a9b52 --- /dev/null +++ b/boost/asio/io_context_strand.hpp @@ -0,0 +1,376 @@ +// +// io_context_strand.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IO_CONTEXT_STRAND_HPP +#define BOOST_ASIO_IO_CONTEXT_STRAND_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +/// Provides serialised handler execution. +/** + * The io_context::strand class provides the ability to post and dispatch + * handlers with the guarantee that none of those handlers will execute + * concurrently. + * + * @par Order of handler invocation + * Given: + * + * @li a strand object @c s + * + * @li an object @c a meeting completion handler requirements + * + * @li an object @c a1 which is an arbitrary copy of @c a made by the + * implementation + * + * @li an object @c b meeting completion handler requirements + * + * @li an object @c b1 which is an arbitrary copy of @c b made by the + * implementation + * + * if any of the following conditions are true: + * + * @li @c s.post(a) happens-before @c s.post(b) + * + * @li @c s.post(a) happens-before @c s.dispatch(b), where the latter is + * performed outside the strand + * + * @li @c s.dispatch(a) happens-before @c s.post(b), where the former is + * performed outside the strand + * + * @li @c s.dispatch(a) happens-before @c s.dispatch(b), where both are + * performed outside the strand + * + * then @c asio_handler_invoke(a1, &a1) happens-before + * @c asio_handler_invoke(b1, &b1). + * + * Note that in the following case: + * @code async_op_1(..., s.wrap(a)); + * async_op_2(..., s.wrap(b)); @endcode + * the completion of the first async operation will perform @c s.dispatch(a), + * and the second will perform @c s.dispatch(b), but the order in which those + * are performed is unspecified. That is, you cannot state whether one + * happens-before the other. Therefore none of the above conditions are met and + * no ordering guarantee is made. + * + * @note The implementation makes no guarantee that handlers posted or + * dispatched through different @c strand objects will be invoked concurrently. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Safe. + * + * @par Concepts: + * Dispatcher. + */ +class io_context::strand +{ +public: + /// Constructor. + /** + * Constructs the strand. + * + * @param io_context The io_context object that the strand will use to + * dispatch handlers that are ready to be run. + */ + explicit strand(boost::asio::io_context& io_context) + : service_(boost::asio::use_service< + boost::asio::detail::strand_service>(io_context)) + { + service_.construct(impl_); + } + + /// Destructor. + /** + * Destroys a strand. + * + * Handlers posted through the strand that have not yet been invoked will + * still be dispatched in a way that meets the guarantee of non-concurrency. + */ + ~strand() + { + } + + /// Obtain the underlying execution context. + boost::asio::io_context& context() const BOOST_ASIO_NOEXCEPT + { + return service_.get_io_context(); + } + + /// Inform the strand that it has some outstanding work to do. + /** + * The strand delegates this call to its underlying io_context. + */ + void on_work_started() const BOOST_ASIO_NOEXCEPT + { + context().get_executor().on_work_started(); + } + + /// Inform the strand that some work is no longer outstanding. + /** + * The strand delegates this call to its underlying io_context. + */ + void on_work_finished() const BOOST_ASIO_NOEXCEPT + { + context().get_executor().on_work_finished(); + } + + /// Request the strand to invoke the given function object. + /** + * This function is used to ask the strand to execute the given function + * object on its underlying io_context. The function object will be executed + * inside this function if the strand is not otherwise busy and if the + * underlying io_context's executor's @c dispatch() function is also able to + * execute the function before returning. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template + void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const + { + typename decay::type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); + service_.dispatch(impl_, tmp); + (void)a; + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use boost::asio::dispatch().) Request the strand to invoke + /// the given handler. + /** + * This function is used to ask the strand to execute the given handler. + * + * The strand object guarantees that handlers posted or dispatched through + * the strand will not be executed concurrently. The handler may be executed + * inside this function if the guarantee can be met. If this function is + * called from within a handler that was posted or dispatched through the same + * strand, then the new handler will be executed immediately. + * + * The strand's guarantee is in addition to the guarantee provided by the + * underlying io_context. The io_context guarantees that the handler will only + * be called in a thread in which the io_context's run member function is + * currently being invoked. + * + * @param handler The handler to be called. The strand will make a copy of the + * handler object as required. The function signature of the handler must be: + * @code void handler(); @endcode + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(LegacyCompletionHandler, void ()) + dispatch(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler) + { + return async_initiate( + initiate_dispatch(), handler, this); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Request the strand to invoke the given function object. + /** + * This function is used to ask the executor to execute the given function + * object. The function object will never be executed inside this function. + * Instead, it will be scheduled to run by the underlying io_context. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template + void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const + { + typename decay::type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); + service_.post(impl_, tmp); + (void)a; + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use boost::asio::post().) Request the strand to invoke the + /// given handler and return immediately. + /** + * This function is used to ask the strand to execute the given handler, but + * without allowing the strand to call the handler from inside this function. + * + * The strand object guarantees that handlers posted or dispatched through + * the strand will not be executed concurrently. The strand's guarantee is in + * addition to the guarantee provided by the underlying io_context. The + * io_context guarantees that the handler will only be called in a thread in + * which the io_context's run member function is currently being invoked. + * + * @param handler The handler to be called. The strand will make a copy of the + * handler object as required. The function signature of the handler must be: + * @code void handler(); @endcode + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(LegacyCompletionHandler, void ()) + post(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler) + { + return async_initiate( + initiate_post(), handler, this); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Request the strand to invoke the given function object. + /** + * This function is used to ask the executor to execute the given function + * object. The function object will never be executed inside this function. + * Instead, it will be scheduled to run by the underlying io_context. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template + void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const + { + typename decay::type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); + service_.post(impl_, tmp); + (void)a; + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use boost::asio::bind_executor().) Create a new handler that + /// automatically dispatches the wrapped handler on the strand. + /** + * This function is used to create a new handler function object that, when + * invoked, will automatically pass the wrapped handler to the strand's + * dispatch function. + * + * @param handler The handler to be wrapped. The strand will make a copy of + * the handler object as required. The function signature of the handler must + * be: @code void handler(A1 a1, ... An an); @endcode + * + * @return A function object that, when invoked, passes the wrapped handler to + * the strand's dispatch function. Given a function object with the signature: + * @code R f(A1 a1, ... An an); @endcode + * If this function object is passed to the wrap function like so: + * @code strand.wrap(f); @endcode + * then the return value is a function object with the signature + * @code void g(A1 a1, ... An an); @endcode + * that, when invoked, executes code equivalent to: + * @code strand.dispatch(boost::bind(f, a1, ... an)); @endcode + */ + template +#if defined(GENERATING_DOCUMENTATION) + unspecified +#else + detail::wrapped_handler +#endif + wrap(Handler handler) + { + return detail::wrapped_handler(*this, handler); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Determine whether the strand is running in the current thread. + /** + * @return @c true if the current thread is executing a handler that was + * submitted to the strand using post(), dispatch() or wrap(). Otherwise + * returns @c false. + */ + bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT + { + return service_.running_in_this_thread(impl_); + } + + /// Compare two strands for equality. + /** + * Two strands are equal if they refer to the same ordered, non-concurrent + * state. + */ + friend bool operator==(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT + { + return a.impl_ == b.impl_; + } + + /// Compare two strands for inequality. + /** + * Two strands are equal if they refer to the same ordered, non-concurrent + * state. + */ + friend bool operator!=(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT + { + return a.impl_ != b.impl_; + } + +private: +#if !defined(BOOST_ASIO_NO_DEPRECATED) + struct initiate_dispatch + { + template + void operator()(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler, + strand* self) const + { + // If you get an error on the following line it means that your + // handler does not meet the documented type requirements for a + // LegacyCompletionHandler. + BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( + LegacyCompletionHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->service_.dispatch(self->impl_, handler2.value); + } + }; + + struct initiate_post + { + template + void operator()(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler, + strand* self) const + { + // If you get an error on the following line it means that your + // handler does not meet the documented type requirements for a + // LegacyCompletionHandler. + BOOST_ASIO_LEGACY_COMPLETION_HANDLER_CHECK( + LegacyCompletionHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->service_.post(self->impl_, handler2.value); + } + }; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + boost::asio::detail::strand_service& service_; + mutable boost::asio::detail::strand_service::implementation_type impl_; +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +#endif // BOOST_ASIO_IO_CONTEXT_STRAND_HPP diff --git a/boost/asio/io_service.hpp b/boost/asio/io_service.hpp new file mode 100644 index 0000000..31f9e98 --- /dev/null +++ b/boost/asio/io_service.hpp @@ -0,0 +1,35 @@ +// +// io_service.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IO_SERVICE_HPP +#define BOOST_ASIO_IO_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +/// Typedef for backwards compatibility. +typedef io_context io_service; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IO_SERVICE_HPP diff --git a/boost/asio/io_service_strand.hpp b/boost/asio/io_service_strand.hpp new file mode 100644 index 0000000..93b811b --- /dev/null +++ b/boost/asio/io_service_strand.hpp @@ -0,0 +1,20 @@ +// +// io_service_strand.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IO_SERVICE_STRAND_HPP +#define BOOST_ASIO_IO_SERVICE_STRAND_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#endif // BOOST_ASIO_IO_SERVICE_STRAND_HPP diff --git a/boost/asio/ip/address.hpp b/boost/asio/ip/address.hpp new file mode 100644 index 0000000..fd6ce95 --- /dev/null +++ b/boost/asio/ip/address.hpp @@ -0,0 +1,270 @@ +// +// ip/address.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_ADDRESS_HPP +#define BOOST_ASIO_IP_ADDRESS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(BOOST_ASIO_NO_IOSTREAM) +# include +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +#include + +namespace boost { +namespace asio { +namespace ip { + +/// Implements version-independent IP addresses. +/** + * The boost::asio::ip::address class provides the ability to use either IP + * version 4 or version 6 addresses. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +class address +{ +public: + /// Default constructor. + BOOST_ASIO_DECL address() BOOST_ASIO_NOEXCEPT; + + /// Construct an address from an IPv4 address. + BOOST_ASIO_DECL address( + const boost::asio::ip::address_v4& ipv4_address) BOOST_ASIO_NOEXCEPT; + + /// Construct an address from an IPv6 address. + BOOST_ASIO_DECL address( + const boost::asio::ip::address_v6& ipv6_address) BOOST_ASIO_NOEXCEPT; + + /// Copy constructor. + BOOST_ASIO_DECL address(const address& other) BOOST_ASIO_NOEXCEPT; + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move constructor. + BOOST_ASIO_DECL address(address&& other) BOOST_ASIO_NOEXCEPT; +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Assign from another address. + BOOST_ASIO_DECL address& operator=(const address& other) BOOST_ASIO_NOEXCEPT; + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move-assign from another address. + BOOST_ASIO_DECL address& operator=(address&& other) BOOST_ASIO_NOEXCEPT; +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Assign from an IPv4 address. + BOOST_ASIO_DECL address& operator=( + const boost::asio::ip::address_v4& ipv4_address) BOOST_ASIO_NOEXCEPT; + + /// Assign from an IPv6 address. + BOOST_ASIO_DECL address& operator=( + const boost::asio::ip::address_v6& ipv6_address) BOOST_ASIO_NOEXCEPT; + + /// Get whether the address is an IP version 4 address. + bool is_v4() const BOOST_ASIO_NOEXCEPT + { + return type_ == ipv4; + } + + /// Get whether the address is an IP version 6 address. + bool is_v6() const BOOST_ASIO_NOEXCEPT + { + return type_ == ipv6; + } + + /// Get the address as an IP version 4 address. + BOOST_ASIO_DECL boost::asio::ip::address_v4 to_v4() const; + + /// Get the address as an IP version 6 address. + BOOST_ASIO_DECL boost::asio::ip::address_v6 to_v6() const; + + /// Get the address as a string. + BOOST_ASIO_DECL std::string to_string() const; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use other overload.) Get the address as a string. + BOOST_ASIO_DECL std::string to_string(boost::system::error_code& ec) const; + + /// (Deprecated: Use make_address().) Create an address from an IPv4 address + /// string in dotted decimal form, or from an IPv6 address in hexadecimal + /// notation. + static address from_string(const char* str); + + /// (Deprecated: Use make_address().) Create an address from an IPv4 address + /// string in dotted decimal form, or from an IPv6 address in hexadecimal + /// notation. + static address from_string(const char* str, boost::system::error_code& ec); + + /// (Deprecated: Use make_address().) Create an address from an IPv4 address + /// string in dotted decimal form, or from an IPv6 address in hexadecimal + /// notation. + static address from_string(const std::string& str); + + /// (Deprecated: Use make_address().) Create an address from an IPv4 address + /// string in dotted decimal form, or from an IPv6 address in hexadecimal + /// notation. + static address from_string( + const std::string& str, boost::system::error_code& ec); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Determine whether the address is a loopback address. + BOOST_ASIO_DECL bool is_loopback() const BOOST_ASIO_NOEXCEPT; + + /// Determine whether the address is unspecified. + BOOST_ASIO_DECL bool is_unspecified() const BOOST_ASIO_NOEXCEPT; + + /// Determine whether the address is a multicast address. + BOOST_ASIO_DECL bool is_multicast() const BOOST_ASIO_NOEXCEPT; + + /// Compare two addresses for equality. + BOOST_ASIO_DECL friend bool operator==(const address& a1, + const address& a2) BOOST_ASIO_NOEXCEPT; + + /// Compare two addresses for inequality. + friend bool operator!=(const address& a1, + const address& a2) BOOST_ASIO_NOEXCEPT + { + return !(a1 == a2); + } + + /// Compare addresses for ordering. + BOOST_ASIO_DECL friend bool operator<(const address& a1, + const address& a2) BOOST_ASIO_NOEXCEPT; + + /// Compare addresses for ordering. + friend bool operator>(const address& a1, + const address& a2) BOOST_ASIO_NOEXCEPT + { + return a2 < a1; + } + + /// Compare addresses for ordering. + friend bool operator<=(const address& a1, + const address& a2) BOOST_ASIO_NOEXCEPT + { + return !(a2 < a1); + } + + /// Compare addresses for ordering. + friend bool operator>=(const address& a1, + const address& a2) BOOST_ASIO_NOEXCEPT + { + return !(a1 < a2); + } + +private: + // The type of the address. + enum { ipv4, ipv6 } type_; + + // The underlying IPv4 address. + boost::asio::ip::address_v4 ipv4_address_; + + // The underlying IPv6 address. + boost::asio::ip::address_v6 ipv6_address_; +}; + +/// Create an address from an IPv4 address string in dotted decimal form, +/// or from an IPv6 address in hexadecimal notation. +/** + * @relates address + */ +BOOST_ASIO_DECL address make_address(const char* str); + +/// Create an address from an IPv4 address string in dotted decimal form, +/// or from an IPv6 address in hexadecimal notation. +/** + * @relates address + */ +BOOST_ASIO_DECL address make_address(const char* str, + boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT; + +/// Create an address from an IPv4 address string in dotted decimal form, +/// or from an IPv6 address in hexadecimal notation. +/** + * @relates address + */ +BOOST_ASIO_DECL address make_address(const std::string& str); + +/// Create an address from an IPv4 address string in dotted decimal form, +/// or from an IPv6 address in hexadecimal notation. +/** + * @relates address + */ +BOOST_ASIO_DECL address make_address(const std::string& str, + boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT; + +#if defined(BOOST_ASIO_HAS_STRING_VIEW) \ + || defined(GENERATING_DOCUMENTATION) + +/// Create an address from an IPv4 address string in dotted decimal form, +/// or from an IPv6 address in hexadecimal notation. +/** + * @relates address + */ +BOOST_ASIO_DECL address make_address(string_view str); + +/// Create an address from an IPv4 address string in dotted decimal form, +/// or from an IPv6 address in hexadecimal notation. +/** + * @relates address + */ +BOOST_ASIO_DECL address make_address(string_view str, + boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT; + +#endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + // || defined(GENERATING_DOCUMENTATION) + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +/// Output an address as a string. +/** + * Used to output a human-readable string for a specified address. + * + * @param os The output stream to which the string will be written. + * + * @param addr The address to be written. + * + * @return The output stream. + * + * @relates boost::asio::ip::address + */ +template +std::basic_ostream& operator<<( + std::basic_ostream& os, const address& addr); + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_IP_ADDRESS_HPP diff --git a/boost/asio/ip/address_v4.hpp b/boost/asio/ip/address_v4.hpp new file mode 100644 index 0000000..b612fa0 --- /dev/null +++ b/boost/asio/ip/address_v4.hpp @@ -0,0 +1,337 @@ +// +// ip/address_v4.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_ADDRESS_V4_HPP +#define BOOST_ASIO_IP_ADDRESS_V4_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(BOOST_ASIO_NO_IOSTREAM) +# include +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +#include + +namespace boost { +namespace asio { +namespace ip { + +/// Implements IP version 4 style addresses. +/** + * The boost::asio::ip::address_v4 class provides the ability to use and + * manipulate IP version 4 addresses. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +class address_v4 +{ +public: + /// The type used to represent an address as an unsigned integer. + typedef uint_least32_t uint_type; + + /// The type used to represent an address as an array of bytes. + /** + * @note This type is defined in terms of the C++0x template @c std::array + * when it is available. Otherwise, it uses @c boost:array. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef array bytes_type; +#else + typedef boost::asio::detail::array bytes_type; +#endif + + /// Default constructor. + address_v4() BOOST_ASIO_NOEXCEPT + { + addr_.s_addr = 0; + } + + /// Construct an address from raw bytes. + BOOST_ASIO_DECL explicit address_v4(const bytes_type& bytes); + + /// Construct an address from an unsigned integer in host byte order. + BOOST_ASIO_DECL explicit address_v4(uint_type addr); + + /// Copy constructor. + address_v4(const address_v4& other) BOOST_ASIO_NOEXCEPT + : addr_(other.addr_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move constructor. + address_v4(address_v4&& other) BOOST_ASIO_NOEXCEPT + : addr_(other.addr_) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Assign from another address. + address_v4& operator=(const address_v4& other) BOOST_ASIO_NOEXCEPT + { + addr_ = other.addr_; + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move-assign from another address. + address_v4& operator=(address_v4&& other) BOOST_ASIO_NOEXCEPT + { + addr_ = other.addr_; + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Get the address in bytes, in network byte order. + BOOST_ASIO_DECL bytes_type to_bytes() const BOOST_ASIO_NOEXCEPT; + + /// Get the address as an unsigned integer in host byte order + BOOST_ASIO_DECL uint_type to_uint() const BOOST_ASIO_NOEXCEPT; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// Get the address as an unsigned long in host byte order + BOOST_ASIO_DECL unsigned long to_ulong() const; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Get the address as a string in dotted decimal format. + BOOST_ASIO_DECL std::string to_string() const; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use other overload.) Get the address as a string in dotted + /// decimal format. + BOOST_ASIO_DECL std::string to_string(boost::system::error_code& ec) const; + + /// (Deprecated: Use make_address_v4().) Create an address from an IP address + /// string in dotted decimal form. + static address_v4 from_string(const char* str); + + /// (Deprecated: Use make_address_v4().) Create an address from an IP address + /// string in dotted decimal form. + static address_v4 from_string( + const char* str, boost::system::error_code& ec); + + /// (Deprecated: Use make_address_v4().) Create an address from an IP address + /// string in dotted decimal form. + static address_v4 from_string(const std::string& str); + + /// (Deprecated: Use make_address_v4().) Create an address from an IP address + /// string in dotted decimal form. + static address_v4 from_string( + const std::string& str, boost::system::error_code& ec); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Determine whether the address is a loopback address. + BOOST_ASIO_DECL bool is_loopback() const BOOST_ASIO_NOEXCEPT; + + /// Determine whether the address is unspecified. + BOOST_ASIO_DECL bool is_unspecified() const BOOST_ASIO_NOEXCEPT; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use network_v4 class.) Determine whether the address is a + /// class A address. + BOOST_ASIO_DECL bool is_class_a() const; + + /// (Deprecated: Use network_v4 class.) Determine whether the address is a + /// class B address. + BOOST_ASIO_DECL bool is_class_b() const; + + /// (Deprecated: Use network_v4 class.) Determine whether the address is a + /// class C address. + BOOST_ASIO_DECL bool is_class_c() const; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Determine whether the address is a multicast address. + BOOST_ASIO_DECL bool is_multicast() const BOOST_ASIO_NOEXCEPT; + + /// Compare two addresses for equality. + friend bool operator==(const address_v4& a1, + const address_v4& a2) BOOST_ASIO_NOEXCEPT + { + return a1.addr_.s_addr == a2.addr_.s_addr; + } + + /// Compare two addresses for inequality. + friend bool operator!=(const address_v4& a1, + const address_v4& a2) BOOST_ASIO_NOEXCEPT + { + return a1.addr_.s_addr != a2.addr_.s_addr; + } + + /// Compare addresses for ordering. + friend bool operator<(const address_v4& a1, + const address_v4& a2) BOOST_ASIO_NOEXCEPT + { + return a1.to_uint() < a2.to_uint(); + } + + /// Compare addresses for ordering. + friend bool operator>(const address_v4& a1, + const address_v4& a2) BOOST_ASIO_NOEXCEPT + { + return a1.to_uint() > a2.to_uint(); + } + + /// Compare addresses for ordering. + friend bool operator<=(const address_v4& a1, + const address_v4& a2) BOOST_ASIO_NOEXCEPT + { + return a1.to_uint() <= a2.to_uint(); + } + + /// Compare addresses for ordering. + friend bool operator>=(const address_v4& a1, + const address_v4& a2) BOOST_ASIO_NOEXCEPT + { + return a1.to_uint() >= a2.to_uint(); + } + + /// Obtain an address object that represents any address. + static address_v4 any() BOOST_ASIO_NOEXCEPT + { + return address_v4(); + } + + /// Obtain an address object that represents the loopback address. + static address_v4 loopback() BOOST_ASIO_NOEXCEPT + { + return address_v4(0x7F000001); + } + + /// Obtain an address object that represents the broadcast address. + static address_v4 broadcast() BOOST_ASIO_NOEXCEPT + { + return address_v4(0xFFFFFFFF); + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use network_v4 class.) Obtain an address object that + /// represents the broadcast address that corresponds to the specified + /// address and netmask. + BOOST_ASIO_DECL static address_v4 broadcast( + const address_v4& addr, const address_v4& mask); + + /// (Deprecated: Use network_v4 class.) Obtain the netmask that corresponds + /// to the address, based on its address class. + BOOST_ASIO_DECL static address_v4 netmask(const address_v4& addr); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +private: + // The underlying IPv4 address. + boost::asio::detail::in4_addr_type addr_; +}; + +/// Create an IPv4 address from raw bytes in network order. +/** + * @relates address_v4 + */ +inline address_v4 make_address_v4(const address_v4::bytes_type& bytes) +{ + return address_v4(bytes); +} + +/// Create an IPv4 address from an unsigned integer in host byte order. +/** + * @relates address_v4 + */ +inline address_v4 make_address_v4(address_v4::uint_type addr) +{ + return address_v4(addr); +} + +/// Create an IPv4 address from an IP address string in dotted decimal form. +/** + * @relates address_v4 + */ +BOOST_ASIO_DECL address_v4 make_address_v4(const char* str); + +/// Create an IPv4 address from an IP address string in dotted decimal form. +/** + * @relates address_v4 + */ +BOOST_ASIO_DECL address_v4 make_address_v4(const char* str, + boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT; + +/// Create an IPv4 address from an IP address string in dotted decimal form. +/** + * @relates address_v4 + */ +BOOST_ASIO_DECL address_v4 make_address_v4(const std::string& str); + +/// Create an IPv4 address from an IP address string in dotted decimal form. +/** + * @relates address_v4 + */ +BOOST_ASIO_DECL address_v4 make_address_v4(const std::string& str, + boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT; + +#if defined(BOOST_ASIO_HAS_STRING_VIEW) \ + || defined(GENERATING_DOCUMENTATION) + +/// Create an IPv4 address from an IP address string in dotted decimal form. +/** + * @relates address_v4 + */ +BOOST_ASIO_DECL address_v4 make_address_v4(string_view str); + +/// Create an IPv4 address from an IP address string in dotted decimal form. +/** + * @relates address_v4 + */ +BOOST_ASIO_DECL address_v4 make_address_v4(string_view str, + boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT; + +#endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + // || defined(GENERATING_DOCUMENTATION) + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +/// Output an address as a string. +/** + * Used to output a human-readable string for a specified address. + * + * @param os The output stream to which the string will be written. + * + * @param addr The address to be written. + * + * @return The output stream. + * + * @relates boost::asio::ip::address_v4 + */ +template +std::basic_ostream& operator<<( + std::basic_ostream& os, const address_v4& addr); + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_IP_ADDRESS_V4_HPP diff --git a/boost/asio/ip/address_v4_iterator.hpp b/boost/asio/ip/address_v4_iterator.hpp new file mode 100644 index 0000000..5a52fe0 --- /dev/null +++ b/boost/asio/ip/address_v4_iterator.hpp @@ -0,0 +1,164 @@ +// +// ip/address_v4_iterator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_ADDRESS_V4_ITERATOR_HPP +#define BOOST_ASIO_IP_ADDRESS_V4_ITERATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +template class basic_address_iterator; + +/// An input iterator that can be used for traversing IPv4 addresses. +/** + * In addition to satisfying the input iterator requirements, this iterator + * also supports decrement. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template <> class basic_address_iterator +{ +public: + /// The type of the elements pointed to by the iterator. + typedef address_v4 value_type; + + /// Distance between two iterators. + typedef std::ptrdiff_t difference_type; + + /// The type of a pointer to an element pointed to by the iterator. + typedef const address_v4* pointer; + + /// The type of a reference to an element pointed to by the iterator. + typedef const address_v4& reference; + + /// Denotes that the iterator satisfies the input iterator requirements. + typedef std::input_iterator_tag iterator_category; + + /// Construct an iterator that points to the specified address. + basic_address_iterator(const address_v4& addr) BOOST_ASIO_NOEXCEPT + : address_(addr) + { + } + + /// Copy constructor. + basic_address_iterator( + const basic_address_iterator& other) BOOST_ASIO_NOEXCEPT + : address_(other.address_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move constructor. + basic_address_iterator(basic_address_iterator&& other) BOOST_ASIO_NOEXCEPT + : address_(BOOST_ASIO_MOVE_CAST(address_v4)(other.address_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Assignment operator. + basic_address_iterator& operator=( + const basic_address_iterator& other) BOOST_ASIO_NOEXCEPT + { + address_ = other.address_; + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move assignment operator. + basic_address_iterator& operator=( + basic_address_iterator&& other) BOOST_ASIO_NOEXCEPT + { + address_ = BOOST_ASIO_MOVE_CAST(address_v4)(other.address_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Dereference the iterator. + const address_v4& operator*() const BOOST_ASIO_NOEXCEPT + { + return address_; + } + + /// Dereference the iterator. + const address_v4* operator->() const BOOST_ASIO_NOEXCEPT + { + return &address_; + } + + /// Pre-increment operator. + basic_address_iterator& operator++() BOOST_ASIO_NOEXCEPT + { + address_ = address_v4((address_.to_uint() + 1) & 0xFFFFFFFF); + return *this; + } + + /// Post-increment operator. + basic_address_iterator operator++(int) BOOST_ASIO_NOEXCEPT + { + basic_address_iterator tmp(*this); + ++*this; + return tmp; + } + + /// Pre-decrement operator. + basic_address_iterator& operator--() BOOST_ASIO_NOEXCEPT + { + address_ = address_v4((address_.to_uint() - 1) & 0xFFFFFFFF); + return *this; + } + + /// Post-decrement operator. + basic_address_iterator operator--(int) + { + basic_address_iterator tmp(*this); + --*this; + return tmp; + } + + /// Compare two addresses for equality. + friend bool operator==(const basic_address_iterator& a, + const basic_address_iterator& b) + { + return a.address_ == b.address_; + } + + /// Compare two addresses for inequality. + friend bool operator!=(const basic_address_iterator& a, + const basic_address_iterator& b) + { + return a.address_ != b.address_; + } + +private: + address_v4 address_; +}; + +/// An input iterator that can be used for traversing IPv4 addresses. +typedef basic_address_iterator address_v4_iterator; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_ADDRESS_V4_ITERATOR_HPP diff --git a/boost/asio/ip/address_v4_range.hpp b/boost/asio/ip/address_v4_range.hpp new file mode 100644 index 0000000..5e9c548 --- /dev/null +++ b/boost/asio/ip/address_v4_range.hpp @@ -0,0 +1,136 @@ +// +// ip/address_v4_range.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_ADDRESS_V4_RANGE_HPP +#define BOOST_ASIO_IP_ADDRESS_V4_RANGE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +template class basic_address_range; + +/// Represents a range of IPv4 addresses. +/** + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template <> class basic_address_range +{ +public: + /// The type of an iterator that points into the range. + typedef basic_address_iterator iterator; + + /// Construct an empty range. + basic_address_range() BOOST_ASIO_NOEXCEPT + : begin_(address_v4()), + end_(address_v4()) + { + } + + /// Construct an range that represents the given range of addresses. + explicit basic_address_range(const iterator& first, + const iterator& last) BOOST_ASIO_NOEXCEPT + : begin_(first), + end_(last) + { + } + + /// Copy constructor. + basic_address_range(const basic_address_range& other) BOOST_ASIO_NOEXCEPT + : begin_(other.begin_), + end_(other.end_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move constructor. + basic_address_range(basic_address_range&& other) BOOST_ASIO_NOEXCEPT + : begin_(BOOST_ASIO_MOVE_CAST(iterator)(other.begin_)), + end_(BOOST_ASIO_MOVE_CAST(iterator)(other.end_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Assignment operator. + basic_address_range& operator=( + const basic_address_range& other) BOOST_ASIO_NOEXCEPT + { + begin_ = other.begin_; + end_ = other.end_; + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move assignment operator. + basic_address_range& operator=( + basic_address_range&& other) BOOST_ASIO_NOEXCEPT + { + begin_ = BOOST_ASIO_MOVE_CAST(iterator)(other.begin_); + end_ = BOOST_ASIO_MOVE_CAST(iterator)(other.end_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Obtain an iterator that points to the start of the range. + iterator begin() const BOOST_ASIO_NOEXCEPT + { + return begin_; + } + + /// Obtain an iterator that points to the end of the range. + iterator end() const BOOST_ASIO_NOEXCEPT + { + return end_; + } + + /// Determine whether the range is empty. + bool empty() const BOOST_ASIO_NOEXCEPT + { + return size() == 0; + } + + /// Return the size of the range. + std::size_t size() const BOOST_ASIO_NOEXCEPT + { + return end_->to_uint() - begin_->to_uint(); + } + + /// Find an address in the range. + iterator find(const address_v4& addr) const BOOST_ASIO_NOEXCEPT + { + return addr >= *begin_ && addr < *end_ ? iterator(addr) : end_; + } + +private: + iterator begin_; + iterator end_; +}; + +/// Represents a range of IPv4 addresses. +typedef basic_address_range address_v4_range; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_ADDRESS_V4_RANGE_HPP diff --git a/boost/asio/ip/address_v6.hpp b/boost/asio/ip/address_v6.hpp new file mode 100644 index 0000000..62dff45 --- /dev/null +++ b/boost/asio/ip/address_v6.hpp @@ -0,0 +1,343 @@ +// +// ip/address_v6.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_ADDRESS_V6_HPP +#define BOOST_ASIO_IP_ADDRESS_V6_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(BOOST_ASIO_NO_IOSTREAM) +# include +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +#include + +namespace boost { +namespace asio { +namespace ip { + +template class basic_address_iterator; + +/// Implements IP version 6 style addresses. +/** + * The boost::asio::ip::address_v6 class provides the ability to use and + * manipulate IP version 6 addresses. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +class address_v6 +{ +public: + /// The type used to represent an address as an array of bytes. + /** + * @note This type is defined in terms of the C++0x template @c std::array + * when it is available. Otherwise, it uses @c boost:array. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef array bytes_type; +#else + typedef boost::asio::detail::array bytes_type; +#endif + + /// Default constructor. + BOOST_ASIO_DECL address_v6() BOOST_ASIO_NOEXCEPT; + + /// Construct an address from raw bytes and scope ID. + BOOST_ASIO_DECL explicit address_v6(const bytes_type& bytes, + unsigned long scope_id = 0); + + /// Copy constructor. + BOOST_ASIO_DECL address_v6(const address_v6& other) BOOST_ASIO_NOEXCEPT; + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move constructor. + BOOST_ASIO_DECL address_v6(address_v6&& other) BOOST_ASIO_NOEXCEPT; +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Assign from another address. + BOOST_ASIO_DECL address_v6& operator=( + const address_v6& other) BOOST_ASIO_NOEXCEPT; + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move-assign from another address. + BOOST_ASIO_DECL address_v6& operator=(address_v6&& other) BOOST_ASIO_NOEXCEPT; +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// The scope ID of the address. + /** + * Returns the scope ID associated with the IPv6 address. + */ + unsigned long scope_id() const BOOST_ASIO_NOEXCEPT + { + return scope_id_; + } + + /// The scope ID of the address. + /** + * Modifies the scope ID associated with the IPv6 address. + */ + void scope_id(unsigned long id) BOOST_ASIO_NOEXCEPT + { + scope_id_ = id; + } + + /// Get the address in bytes, in network byte order. + BOOST_ASIO_DECL bytes_type to_bytes() const BOOST_ASIO_NOEXCEPT; + + /// Get the address as a string. + BOOST_ASIO_DECL std::string to_string() const; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use other overload.) Get the address as a string. + BOOST_ASIO_DECL std::string to_string(boost::system::error_code& ec) const; + + /// (Deprecated: Use make_address_v6().) Create an IPv6 address from an IP + /// address string. + static address_v6 from_string(const char* str); + + /// (Deprecated: Use make_address_v6().) Create an IPv6 address from an IP + /// address string. + static address_v6 from_string( + const char* str, boost::system::error_code& ec); + + /// (Deprecated: Use make_address_v6().) Create an IPv6 address from an IP + /// address string. + static address_v6 from_string(const std::string& str); + + /// (Deprecated: Use make_address_v6().) Create an IPv6 address from an IP + /// address string. + static address_v6 from_string( + const std::string& str, boost::system::error_code& ec); + + /// (Deprecated: Use make_address_v4().) Converts an IPv4-mapped or + /// IPv4-compatible address to an IPv4 address. + BOOST_ASIO_DECL address_v4 to_v4() const; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Determine whether the address is a loopback address. + BOOST_ASIO_DECL bool is_loopback() const BOOST_ASIO_NOEXCEPT; + + /// Determine whether the address is unspecified. + BOOST_ASIO_DECL bool is_unspecified() const BOOST_ASIO_NOEXCEPT; + + /// Determine whether the address is link local. + BOOST_ASIO_DECL bool is_link_local() const BOOST_ASIO_NOEXCEPT; + + /// Determine whether the address is site local. + BOOST_ASIO_DECL bool is_site_local() const BOOST_ASIO_NOEXCEPT; + + /// Determine whether the address is a mapped IPv4 address. + BOOST_ASIO_DECL bool is_v4_mapped() const BOOST_ASIO_NOEXCEPT; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: No replacement.) Determine whether the address is an + /// IPv4-compatible address. + BOOST_ASIO_DECL bool is_v4_compatible() const; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Determine whether the address is a multicast address. + BOOST_ASIO_DECL bool is_multicast() const BOOST_ASIO_NOEXCEPT; + + /// Determine whether the address is a global multicast address. + BOOST_ASIO_DECL bool is_multicast_global() const BOOST_ASIO_NOEXCEPT; + + /// Determine whether the address is a link-local multicast address. + BOOST_ASIO_DECL bool is_multicast_link_local() const BOOST_ASIO_NOEXCEPT; + + /// Determine whether the address is a node-local multicast address. + BOOST_ASIO_DECL bool is_multicast_node_local() const BOOST_ASIO_NOEXCEPT; + + /// Determine whether the address is a org-local multicast address. + BOOST_ASIO_DECL bool is_multicast_org_local() const BOOST_ASIO_NOEXCEPT; + + /// Determine whether the address is a site-local multicast address. + BOOST_ASIO_DECL bool is_multicast_site_local() const BOOST_ASIO_NOEXCEPT; + + /// Compare two addresses for equality. + BOOST_ASIO_DECL friend bool operator==(const address_v6& a1, + const address_v6& a2) BOOST_ASIO_NOEXCEPT; + + /// Compare two addresses for inequality. + friend bool operator!=(const address_v6& a1, + const address_v6& a2) BOOST_ASIO_NOEXCEPT + { + return !(a1 == a2); + } + + /// Compare addresses for ordering. + BOOST_ASIO_DECL friend bool operator<(const address_v6& a1, + const address_v6& a2) BOOST_ASIO_NOEXCEPT; + + /// Compare addresses for ordering. + friend bool operator>(const address_v6& a1, + const address_v6& a2) BOOST_ASIO_NOEXCEPT + { + return a2 < a1; + } + + /// Compare addresses for ordering. + friend bool operator<=(const address_v6& a1, + const address_v6& a2) BOOST_ASIO_NOEXCEPT + { + return !(a2 < a1); + } + + /// Compare addresses for ordering. + friend bool operator>=(const address_v6& a1, + const address_v6& a2) BOOST_ASIO_NOEXCEPT + { + return !(a1 < a2); + } + + /// Obtain an address object that represents any address. + static address_v6 any() BOOST_ASIO_NOEXCEPT + { + return address_v6(); + } + + /// Obtain an address object that represents the loopback address. + BOOST_ASIO_DECL static address_v6 loopback() BOOST_ASIO_NOEXCEPT; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use make_address_v6().) Create an IPv4-mapped IPv6 address. + BOOST_ASIO_DECL static address_v6 v4_mapped(const address_v4& addr); + + /// (Deprecated: No replacement.) Create an IPv4-compatible IPv6 address. + BOOST_ASIO_DECL static address_v6 v4_compatible(const address_v4& addr); +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +private: + friend class basic_address_iterator; + + // The underlying IPv6 address. + boost::asio::detail::in6_addr_type addr_; + + // The scope ID associated with the address. + unsigned long scope_id_; +}; + +/// Create an IPv6 address from raw bytes and scope ID. +/** + * @relates address_v6 + */ +inline address_v6 make_address_v6(const address_v6::bytes_type& bytes, + unsigned long scope_id = 0) +{ + return address_v6(bytes, scope_id); +} + +/// Create an IPv6 address from an IP address string. +/** + * @relates address_v6 + */ +BOOST_ASIO_DECL address_v6 make_address_v6(const char* str); + +/// Create an IPv6 address from an IP address string. +/** + * @relates address_v6 + */ +BOOST_ASIO_DECL address_v6 make_address_v6(const char* str, + boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT; + +/// Createan IPv6 address from an IP address string. +/** + * @relates address_v6 + */ +BOOST_ASIO_DECL address_v6 make_address_v6(const std::string& str); + +/// Create an IPv6 address from an IP address string. +/** + * @relates address_v6 + */ +BOOST_ASIO_DECL address_v6 make_address_v6(const std::string& str, + boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT; + +#if defined(BOOST_ASIO_HAS_STRING_VIEW) \ + || defined(GENERATING_DOCUMENTATION) + +/// Create an IPv6 address from an IP address string. +/** + * @relates address_v6 + */ +BOOST_ASIO_DECL address_v6 make_address_v6(string_view str); + +/// Create an IPv6 address from an IP address string. +/** + * @relates address_v6 + */ +BOOST_ASIO_DECL address_v6 make_address_v6(string_view str, + boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT; + +#endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + // || defined(GENERATING_DOCUMENTATION) + +/// Tag type used for distinguishing overloads that deal in IPv4-mapped IPv6 +/// addresses. +enum v4_mapped_t { v4_mapped }; + +/// Create an IPv4 address from a IPv4-mapped IPv6 address. +/** + * @relates address_v4 + */ +BOOST_ASIO_DECL address_v4 make_address_v4( + v4_mapped_t, const address_v6& v6_addr); + +/// Create an IPv4-mapped IPv6 address from an IPv4 address. +/** + * @relates address_v6 + */ +BOOST_ASIO_DECL address_v6 make_address_v6( + v4_mapped_t, const address_v4& v4_addr); + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +/// Output an address as a string. +/** + * Used to output a human-readable string for a specified address. + * + * @param os The output stream to which the string will be written. + * + * @param addr The address to be written. + * + * @return The output stream. + * + * @relates boost::asio::ip::address_v6 + */ +template +std::basic_ostream& operator<<( + std::basic_ostream& os, const address_v6& addr); + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_IP_ADDRESS_V6_HPP diff --git a/boost/asio/ip/address_v6_iterator.hpp b/boost/asio/ip/address_v6_iterator.hpp new file mode 100644 index 0000000..4598a87 --- /dev/null +++ b/boost/asio/ip/address_v6_iterator.hpp @@ -0,0 +1,185 @@ +// +// ip/address_v6_iterator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Oliver Kowalke (oliver dot kowalke at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_ADDRESS_V6_ITERATOR_HPP +#define BOOST_ASIO_IP_ADDRESS_V6_ITERATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +template class basic_address_iterator; + +/// An input iterator that can be used for traversing IPv6 addresses. +/** + * In addition to satisfying the input iterator requirements, this iterator + * also supports decrement. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template <> class basic_address_iterator +{ +public: + /// The type of the elements pointed to by the iterator. + typedef address_v6 value_type; + + /// Distance between two iterators. + typedef std::ptrdiff_t difference_type; + + /// The type of a pointer to an element pointed to by the iterator. + typedef const address_v6* pointer; + + /// The type of a reference to an element pointed to by the iterator. + typedef const address_v6& reference; + + /// Denotes that the iterator satisfies the input iterator requirements. + typedef std::input_iterator_tag iterator_category; + + /// Construct an iterator that points to the specified address. + basic_address_iterator(const address_v6& addr) BOOST_ASIO_NOEXCEPT + : address_(addr) + { + } + + /// Copy constructor. + basic_address_iterator( + const basic_address_iterator& other) BOOST_ASIO_NOEXCEPT + : address_(other.address_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move constructor. + basic_address_iterator(basic_address_iterator&& other) BOOST_ASIO_NOEXCEPT + : address_(BOOST_ASIO_MOVE_CAST(address_v6)(other.address_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Assignment operator. + basic_address_iterator& operator=( + const basic_address_iterator& other) BOOST_ASIO_NOEXCEPT + { + address_ = other.address_; + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move assignment operator. + basic_address_iterator& operator=( + basic_address_iterator&& other) BOOST_ASIO_NOEXCEPT + { + address_ = BOOST_ASIO_MOVE_CAST(address_v6)(other.address_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Dereference the iterator. + const address_v6& operator*() const BOOST_ASIO_NOEXCEPT + { + return address_; + } + + /// Dereference the iterator. + const address_v6* operator->() const BOOST_ASIO_NOEXCEPT + { + return &address_; + } + + /// Pre-increment operator. + basic_address_iterator& operator++() BOOST_ASIO_NOEXCEPT + { + for (int i = 15; i >= 0; --i) + { + if (address_.addr_.s6_addr[i] < 0xFF) + { + ++address_.addr_.s6_addr[i]; + break; + } + + address_.addr_.s6_addr[i] = 0; + } + + return *this; + } + + /// Post-increment operator. + basic_address_iterator operator++(int) BOOST_ASIO_NOEXCEPT + { + basic_address_iterator tmp(*this); + ++*this; + return tmp; + } + + /// Pre-decrement operator. + basic_address_iterator& operator--() BOOST_ASIO_NOEXCEPT + { + for (int i = 15; i >= 0; --i) + { + if (address_.addr_.s6_addr[i] > 0) + { + --address_.addr_.s6_addr[i]; + break; + } + + address_.addr_.s6_addr[i] = 0xFF; + } + + return *this; + } + + /// Post-decrement operator. + basic_address_iterator operator--(int) + { + basic_address_iterator tmp(*this); + --*this; + return tmp; + } + + /// Compare two addresses for equality. + friend bool operator==(const basic_address_iterator& a, + const basic_address_iterator& b) + { + return a.address_ == b.address_; + } + + /// Compare two addresses for inequality. + friend bool operator!=(const basic_address_iterator& a, + const basic_address_iterator& b) + { + return a.address_ != b.address_; + } + +private: + address_v6 address_; +}; + +/// An input iterator that can be used for traversing IPv6 addresses. +typedef basic_address_iterator address_v6_iterator; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_ADDRESS_V6_ITERATOR_HPP diff --git a/boost/asio/ip/address_v6_range.hpp b/boost/asio/ip/address_v6_range.hpp new file mode 100644 index 0000000..9189fde --- /dev/null +++ b/boost/asio/ip/address_v6_range.hpp @@ -0,0 +1,131 @@ +// +// ip/address_v6_range.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Oliver Kowalke (oliver dot kowalke at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_ADDRESS_V6_RANGE_HPP +#define BOOST_ASIO_IP_ADDRESS_V6_RANGE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +template class basic_address_range; + +/// Represents a range of IPv6 addresses. +/** + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template <> class basic_address_range +{ +public: + /// The type of an iterator that points into the range. + typedef basic_address_iterator iterator; + + /// Construct an empty range. + basic_address_range() BOOST_ASIO_NOEXCEPT + : begin_(address_v6()), + end_(address_v6()) + { + } + + /// Construct an range that represents the given range of addresses. + explicit basic_address_range(const iterator& first, + const iterator& last) BOOST_ASIO_NOEXCEPT + : begin_(first), + end_(last) + { + } + + /// Copy constructor. + basic_address_range(const basic_address_range& other) BOOST_ASIO_NOEXCEPT + : begin_(other.begin_), + end_(other.end_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move constructor. + basic_address_range(basic_address_range&& other) BOOST_ASIO_NOEXCEPT + : begin_(BOOST_ASIO_MOVE_CAST(iterator)(other.begin_)), + end_(BOOST_ASIO_MOVE_CAST(iterator)(other.end_)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Assignment operator. + basic_address_range& operator=( + const basic_address_range& other) BOOST_ASIO_NOEXCEPT + { + begin_ = other.begin_; + end_ = other.end_; + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move assignment operator. + basic_address_range& operator=( + basic_address_range&& other) BOOST_ASIO_NOEXCEPT + { + begin_ = BOOST_ASIO_MOVE_CAST(iterator)(other.begin_); + end_ = BOOST_ASIO_MOVE_CAST(iterator)(other.end_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Obtain an iterator that points to the start of the range. + iterator begin() const BOOST_ASIO_NOEXCEPT + { + return begin_; + } + + /// Obtain an iterator that points to the end of the range. + iterator end() const BOOST_ASIO_NOEXCEPT + { + return end_; + } + + /// Determine whether the range is empty. + bool empty() const BOOST_ASIO_NOEXCEPT + { + return begin_ == end_; + } + + /// Find an address in the range. + iterator find(const address_v6& addr) const BOOST_ASIO_NOEXCEPT + { + return addr >= *begin_ && addr < *end_ ? iterator(addr) : end_; + } + +private: + iterator begin_; + iterator end_; +}; + +/// Represents a range of IPv6 addresses. +typedef basic_address_range address_v6_range; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_ADDRESS_V6_RANGE_HPP diff --git a/boost/asio/ip/bad_address_cast.hpp b/boost/asio/ip/bad_address_cast.hpp new file mode 100644 index 0000000..da06983 --- /dev/null +++ b/boost/asio/ip/bad_address_cast.hpp @@ -0,0 +1,55 @@ +// +// ip/bad_address_cast.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_BAD_ADDRESS_CAST_HPP +#define BOOST_ASIO_IP_BAD_ADDRESS_CAST_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +/// Thrown to indicate a failed address conversion. +class bad_address_cast : +#if defined(BOOST_ASIO_MSVC) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS + public std::exception +#else + public std::bad_cast +#endif +{ +public: + /// Default constructor. + bad_address_cast() {} + + /// Destructor. + virtual ~bad_address_cast() BOOST_ASIO_NOEXCEPT_OR_NOTHROW {} + + /// Get the message associated with the exception. + virtual const char* what() const BOOST_ASIO_NOEXCEPT_OR_NOTHROW + { + return "bad address cast"; + } +}; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_ADDRESS_HPP diff --git a/boost/asio/ip/basic_endpoint.hpp b/boost/asio/ip/basic_endpoint.hpp new file mode 100644 index 0000000..0951fd7 --- /dev/null +++ b/boost/asio/ip/basic_endpoint.hpp @@ -0,0 +1,266 @@ +// +// ip/basic_endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_BASIC_ENDPOINT_HPP +#define BOOST_ASIO_IP_BASIC_ENDPOINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#if !defined(BOOST_ASIO_NO_IOSTREAM) +# include +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +#include + +namespace boost { +namespace asio { +namespace ip { + +/// Describes an endpoint for a version-independent IP socket. +/** + * The boost::asio::ip::basic_endpoint class template describes an endpoint that + * may be associated with a particular socket. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Concepts: + * Endpoint. + */ +template +class basic_endpoint +{ +public: + /// The protocol type associated with the endpoint. + typedef InternetProtocol protocol_type; + + /// The type of the endpoint structure. This type is dependent on the + /// underlying implementation of the socket layer. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined data_type; +#else + typedef boost::asio::detail::socket_addr_type data_type; +#endif + + /// Default constructor. + basic_endpoint() BOOST_ASIO_NOEXCEPT + : impl_() + { + } + + /// Construct an endpoint using a port number, specified in the host's byte + /// order. The IP address will be the any address (i.e. INADDR_ANY or + /// in6addr_any). This constructor would typically be used for accepting new + /// connections. + /** + * @par Examples + * To initialise an IPv4 TCP endpoint for port 1234, use: + * @code + * boost::asio::ip::tcp::endpoint ep(boost::asio::ip::tcp::v4(), 1234); + * @endcode + * + * To specify an IPv6 UDP endpoint for port 9876, use: + * @code + * boost::asio::ip::udp::endpoint ep(boost::asio::ip::udp::v6(), 9876); + * @endcode + */ + basic_endpoint(const InternetProtocol& internet_protocol, + unsigned short port_num) BOOST_ASIO_NOEXCEPT + : impl_(internet_protocol.family(), port_num) + { + } + + /// Construct an endpoint using a port number and an IP address. This + /// constructor may be used for accepting connections on a specific interface + /// or for making a connection to a remote endpoint. + basic_endpoint(const boost::asio::ip::address& addr, + unsigned short port_num) BOOST_ASIO_NOEXCEPT + : impl_(addr, port_num) + { + } + + /// Copy constructor. + basic_endpoint(const basic_endpoint& other) BOOST_ASIO_NOEXCEPT + : impl_(other.impl_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move constructor. + basic_endpoint(basic_endpoint&& other) BOOST_ASIO_NOEXCEPT + : impl_(other.impl_) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Assign from another endpoint. + basic_endpoint& operator=(const basic_endpoint& other) BOOST_ASIO_NOEXCEPT + { + impl_ = other.impl_; + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-assign from another endpoint. + basic_endpoint& operator=(basic_endpoint&& other) BOOST_ASIO_NOEXCEPT + { + impl_ = other.impl_; + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// The protocol associated with the endpoint. + protocol_type protocol() const BOOST_ASIO_NOEXCEPT + { + if (impl_.is_v4()) + return InternetProtocol::v4(); + return InternetProtocol::v6(); + } + + /// Get the underlying endpoint in the native type. + data_type* data() BOOST_ASIO_NOEXCEPT + { + return impl_.data(); + } + + /// Get the underlying endpoint in the native type. + const data_type* data() const BOOST_ASIO_NOEXCEPT + { + return impl_.data(); + } + + /// Get the underlying size of the endpoint in the native type. + std::size_t size() const BOOST_ASIO_NOEXCEPT + { + return impl_.size(); + } + + /// Set the underlying size of the endpoint in the native type. + void resize(std::size_t new_size) + { + impl_.resize(new_size); + } + + /// Get the capacity of the endpoint in the native type. + std::size_t capacity() const BOOST_ASIO_NOEXCEPT + { + return impl_.capacity(); + } + + /// Get the port associated with the endpoint. The port number is always in + /// the host's byte order. + unsigned short port() const BOOST_ASIO_NOEXCEPT + { + return impl_.port(); + } + + /// Set the port associated with the endpoint. The port number is always in + /// the host's byte order. + void port(unsigned short port_num) BOOST_ASIO_NOEXCEPT + { + impl_.port(port_num); + } + + /// Get the IP address associated with the endpoint. + boost::asio::ip::address address() const BOOST_ASIO_NOEXCEPT + { + return impl_.address(); + } + + /// Set the IP address associated with the endpoint. + void address(const boost::asio::ip::address& addr) BOOST_ASIO_NOEXCEPT + { + impl_.address(addr); + } + + /// Compare two endpoints for equality. + friend bool operator==(const basic_endpoint& e1, + const basic_endpoint& e2) BOOST_ASIO_NOEXCEPT + { + return e1.impl_ == e2.impl_; + } + + /// Compare two endpoints for inequality. + friend bool operator!=(const basic_endpoint& e1, + const basic_endpoint& e2) BOOST_ASIO_NOEXCEPT + { + return !(e1 == e2); + } + + /// Compare endpoints for ordering. + friend bool operator<(const basic_endpoint& e1, + const basic_endpoint& e2) BOOST_ASIO_NOEXCEPT + { + return e1.impl_ < e2.impl_; + } + + /// Compare endpoints for ordering. + friend bool operator>(const basic_endpoint& e1, + const basic_endpoint& e2) BOOST_ASIO_NOEXCEPT + { + return e2.impl_ < e1.impl_; + } + + /// Compare endpoints for ordering. + friend bool operator<=(const basic_endpoint& e1, + const basic_endpoint& e2) BOOST_ASIO_NOEXCEPT + { + return !(e2 < e1); + } + + /// Compare endpoints for ordering. + friend bool operator>=(const basic_endpoint& e1, + const basic_endpoint& e2) BOOST_ASIO_NOEXCEPT + { + return !(e1 < e2); + } + +private: + // The underlying IP endpoint. + boost::asio::ip::detail::endpoint impl_; +}; + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +/// Output an endpoint as a string. +/** + * Used to output a human-readable string for a specified endpoint. + * + * @param os The output stream to which the string will be written. + * + * @param endpoint The endpoint to be written. + * + * @return The output stream. + * + * @relates boost::asio::ip::basic_endpoint + */ +template +std::basic_ostream& operator<<( + std::basic_ostream& os, + const basic_endpoint& endpoint); + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // BOOST_ASIO_IP_BASIC_ENDPOINT_HPP diff --git a/boost/asio/ip/basic_resolver.hpp b/boost/asio/ip/basic_resolver.hpp new file mode 100644 index 0000000..b937ce5 --- /dev/null +++ b/boost/asio/ip/basic_resolver.hpp @@ -0,0 +1,984 @@ +// +// ip/basic_resolver.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_BASIC_RESOLVER_HPP +#define BOOST_ASIO_IP_BASIC_RESOLVER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +# include +#else +# include +#endif + +#if defined(BOOST_ASIO_HAS_MOVE) +# include +#endif // defined(BOOST_ASIO_HAS_MOVE) + +#include + +namespace boost { +namespace asio { +namespace ip { + +#if !defined(BOOST_ASIO_IP_BASIC_RESOLVER_FWD_DECL) +#define BOOST_ASIO_IP_BASIC_RESOLVER_FWD_DECL + +// Forward declaration with defaulted arguments. +template +class basic_resolver; + +#endif // !defined(BOOST_ASIO_IP_BASIC_RESOLVER_FWD_DECL) + +/// Provides endpoint resolution functionality. +/** + * The basic_resolver class template provides the ability to resolve a query + * to a list of endpoints. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_resolver + : public resolver_base +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// The protocol type. + typedef InternetProtocol protocol_type; + + /// The endpoint type. + typedef typename InternetProtocol::endpoint endpoint_type; + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated.) The query type. + typedef basic_resolver_query query; + + /// (Deprecated.) The iterator type. + typedef basic_resolver_iterator iterator; +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// The results type. + typedef basic_resolver_results results_type; + + /// Construct with executor. + /** + * This constructor creates a basic_resolver. + * + * @param ex The I/O executor that the resolver will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * resolver. + */ + explicit basic_resolver(const executor_type& ex) + : impl_(ex) + { + } + + /// Construct with execution context. + /** + * This constructor creates a basic_resolver. + * + * @param context An execution context which provides the I/O executor that + * the resolver will use, by default, to dispatch handlers for any + * asynchronous operations performed on the resolver. + */ + template + explicit basic_resolver(ExecutionContext& context, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a basic_resolver from another. + /** + * This constructor moves a resolver from one object to another. + * + * @param other The other basic_resolver object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_resolver(const executor_type&) constructor. + */ + basic_resolver(basic_resolver&& other) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a basic_resolver from another. + /** + * This assignment operator moves a resolver from one object to another. + * Cancels any outstanding asynchronous operations associated with the target + * object. + * + * @param other The other basic_resolver object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_resolver(const executor_type&) constructor. + */ + basic_resolver& operator=(basic_resolver&& other) + { + impl_ = std::move(other.impl_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destroys the resolver. + /** + * This function destroys the resolver, cancelling any outstanding + * asynchronous wait operations associated with the resolver as if by calling + * @c cancel. + */ + ~basic_resolver() + { + } + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return impl_.get_executor(); + } + + /// Cancel any asynchronous operations that are waiting on the resolver. + /** + * This function forces the completion of any pending asynchronous + * operations on the host resolver. The handler for each cancelled operation + * will be invoked with the boost::asio::error::operation_aborted error code. + */ + void cancel() + { + return impl_.get_service().cancel(impl_.get_implementation()); + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use overload with separate host and service parameters.) + /// Perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve a query into a list of endpoint entries. + * + * @param q A query object that determines what endpoints will be returned. + * + * @returns A range object representing the list of endpoint entries. A + * successful call to this function is guaranteed to return a non-empty + * range. + * + * @throws boost::system::system_error Thrown on failure. + */ + results_type resolve(const query& q) + { + boost::system::error_code ec; + results_type r = impl_.get_service().resolve( + impl_.get_implementation(), q, ec); + boost::asio::detail::throw_error(ec, "resolve"); + return r; + } + + /// (Deprecated: Use overload with separate host and service parameters.) + /// Perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve a query into a list of endpoint entries. + * + * @param q A query object that determines what endpoints will be returned. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns A range object representing the list of endpoint entries. An + * empty range is returned if an error occurs. A successful call to this + * function is guaranteed to return a non-empty range. + */ + results_type resolve(const query& q, boost::system::error_code& ec) + { + return impl_.get_service().resolve(impl_.get_implementation(), q, ec); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @returns A range object representing the list of endpoint entries. A + * successful call to this function is guaranteed to return a non-empty + * range. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note On POSIX systems, host names may be locally defined in the file + * /etc/hosts. On Windows, host names may be defined in the file + * c:\\windows\\system32\\drivers\\etc\\hosts. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ + results_type resolve(BOOST_ASIO_STRING_VIEW_PARAM host, + BOOST_ASIO_STRING_VIEW_PARAM service) + { + return resolve(host, service, resolver_base::flags()); + } + + /// Perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns A range object representing the list of endpoint entries. An + * empty range is returned if an error occurs. A successful call to this + * function is guaranteed to return a non-empty range. + * + * @note On POSIX systems, host names may be locally defined in the file + * /etc/hosts. On Windows, host names may be defined in the file + * c:\\windows\\system32\\drivers\\etc\\hosts. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ + results_type resolve(BOOST_ASIO_STRING_VIEW_PARAM host, + BOOST_ASIO_STRING_VIEW_PARAM service, boost::system::error_code& ec) + { + return resolve(host, service, resolver_base::flags(), ec); + } + + /// Perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for communication with + * remote hosts. See the @ref resolver_base documentation for the set of + * available flags. + * + * @returns A range object representing the list of endpoint entries. A + * successful call to this function is guaranteed to return a non-empty + * range. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note On POSIX systems, host names may be locally defined in the file + * /etc/hosts. On Windows, host names may be defined in the file + * c:\\windows\\system32\\drivers\\etc\\hosts. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ + results_type resolve(BOOST_ASIO_STRING_VIEW_PARAM host, + BOOST_ASIO_STRING_VIEW_PARAM service, resolver_base::flags resolve_flags) + { + boost::system::error_code ec; + basic_resolver_query q(static_cast(host), + static_cast(service), resolve_flags); + results_type r = impl_.get_service().resolve( + impl_.get_implementation(), q, ec); + boost::asio::detail::throw_error(ec, "resolve"); + return r; + } + + /// Perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for communication with + * remote hosts. See the @ref resolver_base documentation for the set of + * available flags. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns A range object representing the list of endpoint entries. An + * empty range is returned if an error occurs. A successful call to this + * function is guaranteed to return a non-empty range. + * + * @note On POSIX systems, host names may be locally defined in the file + * /etc/hosts. On Windows, host names may be defined in the file + * c:\\windows\\system32\\drivers\\etc\\hosts. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ + results_type resolve(BOOST_ASIO_STRING_VIEW_PARAM host, + BOOST_ASIO_STRING_VIEW_PARAM service, resolver_base::flags resolve_flags, + boost::system::error_code& ec) + { + basic_resolver_query q(static_cast(host), + static_cast(service), resolve_flags); + return impl_.get_service().resolve(impl_.get_implementation(), q, ec); + } + + /// Perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param protocol A protocol object, normally representing either the IPv4 or + * IPv6 version of an internet protocol. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @returns A range object representing the list of endpoint entries. A + * successful call to this function is guaranteed to return a non-empty + * range. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note On POSIX systems, host names may be locally defined in the file + * /etc/hosts. On Windows, host names may be defined in the file + * c:\\windows\\system32\\drivers\\etc\\hosts. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ + results_type resolve(const protocol_type& protocol, + BOOST_ASIO_STRING_VIEW_PARAM host, BOOST_ASIO_STRING_VIEW_PARAM service) + { + return resolve(protocol, host, service, resolver_base::flags()); + } + + /// Perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param protocol A protocol object, normally representing either the IPv4 or + * IPv6 version of an internet protocol. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns A range object representing the list of endpoint entries. An + * empty range is returned if an error occurs. A successful call to this + * function is guaranteed to return a non-empty range. + * + * @note On POSIX systems, host names may be locally defined in the file + * /etc/hosts. On Windows, host names may be defined in the file + * c:\\windows\\system32\\drivers\\etc\\hosts. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ + results_type resolve(const protocol_type& protocol, + BOOST_ASIO_STRING_VIEW_PARAM host, BOOST_ASIO_STRING_VIEW_PARAM service, + boost::system::error_code& ec) + { + return resolve(protocol, host, service, resolver_base::flags(), ec); + } + + /// Perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param protocol A protocol object, normally representing either the IPv4 or + * IPv6 version of an internet protocol. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for communication with + * remote hosts. See the @ref resolver_base documentation for the set of + * available flags. + * + * @returns A range object representing the list of endpoint entries. A + * successful call to this function is guaranteed to return a non-empty + * range. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note On POSIX systems, host names may be locally defined in the file + * /etc/hosts. On Windows, host names may be defined in the file + * c:\\windows\\system32\\drivers\\etc\\hosts. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ + results_type resolve(const protocol_type& protocol, + BOOST_ASIO_STRING_VIEW_PARAM host, BOOST_ASIO_STRING_VIEW_PARAM service, + resolver_base::flags resolve_flags) + { + boost::system::error_code ec; + basic_resolver_query q( + protocol, static_cast(host), + static_cast(service), resolve_flags); + results_type r = impl_.get_service().resolve( + impl_.get_implementation(), q, ec); + boost::asio::detail::throw_error(ec, "resolve"); + return r; + } + + /// Perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param protocol A protocol object, normally representing either the IPv4 or + * IPv6 version of an internet protocol. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for communication with + * remote hosts. See the @ref resolver_base documentation for the set of + * available flags. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns A range object representing the list of endpoint entries. An + * empty range is returned if an error occurs. A successful call to this + * function is guaranteed to return a non-empty range. + * + * @note On POSIX systems, host names may be locally defined in the file + * /etc/hosts. On Windows, host names may be defined in the file + * c:\\windows\\system32\\drivers\\etc\\hosts. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ + results_type resolve(const protocol_type& protocol, + BOOST_ASIO_STRING_VIEW_PARAM host, BOOST_ASIO_STRING_VIEW_PARAM service, + resolver_base::flags resolve_flags, boost::system::error_code& ec) + { + basic_resolver_query q( + protocol, static_cast(host), + static_cast(service), resolve_flags); + return impl_.get_service().resolve(impl_.get_implementation(), q, ec); + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use overload with separate host and service parameters.) + /// Asynchronously perform forward resolution of a query to a list of entries. + /** + * This function is used to asynchronously resolve a query into a list of + * endpoint entries. + * + * @param q A query object that determines what endpoints will be returned. + * + * @param handler The handler to be called when the resolve operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * resolver::results_type results // Resolved endpoints as a range. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * A successful resolve operation is guaranteed to pass a non-empty range to + * the handler. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, + void (boost::system::error_code, results_type)) + async_resolve(const query& q, + BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) + { + return boost::asio::async_initiate( + initiate_async_resolve(), handler, this, q); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Asynchronously perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param handler The handler to be called when the resolve operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * resolver::results_type results // Resolved endpoints as a range. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * A successful resolve operation is guaranteed to pass a non-empty range to + * the handler. + * + * @note On POSIX systems, host names may be locally defined in the file + * /etc/hosts. On Windows, host names may be defined in the file + * c:\\windows\\system32\\drivers\\etc\\hosts. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, + void (boost::system::error_code, results_type)) + async_resolve(BOOST_ASIO_STRING_VIEW_PARAM host, + BOOST_ASIO_STRING_VIEW_PARAM service, + BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) + { + return async_resolve(host, service, resolver_base::flags(), + BOOST_ASIO_MOVE_CAST(ResolveHandler)(handler)); + } + + /// Asynchronously perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for communication with + * remote hosts. See the @ref resolver_base documentation for the set of + * available flags. + * + * @param handler The handler to be called when the resolve operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * resolver::results_type results // Resolved endpoints as a range. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * A successful resolve operation is guaranteed to pass a non-empty range to + * the handler. + * + * @note On POSIX systems, host names may be locally defined in the file + * /etc/hosts. On Windows, host names may be defined in the file + * c:\\windows\\system32\\drivers\\etc\\hosts. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, + void (boost::system::error_code, results_type)) + async_resolve(BOOST_ASIO_STRING_VIEW_PARAM host, + BOOST_ASIO_STRING_VIEW_PARAM service, + resolver_base::flags resolve_flags, + BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) + { + basic_resolver_query q(static_cast(host), + static_cast(service), resolve_flags); + + return boost::asio::async_initiate( + initiate_async_resolve(), handler, this, q); + } + + /// Asynchronously perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param protocol A protocol object, normally representing either the IPv4 or + * IPv6 version of an internet protocol. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param handler The handler to be called when the resolve operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * resolver::results_type results // Resolved endpoints as a range. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * A successful resolve operation is guaranteed to pass a non-empty range to + * the handler. + * + * @note On POSIX systems, host names may be locally defined in the file + * /etc/hosts. On Windows, host names may be defined in the file + * c:\\windows\\system32\\drivers\\etc\\hosts. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, + void (boost::system::error_code, results_type)) + async_resolve(const protocol_type& protocol, + BOOST_ASIO_STRING_VIEW_PARAM host, BOOST_ASIO_STRING_VIEW_PARAM service, + BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) + { + return async_resolve(protocol, host, service, resolver_base::flags(), + BOOST_ASIO_MOVE_CAST(ResolveHandler)(handler)); + } + + /// Asynchronously perform forward resolution of a query to a list of entries. + /** + * This function is used to resolve host and service names into a list of + * endpoint entries. + * + * @param protocol A protocol object, normally representing either the IPv4 or + * IPv6 version of an internet protocol. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for communication with + * remote hosts. See the @ref resolver_base documentation for the set of + * available flags. + * + * @param handler The handler to be called when the resolve operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * resolver::results_type results // Resolved endpoints as a range. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * A successful resolve operation is guaranteed to pass a non-empty range to + * the handler. + * + * @note On POSIX systems, host names may be locally defined in the file + * /etc/hosts. On Windows, host names may be defined in the file + * c:\\windows\\system32\\drivers\\etc\\hosts. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, + void (boost::system::error_code, results_type)) + async_resolve(const protocol_type& protocol, + BOOST_ASIO_STRING_VIEW_PARAM host, BOOST_ASIO_STRING_VIEW_PARAM service, + resolver_base::flags resolve_flags, + BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) + { + basic_resolver_query q( + protocol, static_cast(host), + static_cast(service), resolve_flags); + + return boost::asio::async_initiate( + initiate_async_resolve(), handler, this, q); + } + + /// Perform reverse resolution of an endpoint to a list of entries. + /** + * This function is used to resolve an endpoint into a list of endpoint + * entries. + * + * @param e An endpoint object that determines what endpoints will be + * returned. + * + * @returns A range object representing the list of endpoint entries. A + * successful call to this function is guaranteed to return a non-empty + * range. + * + * @throws boost::system::system_error Thrown on failure. + */ + results_type resolve(const endpoint_type& e) + { + boost::system::error_code ec; + results_type i = impl_.get_service().resolve( + impl_.get_implementation(), e, ec); + boost::asio::detail::throw_error(ec, "resolve"); + return i; + } + + /// Perform reverse resolution of an endpoint to a list of entries. + /** + * This function is used to resolve an endpoint into a list of endpoint + * entries. + * + * @param e An endpoint object that determines what endpoints will be + * returned. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns A range object representing the list of endpoint entries. An + * empty range is returned if an error occurs. A successful call to this + * function is guaranteed to return a non-empty range. + */ + results_type resolve(const endpoint_type& e, boost::system::error_code& ec) + { + return impl_.get_service().resolve(impl_.get_implementation(), e, ec); + } + + /// Asynchronously perform reverse resolution of an endpoint to a list of + /// entries. + /** + * This function is used to asynchronously resolve an endpoint into a list of + * endpoint entries. + * + * @param e An endpoint object that determines what endpoints will be + * returned. + * + * @param handler The handler to be called when the resolve operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * resolver::results_type results // Resolved endpoints as a range. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * A successful resolve operation is guaranteed to pass a non-empty range to + * the handler. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ResolveHandler, + void (boost::system::error_code, results_type)) + async_resolve(const endpoint_type& e, + BOOST_ASIO_MOVE_ARG(ResolveHandler) handler) + { + return boost::asio::async_initiate( + initiate_async_resolve(), handler, this, e); + } + +private: + // Disallow copying and assignment. + basic_resolver(const basic_resolver&) BOOST_ASIO_DELETED; + basic_resolver& operator=(const basic_resolver&) BOOST_ASIO_DELETED; + + struct initiate_async_resolve + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ResolveHandler) handler, + basic_resolver* self, const Query& q) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ResolveHandler. + BOOST_ASIO_RESOLVE_HANDLER_CHECK( + ResolveHandler, handler, results_type) type_check; + + boost::asio::detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_resolve( + self->impl_.get_implementation(), q, handler2.value, + self->impl_.get_implementation_executor()); + } + }; + +# if defined(BOOST_ASIO_WINDOWS_RUNTIME) + boost::asio::detail::io_object_impl< + boost::asio::detail::winrt_resolver_service, + Executor> impl_; +# else + boost::asio::detail::io_object_impl< + boost::asio::detail::resolver_service, + Executor> impl_; +# endif +}; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_BASIC_RESOLVER_HPP diff --git a/boost/asio/ip/basic_resolver_entry.hpp b/boost/asio/ip/basic_resolver_entry.hpp new file mode 100644 index 0000000..c00f17a --- /dev/null +++ b/boost/asio/ip/basic_resolver_entry.hpp @@ -0,0 +1,115 @@ +// +// ip/basic_resolver_entry.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_BASIC_RESOLVER_ENTRY_HPP +#define BOOST_ASIO_IP_BASIC_RESOLVER_ENTRY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +/// An entry produced by a resolver. +/** + * The boost::asio::ip::basic_resolver_entry class template describes an entry + * as returned by a resolver. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_resolver_entry +{ +public: + /// The protocol type associated with the endpoint entry. + typedef InternetProtocol protocol_type; + + /// The endpoint type associated with the endpoint entry. + typedef typename InternetProtocol::endpoint endpoint_type; + + /// Default constructor. + basic_resolver_entry() + { + } + + /// Construct with specified endpoint, host name and service name. + basic_resolver_entry(const endpoint_type& ep, + BOOST_ASIO_STRING_VIEW_PARAM host, BOOST_ASIO_STRING_VIEW_PARAM service) + : endpoint_(ep), + host_name_(static_cast(host)), + service_name_(static_cast(service)) + { + } + + /// Get the endpoint associated with the entry. + endpoint_type endpoint() const + { + return endpoint_; + } + + /// Convert to the endpoint associated with the entry. + operator endpoint_type() const + { + return endpoint_; + } + + /// Get the host name associated with the entry. + std::string host_name() const + { + return host_name_; + } + + /// Get the host name associated with the entry. + template + std::basic_string, Allocator> host_name( + const Allocator& alloc = Allocator()) const + { + return std::basic_string, Allocator>( + host_name_.c_str(), alloc); + } + + /// Get the service name associated with the entry. + std::string service_name() const + { + return service_name_; + } + + /// Get the service name associated with the entry. + template + std::basic_string, Allocator> service_name( + const Allocator& alloc = Allocator()) const + { + return std::basic_string, Allocator>( + service_name_.c_str(), alloc); + } + +private: + endpoint_type endpoint_; + std::string host_name_; + std::string service_name_; +}; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_BASIC_RESOLVER_ENTRY_HPP diff --git a/boost/asio/ip/basic_resolver_iterator.hpp b/boost/asio/ip/basic_resolver_iterator.hpp new file mode 100644 index 0000000..5564a78 --- /dev/null +++ b/boost/asio/ip/basic_resolver_iterator.hpp @@ -0,0 +1,194 @@ +// +// ip/basic_resolver_iterator.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_BASIC_RESOLVER_ITERATOR_HPP +#define BOOST_ASIO_IP_BASIC_RESOLVER_ITERATOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +# include +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include + +namespace boost { +namespace asio { +namespace ip { + +/// An iterator over the entries produced by a resolver. +/** + * The boost::asio::ip::basic_resolver_iterator class template is used to define + * iterators over the results returned by a resolver. + * + * The iterator's value_type, obtained when the iterator is dereferenced, is: + * @code const basic_resolver_entry @endcode + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_resolver_iterator +{ +public: + /// The type used for the distance between two iterators. + typedef std::ptrdiff_t difference_type; + + /// The type of the value pointed to by the iterator. + typedef basic_resolver_entry value_type; + + /// The type of the result of applying operator->() to the iterator. + typedef const basic_resolver_entry* pointer; + + /// The type of the result of applying operator*() to the iterator. + typedef const basic_resolver_entry& reference; + + /// The iterator category. + typedef std::forward_iterator_tag iterator_category; + + /// Default constructor creates an end iterator. + basic_resolver_iterator() + : index_(0) + { + } + + /// Copy constructor. + basic_resolver_iterator(const basic_resolver_iterator& other) + : values_(other.values_), + index_(other.index_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move constructor. + basic_resolver_iterator(basic_resolver_iterator&& other) + : values_(BOOST_ASIO_MOVE_CAST(values_ptr_type)(other.values_)), + index_(other.index_) + { + other.index_ = 0; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Assignment operator. + basic_resolver_iterator& operator=(const basic_resolver_iterator& other) + { + values_ = other.values_; + index_ = other.index_; + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-assignment operator. + basic_resolver_iterator& operator=(basic_resolver_iterator&& other) + { + if (this != &other) + { + values_ = BOOST_ASIO_MOVE_CAST(values_ptr_type)(other.values_); + index_ = other.index_; + other.index_ = 0; + } + + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Dereference an iterator. + const basic_resolver_entry& operator*() const + { + return dereference(); + } + + /// Dereference an iterator. + const basic_resolver_entry* operator->() const + { + return &dereference(); + } + + /// Increment operator (prefix). + basic_resolver_iterator& operator++() + { + increment(); + return *this; + } + + /// Increment operator (postfix). + basic_resolver_iterator operator++(int) + { + basic_resolver_iterator tmp(*this); + ++*this; + return tmp; + } + + /// Test two iterators for equality. + friend bool operator==(const basic_resolver_iterator& a, + const basic_resolver_iterator& b) + { + return a.equal(b); + } + + /// Test two iterators for inequality. + friend bool operator!=(const basic_resolver_iterator& a, + const basic_resolver_iterator& b) + { + return !a.equal(b); + } + +protected: + void increment() + { + if (++index_ == values_->size()) + { + // Reset state to match a default constructed end iterator. + values_.reset(); + index_ = 0; + } + } + + bool equal(const basic_resolver_iterator& other) const + { + if (!values_ && !other.values_) + return true; + if (values_ != other.values_) + return false; + return index_ == other.index_; + } + + const basic_resolver_entry& dereference() const + { + return (*values_)[index_]; + } + + typedef std::vector > values_type; + typedef boost::asio::detail::shared_ptr values_ptr_type; + values_ptr_type values_; + std::size_t index_; +}; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_BASIC_RESOLVER_ITERATOR_HPP diff --git a/boost/asio/ip/basic_resolver_query.hpp b/boost/asio/ip/basic_resolver_query.hpp new file mode 100644 index 0000000..e01597e --- /dev/null +++ b/boost/asio/ip/basic_resolver_query.hpp @@ -0,0 +1,246 @@ +// +// ip/basic_resolver_query.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_BASIC_RESOLVER_QUERY_HPP +#define BOOST_ASIO_IP_BASIC_RESOLVER_QUERY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +/// An query to be passed to a resolver. +/** + * The boost::asio::ip::basic_resolver_query class template describes a query + * that can be passed to a resolver. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_resolver_query + : public resolver_query_base +{ +public: + /// The protocol type associated with the endpoint query. + typedef InternetProtocol protocol_type; + + /// Construct with specified service name for any protocol. + /** + * This constructor is typically used to perform name resolution for local + * service binding. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for local service + * binding. + * + * @note On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ + basic_resolver_query(const std::string& service, + resolver_query_base::flags resolve_flags = passive | address_configured) + : hints_(), + host_name_(), + service_name_(service) + { + typename InternetProtocol::endpoint endpoint; + hints_.ai_flags = static_cast(resolve_flags); + hints_.ai_family = PF_UNSPEC; + hints_.ai_socktype = endpoint.protocol().type(); + hints_.ai_protocol = endpoint.protocol().protocol(); + hints_.ai_addrlen = 0; + hints_.ai_canonname = 0; + hints_.ai_addr = 0; + hints_.ai_next = 0; + } + + /// Construct with specified service name for a given protocol. + /** + * This constructor is typically used to perform name resolution for local + * service binding with a specific protocol version. + * + * @param protocol A protocol object, normally representing either the IPv4 or + * IPv6 version of an internet protocol. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for local service + * binding. + * + * @note On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ + basic_resolver_query(const protocol_type& protocol, + const std::string& service, + resolver_query_base::flags resolve_flags = passive | address_configured) + : hints_(), + host_name_(), + service_name_(service) + { + hints_.ai_flags = static_cast(resolve_flags); + hints_.ai_family = protocol.family(); + hints_.ai_socktype = protocol.type(); + hints_.ai_protocol = protocol.protocol(); + hints_.ai_addrlen = 0; + hints_.ai_canonname = 0; + hints_.ai_addr = 0; + hints_.ai_next = 0; + } + + /// Construct with specified host name and service name for any protocol. + /** + * This constructor is typically used to perform name resolution for + * communication with remote hosts. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for communication with + * remote hosts. + * + * @note On POSIX systems, host names may be locally defined in the file + * /etc/hosts. On Windows, host names may be defined in the file + * c:\\windows\\system32\\drivers\\etc\\hosts. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ + basic_resolver_query(const std::string& host, const std::string& service, + resolver_query_base::flags resolve_flags = address_configured) + : hints_(), + host_name_(host), + service_name_(service) + { + typename InternetProtocol::endpoint endpoint; + hints_.ai_flags = static_cast(resolve_flags); + hints_.ai_family = BOOST_ASIO_OS_DEF(AF_UNSPEC); + hints_.ai_socktype = endpoint.protocol().type(); + hints_.ai_protocol = endpoint.protocol().protocol(); + hints_.ai_addrlen = 0; + hints_.ai_canonname = 0; + hints_.ai_addr = 0; + hints_.ai_next = 0; + } + + /// Construct with specified host name and service name for a given protocol. + /** + * This constructor is typically used to perform name resolution for + * communication with remote hosts. + * + * @param protocol A protocol object, normally representing either the IPv4 or + * IPv6 version of an internet protocol. + * + * @param host A string identifying a location. May be a descriptive name or + * a numeric address string. If an empty string and the passive flag has been + * specified, the resolved endpoints are suitable for local service binding. + * If an empty string and passive is not specified, the resolved endpoints + * will use the loopback address. + * + * @param service A string identifying the requested service. This may be a + * descriptive name or a numeric string corresponding to a port number. May + * be an empty string, in which case all resolved endpoints will have a port + * number of 0. + * + * @param resolve_flags A set of flags that determine how name resolution + * should be performed. The default flags are suitable for communication with + * remote hosts. + * + * @note On POSIX systems, host names may be locally defined in the file + * /etc/hosts. On Windows, host names may be defined in the file + * c:\\windows\\system32\\drivers\\etc\\hosts. Remote host name + * resolution is performed using DNS. Operating systems may use additional + * locations when resolving host names (such as NETBIOS names on Windows). + * + * On POSIX systems, service names are typically defined in the file + * /etc/services. On Windows, service names may be found in the file + * c:\\windows\\system32\\drivers\\etc\\services. Operating systems + * may use additional locations when resolving service names. + */ + basic_resolver_query(const protocol_type& protocol, + const std::string& host, const std::string& service, + resolver_query_base::flags resolve_flags = address_configured) + : hints_(), + host_name_(host), + service_name_(service) + { + hints_.ai_flags = static_cast(resolve_flags); + hints_.ai_family = protocol.family(); + hints_.ai_socktype = protocol.type(); + hints_.ai_protocol = protocol.protocol(); + hints_.ai_addrlen = 0; + hints_.ai_canonname = 0; + hints_.ai_addr = 0; + hints_.ai_next = 0; + } + + /// Get the hints associated with the query. + const boost::asio::detail::addrinfo_type& hints() const + { + return hints_; + } + + /// Get the host name associated with the query. + std::string host_name() const + { + return host_name_; + } + + /// Get the service name associated with the query. + std::string service_name() const + { + return service_name_; + } + +private: + boost::asio::detail::addrinfo_type hints_; + std::string host_name_; + std::string service_name_; +}; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_BASIC_RESOLVER_QUERY_HPP diff --git a/boost/asio/ip/basic_resolver_results.hpp b/boost/asio/ip/basic_resolver_results.hpp new file mode 100644 index 0000000..64d1937 --- /dev/null +++ b/boost/asio/ip/basic_resolver_results.hpp @@ -0,0 +1,313 @@ +// +// ip/basic_resolver_results.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_BASIC_RESOLVER_RESULTS_HPP +#define BOOST_ASIO_IP_BASIC_RESOLVER_RESULTS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_WINDOWS_RUNTIME) +# include +#endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) + +#include + +namespace boost { +namespace asio { +namespace ip { + +/// A range of entries produced by a resolver. +/** + * The boost::asio::ip::basic_resolver_results class template is used to define + * a range over the results returned by a resolver. + * + * The iterator's value_type, obtained when a results iterator is dereferenced, + * is: @code const basic_resolver_entry @endcode + * + * @note For backward compatibility, basic_resolver_results is derived from + * basic_resolver_iterator. This derivation is deprecated. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_resolver_results +#if !defined(BOOST_ASIO_NO_DEPRECATED) + : public basic_resolver_iterator +#else // !defined(BOOST_ASIO_NO_DEPRECATED) + : private basic_resolver_iterator +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) +{ +public: + /// The protocol type associated with the results. + typedef InternetProtocol protocol_type; + + /// The endpoint type associated with the results. + typedef typename protocol_type::endpoint endpoint_type; + + /// The type of a value in the results range. + typedef basic_resolver_entry value_type; + + /// The type of a const reference to a value in the range. + typedef const value_type& const_reference; + + /// The type of a non-const reference to a value in the range. + typedef value_type& reference; + + /// The type of an iterator into the range. + typedef basic_resolver_iterator const_iterator; + + /// The type of an iterator into the range. + typedef const_iterator iterator; + + /// Type used to represent the distance between two iterators in the range. + typedef std::ptrdiff_t difference_type; + + /// Type used to represent a count of the elements in the range. + typedef std::size_t size_type; + + /// Default constructor creates an empty range. + basic_resolver_results() + { + } + + /// Copy constructor. + basic_resolver_results(const basic_resolver_results& other) + : basic_resolver_iterator(other) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move constructor. + basic_resolver_results(basic_resolver_results&& other) + : basic_resolver_iterator( + BOOST_ASIO_MOVE_CAST(basic_resolver_results)(other)) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Assignment operator. + basic_resolver_results& operator=(const basic_resolver_results& other) + { + basic_resolver_iterator::operator=(other); + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-assignment operator. + basic_resolver_results& operator=(basic_resolver_results&& other) + { + basic_resolver_iterator::operator=( + BOOST_ASIO_MOVE_CAST(basic_resolver_results)(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + +#if !defined(GENERATING_DOCUMENTATION) + // Create results from an addrinfo list returned by getaddrinfo. + static basic_resolver_results create( + boost::asio::detail::addrinfo_type* address_info, + const std::string& host_name, const std::string& service_name) + { + basic_resolver_results results; + if (!address_info) + return results; + + std::string actual_host_name = host_name; + if (address_info->ai_canonname) + actual_host_name = address_info->ai_canonname; + + results.values_.reset(new values_type); + + while (address_info) + { + if (address_info->ai_family == BOOST_ASIO_OS_DEF(AF_INET) + || address_info->ai_family == BOOST_ASIO_OS_DEF(AF_INET6)) + { + using namespace std; // For memcpy. + typename InternetProtocol::endpoint endpoint; + endpoint.resize(static_cast(address_info->ai_addrlen)); + memcpy(endpoint.data(), address_info->ai_addr, + address_info->ai_addrlen); + results.values_->push_back( + basic_resolver_entry(endpoint, + actual_host_name, service_name)); + } + address_info = address_info->ai_next; + } + + return results; + } + + // Create results from an endpoint, host name and service name. + static basic_resolver_results create(const endpoint_type& endpoint, + const std::string& host_name, const std::string& service_name) + { + basic_resolver_results results; + results.values_.reset(new values_type); + results.values_->push_back( + basic_resolver_entry( + endpoint, host_name, service_name)); + return results; + } + + // Create results from a sequence of endpoints, host and service name. + template + static basic_resolver_results create( + EndpointIterator begin, EndpointIterator end, + const std::string& host_name, const std::string& service_name) + { + basic_resolver_results results; + if (begin != end) + { + results.values_.reset(new values_type); + for (EndpointIterator ep_iter = begin; ep_iter != end; ++ep_iter) + { + results.values_->push_back( + basic_resolver_entry( + *ep_iter, host_name, service_name)); + } + } + return results; + } + +# if defined(BOOST_ASIO_WINDOWS_RUNTIME) + // Create results from a Windows Runtime list of EndpointPair objects. + static basic_resolver_results create( + Windows::Foundation::Collections::IVectorView< + Windows::Networking::EndpointPair^>^ endpoints, + const boost::asio::detail::addrinfo_type& hints, + const std::string& host_name, const std::string& service_name) + { + basic_resolver_results results; + if (endpoints->Size) + { + results.values_.reset(new values_type); + for (unsigned int i = 0; i < endpoints->Size; ++i) + { + auto pair = endpoints->GetAt(i); + + if (hints.ai_family == BOOST_ASIO_OS_DEF(AF_INET) + && pair->RemoteHostName->Type + != Windows::Networking::HostNameType::Ipv4) + continue; + + if (hints.ai_family == BOOST_ASIO_OS_DEF(AF_INET6) + && pair->RemoteHostName->Type + != Windows::Networking::HostNameType::Ipv6) + continue; + + results.values_->push_back( + basic_resolver_entry( + typename InternetProtocol::endpoint( + ip::make_address( + boost::asio::detail::winrt_utils::string( + pair->RemoteHostName->CanonicalName)), + boost::asio::detail::winrt_utils::integer( + pair->RemoteServiceName)), + host_name, service_name)); + } + } + return results; + } +# endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) +#endif // !defined(GENERATING_DOCUMENTATION) + + /// Get the number of entries in the results range. + size_type size() const BOOST_ASIO_NOEXCEPT + { + return this->values_ ? this->values_->size() : 0; + } + + /// Get the maximum number of entries permitted in a results range. + size_type max_size() const BOOST_ASIO_NOEXCEPT + { + return this->values_ ? this->values_->max_size() : values_type().max_size(); + } + + /// Determine whether the results range is empty. + bool empty() const BOOST_ASIO_NOEXCEPT + { + return this->values_ ? this->values_->empty() : true; + } + + /// Obtain a begin iterator for the results range. + const_iterator begin() const + { + basic_resolver_results tmp(*this); + tmp.index_ = 0; + return BOOST_ASIO_MOVE_CAST(basic_resolver_results)(tmp); + } + + /// Obtain an end iterator for the results range. + const_iterator end() const + { + return const_iterator(); + } + + /// Obtain a begin iterator for the results range. + const_iterator cbegin() const + { + return begin(); + } + + /// Obtain an end iterator for the results range. + const_iterator cend() const + { + return end(); + } + + /// Swap the results range with another. + void swap(basic_resolver_results& that) BOOST_ASIO_NOEXCEPT + { + if (this != &that) + { + this->values_.swap(that.values_); + std::size_t index = this->index_; + this->index_ = that.index_; + that.index_ = index; + } + } + + /// Test two iterators for equality. + friend bool operator==(const basic_resolver_results& a, + const basic_resolver_results& b) + { + return a.equal(b); + } + + /// Test two iterators for inequality. + friend bool operator!=(const basic_resolver_results& a, + const basic_resolver_results& b) + { + return !a.equal(b); + } + +private: + typedef std::vector > values_type; +}; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_BASIC_RESOLVER_RESULTS_HPP diff --git a/boost/asio/ip/detail/endpoint.hpp b/boost/asio/ip/detail/endpoint.hpp new file mode 100644 index 0000000..690e6b1 --- /dev/null +++ b/boost/asio/ip/detail/endpoint.hpp @@ -0,0 +1,143 @@ +// +// ip/detail/endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_DETAIL_ENDPOINT_HPP +#define BOOST_ASIO_IP_DETAIL_ENDPOINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { +namespace detail { + +// Helper class for implementating an IP endpoint. +class endpoint +{ +public: + // Default constructor. + BOOST_ASIO_DECL endpoint() BOOST_ASIO_NOEXCEPT; + + // Construct an endpoint using a family and port number. + BOOST_ASIO_DECL endpoint(int family, + unsigned short port_num) BOOST_ASIO_NOEXCEPT; + + // Construct an endpoint using an address and port number. + BOOST_ASIO_DECL endpoint(const boost::asio::ip::address& addr, + unsigned short port_num) BOOST_ASIO_NOEXCEPT; + + // Copy constructor. + endpoint(const endpoint& other) BOOST_ASIO_NOEXCEPT + : data_(other.data_) + { + } + + // Assign from another endpoint. + endpoint& operator=(const endpoint& other) BOOST_ASIO_NOEXCEPT + { + data_ = other.data_; + return *this; + } + + // Get the underlying endpoint in the native type. + boost::asio::detail::socket_addr_type* data() BOOST_ASIO_NOEXCEPT + { + return &data_.base; + } + + // Get the underlying endpoint in the native type. + const boost::asio::detail::socket_addr_type* data() const BOOST_ASIO_NOEXCEPT + { + return &data_.base; + } + + // Get the underlying size of the endpoint in the native type. + std::size_t size() const BOOST_ASIO_NOEXCEPT + { + if (is_v4()) + return sizeof(boost::asio::detail::sockaddr_in4_type); + else + return sizeof(boost::asio::detail::sockaddr_in6_type); + } + + // Set the underlying size of the endpoint in the native type. + BOOST_ASIO_DECL void resize(std::size_t new_size); + + // Get the capacity of the endpoint in the native type. + std::size_t capacity() const BOOST_ASIO_NOEXCEPT + { + return sizeof(data_); + } + + // Get the port associated with the endpoint. + BOOST_ASIO_DECL unsigned short port() const BOOST_ASIO_NOEXCEPT; + + // Set the port associated with the endpoint. + BOOST_ASIO_DECL void port(unsigned short port_num) BOOST_ASIO_NOEXCEPT; + + // Get the IP address associated with the endpoint. + BOOST_ASIO_DECL boost::asio::ip::address address() const BOOST_ASIO_NOEXCEPT; + + // Set the IP address associated with the endpoint. + BOOST_ASIO_DECL void address( + const boost::asio::ip::address& addr) BOOST_ASIO_NOEXCEPT; + + // Compare two endpoints for equality. + BOOST_ASIO_DECL friend bool operator==(const endpoint& e1, + const endpoint& e2) BOOST_ASIO_NOEXCEPT; + + // Compare endpoints for ordering. + BOOST_ASIO_DECL friend bool operator<(const endpoint& e1, + const endpoint& e2) BOOST_ASIO_NOEXCEPT; + + // Determine whether the endpoint is IPv4. + bool is_v4() const BOOST_ASIO_NOEXCEPT + { + return data_.base.sa_family == BOOST_ASIO_OS_DEF(AF_INET); + } + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + // Convert to a string. + BOOST_ASIO_DECL std::string to_string() const; +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +private: + // The underlying IP socket address. + union data_union + { + boost::asio::detail::socket_addr_type base; + boost::asio::detail::sockaddr_in4_type v4; + boost::asio::detail::sockaddr_in6_type v6; + } data_; +}; + +} // namespace detail +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_IP_DETAIL_ENDPOINT_HPP diff --git a/boost/asio/ip/detail/impl/endpoint.ipp b/boost/asio/ip/detail/impl/endpoint.ipp new file mode 100644 index 0000000..9297429 --- /dev/null +++ b/boost/asio/ip/detail/impl/endpoint.ipp @@ -0,0 +1,201 @@ +// +// ip/detail/impl/endpoint.ipp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP +#define BOOST_ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#if !defined(BOOST_ASIO_NO_IOSTREAM) +# include +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { +namespace detail { + +endpoint::endpoint() BOOST_ASIO_NOEXCEPT + : data_() +{ + data_.v4.sin_family = BOOST_ASIO_OS_DEF(AF_INET); + data_.v4.sin_port = 0; + data_.v4.sin_addr.s_addr = BOOST_ASIO_OS_DEF(INADDR_ANY); +} + +endpoint::endpoint(int family, unsigned short port_num) BOOST_ASIO_NOEXCEPT + : data_() +{ + using namespace std; // For memcpy. + if (family == BOOST_ASIO_OS_DEF(AF_INET)) + { + data_.v4.sin_family = BOOST_ASIO_OS_DEF(AF_INET); + data_.v4.sin_port = + boost::asio::detail::socket_ops::host_to_network_short(port_num); + data_.v4.sin_addr.s_addr = BOOST_ASIO_OS_DEF(INADDR_ANY); + } + else + { + data_.v6.sin6_family = BOOST_ASIO_OS_DEF(AF_INET6); + data_.v6.sin6_port = + boost::asio::detail::socket_ops::host_to_network_short(port_num); + data_.v6.sin6_flowinfo = 0; + data_.v6.sin6_addr.s6_addr[0] = 0; data_.v6.sin6_addr.s6_addr[1] = 0; + data_.v6.sin6_addr.s6_addr[2] = 0; data_.v6.sin6_addr.s6_addr[3] = 0; + data_.v6.sin6_addr.s6_addr[4] = 0; data_.v6.sin6_addr.s6_addr[5] = 0; + data_.v6.sin6_addr.s6_addr[6] = 0; data_.v6.sin6_addr.s6_addr[7] = 0; + data_.v6.sin6_addr.s6_addr[8] = 0; data_.v6.sin6_addr.s6_addr[9] = 0; + data_.v6.sin6_addr.s6_addr[10] = 0; data_.v6.sin6_addr.s6_addr[11] = 0; + data_.v6.sin6_addr.s6_addr[12] = 0; data_.v6.sin6_addr.s6_addr[13] = 0; + data_.v6.sin6_addr.s6_addr[14] = 0; data_.v6.sin6_addr.s6_addr[15] = 0; + data_.v6.sin6_scope_id = 0; + } +} + +endpoint::endpoint(const boost::asio::ip::address& addr, + unsigned short port_num) BOOST_ASIO_NOEXCEPT + : data_() +{ + using namespace std; // For memcpy. + if (addr.is_v4()) + { + data_.v4.sin_family = BOOST_ASIO_OS_DEF(AF_INET); + data_.v4.sin_port = + boost::asio::detail::socket_ops::host_to_network_short(port_num); + data_.v4.sin_addr.s_addr = + boost::asio::detail::socket_ops::host_to_network_long( + addr.to_v4().to_uint()); + } + else + { + data_.v6.sin6_family = BOOST_ASIO_OS_DEF(AF_INET6); + data_.v6.sin6_port = + boost::asio::detail::socket_ops::host_to_network_short(port_num); + data_.v6.sin6_flowinfo = 0; + boost::asio::ip::address_v6 v6_addr = addr.to_v6(); + boost::asio::ip::address_v6::bytes_type bytes = v6_addr.to_bytes(); + memcpy(data_.v6.sin6_addr.s6_addr, bytes.data(), 16); + data_.v6.sin6_scope_id = + static_cast( + v6_addr.scope_id()); + } +} + +void endpoint::resize(std::size_t new_size) +{ + if (new_size > sizeof(boost::asio::detail::sockaddr_storage_type)) + { + boost::system::error_code ec(boost::asio::error::invalid_argument); + boost::asio::detail::throw_error(ec); + } +} + +unsigned short endpoint::port() const BOOST_ASIO_NOEXCEPT +{ + if (is_v4()) + { + return boost::asio::detail::socket_ops::network_to_host_short( + data_.v4.sin_port); + } + else + { + return boost::asio::detail::socket_ops::network_to_host_short( + data_.v6.sin6_port); + } +} + +void endpoint::port(unsigned short port_num) BOOST_ASIO_NOEXCEPT +{ + if (is_v4()) + { + data_.v4.sin_port + = boost::asio::detail::socket_ops::host_to_network_short(port_num); + } + else + { + data_.v6.sin6_port + = boost::asio::detail::socket_ops::host_to_network_short(port_num); + } +} + +boost::asio::ip::address endpoint::address() const BOOST_ASIO_NOEXCEPT +{ + using namespace std; // For memcpy. + if (is_v4()) + { + return boost::asio::ip::address_v4( + boost::asio::detail::socket_ops::network_to_host_long( + data_.v4.sin_addr.s_addr)); + } + else + { + boost::asio::ip::address_v6::bytes_type bytes; +#if defined(BOOST_ASIO_HAS_STD_ARRAY) + memcpy(bytes.data(), data_.v6.sin6_addr.s6_addr, 16); +#else // defined(BOOST_ASIO_HAS_STD_ARRAY) + memcpy(bytes.elems, data_.v6.sin6_addr.s6_addr, 16); +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) + return boost::asio::ip::address_v6(bytes, data_.v6.sin6_scope_id); + } +} + +void endpoint::address(const boost::asio::ip::address& addr) BOOST_ASIO_NOEXCEPT +{ + endpoint tmp_endpoint(addr, port()); + data_ = tmp_endpoint.data_; +} + +bool operator==(const endpoint& e1, const endpoint& e2) BOOST_ASIO_NOEXCEPT +{ + return e1.address() == e2.address() && e1.port() == e2.port(); +} + +bool operator<(const endpoint& e1, const endpoint& e2) BOOST_ASIO_NOEXCEPT +{ + if (e1.address() < e2.address()) + return true; + if (e1.address() != e2.address()) + return false; + return e1.port() < e2.port(); +} + +#if !defined(BOOST_ASIO_NO_IOSTREAM) +std::string endpoint::to_string() const +{ + std::ostringstream tmp_os; + tmp_os.imbue(std::locale::classic()); + if (is_v4()) + tmp_os << address(); + else + tmp_os << '[' << address() << ']'; + tmp_os << ':' << port(); + + return tmp_os.str(); +} +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +} // namespace detail +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP diff --git a/boost/asio/ip/detail/socket_option.hpp b/boost/asio/ip/detail/socket_option.hpp new file mode 100644 index 0000000..7f8b3f5 --- /dev/null +++ b/boost/asio/ip/detail/socket_option.hpp @@ -0,0 +1,568 @@ +// +// detail/socket_option.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_DETAIL_SOCKET_OPTION_HPP +#define BOOST_ASIO_IP_DETAIL_SOCKET_OPTION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { +namespace detail { +namespace socket_option { + +// Helper template for implementing multicast enable loopback options. +template +class multicast_enable_loopback +{ +public: +#if defined(__sun) || defined(__osf__) + typedef unsigned char ipv4_value_type; + typedef unsigned char ipv6_value_type; +#elif defined(_AIX) || defined(__hpux) || defined(__QNXNTO__) + typedef unsigned char ipv4_value_type; + typedef unsigned int ipv6_value_type; +#else + typedef int ipv4_value_type; + typedef int ipv6_value_type; +#endif + + // Default constructor. + multicast_enable_loopback() + : ipv4_value_(0), + ipv6_value_(0) + { + } + + // Construct with a specific option value. + explicit multicast_enable_loopback(bool v) + : ipv4_value_(v ? 1 : 0), + ipv6_value_(v ? 1 : 0) + { + } + + // Set the value of the boolean. + multicast_enable_loopback& operator=(bool v) + { + ipv4_value_ = v ? 1 : 0; + ipv6_value_ = v ? 1 : 0; + return *this; + } + + // Get the current value of the boolean. + bool value() const + { + return !!ipv4_value_; + } + + // Convert to bool. + operator bool() const + { + return !!ipv4_value_; + } + + // Test for false. + bool operator!() const + { + return !ipv4_value_; + } + + // Get the level of the socket option. + template + int level(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return IPv6_Level; + return IPv4_Level; + } + + // Get the name of the socket option. + template + int name(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return IPv6_Name; + return IPv4_Name; + } + + // Get the address of the boolean data. + template + void* data(const Protocol& protocol) + { + if (protocol.family() == PF_INET6) + return &ipv6_value_; + return &ipv4_value_; + } + + // Get the address of the boolean data. + template + const void* data(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return &ipv6_value_; + return &ipv4_value_; + } + + // Get the size of the boolean data. + template + std::size_t size(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return sizeof(ipv6_value_); + return sizeof(ipv4_value_); + } + + // Set the size of the boolean data. + template + void resize(const Protocol& protocol, std::size_t s) + { + if (protocol.family() == PF_INET6) + { + if (s != sizeof(ipv6_value_)) + { + std::length_error ex("multicast_enable_loopback socket option resize"); + boost::asio::detail::throw_exception(ex); + } + ipv4_value_ = ipv6_value_ ? 1 : 0; + } + else + { + if (s != sizeof(ipv4_value_)) + { + std::length_error ex("multicast_enable_loopback socket option resize"); + boost::asio::detail::throw_exception(ex); + } + ipv6_value_ = ipv4_value_ ? 1 : 0; + } + } + +private: + ipv4_value_type ipv4_value_; + ipv6_value_type ipv6_value_; +}; + +// Helper template for implementing unicast hops options. +template +class unicast_hops +{ +public: + // Default constructor. + unicast_hops() + : value_(0) + { + } + + // Construct with a specific option value. + explicit unicast_hops(int v) + : value_(v) + { + } + + // Set the value of the option. + unicast_hops& operator=(int v) + { + value_ = v; + return *this; + } + + // Get the current value of the option. + int value() const + { + return value_; + } + + // Get the level of the socket option. + template + int level(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return IPv6_Level; + return IPv4_Level; + } + + // Get the name of the socket option. + template + int name(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return IPv6_Name; + return IPv4_Name; + } + + // Get the address of the data. + template + int* data(const Protocol&) + { + return &value_; + } + + // Get the address of the data. + template + const int* data(const Protocol&) const + { + return &value_; + } + + // Get the size of the data. + template + std::size_t size(const Protocol&) const + { + return sizeof(value_); + } + + // Set the size of the data. + template + void resize(const Protocol&, std::size_t s) + { + if (s != sizeof(value_)) + { + std::length_error ex("unicast hops socket option resize"); + boost::asio::detail::throw_exception(ex); + } +#if defined(__hpux) + if (value_ < 0) + value_ = value_ & 0xFF; +#endif + } + +private: + int value_; +}; + +// Helper template for implementing multicast hops options. +template +class multicast_hops +{ +public: +#if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) + typedef int ipv4_value_type; +#else + typedef unsigned char ipv4_value_type; +#endif + typedef int ipv6_value_type; + + // Default constructor. + multicast_hops() + : ipv4_value_(0), + ipv6_value_(0) + { + } + + // Construct with a specific option value. + explicit multicast_hops(int v) + { + if (v < 0 || v > 255) + { + std::out_of_range ex("multicast hops value out of range"); + boost::asio::detail::throw_exception(ex); + } + ipv4_value_ = (ipv4_value_type)v; + ipv6_value_ = v; + } + + // Set the value of the option. + multicast_hops& operator=(int v) + { + if (v < 0 || v > 255) + { + std::out_of_range ex("multicast hops value out of range"); + boost::asio::detail::throw_exception(ex); + } + ipv4_value_ = (ipv4_value_type)v; + ipv6_value_ = v; + return *this; + } + + // Get the current value of the option. + int value() const + { + return ipv6_value_; + } + + // Get the level of the socket option. + template + int level(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return IPv6_Level; + return IPv4_Level; + } + + // Get the name of the socket option. + template + int name(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return IPv6_Name; + return IPv4_Name; + } + + // Get the address of the data. + template + void* data(const Protocol& protocol) + { + if (protocol.family() == PF_INET6) + return &ipv6_value_; + return &ipv4_value_; + } + + // Get the address of the data. + template + const void* data(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return &ipv6_value_; + return &ipv4_value_; + } + + // Get the size of the data. + template + std::size_t size(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return sizeof(ipv6_value_); + return sizeof(ipv4_value_); + } + + // Set the size of the data. + template + void resize(const Protocol& protocol, std::size_t s) + { + if (protocol.family() == PF_INET6) + { + if (s != sizeof(ipv6_value_)) + { + std::length_error ex("multicast hops socket option resize"); + boost::asio::detail::throw_exception(ex); + } + if (ipv6_value_ < 0) + ipv4_value_ = 0; + else if (ipv6_value_ > 255) + ipv4_value_ = 255; + else + ipv4_value_ = (ipv4_value_type)ipv6_value_; + } + else + { + if (s != sizeof(ipv4_value_)) + { + std::length_error ex("multicast hops socket option resize"); + boost::asio::detail::throw_exception(ex); + } + ipv6_value_ = ipv4_value_; + } + } + +private: + ipv4_value_type ipv4_value_; + ipv6_value_type ipv6_value_; +}; + +// Helper template for implementing ip_mreq-based options. +template +class multicast_request +{ +public: + // Default constructor. + multicast_request() + : ipv4_value_(), // Zero-initialisation gives the "any" address. + ipv6_value_() // Zero-initialisation gives the "any" address. + { + } + + // Construct with multicast address only. + explicit multicast_request(const address& multicast_address) + : ipv4_value_(), // Zero-initialisation gives the "any" address. + ipv6_value_() // Zero-initialisation gives the "any" address. + { + if (multicast_address.is_v6()) + { + using namespace std; // For memcpy. + address_v6 ipv6_address = multicast_address.to_v6(); + address_v6::bytes_type bytes = ipv6_address.to_bytes(); + memcpy(ipv6_value_.ipv6mr_multiaddr.s6_addr, bytes.data(), 16); + ipv6_value_.ipv6mr_interface = ipv6_address.scope_id(); + } + else + { + ipv4_value_.imr_multiaddr.s_addr = + boost::asio::detail::socket_ops::host_to_network_long( + multicast_address.to_v4().to_uint()); + ipv4_value_.imr_interface.s_addr = + boost::asio::detail::socket_ops::host_to_network_long( + address_v4::any().to_uint()); + } + } + + // Construct with multicast address and IPv4 address specifying an interface. + explicit multicast_request(const address_v4& multicast_address, + const address_v4& network_interface = address_v4::any()) + : ipv6_value_() // Zero-initialisation gives the "any" address. + { + ipv4_value_.imr_multiaddr.s_addr = + boost::asio::detail::socket_ops::host_to_network_long( + multicast_address.to_uint()); + ipv4_value_.imr_interface.s_addr = + boost::asio::detail::socket_ops::host_to_network_long( + network_interface.to_uint()); + } + + // Construct with multicast address and IPv6 network interface index. + explicit multicast_request( + const address_v6& multicast_address, + unsigned long network_interface = 0) + : ipv4_value_() // Zero-initialisation gives the "any" address. + { + using namespace std; // For memcpy. + address_v6::bytes_type bytes = multicast_address.to_bytes(); + memcpy(ipv6_value_.ipv6mr_multiaddr.s6_addr, bytes.data(), 16); + if (network_interface) + ipv6_value_.ipv6mr_interface = network_interface; + else + ipv6_value_.ipv6mr_interface = multicast_address.scope_id(); + } + + // Get the level of the socket option. + template + int level(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return IPv6_Level; + return IPv4_Level; + } + + // Get the name of the socket option. + template + int name(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return IPv6_Name; + return IPv4_Name; + } + + // Get the address of the option data. + template + const void* data(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return &ipv6_value_; + return &ipv4_value_; + } + + // Get the size of the option data. + template + std::size_t size(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return sizeof(ipv6_value_); + return sizeof(ipv4_value_); + } + +private: + boost::asio::detail::in4_mreq_type ipv4_value_; + boost::asio::detail::in6_mreq_type ipv6_value_; +}; + +// Helper template for implementing options that specify a network interface. +template +class network_interface +{ +public: + // Default constructor. + network_interface() + { + ipv4_value_.s_addr = + boost::asio::detail::socket_ops::host_to_network_long( + address_v4::any().to_uint()); + ipv6_value_ = 0; + } + + // Construct with IPv4 interface. + explicit network_interface(const address_v4& ipv4_interface) + { + ipv4_value_.s_addr = + boost::asio::detail::socket_ops::host_to_network_long( + ipv4_interface.to_uint()); + ipv6_value_ = 0; + } + + // Construct with IPv6 interface. + explicit network_interface(unsigned int ipv6_interface) + { + ipv4_value_.s_addr = + boost::asio::detail::socket_ops::host_to_network_long( + address_v4::any().to_uint()); + ipv6_value_ = ipv6_interface; + } + + // Get the level of the socket option. + template + int level(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return IPv6_Level; + return IPv4_Level; + } + + // Get the name of the socket option. + template + int name(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return IPv6_Name; + return IPv4_Name; + } + + // Get the address of the option data. + template + const void* data(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return &ipv6_value_; + return &ipv4_value_; + } + + // Get the size of the option data. + template + std::size_t size(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return sizeof(ipv6_value_); + return sizeof(ipv4_value_); + } + +private: + boost::asio::detail::in4_addr_type ipv4_value_; + unsigned int ipv6_value_; +}; + +} // namespace socket_option +} // namespace detail +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_DETAIL_SOCKET_OPTION_HPP diff --git a/boost/asio/ip/host_name.hpp b/boost/asio/ip/host_name.hpp new file mode 100644 index 0000000..bb893ef --- /dev/null +++ b/boost/asio/ip/host_name.hpp @@ -0,0 +1,44 @@ +// +// ip/host_name.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_HOST_NAME_HPP +#define BOOST_ASIO_IP_HOST_NAME_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +/// Get the current host name. +BOOST_ASIO_DECL std::string host_name(); + +/// Get the current host name. +BOOST_ASIO_DECL std::string host_name(boost::system::error_code& ec); + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_IP_HOST_NAME_HPP diff --git a/boost/asio/ip/icmp.hpp b/boost/asio/ip/icmp.hpp new file mode 100644 index 0000000..229529f --- /dev/null +++ b/boost/asio/ip/icmp.hpp @@ -0,0 +1,117 @@ +// +// ip/icmp.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_ICMP_HPP +#define BOOST_ASIO_IP_ICMP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +/// Encapsulates the flags needed for ICMP. +/** + * The boost::asio::ip::icmp class contains flags necessary for ICMP sockets. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Safe. + * + * @par Concepts: + * Protocol, InternetProtocol. + */ +class icmp +{ +public: + /// The type of a ICMP endpoint. + typedef basic_endpoint endpoint; + + /// Construct to represent the IPv4 ICMP protocol. + static icmp v4() + { + return icmp(BOOST_ASIO_OS_DEF(IPPROTO_ICMP), + BOOST_ASIO_OS_DEF(AF_INET)); + } + + /// Construct to represent the IPv6 ICMP protocol. + static icmp v6() + { + return icmp(BOOST_ASIO_OS_DEF(IPPROTO_ICMPV6), + BOOST_ASIO_OS_DEF(AF_INET6)); + } + + /// Obtain an identifier for the type of the protocol. + int type() const + { + return BOOST_ASIO_OS_DEF(SOCK_RAW); + } + + /// Obtain an identifier for the protocol. + int protocol() const + { + return protocol_; + } + + /// Obtain an identifier for the protocol family. + int family() const + { + return family_; + } + + /// The ICMP socket type. + typedef basic_raw_socket socket; + + /// The ICMP resolver type. + typedef basic_resolver resolver; + + /// Compare two protocols for equality. + friend bool operator==(const icmp& p1, const icmp& p2) + { + return p1.protocol_ == p2.protocol_ && p1.family_ == p2.family_; + } + + /// Compare two protocols for inequality. + friend bool operator!=(const icmp& p1, const icmp& p2) + { + return p1.protocol_ != p2.protocol_ || p1.family_ != p2.family_; + } + +private: + // Construct with a specific family. + explicit icmp(int protocol_id, int protocol_family) + : protocol_(protocol_id), + family_(protocol_family) + { + } + + int protocol_; + int family_; +}; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_ICMP_HPP diff --git a/boost/asio/ip/impl/address.hpp b/boost/asio/ip/impl/address.hpp new file mode 100644 index 0000000..63f6b2e --- /dev/null +++ b/boost/asio/ip/impl/address.hpp @@ -0,0 +1,69 @@ +// +// ip/impl/address.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_ADDRESS_HPP +#define BOOST_ASIO_IP_IMPL_ADDRESS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + +inline address address::from_string(const char* str) +{ + return boost::asio::ip::make_address(str); +} + +inline address address::from_string( + const char* str, boost::system::error_code& ec) +{ + return boost::asio::ip::make_address(str, ec); +} + +inline address address::from_string(const std::string& str) +{ + return boost::asio::ip::make_address(str); +} + +inline address address::from_string( + const std::string& str, boost::system::error_code& ec) +{ + return boost::asio::ip::make_address(str, ec); +} + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, const address& addr) +{ + return os << addr.to_string().c_str(); +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +#endif // BOOST_ASIO_IP_IMPL_ADDRESS_HPP diff --git a/boost/asio/ip/impl/address.ipp b/boost/asio/ip/impl/address.ipp new file mode 100644 index 0000000..2dc5529 --- /dev/null +++ b/boost/asio/ip/impl/address.ipp @@ -0,0 +1,241 @@ +// +// ip/impl/address.ipp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_ADDRESS_IPP +#define BOOST_ASIO_IP_IMPL_ADDRESS_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +address::address() BOOST_ASIO_NOEXCEPT + : type_(ipv4), + ipv4_address_(), + ipv6_address_() +{ +} + +address::address( + const boost::asio::ip::address_v4& ipv4_address) BOOST_ASIO_NOEXCEPT + : type_(ipv4), + ipv4_address_(ipv4_address), + ipv6_address_() +{ +} + +address::address( + const boost::asio::ip::address_v6& ipv6_address) BOOST_ASIO_NOEXCEPT + : type_(ipv6), + ipv4_address_(), + ipv6_address_(ipv6_address) +{ +} + +address::address(const address& other) BOOST_ASIO_NOEXCEPT + : type_(other.type_), + ipv4_address_(other.ipv4_address_), + ipv6_address_(other.ipv6_address_) +{ +} + +#if defined(BOOST_ASIO_HAS_MOVE) +address::address(address&& other) BOOST_ASIO_NOEXCEPT + : type_(other.type_), + ipv4_address_(other.ipv4_address_), + ipv6_address_(other.ipv6_address_) +{ +} +#endif // defined(BOOST_ASIO_HAS_MOVE) + +address& address::operator=(const address& other) BOOST_ASIO_NOEXCEPT +{ + type_ = other.type_; + ipv4_address_ = other.ipv4_address_; + ipv6_address_ = other.ipv6_address_; + return *this; +} + +#if defined(BOOST_ASIO_HAS_MOVE) +address& address::operator=(address&& other) BOOST_ASIO_NOEXCEPT +{ + type_ = other.type_; + ipv4_address_ = other.ipv4_address_; + ipv6_address_ = other.ipv6_address_; + return *this; +} +#endif // defined(BOOST_ASIO_HAS_MOVE) + +address& address::operator=( + const boost::asio::ip::address_v4& ipv4_address) BOOST_ASIO_NOEXCEPT +{ + type_ = ipv4; + ipv4_address_ = ipv4_address; + ipv6_address_ = boost::asio::ip::address_v6(); + return *this; +} + +address& address::operator=( + const boost::asio::ip::address_v6& ipv6_address) BOOST_ASIO_NOEXCEPT +{ + type_ = ipv6; + ipv4_address_ = boost::asio::ip::address_v4(); + ipv6_address_ = ipv6_address; + return *this; +} + +address make_address(const char* str) +{ + boost::system::error_code ec; + address addr = make_address(str, ec); + boost::asio::detail::throw_error(ec); + return addr; +} + +address make_address(const char* str, + boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT +{ + boost::asio::ip::address_v6 ipv6_address = + boost::asio::ip::make_address_v6(str, ec); + if (!ec) + return address(ipv6_address); + + boost::asio::ip::address_v4 ipv4_address = + boost::asio::ip::make_address_v4(str, ec); + if (!ec) + return address(ipv4_address); + + return address(); +} + +address make_address(const std::string& str) +{ + return make_address(str.c_str()); +} + +address make_address(const std::string& str, + boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT +{ + return make_address(str.c_str(), ec); +} + +#if defined(BOOST_ASIO_HAS_STRING_VIEW) + +address make_address(string_view str) +{ + return make_address(static_cast(str)); +} + +address make_address(string_view str, + boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT +{ + return make_address(static_cast(str), ec); +} + +#endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + +boost::asio::ip::address_v4 address::to_v4() const +{ + if (type_ != ipv4) + { + bad_address_cast ex; + boost::asio::detail::throw_exception(ex); + } + return ipv4_address_; +} + +boost::asio::ip::address_v6 address::to_v6() const +{ + if (type_ != ipv6) + { + bad_address_cast ex; + boost::asio::detail::throw_exception(ex); + } + return ipv6_address_; +} + +std::string address::to_string() const +{ + if (type_ == ipv6) + return ipv6_address_.to_string(); + return ipv4_address_.to_string(); +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +std::string address::to_string(boost::system::error_code& ec) const +{ + if (type_ == ipv6) + return ipv6_address_.to_string(ec); + return ipv4_address_.to_string(ec); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +bool address::is_loopback() const BOOST_ASIO_NOEXCEPT +{ + return (type_ == ipv4) + ? ipv4_address_.is_loopback() + : ipv6_address_.is_loopback(); +} + +bool address::is_unspecified() const BOOST_ASIO_NOEXCEPT +{ + return (type_ == ipv4) + ? ipv4_address_.is_unspecified() + : ipv6_address_.is_unspecified(); +} + +bool address::is_multicast() const BOOST_ASIO_NOEXCEPT +{ + return (type_ == ipv4) + ? ipv4_address_.is_multicast() + : ipv6_address_.is_multicast(); +} + +bool operator==(const address& a1, const address& a2) BOOST_ASIO_NOEXCEPT +{ + if (a1.type_ != a2.type_) + return false; + if (a1.type_ == address::ipv6) + return a1.ipv6_address_ == a2.ipv6_address_; + return a1.ipv4_address_ == a2.ipv4_address_; +} + +bool operator<(const address& a1, const address& a2) BOOST_ASIO_NOEXCEPT +{ + if (a1.type_ < a2.type_) + return true; + if (a1.type_ > a2.type_) + return false; + if (a1.type_ == address::ipv6) + return a1.ipv6_address_ < a2.ipv6_address_; + return a1.ipv4_address_ < a2.ipv4_address_; +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_IMPL_ADDRESS_IPP diff --git a/boost/asio/ip/impl/address_v4.hpp b/boost/asio/ip/impl/address_v4.hpp new file mode 100644 index 0000000..98bd89d --- /dev/null +++ b/boost/asio/ip/impl/address_v4.hpp @@ -0,0 +1,69 @@ +// +// ip/impl/address_v4.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_ADDRESS_V4_HPP +#define BOOST_ASIO_IP_IMPL_ADDRESS_V4_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + +inline address_v4 address_v4::from_string(const char* str) +{ + return boost::asio::ip::make_address_v4(str); +} + +inline address_v4 address_v4::from_string( + const char* str, boost::system::error_code& ec) +{ + return boost::asio::ip::make_address_v4(str, ec); +} + +inline address_v4 address_v4::from_string(const std::string& str) +{ + return boost::asio::ip::make_address_v4(str); +} + +inline address_v4 address_v4::from_string( + const std::string& str, boost::system::error_code& ec) +{ + return boost::asio::ip::make_address_v4(str, ec); +} + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, const address_v4& addr) +{ + return os << addr.to_string().c_str(); +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +#endif // BOOST_ASIO_IP_IMPL_ADDRESS_V4_HPP diff --git a/boost/asio/ip/impl/address_v4.ipp b/boost/asio/ip/impl/address_v4.ipp new file mode 100644 index 0000000..c572100 --- /dev/null +++ b/boost/asio/ip/impl/address_v4.ipp @@ -0,0 +1,212 @@ +// +// ip/impl/address_v4.ipp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_ADDRESS_V4_IPP +#define BOOST_ASIO_IP_IMPL_ADDRESS_V4_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +address_v4::address_v4(const address_v4::bytes_type& bytes) +{ +#if UCHAR_MAX > 0xFF + if (bytes[0] > 0xFF || bytes[1] > 0xFF + || bytes[2] > 0xFF || bytes[3] > 0xFF) + { + std::out_of_range ex("address_v4 from bytes_type"); + boost::asio::detail::throw_exception(ex); + } +#endif // UCHAR_MAX > 0xFF + + using namespace std; // For memcpy. + memcpy(&addr_.s_addr, bytes.data(), 4); +} + +address_v4::address_v4(address_v4::uint_type addr) +{ + if ((std::numeric_limits::max)() > 0xFFFFFFFF) + { + std::out_of_range ex("address_v4 from unsigned integer"); + boost::asio::detail::throw_exception(ex); + } + + addr_.s_addr = boost::asio::detail::socket_ops::host_to_network_long( + static_cast(addr)); +} + +address_v4::bytes_type address_v4::to_bytes() const BOOST_ASIO_NOEXCEPT +{ + using namespace std; // For memcpy. + bytes_type bytes; +#if defined(BOOST_ASIO_HAS_STD_ARRAY) + memcpy(bytes.data(), &addr_.s_addr, 4); +#else // defined(BOOST_ASIO_HAS_STD_ARRAY) + memcpy(bytes.elems, &addr_.s_addr, 4); +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) + return bytes; +} + +address_v4::uint_type address_v4::to_uint() const BOOST_ASIO_NOEXCEPT +{ + return boost::asio::detail::socket_ops::network_to_host_long(addr_.s_addr); +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +unsigned long address_v4::to_ulong() const +{ + return boost::asio::detail::socket_ops::network_to_host_long(addr_.s_addr); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +std::string address_v4::to_string() const +{ + boost::system::error_code ec; + char addr_str[boost::asio::detail::max_addr_v4_str_len]; + const char* addr = + boost::asio::detail::socket_ops::inet_ntop( + BOOST_ASIO_OS_DEF(AF_INET), &addr_, addr_str, + boost::asio::detail::max_addr_v4_str_len, 0, ec); + if (addr == 0) + boost::asio::detail::throw_error(ec); + return addr; +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +std::string address_v4::to_string(boost::system::error_code& ec) const +{ + char addr_str[boost::asio::detail::max_addr_v4_str_len]; + const char* addr = + boost::asio::detail::socket_ops::inet_ntop( + BOOST_ASIO_OS_DEF(AF_INET), &addr_, addr_str, + boost::asio::detail::max_addr_v4_str_len, 0, ec); + if (addr == 0) + return std::string(); + return addr; +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +bool address_v4::is_loopback() const BOOST_ASIO_NOEXCEPT +{ + return (to_uint() & 0xFF000000) == 0x7F000000; +} + +bool address_v4::is_unspecified() const BOOST_ASIO_NOEXCEPT +{ + return to_uint() == 0; +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +bool address_v4::is_class_a() const +{ + return (to_uint() & 0x80000000) == 0; +} + +bool address_v4::is_class_b() const +{ + return (to_uint() & 0xC0000000) == 0x80000000; +} + +bool address_v4::is_class_c() const +{ + return (to_uint() & 0xE0000000) == 0xC0000000; +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +bool address_v4::is_multicast() const BOOST_ASIO_NOEXCEPT +{ + return (to_uint() & 0xF0000000) == 0xE0000000; +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +address_v4 address_v4::broadcast(const address_v4& addr, const address_v4& mask) +{ + return address_v4(addr.to_uint() | (mask.to_uint() ^ 0xFFFFFFFF)); +} + +address_v4 address_v4::netmask(const address_v4& addr) +{ + if (addr.is_class_a()) + return address_v4(0xFF000000); + if (addr.is_class_b()) + return address_v4(0xFFFF0000); + if (addr.is_class_c()) + return address_v4(0xFFFFFF00); + return address_v4(0xFFFFFFFF); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +address_v4 make_address_v4(const char* str) +{ + boost::system::error_code ec; + address_v4 addr = make_address_v4(str, ec); + boost::asio::detail::throw_error(ec); + return addr; +} + +address_v4 make_address_v4(const char* str, + boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT +{ + address_v4::bytes_type bytes; + if (boost::asio::detail::socket_ops::inet_pton( + BOOST_ASIO_OS_DEF(AF_INET), str, &bytes, 0, ec) <= 0) + return address_v4(); + return address_v4(bytes); +} + +address_v4 make_address_v4(const std::string& str) +{ + return make_address_v4(str.c_str()); +} + +address_v4 make_address_v4(const std::string& str, + boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT +{ + return make_address_v4(str.c_str(), ec); +} + +#if defined(BOOST_ASIO_HAS_STRING_VIEW) + +address_v4 make_address_v4(string_view str) +{ + return make_address_v4(static_cast(str)); +} + +address_v4 make_address_v4(string_view str, + boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT +{ + return make_address_v4(static_cast(str), ec); +} + +#endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_IMPL_ADDRESS_V4_IPP diff --git a/boost/asio/ip/impl/address_v6.hpp b/boost/asio/ip/impl/address_v6.hpp new file mode 100644 index 0000000..ebfd467 --- /dev/null +++ b/boost/asio/ip/impl/address_v6.hpp @@ -0,0 +1,69 @@ +// +// ip/impl/address_v6.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_ADDRESS_V6_HPP +#define BOOST_ASIO_IP_IMPL_ADDRESS_V6_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + +inline address_v6 address_v6::from_string(const char* str) +{ + return boost::asio::ip::make_address_v6(str); +} + +inline address_v6 address_v6::from_string( + const char* str, boost::system::error_code& ec) +{ + return boost::asio::ip::make_address_v6(str, ec); +} + +inline address_v6 address_v6::from_string(const std::string& str) +{ + return boost::asio::ip::make_address_v6(str); +} + +inline address_v6 address_v6::from_string( + const std::string& str, boost::system::error_code& ec) +{ + return boost::asio::ip::make_address_v6(str, ec); +} + +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, const address_v6& addr) +{ + return os << addr.to_string().c_str(); +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +#endif // BOOST_ASIO_IP_IMPL_ADDRESS_V6_HPP diff --git a/boost/asio/ip/impl/address_v6.ipp b/boost/asio/ip/impl/address_v6.ipp new file mode 100644 index 0000000..7ea2f24 --- /dev/null +++ b/boost/asio/ip/impl/address_v6.ipp @@ -0,0 +1,352 @@ +// +// ip/impl/address_v6.ipp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP +#define BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +address_v6::address_v6() BOOST_ASIO_NOEXCEPT + : addr_(), + scope_id_(0) +{ +} + +address_v6::address_v6(const address_v6::bytes_type& bytes, + unsigned long scope) + : scope_id_(scope) +{ +#if UCHAR_MAX > 0xFF + for (std::size_t i = 0; i < bytes.size(); ++i) + { + if (bytes[i] > 0xFF) + { + std::out_of_range ex("address_v6 from bytes_type"); + boost::asio::detail::throw_exception(ex); + } + } +#endif // UCHAR_MAX > 0xFF + + using namespace std; // For memcpy. + memcpy(addr_.s6_addr, bytes.data(), 16); +} + +address_v6::address_v6(const address_v6& other) BOOST_ASIO_NOEXCEPT + : addr_(other.addr_), + scope_id_(other.scope_id_) +{ +} + +#if defined(BOOST_ASIO_HAS_MOVE) +address_v6::address_v6(address_v6&& other) BOOST_ASIO_NOEXCEPT + : addr_(other.addr_), + scope_id_(other.scope_id_) +{ +} +#endif // defined(BOOST_ASIO_HAS_MOVE) + +address_v6& address_v6::operator=(const address_v6& other) BOOST_ASIO_NOEXCEPT +{ + addr_ = other.addr_; + scope_id_ = other.scope_id_; + return *this; +} + +#if defined(BOOST_ASIO_HAS_MOVE) +address_v6& address_v6::operator=(address_v6&& other) BOOST_ASIO_NOEXCEPT +{ + addr_ = other.addr_; + scope_id_ = other.scope_id_; + return *this; +} +#endif // defined(BOOST_ASIO_HAS_MOVE) + +address_v6::bytes_type address_v6::to_bytes() const BOOST_ASIO_NOEXCEPT +{ + using namespace std; // For memcpy. + bytes_type bytes; +#if defined(BOOST_ASIO_HAS_STD_ARRAY) + memcpy(bytes.data(), addr_.s6_addr, 16); +#else // defined(BOOST_ASIO_HAS_STD_ARRAY) + memcpy(bytes.elems, addr_.s6_addr, 16); +#endif // defined(BOOST_ASIO_HAS_STD_ARRAY) + return bytes; +} + +std::string address_v6::to_string() const +{ + boost::system::error_code ec; + char addr_str[boost::asio::detail::max_addr_v6_str_len]; + const char* addr = + boost::asio::detail::socket_ops::inet_ntop( + BOOST_ASIO_OS_DEF(AF_INET6), &addr_, addr_str, + boost::asio::detail::max_addr_v6_str_len, scope_id_, ec); + if (addr == 0) + boost::asio::detail::throw_error(ec); + return addr; +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +std::string address_v6::to_string(boost::system::error_code& ec) const +{ + char addr_str[boost::asio::detail::max_addr_v6_str_len]; + const char* addr = + boost::asio::detail::socket_ops::inet_ntop( + BOOST_ASIO_OS_DEF(AF_INET6), &addr_, addr_str, + boost::asio::detail::max_addr_v6_str_len, scope_id_, ec); + if (addr == 0) + return std::string(); + return addr; +} + +address_v4 address_v6::to_v4() const +{ + if (!is_v4_mapped() && !is_v4_compatible()) + { + bad_address_cast ex; + boost::asio::detail::throw_exception(ex); + } + + address_v4::bytes_type v4_bytes = { { addr_.s6_addr[12], + addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } }; + return address_v4(v4_bytes); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +bool address_v6::is_loopback() const BOOST_ASIO_NOEXCEPT +{ + return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) + && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) + && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) + && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) + && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) + && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) + && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) + && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 1)); +} + +bool address_v6::is_unspecified() const BOOST_ASIO_NOEXCEPT +{ + return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) + && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) + && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) + && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) + && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) + && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) + && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) + && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 0)); +} + +bool address_v6::is_link_local() const BOOST_ASIO_NOEXCEPT +{ + return ((addr_.s6_addr[0] == 0xfe) && ((addr_.s6_addr[1] & 0xc0) == 0x80)); +} + +bool address_v6::is_site_local() const BOOST_ASIO_NOEXCEPT +{ + return ((addr_.s6_addr[0] == 0xfe) && ((addr_.s6_addr[1] & 0xc0) == 0xc0)); +} + +bool address_v6::is_v4_mapped() const BOOST_ASIO_NOEXCEPT +{ + return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) + && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) + && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) + && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) + && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) + && (addr_.s6_addr[10] == 0xff) && (addr_.s6_addr[11] == 0xff)); +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +bool address_v6::is_v4_compatible() const +{ + return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) + && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) + && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) + && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) + && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) + && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) + && !((addr_.s6_addr[12] == 0) + && (addr_.s6_addr[13] == 0) + && (addr_.s6_addr[14] == 0) + && ((addr_.s6_addr[15] == 0) || (addr_.s6_addr[15] == 1)))); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +bool address_v6::is_multicast() const BOOST_ASIO_NOEXCEPT +{ + return (addr_.s6_addr[0] == 0xff); +} + +bool address_v6::is_multicast_global() const BOOST_ASIO_NOEXCEPT +{ + return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x0e)); +} + +bool address_v6::is_multicast_link_local() const BOOST_ASIO_NOEXCEPT +{ + return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x02)); +} + +bool address_v6::is_multicast_node_local() const BOOST_ASIO_NOEXCEPT +{ + return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x01)); +} + +bool address_v6::is_multicast_org_local() const BOOST_ASIO_NOEXCEPT +{ + return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x08)); +} + +bool address_v6::is_multicast_site_local() const BOOST_ASIO_NOEXCEPT +{ + return ((addr_.s6_addr[0] == 0xff) && ((addr_.s6_addr[1] & 0x0f) == 0x05)); +} + +bool operator==(const address_v6& a1, const address_v6& a2) BOOST_ASIO_NOEXCEPT +{ + using namespace std; // For memcmp. + return memcmp(&a1.addr_, &a2.addr_, + sizeof(boost::asio::detail::in6_addr_type)) == 0 + && a1.scope_id_ == a2.scope_id_; +} + +bool operator<(const address_v6& a1, const address_v6& a2) BOOST_ASIO_NOEXCEPT +{ + using namespace std; // For memcmp. + int memcmp_result = memcmp(&a1.addr_, &a2.addr_, + sizeof(boost::asio::detail::in6_addr_type)); + if (memcmp_result < 0) + return true; + if (memcmp_result > 0) + return false; + return a1.scope_id_ < a2.scope_id_; +} + +address_v6 address_v6::loopback() BOOST_ASIO_NOEXCEPT +{ + address_v6 tmp; + tmp.addr_.s6_addr[15] = 1; + return tmp; +} + +#if !defined(BOOST_ASIO_NO_DEPRECATED) +address_v6 address_v6::v4_mapped(const address_v4& addr) +{ + address_v4::bytes_type v4_bytes = addr.to_bytes(); + bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, + v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; + return address_v6(v6_bytes); +} + +address_v6 address_v6::v4_compatible(const address_v4& addr) +{ + address_v4::bytes_type v4_bytes = addr.to_bytes(); + bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; + return address_v6(v6_bytes); +} +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +address_v6 make_address_v6(const char* str) +{ + boost::system::error_code ec; + address_v6 addr = make_address_v6(str, ec); + boost::asio::detail::throw_error(ec); + return addr; +} + +address_v6 make_address_v6(const char* str, + boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT +{ + address_v6::bytes_type bytes; + unsigned long scope_id = 0; + if (boost::asio::detail::socket_ops::inet_pton( + BOOST_ASIO_OS_DEF(AF_INET6), str, &bytes[0], &scope_id, ec) <= 0) + return address_v6(); + return address_v6(bytes, scope_id); +} + +address_v6 make_address_v6(const std::string& str) +{ + return make_address_v6(str.c_str()); +} + +address_v6 make_address_v6(const std::string& str, + boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT +{ + return make_address_v6(str.c_str(), ec); +} + +#if defined(BOOST_ASIO_HAS_STRING_VIEW) + +address_v6 make_address_v6(string_view str) +{ + return make_address_v6(static_cast(str)); +} + +address_v6 make_address_v6(string_view str, + boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT +{ + return make_address_v6(static_cast(str), ec); +} + +#endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + +address_v4 make_address_v4( + v4_mapped_t, const address_v6& v6_addr) +{ + if (!v6_addr.is_v4_mapped()) + { + bad_address_cast ex; + boost::asio::detail::throw_exception(ex); + } + + address_v6::bytes_type v6_bytes = v6_addr.to_bytes(); + address_v4::bytes_type v4_bytes = { { v6_bytes[12], + v6_bytes[13], v6_bytes[14], v6_bytes[15] } }; + return address_v4(v4_bytes); +} + +address_v6 make_address_v6( + v4_mapped_t, const address_v4& v4_addr) +{ + address_v4::bytes_type v4_bytes = v4_addr.to_bytes(); + address_v6::bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0xFF, 0xFF, v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; + return address_v6(v6_bytes); +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP diff --git a/boost/asio/ip/impl/basic_endpoint.hpp b/boost/asio/ip/impl/basic_endpoint.hpp new file mode 100644 index 0000000..5eba925 --- /dev/null +++ b/boost/asio/ip/impl/basic_endpoint.hpp @@ -0,0 +1,45 @@ +// +// ip/impl/basic_endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_BASIC_ENDPOINT_HPP +#define BOOST_ASIO_IP_IMPL_BASIC_ENDPOINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, + const basic_endpoint& endpoint) +{ + boost::asio::ip::detail::endpoint tmp_ep(endpoint.address(), endpoint.port()); + return os << tmp_ep.to_string().c_str(); +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +#endif // BOOST_ASIO_IP_IMPL_BASIC_ENDPOINT_HPP diff --git a/boost/asio/ip/impl/host_name.ipp b/boost/asio/ip/impl/host_name.ipp new file mode 100644 index 0000000..565e545 --- /dev/null +++ b/boost/asio/ip/impl/host_name.ipp @@ -0,0 +1,56 @@ +// +// ip/impl/host_name.ipp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_HOST_NAME_IPP +#define BOOST_ASIO_IP_IMPL_HOST_NAME_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +std::string host_name() +{ + char name[1024]; + boost::system::error_code ec; + if (boost::asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) + { + boost::asio::detail::throw_error(ec); + return std::string(); + } + return std::string(name); +} + +std::string host_name(boost::system::error_code& ec) +{ + char name[1024]; + if (boost::asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) + return std::string(); + return std::string(name); +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_IMPL_HOST_NAME_IPP diff --git a/boost/asio/ip/impl/network_v4.hpp b/boost/asio/ip/impl/network_v4.hpp new file mode 100644 index 0000000..e20a6fe --- /dev/null +++ b/boost/asio/ip/impl/network_v4.hpp @@ -0,0 +1,56 @@ +// +// ip/impl/network_v4.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_NETWORK_V4_HPP +#define BOOST_ASIO_IP_IMPL_NETWORK_V4_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, const network_v4& addr) +{ + boost::system::error_code ec; + std::string s = addr.to_string(ec); + if (ec) + { + if (os.exceptions() & std::basic_ostream::failbit) + boost::asio::detail::throw_error(ec); + else + os.setstate(std::basic_ostream::failbit); + } + else + for (std::string::iterator i = s.begin(); i != s.end(); ++i) + os << os.widen(*i); + return os; +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +#endif // BOOST_ASIO_IP_IMPL_NETWORK_V4_HPP diff --git a/boost/asio/ip/impl/network_v4.ipp b/boost/asio/ip/impl/network_v4.ipp new file mode 100644 index 0000000..d443475 --- /dev/null +++ b/boost/asio/ip/impl/network_v4.ipp @@ -0,0 +1,218 @@ +// +// ip/impl/network_v4.ipp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_NETWORK_V4_IPP +#define BOOST_ASIO_IP_IMPL_NETWORK_V4_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +network_v4::network_v4(const address_v4& addr, unsigned short prefix_len) + : address_(addr), + prefix_length_(prefix_len) +{ + if (prefix_len > 32) + { + std::out_of_range ex("prefix length too large"); + boost::asio::detail::throw_exception(ex); + } +} + +network_v4::network_v4(const address_v4& addr, const address_v4& mask) + : address_(addr), + prefix_length_(0) +{ + address_v4::bytes_type mask_bytes = mask.to_bytes(); + bool finished = false; + for (std::size_t i = 0; i < mask_bytes.size(); ++i) + { + if (finished) + { + if (mask_bytes[i]) + { + std::invalid_argument ex("non-contiguous netmask"); + boost::asio::detail::throw_exception(ex); + } + continue; + } + else + { + switch (mask_bytes[i]) + { + case 255: + prefix_length_ += 8; + break; + case 254: // prefix_length_ += 7 + prefix_length_ += 1; + case 252: // prefix_length_ += 6 + prefix_length_ += 1; + case 248: // prefix_length_ += 5 + prefix_length_ += 1; + case 240: // prefix_length_ += 4 + prefix_length_ += 1; + case 224: // prefix_length_ += 3 + prefix_length_ += 1; + case 192: // prefix_length_ += 2 + prefix_length_ += 1; + case 128: // prefix_length_ += 1 + prefix_length_ += 1; + case 0: // nbits += 0 + finished = true; + break; + default: + std::out_of_range ex("non-contiguous netmask"); + boost::asio::detail::throw_exception(ex); + } + } + } +} + +address_v4 network_v4::netmask() const BOOST_ASIO_NOEXCEPT +{ + uint32_t nmbits = 0xffffffff; + if (prefix_length_ == 0) + nmbits = 0; + else + nmbits = nmbits << (32 - prefix_length_); + return address_v4(nmbits); +} + +address_v4_range network_v4::hosts() const BOOST_ASIO_NOEXCEPT +{ + return is_host() + ? address_v4_range(address_, address_v4(address_.to_uint() + 1)) + : address_v4_range(address_v4(network().to_uint() + 1), broadcast()); +} + +bool network_v4::is_subnet_of(const network_v4& other) const +{ + if (other.prefix_length_ >= prefix_length_) + return false; // Only real subsets are allowed. + const network_v4 me(address_, other.prefix_length_); + return other.canonical() == me.canonical(); +} + +std::string network_v4::to_string() const +{ + boost::system::error_code ec; + std::string addr = to_string(ec); + boost::asio::detail::throw_error(ec); + return addr; +} + +std::string network_v4::to_string(boost::system::error_code& ec) const +{ + using namespace std; // For sprintf. + ec = boost::system::error_code(); + char prefix_len[16]; +#if defined(BOOST_ASIO_HAS_SECURE_RTL) + sprintf_s(prefix_len, sizeof(prefix_len), "/%u", prefix_length_); +#else // defined(BOOST_ASIO_HAS_SECURE_RTL) + sprintf(prefix_len, "/%u", prefix_length_); +#endif // defined(BOOST_ASIO_HAS_SECURE_RTL) + return address_.to_string() + prefix_len; +} + +network_v4 make_network_v4(const char* str) +{ + return make_network_v4(std::string(str)); +} + +network_v4 make_network_v4(const char* str, boost::system::error_code& ec) +{ + return make_network_v4(std::string(str), ec); +} + +network_v4 make_network_v4(const std::string& str) +{ + boost::system::error_code ec; + network_v4 net = make_network_v4(str, ec); + boost::asio::detail::throw_error(ec); + return net; +} + +network_v4 make_network_v4(const std::string& str, + boost::system::error_code& ec) +{ + std::string::size_type pos = str.find_first_of("/"); + + if (pos == std::string::npos) + { + ec = boost::asio::error::invalid_argument; + return network_v4(); + } + + if (pos == str.size() - 1) + { + ec = boost::asio::error::invalid_argument; + return network_v4(); + } + + std::string::size_type end = str.find_first_not_of("0123456789", pos + 1); + if (end != std::string::npos) + { + ec = boost::asio::error::invalid_argument; + return network_v4(); + } + + const address_v4 addr = make_address_v4(str.substr(0, pos), ec); + if (ec) + return network_v4(); + + const int prefix_len = std::atoi(str.substr(pos + 1).c_str()); + if (prefix_len < 0 || prefix_len > 32) + { + ec = boost::asio::error::invalid_argument; + return network_v4(); + } + + return network_v4(addr, static_cast(prefix_len)); +} + +#if defined(BOOST_ASIO_HAS_STRING_VIEW) + +network_v4 make_network_v4(string_view str) +{ + return make_network_v4(static_cast(str)); +} + +network_v4 make_network_v4(string_view str, + boost::system::error_code& ec) +{ + return make_network_v4(static_cast(str), ec); +} + +#endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_IMPL_NETWORK_V4_IPP diff --git a/boost/asio/ip/impl/network_v6.hpp b/boost/asio/ip/impl/network_v6.hpp new file mode 100644 index 0000000..6be5ab5 --- /dev/null +++ b/boost/asio/ip/impl/network_v6.hpp @@ -0,0 +1,55 @@ +// +// ip/impl/network_v6.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_NETWORK_V6_HPP +#define BOOST_ASIO_IP_IMPL_NETWORK_V6_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +template +std::basic_ostream& operator<<( + std::basic_ostream& os, const network_v6& addr) +{ + boost::system::error_code ec; + std::string s = addr.to_string(ec); + if (ec) + { + if (os.exceptions() & std::basic_ostream::failbit) + boost::asio::detail::throw_error(ec); + else + os.setstate(std::basic_ostream::failbit); + } + else + for (std::string::iterator i = s.begin(); i != s.end(); ++i) + os << os.widen(*i); + return os; +} + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +#endif // BOOST_ASIO_IP_IMPL_NETWORK_V6_HPP diff --git a/boost/asio/ip/impl/network_v6.ipp b/boost/asio/ip/impl/network_v6.ipp new file mode 100644 index 0000000..cbdb974 --- /dev/null +++ b/boost/asio/ip/impl/network_v6.ipp @@ -0,0 +1,187 @@ +// +// ip/impl/network_v6.ipp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_IMPL_NETWORK_V6_IPP +#define BOOST_ASIO_IP_IMPL_NETWORK_V6_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +network_v6::network_v6(const address_v6& addr, unsigned short prefix_len) + : address_(addr), + prefix_length_(prefix_len) +{ + if (prefix_len > 128) + { + std::out_of_range ex("prefix length too large"); + boost::asio::detail::throw_exception(ex); + } +} + +BOOST_ASIO_DECL address_v6 network_v6::network() const BOOST_ASIO_NOEXCEPT +{ + address_v6::bytes_type bytes(address_.to_bytes()); + for (std::size_t i = 0; i < 16; ++i) + { + if (prefix_length_ <= i * 8) + bytes[i] = 0; + else if (prefix_length_ < (i + 1) * 8) + bytes[i] &= 0xFF00 >> (prefix_length_ % 8); + } + return address_v6(bytes, address_.scope_id()); +} + +address_v6_range network_v6::hosts() const BOOST_ASIO_NOEXCEPT +{ + address_v6::bytes_type begin_bytes(address_.to_bytes()); + address_v6::bytes_type end_bytes(address_.to_bytes()); + for (std::size_t i = 0; i < 16; ++i) + { + if (prefix_length_ <= i * 8) + { + begin_bytes[i] = 0; + end_bytes[i] = 0xFF; + } + else if (prefix_length_ < (i + 1) * 8) + { + begin_bytes[i] &= 0xFF00 >> (prefix_length_ % 8); + end_bytes[i] |= 0xFF >> (prefix_length_ % 8); + } + } + return address_v6_range( + address_v6_iterator(address_v6(begin_bytes, address_.scope_id())), + ++address_v6_iterator(address_v6(end_bytes, address_.scope_id()))); +} + +bool network_v6::is_subnet_of(const network_v6& other) const +{ + if (other.prefix_length_ >= prefix_length_) + return false; // Only real subsets are allowed. + const network_v6 me(address_, other.prefix_length_); + return other.canonical() == me.canonical(); +} + +std::string network_v6::to_string() const +{ + boost::system::error_code ec; + std::string addr = to_string(ec); + boost::asio::detail::throw_error(ec); + return addr; +} + +std::string network_v6::to_string(boost::system::error_code& ec) const +{ + using namespace std; // For sprintf. + ec = boost::system::error_code(); + char prefix_len[16]; +#if defined(BOOST_ASIO_HAS_SECURE_RTL) + sprintf_s(prefix_len, sizeof(prefix_len), "/%u", prefix_length_); +#else // defined(BOOST_ASIO_HAS_SECURE_RTL) + sprintf(prefix_len, "/%u", prefix_length_); +#endif // defined(BOOST_ASIO_HAS_SECURE_RTL) + return address_.to_string() + prefix_len; +} + +network_v6 make_network_v6(const char* str) +{ + return make_network_v6(std::string(str)); +} + +network_v6 make_network_v6(const char* str, boost::system::error_code& ec) +{ + return make_network_v6(std::string(str), ec); +} + +network_v6 make_network_v6(const std::string& str) +{ + boost::system::error_code ec; + network_v6 net = make_network_v6(str, ec); + boost::asio::detail::throw_error(ec); + return net; +} + +network_v6 make_network_v6(const std::string& str, + boost::system::error_code& ec) +{ + std::string::size_type pos = str.find_first_of("/"); + + if (pos == std::string::npos) + { + ec = boost::asio::error::invalid_argument; + return network_v6(); + } + + if (pos == str.size() - 1) + { + ec = boost::asio::error::invalid_argument; + return network_v6(); + } + + std::string::size_type end = str.find_first_not_of("0123456789", pos + 1); + if (end != std::string::npos) + { + ec = boost::asio::error::invalid_argument; + return network_v6(); + } + + const address_v6 addr = make_address_v6(str.substr(0, pos), ec); + if (ec) + return network_v6(); + + const int prefix_len = std::atoi(str.substr(pos + 1).c_str()); + if (prefix_len < 0 || prefix_len > 128) + { + ec = boost::asio::error::invalid_argument; + return network_v6(); + } + + return network_v6(addr, static_cast(prefix_len)); +} + +#if defined(BOOST_ASIO_HAS_STRING_VIEW) + +network_v6 make_network_v6(string_view str) +{ + return make_network_v6(static_cast(str)); +} + +network_v6 make_network_v6(string_view str, + boost::system::error_code& ec) +{ + return make_network_v6(static_cast(str), ec); +} + +#endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_IMPL_NETWORK_V6_IPP diff --git a/boost/asio/ip/multicast.hpp b/boost/asio/ip/multicast.hpp new file mode 100644 index 0000000..d863284 --- /dev/null +++ b/boost/asio/ip/multicast.hpp @@ -0,0 +1,193 @@ +// +// ip/multicast.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_MULTICAST_HPP +#define BOOST_ASIO_IP_MULTICAST_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { +namespace multicast { + +/// Socket option to join a multicast group on a specified interface. +/** + * Implements the IPPROTO_IP/IP_ADD_MEMBERSHIP socket option. + * + * @par Examples + * Setting the option to join a multicast group: + * @code + * boost::asio::ip::udp::socket socket(my_context); + * ... + * boost::asio::ip::address multicast_address = + * boost::asio::ip::address::from_string("225.0.0.1"); + * boost::asio::ip::multicast::join_group option(multicast_address); + * socket.set_option(option); + * @endcode + * + * @par Concepts: + * SettableSocketOption. + */ +#if defined(GENERATING_DOCUMENTATION) +typedef implementation_defined join_group; +#else +typedef boost::asio::ip::detail::socket_option::multicast_request< + BOOST_ASIO_OS_DEF(IPPROTO_IP), + BOOST_ASIO_OS_DEF(IP_ADD_MEMBERSHIP), + BOOST_ASIO_OS_DEF(IPPROTO_IPV6), + BOOST_ASIO_OS_DEF(IPV6_JOIN_GROUP)> join_group; +#endif + +/// Socket option to leave a multicast group on a specified interface. +/** + * Implements the IPPROTO_IP/IP_DROP_MEMBERSHIP socket option. + * + * @par Examples + * Setting the option to leave a multicast group: + * @code + * boost::asio::ip::udp::socket socket(my_context); + * ... + * boost::asio::ip::address multicast_address = + * boost::asio::ip::address::from_string("225.0.0.1"); + * boost::asio::ip::multicast::leave_group option(multicast_address); + * socket.set_option(option); + * @endcode + * + * @par Concepts: + * SettableSocketOption. + */ +#if defined(GENERATING_DOCUMENTATION) +typedef implementation_defined leave_group; +#else +typedef boost::asio::ip::detail::socket_option::multicast_request< + BOOST_ASIO_OS_DEF(IPPROTO_IP), + BOOST_ASIO_OS_DEF(IP_DROP_MEMBERSHIP), + BOOST_ASIO_OS_DEF(IPPROTO_IPV6), + BOOST_ASIO_OS_DEF(IPV6_LEAVE_GROUP)> leave_group; +#endif + +/// Socket option for local interface to use for outgoing multicast packets. +/** + * Implements the IPPROTO_IP/IP_MULTICAST_IF socket option. + * + * @par Examples + * Setting the option: + * @code + * boost::asio::ip::udp::socket socket(my_context); + * ... + * boost::asio::ip::address_v4 local_interface = + * boost::asio::ip::address_v4::from_string("1.2.3.4"); + * boost::asio::ip::multicast::outbound_interface option(local_interface); + * socket.set_option(option); + * @endcode + * + * @par Concepts: + * SettableSocketOption. + */ +#if defined(GENERATING_DOCUMENTATION) +typedef implementation_defined outbound_interface; +#else +typedef boost::asio::ip::detail::socket_option::network_interface< + BOOST_ASIO_OS_DEF(IPPROTO_IP), + BOOST_ASIO_OS_DEF(IP_MULTICAST_IF), + BOOST_ASIO_OS_DEF(IPPROTO_IPV6), + BOOST_ASIO_OS_DEF(IPV6_MULTICAST_IF)> outbound_interface; +#endif + +/// Socket option for time-to-live associated with outgoing multicast packets. +/** + * Implements the IPPROTO_IP/IP_MULTICAST_TTL socket option. + * + * @par Examples + * Setting the option: + * @code + * boost::asio::ip::udp::socket socket(my_context); + * ... + * boost::asio::ip::multicast::hops option(4); + * socket.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * boost::asio::ip::udp::socket socket(my_context); + * ... + * boost::asio::ip::multicast::hops option; + * socket.get_option(option); + * int ttl = option.value(); + * @endcode + * + * @par Concepts: + * GettableSocketOption, SettableSocketOption. + */ +#if defined(GENERATING_DOCUMENTATION) +typedef implementation_defined hops; +#else +typedef boost::asio::ip::detail::socket_option::multicast_hops< + BOOST_ASIO_OS_DEF(IPPROTO_IP), + BOOST_ASIO_OS_DEF(IP_MULTICAST_TTL), + BOOST_ASIO_OS_DEF(IPPROTO_IPV6), + BOOST_ASIO_OS_DEF(IPV6_MULTICAST_HOPS)> hops; +#endif + +/// Socket option determining whether outgoing multicast packets will be +/// received on the same socket if it is a member of the multicast group. +/** + * Implements the IPPROTO_IP/IP_MULTICAST_LOOP socket option. + * + * @par Examples + * Setting the option: + * @code + * boost::asio::ip::udp::socket socket(my_context); + * ... + * boost::asio::ip::multicast::enable_loopback option(true); + * socket.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * boost::asio::ip::udp::socket socket(my_context); + * ... + * boost::asio::ip::multicast::enable_loopback option; + * socket.get_option(option); + * bool is_set = option.value(); + * @endcode + * + * @par Concepts: + * GettableSocketOption, SettableSocketOption. + */ +#if defined(GENERATING_DOCUMENTATION) +typedef implementation_defined enable_loopback; +#else +typedef boost::asio::ip::detail::socket_option::multicast_enable_loopback< + BOOST_ASIO_OS_DEF(IPPROTO_IP), + BOOST_ASIO_OS_DEF(IP_MULTICAST_LOOP), + BOOST_ASIO_OS_DEF(IPPROTO_IPV6), + BOOST_ASIO_OS_DEF(IPV6_MULTICAST_LOOP)> enable_loopback; +#endif + +} // namespace multicast +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_MULTICAST_HPP diff --git a/boost/asio/ip/network_v4.hpp b/boost/asio/ip/network_v4.hpp new file mode 100644 index 0000000..25cbbce --- /dev/null +++ b/boost/asio/ip/network_v4.hpp @@ -0,0 +1,263 @@ +// +// ip/network_v4.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_NETWORK_V4_HPP +#define BOOST_ASIO_IP_NETWORK_V4_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +/// Represents an IPv4 network. +/** + * The boost::asio::ip::network_v4 class provides the ability to use and + * manipulate IP version 4 networks. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +class network_v4 +{ +public: + /// Default constructor. + network_v4() BOOST_ASIO_NOEXCEPT + : address_(), + prefix_length_(0) + { + } + + /// Construct a network based on the specified address and prefix length. + BOOST_ASIO_DECL network_v4(const address_v4& addr, + unsigned short prefix_len); + + /// Construct network based on the specified address and netmask. + BOOST_ASIO_DECL network_v4(const address_v4& addr, + const address_v4& mask); + + /// Copy constructor. + network_v4(const network_v4& other) BOOST_ASIO_NOEXCEPT + : address_(other.address_), + prefix_length_(other.prefix_length_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move constructor. + network_v4(network_v4&& other) BOOST_ASIO_NOEXCEPT + : address_(BOOST_ASIO_MOVE_CAST(address_v4)(other.address_)), + prefix_length_(other.prefix_length_) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Assign from another network. + network_v4& operator=(const network_v4& other) BOOST_ASIO_NOEXCEPT + { + address_ = other.address_; + prefix_length_ = other.prefix_length_; + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move-assign from another network. + network_v4& operator=(network_v4&& other) BOOST_ASIO_NOEXCEPT + { + address_ = BOOST_ASIO_MOVE_CAST(address_v4)(other.address_); + prefix_length_ = other.prefix_length_; + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Obtain the address object specified when the network object was created. + address_v4 address() const BOOST_ASIO_NOEXCEPT + { + return address_; + } + + /// Obtain the prefix length that was specified when the network object was + /// created. + unsigned short prefix_length() const BOOST_ASIO_NOEXCEPT + { + return prefix_length_; + } + + /// Obtain the netmask that was specified when the network object was created. + BOOST_ASIO_DECL address_v4 netmask() const BOOST_ASIO_NOEXCEPT; + + /// Obtain an address object that represents the network address. + address_v4 network() const BOOST_ASIO_NOEXCEPT + { + return address_v4(address_.to_uint() & netmask().to_uint()); + } + + /// Obtain an address object that represents the network's broadcast address. + address_v4 broadcast() const BOOST_ASIO_NOEXCEPT + { + return address_v4(network().to_uint() | (netmask().to_uint() ^ 0xFFFFFFFF)); + } + + /// Obtain an address range corresponding to the hosts in the network. + BOOST_ASIO_DECL address_v4_range hosts() const BOOST_ASIO_NOEXCEPT; + + /// Obtain the true network address, omitting any host bits. + network_v4 canonical() const BOOST_ASIO_NOEXCEPT + { + return network_v4(network(), netmask()); + } + + /// Test if network is a valid host address. + bool is_host() const BOOST_ASIO_NOEXCEPT + { + return prefix_length_ == 32; + } + + /// Test if a network is a real subnet of another network. + BOOST_ASIO_DECL bool is_subnet_of(const network_v4& other) const; + + /// Get the network as an address in dotted decimal format. + BOOST_ASIO_DECL std::string to_string() const; + + /// Get the network as an address in dotted decimal format. + BOOST_ASIO_DECL std::string to_string(boost::system::error_code& ec) const; + + /// Compare two networks for equality. + friend bool operator==(const network_v4& a, const network_v4& b) + { + return a.address_ == b.address_ && a.prefix_length_ == b.prefix_length_; + } + + /// Compare two networks for inequality. + friend bool operator!=(const network_v4& a, const network_v4& b) + { + return !(a == b); + } + +private: + address_v4 address_; + unsigned short prefix_length_; +}; + +/// Create an IPv4 network from an address and prefix length. +/** + * @relates address_v4 + */ +inline network_v4 make_network_v4( + const address_v4& addr, unsigned short prefix_len) +{ + return network_v4(addr, prefix_len); +} + +/// Create an IPv4 network from an address and netmask. +/** + * @relates address_v4 + */ +inline network_v4 make_network_v4( + const address_v4& addr, const address_v4& mask) +{ + return network_v4(addr, mask); +} + +/// Create an IPv4 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v4 + */ +BOOST_ASIO_DECL network_v4 make_network_v4(const char* str); + +/// Create an IPv4 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v4 + */ +BOOST_ASIO_DECL network_v4 make_network_v4( + const char* str, boost::system::error_code& ec); + +/// Create an IPv4 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v4 + */ +BOOST_ASIO_DECL network_v4 make_network_v4(const std::string& str); + +/// Create an IPv4 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v4 + */ +BOOST_ASIO_DECL network_v4 make_network_v4( + const std::string& str, boost::system::error_code& ec); + +#if defined(BOOST_ASIO_HAS_STRING_VIEW) \ + || defined(GENERATING_DOCUMENTATION) + +/// Create an IPv4 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v4 + */ +BOOST_ASIO_DECL network_v4 make_network_v4(string_view str); + +/// Create an IPv4 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v4 + */ +BOOST_ASIO_DECL network_v4 make_network_v4( + string_view str, boost::system::error_code& ec); + +#endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + // || defined(GENERATING_DOCUMENTATION) + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +/// Output a network as a string. +/** + * Used to output a human-readable string for a specified network. + * + * @param os The output stream to which the string will be written. + * + * @param net The network to be written. + * + * @return The output stream. + * + * @relates boost::asio::ip::address_v4 + */ +template +std::basic_ostream& operator<<( + std::basic_ostream& os, const network_v4& net); + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_IP_NETWORK_V4_HPP diff --git a/boost/asio/ip/network_v6.hpp b/boost/asio/ip/network_v6.hpp new file mode 100644 index 0000000..dce9508 --- /dev/null +++ b/boost/asio/ip/network_v6.hpp @@ -0,0 +1,237 @@ +// +// ip/network_v6.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2014 Oliver Kowalke (oliver dot kowalke at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_NETWORK_V6_HPP +#define BOOST_ASIO_IP_NETWORK_V6_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +/// Represents an IPv6 network. +/** + * The boost::asio::ip::network_v6 class provides the ability to use and + * manipulate IP version 6 networks. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +class network_v6 +{ +public: + /// Default constructor. + network_v6() BOOST_ASIO_NOEXCEPT + : address_(), + prefix_length_(0) + { + } + + /// Construct a network based on the specified address and prefix length. + BOOST_ASIO_DECL network_v6(const address_v6& addr, + unsigned short prefix_len); + + /// Copy constructor. + network_v6(const network_v6& other) BOOST_ASIO_NOEXCEPT + : address_(other.address_), + prefix_length_(other.prefix_length_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move constructor. + network_v6(network_v6&& other) BOOST_ASIO_NOEXCEPT + : address_(BOOST_ASIO_MOVE_CAST(address_v6)(other.address_)), + prefix_length_(other.prefix_length_) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Assign from another network. + network_v6& operator=(const network_v6& other) BOOST_ASIO_NOEXCEPT + { + address_ = other.address_; + prefix_length_ = other.prefix_length_; + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move-assign from another network. + network_v6& operator=(network_v6&& other) BOOST_ASIO_NOEXCEPT + { + address_ = BOOST_ASIO_MOVE_CAST(address_v6)(other.address_); + prefix_length_ = other.prefix_length_; + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Obtain the address object specified when the network object was created. + address_v6 address() const BOOST_ASIO_NOEXCEPT + { + return address_; + } + + /// Obtain the prefix length that was specified when the network object was + /// created. + unsigned short prefix_length() const BOOST_ASIO_NOEXCEPT + { + return prefix_length_; + } + + /// Obtain an address object that represents the network address. + BOOST_ASIO_DECL address_v6 network() const BOOST_ASIO_NOEXCEPT; + + /// Obtain an address range corresponding to the hosts in the network. + BOOST_ASIO_DECL address_v6_range hosts() const BOOST_ASIO_NOEXCEPT; + + /// Obtain the true network address, omitting any host bits. + network_v6 canonical() const BOOST_ASIO_NOEXCEPT + { + return network_v6(network(), prefix_length()); + } + + /// Test if network is a valid host address. + bool is_host() const BOOST_ASIO_NOEXCEPT + { + return prefix_length_ == 128; + } + + /// Test if a network is a real subnet of another network. + BOOST_ASIO_DECL bool is_subnet_of(const network_v6& other) const; + + /// Get the network as an address in dotted decimal format. + BOOST_ASIO_DECL std::string to_string() const; + + /// Get the network as an address in dotted decimal format. + BOOST_ASIO_DECL std::string to_string(boost::system::error_code& ec) const; + + /// Compare two networks for equality. + friend bool operator==(const network_v6& a, const network_v6& b) + { + return a.address_ == b.address_ && a.prefix_length_ == b.prefix_length_; + } + + /// Compare two networks for inequality. + friend bool operator!=(const network_v6& a, const network_v6& b) + { + return !(a == b); + } + +private: + address_v6 address_; + unsigned short prefix_length_; +}; + +/// Create an IPv6 network from an address and prefix length. +/** + * @relates address_v6 + */ +inline network_v6 make_network_v6( + const address_v6& addr, unsigned short prefix_len) +{ + return network_v6(addr, prefix_len); +} + +/// Create an IPv6 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v6 + */ +BOOST_ASIO_DECL network_v6 make_network_v6(const char* str); + +/// Create an IPv6 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v6 + */ +BOOST_ASIO_DECL network_v6 make_network_v6( + const char* str, boost::system::error_code& ec); + +/// Create an IPv6 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v6 + */ +BOOST_ASIO_DECL network_v6 make_network_v6(const std::string& str); + +/// Create an IPv6 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v6 + */ +BOOST_ASIO_DECL network_v6 make_network_v6( + const std::string& str, boost::system::error_code& ec); + +#if defined(BOOST_ASIO_HAS_STRING_VIEW) \ + || defined(GENERATING_DOCUMENTATION) + +/// Create an IPv6 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v6 + */ +BOOST_ASIO_DECL network_v6 make_network_v6(string_view str); + +/// Create an IPv6 network from a string containing IP address and prefix +/// length. +/** + * @relates network_v6 + */ +BOOST_ASIO_DECL network_v6 make_network_v6( + string_view str, boost::system::error_code& ec); + +#endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + // || defined(GENERATING_DOCUMENTATION) + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +/// Output a network as a string. +/** + * Used to output a human-readable string for a specified network. + * + * @param os The output stream to which the string will be written. + * + * @param net The network to be written. + * + * @return The output stream. + * + * @relates boost::asio::ip::address_v6 + */ +template +std::basic_ostream& operator<<( + std::basic_ostream& os, const network_v6& net); + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_IP_NETWORK_V6_HPP diff --git a/boost/asio/ip/resolver_base.hpp b/boost/asio/ip/resolver_base.hpp new file mode 100644 index 0000000..a61565f --- /dev/null +++ b/boost/asio/ip/resolver_base.hpp @@ -0,0 +1,131 @@ +// +// ip/resolver_base.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_RESOLVER_BASE_HPP +#define BOOST_ASIO_IP_RESOLVER_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +/// The resolver_base class is used as a base for the basic_resolver class +/// templates to provide a common place to define the flag constants. +class resolver_base +{ +public: +#if defined(GENERATING_DOCUMENTATION) + /// A bitmask type (C++ Std [lib.bitmask.types]). + typedef unspecified flags; + + /// Determine the canonical name of the host specified in the query. + static const flags canonical_name = implementation_defined; + + /// Indicate that returned endpoint is intended for use as a locally bound + /// socket endpoint. + static const flags passive = implementation_defined; + + /// Host name should be treated as a numeric string defining an IPv4 or IPv6 + /// address and no name resolution should be attempted. + static const flags numeric_host = implementation_defined; + + /// Service name should be treated as a numeric string defining a port number + /// and no name resolution should be attempted. + static const flags numeric_service = implementation_defined; + + /// If the query protocol family is specified as IPv6, return IPv4-mapped + /// IPv6 addresses on finding no IPv6 addresses. + static const flags v4_mapped = implementation_defined; + + /// If used with v4_mapped, return all matching IPv6 and IPv4 addresses. + static const flags all_matching = implementation_defined; + + /// Only return IPv4 addresses if a non-loopback IPv4 address is configured + /// for the system. Only return IPv6 addresses if a non-loopback IPv6 address + /// is configured for the system. + static const flags address_configured = implementation_defined; +#else + enum flags + { + canonical_name = BOOST_ASIO_OS_DEF(AI_CANONNAME), + passive = BOOST_ASIO_OS_DEF(AI_PASSIVE), + numeric_host = BOOST_ASIO_OS_DEF(AI_NUMERICHOST), + numeric_service = BOOST_ASIO_OS_DEF(AI_NUMERICSERV), + v4_mapped = BOOST_ASIO_OS_DEF(AI_V4MAPPED), + all_matching = BOOST_ASIO_OS_DEF(AI_ALL), + address_configured = BOOST_ASIO_OS_DEF(AI_ADDRCONFIG) + }; + + // Implement bitmask operations as shown in C++ Std [lib.bitmask.types]. + + friend flags operator&(flags x, flags y) + { + return static_cast( + static_cast(x) & static_cast(y)); + } + + friend flags operator|(flags x, flags y) + { + return static_cast( + static_cast(x) | static_cast(y)); + } + + friend flags operator^(flags x, flags y) + { + return static_cast( + static_cast(x) ^ static_cast(y)); + } + + friend flags operator~(flags x) + { + return static_cast(~static_cast(x)); + } + + friend flags& operator&=(flags& x, flags y) + { + x = x & y; + return x; + } + + friend flags& operator|=(flags& x, flags y) + { + x = x | y; + return x; + } + + friend flags& operator^=(flags& x, flags y) + { + x = x ^ y; + return x; + } +#endif + +protected: + /// Protected destructor to prevent deletion through this type. + ~resolver_base() + { + } +}; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_RESOLVER_BASE_HPP diff --git a/boost/asio/ip/resolver_query_base.hpp b/boost/asio/ip/resolver_query_base.hpp new file mode 100644 index 0000000..9e0a032 --- /dev/null +++ b/boost/asio/ip/resolver_query_base.hpp @@ -0,0 +1,45 @@ +// +// ip/resolver_query_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_RESOLVER_QUERY_BASE_HPP +#define BOOST_ASIO_IP_RESOLVER_QUERY_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +/// The resolver_query_base class is used as a base for the +/// basic_resolver_query class templates to provide a common place to define +/// the flag constants. +class resolver_query_base : public resolver_base +{ +protected: + /// Protected destructor to prevent deletion through this type. + ~resolver_query_base() + { + } +}; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_RESOLVER_QUERY_BASE_HPP diff --git a/boost/asio/ip/tcp.hpp b/boost/asio/ip/tcp.hpp new file mode 100644 index 0000000..d37b012 --- /dev/null +++ b/boost/asio/ip/tcp.hpp @@ -0,0 +1,157 @@ +// +// ip/tcp.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_TCP_HPP +#define BOOST_ASIO_IP_TCP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +/// Encapsulates the flags needed for TCP. +/** + * The boost::asio::ip::tcp class contains flags necessary for TCP sockets. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Safe. + * + * @par Concepts: + * Protocol, InternetProtocol. + */ +class tcp +{ +public: + /// The type of a TCP endpoint. + typedef basic_endpoint endpoint; + + /// Construct to represent the IPv4 TCP protocol. + static tcp v4() + { + return tcp(BOOST_ASIO_OS_DEF(AF_INET)); + } + + /// Construct to represent the IPv6 TCP protocol. + static tcp v6() + { + return tcp(BOOST_ASIO_OS_DEF(AF_INET6)); + } + + /// Obtain an identifier for the type of the protocol. + int type() const + { + return BOOST_ASIO_OS_DEF(SOCK_STREAM); + } + + /// Obtain an identifier for the protocol. + int protocol() const + { + return BOOST_ASIO_OS_DEF(IPPROTO_TCP); + } + + /// Obtain an identifier for the protocol family. + int family() const + { + return family_; + } + + /// The TCP socket type. + typedef basic_stream_socket socket; + + /// The TCP acceptor type. + typedef basic_socket_acceptor acceptor; + + /// The TCP resolver type. + typedef basic_resolver resolver; + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + /// The TCP iostream type. + typedef basic_socket_iostream iostream; +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + + /// Socket option for disabling the Nagle algorithm. + /** + * Implements the IPPROTO_TCP/TCP_NODELAY socket option. + * + * @par Examples + * Setting the option: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::ip::tcp::no_delay option(true); + * socket.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::ip::tcp::no_delay option; + * socket.get_option(option); + * bool is_set = option.value(); + * @endcode + * + * @par Concepts: + * Socket_Option, Boolean_Socket_Option. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined no_delay; +#else + typedef boost::asio::detail::socket_option::boolean< + BOOST_ASIO_OS_DEF(IPPROTO_TCP), BOOST_ASIO_OS_DEF(TCP_NODELAY)> no_delay; +#endif + + /// Compare two protocols for equality. + friend bool operator==(const tcp& p1, const tcp& p2) + { + return p1.family_ == p2.family_; + } + + /// Compare two protocols for inequality. + friend bool operator!=(const tcp& p1, const tcp& p2) + { + return p1.family_ != p2.family_; + } + +private: + // Construct with a specific family. + explicit tcp(int protocol_family) + : family_(protocol_family) + { + } + + int family_; +}; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_TCP_HPP diff --git a/boost/asio/ip/udp.hpp b/boost/asio/ip/udp.hpp new file mode 100644 index 0000000..8ba20b4 --- /dev/null +++ b/boost/asio/ip/udp.hpp @@ -0,0 +1,113 @@ +// +// ip/udp.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_UDP_HPP +#define BOOST_ASIO_IP_UDP_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +/// Encapsulates the flags needed for UDP. +/** + * The boost::asio::ip::udp class contains flags necessary for UDP sockets. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Safe. + * + * @par Concepts: + * Protocol, InternetProtocol. + */ +class udp +{ +public: + /// The type of a UDP endpoint. + typedef basic_endpoint endpoint; + + /// Construct to represent the IPv4 UDP protocol. + static udp v4() + { + return udp(BOOST_ASIO_OS_DEF(AF_INET)); + } + + /// Construct to represent the IPv6 UDP protocol. + static udp v6() + { + return udp(BOOST_ASIO_OS_DEF(AF_INET6)); + } + + /// Obtain an identifier for the type of the protocol. + int type() const + { + return BOOST_ASIO_OS_DEF(SOCK_DGRAM); + } + + /// Obtain an identifier for the protocol. + int protocol() const + { + return BOOST_ASIO_OS_DEF(IPPROTO_UDP); + } + + /// Obtain an identifier for the protocol family. + int family() const + { + return family_; + } + + /// The UDP socket type. + typedef basic_datagram_socket socket; + + /// The UDP resolver type. + typedef basic_resolver resolver; + + /// Compare two protocols for equality. + friend bool operator==(const udp& p1, const udp& p2) + { + return p1.family_ == p2.family_; + } + + /// Compare two protocols for inequality. + friend bool operator!=(const udp& p1, const udp& p2) + { + return p1.family_ != p2.family_; + } + +private: + // Construct with a specific family. + explicit udp(int protocol_family) + : family_(protocol_family) + { + } + + int family_; +}; + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_UDP_HPP diff --git a/boost/asio/ip/unicast.hpp b/boost/asio/ip/unicast.hpp new file mode 100644 index 0000000..2cfcc59 --- /dev/null +++ b/boost/asio/ip/unicast.hpp @@ -0,0 +1,72 @@ +// +// ip/unicast.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_UNICAST_HPP +#define BOOST_ASIO_IP_UNICAST_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { +namespace unicast { + +/// Socket option for time-to-live associated with outgoing unicast packets. +/** + * Implements the IPPROTO_IP/IP_UNICAST_TTL socket option. + * + * @par Examples + * Setting the option: + * @code + * boost::asio::ip::udp::socket socket(my_context); + * ... + * boost::asio::ip::unicast::hops option(4); + * socket.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * boost::asio::ip::udp::socket socket(my_context); + * ... + * boost::asio::ip::unicast::hops option; + * socket.get_option(option); + * int ttl = option.value(); + * @endcode + * + * @par Concepts: + * GettableSocketOption, SettableSocketOption. + */ +#if defined(GENERATING_DOCUMENTATION) +typedef implementation_defined hops; +#else +typedef boost::asio::ip::detail::socket_option::unicast_hops< + BOOST_ASIO_OS_DEF(IPPROTO_IP), + BOOST_ASIO_OS_DEF(IP_TTL), + BOOST_ASIO_OS_DEF(IPPROTO_IPV6), + BOOST_ASIO_OS_DEF(IPV6_UNICAST_HOPS)> hops; +#endif + +} // namespace unicast +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_UNICAST_HPP diff --git a/boost/asio/ip/v6_only.hpp b/boost/asio/ip/v6_only.hpp new file mode 100644 index 0000000..54f4706 --- /dev/null +++ b/boost/asio/ip/v6_only.hpp @@ -0,0 +1,71 @@ +// +// ip/v6_only.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IP_V6_ONLY_HPP +#define BOOST_ASIO_IP_V6_ONLY_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace ip { + +/// Socket option for determining whether an IPv6 socket supports IPv6 +/// communication only. +/** + * Implements the IPPROTO_IPV6/IP_V6ONLY socket option. + * + * @par Examples + * Setting the option: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::ip::v6_only option(true); + * socket.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::ip::v6_only option; + * socket.get_option(option); + * bool v6_only = option.value(); + * @endcode + * + * @par Concepts: + * GettableSocketOption, SettableSocketOption. + */ +#if defined(GENERATING_DOCUMENTATION) +typedef implementation_defined v6_only; +#elif defined(IPV6_V6ONLY) +typedef boost::asio::detail::socket_option::boolean< + IPPROTO_IPV6, IPV6_V6ONLY> v6_only; +#else +typedef boost::asio::detail::socket_option::boolean< + boost::asio::detail::custom_socket_option_level, + boost::asio::detail::always_fail_option> v6_only; +#endif + +} // namespace ip +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IP_V6_ONLY_HPP diff --git a/boost/asio/is_executor.hpp b/boost/asio/is_executor.hpp new file mode 100644 index 0000000..6cb8bb8 --- /dev/null +++ b/boost/asio/is_executor.hpp @@ -0,0 +1,48 @@ +// +// is_executor.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IS_EXECUTOR_HPP +#define BOOST_ASIO_IS_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { + +/// The is_executor trait detects whether a type T meets the Executor type +/// requirements. +/** + * Class template @c is_executor is a UnaryTypeTrait that is derived from @c + * true_type if the type @c T meets the syntactic requirements for Executor, + * otherwise @c false_type. + */ +template +struct is_executor +#if defined(GENERATING_DOCUMENTATION) + : integral_constant +#else // defined(GENERATING_DOCUMENTATION) + : boost::asio::detail::is_executor +#endif // defined(GENERATING_DOCUMENTATION) +{ +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IS_EXECUTOR_HPP diff --git a/boost/asio/is_read_buffered.hpp b/boost/asio/is_read_buffered.hpp new file mode 100644 index 0000000..bc97ba7 --- /dev/null +++ b/boost/asio/is_read_buffered.hpp @@ -0,0 +1,61 @@ +// +// is_read_buffered.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IS_READ_BUFFERED_HPP +#define BOOST_ASIO_IS_READ_BUFFERED_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +namespace detail { + +template +char is_read_buffered_helper(buffered_stream* s); + +template +char is_read_buffered_helper(buffered_read_stream* s); + +struct is_read_buffered_big_type { char data[10]; }; +is_read_buffered_big_type is_read_buffered_helper(...); + +} // namespace detail + +/// The is_read_buffered class is a traits class that may be used to determine +/// whether a stream type supports buffering of read data. +template +class is_read_buffered +{ +public: +#if defined(GENERATING_DOCUMENTATION) + /// The value member is true only if the Stream type supports buffering of + /// read data. + static const bool value; +#else + BOOST_ASIO_STATIC_CONSTANT(bool, + value = sizeof(detail::is_read_buffered_helper((Stream*)0)) == 1); +#endif +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IS_READ_BUFFERED_HPP diff --git a/boost/asio/is_write_buffered.hpp b/boost/asio/is_write_buffered.hpp new file mode 100644 index 0000000..5ed8318 --- /dev/null +++ b/boost/asio/is_write_buffered.hpp @@ -0,0 +1,61 @@ +// +// is_write_buffered.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_IS_WRITE_BUFFERED_HPP +#define BOOST_ASIO_IS_WRITE_BUFFERED_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +namespace detail { + +template +char is_write_buffered_helper(buffered_stream* s); + +template +char is_write_buffered_helper(buffered_write_stream* s); + +struct is_write_buffered_big_type { char data[10]; }; +is_write_buffered_big_type is_write_buffered_helper(...); + +} // namespace detail + +/// The is_write_buffered class is a traits class that may be used to determine +/// whether a stream type supports buffering of written data. +template +class is_write_buffered +{ +public: +#if defined(GENERATING_DOCUMENTATION) + /// The value member is true only if the Stream type supports buffering of + /// written data. + static const bool value; +#else + BOOST_ASIO_STATIC_CONSTANT(bool, + value = sizeof(detail::is_write_buffered_helper((Stream*)0)) == 1); +#endif +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_IS_WRITE_BUFFERED_HPP diff --git a/boost/asio/local/basic_endpoint.hpp b/boost/asio/local/basic_endpoint.hpp new file mode 100644 index 0000000..835eb20 --- /dev/null +++ b/boost/asio/local/basic_endpoint.hpp @@ -0,0 +1,249 @@ +// +// local/basic_endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Derived from a public domain implementation written by Daniel Casimiro. +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_LOCAL_BASIC_ENDPOINT_HPP +#define BOOST_ASIO_LOCAL_BASIC_ENDPOINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) \ + || defined(GENERATING_DOCUMENTATION) + +#include + +#if !defined(BOOST_ASIO_NO_IOSTREAM) +# include +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +#include + +namespace boost { +namespace asio { +namespace local { + +/// Describes an endpoint for a UNIX socket. +/** + * The boost::asio::local::basic_endpoint class template describes an endpoint + * that may be associated with a particular UNIX socket. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Concepts: + * Endpoint. + */ +template +class basic_endpoint +{ +public: + /// The protocol type associated with the endpoint. + typedef Protocol protocol_type; + + /// The type of the endpoint structure. This type is dependent on the + /// underlying implementation of the socket layer. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined data_type; +#else + typedef boost::asio::detail::socket_addr_type data_type; +#endif + + /// Default constructor. + basic_endpoint() + { + } + + /// Construct an endpoint using the specified path name. + basic_endpoint(const char* path_name) + : impl_(path_name) + { + } + + /// Construct an endpoint using the specified path name. + basic_endpoint(const std::string& path_name) + : impl_(path_name) + { + } + + #if defined(BOOST_ASIO_HAS_STRING_VIEW) + /// Construct an endpoint using the specified path name. + basic_endpoint(string_view path_name) + : impl_(path_name) + { + } + #endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + + /// Copy constructor. + basic_endpoint(const basic_endpoint& other) + : impl_(other.impl_) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move constructor. + basic_endpoint(basic_endpoint&& other) + : impl_(other.impl_) + { + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// Assign from another endpoint. + basic_endpoint& operator=(const basic_endpoint& other) + { + impl_ = other.impl_; + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) + /// Move-assign from another endpoint. + basic_endpoint& operator=(basic_endpoint&& other) + { + impl_ = other.impl_; + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) + + /// The protocol associated with the endpoint. + protocol_type protocol() const + { + return protocol_type(); + } + + /// Get the underlying endpoint in the native type. + data_type* data() + { + return impl_.data(); + } + + /// Get the underlying endpoint in the native type. + const data_type* data() const + { + return impl_.data(); + } + + /// Get the underlying size of the endpoint in the native type. + std::size_t size() const + { + return impl_.size(); + } + + /// Set the underlying size of the endpoint in the native type. + void resize(std::size_t new_size) + { + impl_.resize(new_size); + } + + /// Get the capacity of the endpoint in the native type. + std::size_t capacity() const + { + return impl_.capacity(); + } + + /// Get the path associated with the endpoint. + std::string path() const + { + return impl_.path(); + } + + /// Set the path associated with the endpoint. + void path(const char* p) + { + impl_.path(p); + } + + /// Set the path associated with the endpoint. + void path(const std::string& p) + { + impl_.path(p); + } + + /// Compare two endpoints for equality. + friend bool operator==(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return e1.impl_ == e2.impl_; + } + + /// Compare two endpoints for inequality. + friend bool operator!=(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return !(e1.impl_ == e2.impl_); + } + + /// Compare endpoints for ordering. + friend bool operator<(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return e1.impl_ < e2.impl_; + } + + /// Compare endpoints for ordering. + friend bool operator>(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return e2.impl_ < e1.impl_; + } + + /// Compare endpoints for ordering. + friend bool operator<=(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return !(e2 < e1); + } + + /// Compare endpoints for ordering. + friend bool operator>=(const basic_endpoint& e1, + const basic_endpoint& e2) + { + return !(e1 < e2); + } + +private: + // The underlying UNIX domain endpoint. + boost::asio::local::detail::endpoint impl_; +}; + +/// Output an endpoint as a string. +/** + * Used to output a human-readable string for a specified endpoint. + * + * @param os The output stream to which the string will be written. + * + * @param endpoint The endpoint to be written. + * + * @return The output stream. + * + * @relates boost::asio::local::basic_endpoint + */ +template +std::basic_ostream& operator<<( + std::basic_ostream& os, + const basic_endpoint& endpoint) +{ + os << endpoint.path(); + return os; +} + +} // namespace local +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_LOCAL_BASIC_ENDPOINT_HPP diff --git a/boost/asio/local/connect_pair.hpp b/boost/asio/local/connect_pair.hpp new file mode 100644 index 0000000..6ee9a23 --- /dev/null +++ b/boost/asio/local/connect_pair.hpp @@ -0,0 +1,103 @@ +// +// local/connect_pair.hpp +// ~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_LOCAL_CONNECT_PAIR_HPP +#define BOOST_ASIO_LOCAL_CONNECT_PAIR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) \ + || defined(GENERATING_DOCUMENTATION) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace local { + +/// Create a pair of connected sockets. +template +void connect_pair(basic_socket& socket1, + basic_socket& socket2); + +/// Create a pair of connected sockets. +template +BOOST_ASIO_SYNC_OP_VOID connect_pair(basic_socket& socket1, + basic_socket& socket2, boost::system::error_code& ec); + +template +inline void connect_pair(basic_socket& socket1, + basic_socket& socket2) +{ + boost::system::error_code ec; + connect_pair(socket1, socket2, ec); + boost::asio::detail::throw_error(ec, "connect_pair"); +} + +template +inline BOOST_ASIO_SYNC_OP_VOID connect_pair( + basic_socket& socket1, + basic_socket& socket2, boost::system::error_code& ec) +{ + // Check that this function is only being used with a UNIX domain socket. + boost::asio::local::basic_endpoint* tmp + = static_cast(0); + (void)tmp; + + Protocol protocol; + boost::asio::detail::socket_type sv[2]; + if (boost::asio::detail::socket_ops::socketpair(protocol.family(), + protocol.type(), protocol.protocol(), sv, ec) + == boost::asio::detail::socket_error_retval) + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + + socket1.assign(protocol, sv[0], ec); + if (ec) + { + boost::system::error_code temp_ec; + boost::asio::detail::socket_ops::state_type state[2] = { 0, 0 }; + boost::asio::detail::socket_ops::close(sv[0], state[0], true, temp_ec); + boost::asio::detail::socket_ops::close(sv[1], state[1], true, temp_ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + socket2.assign(protocol, sv[1], ec); + if (ec) + { + boost::system::error_code temp_ec; + socket1.close(temp_ec); + boost::asio::detail::socket_ops::state_type state = 0; + boost::asio::detail::socket_ops::close(sv[1], state, true, temp_ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); +} + +} // namespace local +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_LOCAL_CONNECT_PAIR_HPP diff --git a/boost/asio/local/datagram_protocol.hpp b/boost/asio/local/datagram_protocol.hpp new file mode 100644 index 0000000..b29add6 --- /dev/null +++ b/boost/asio/local/datagram_protocol.hpp @@ -0,0 +1,82 @@ +// +// local/datagram_protocol.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_LOCAL_DATAGRAM_PROTOCOL_HPP +#define BOOST_ASIO_LOCAL_DATAGRAM_PROTOCOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) \ + || defined(GENERATING_DOCUMENTATION) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace local { + +/// Encapsulates the flags needed for datagram-oriented UNIX sockets. +/** + * The boost::asio::local::datagram_protocol class contains flags necessary for + * datagram-oriented UNIX domain sockets. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Safe. + * + * @par Concepts: + * Protocol. + */ +class datagram_protocol +{ +public: + /// Obtain an identifier for the type of the protocol. + int type() const + { + return SOCK_DGRAM; + } + + /// Obtain an identifier for the protocol. + int protocol() const + { + return 0; + } + + /// Obtain an identifier for the protocol family. + int family() const + { + return AF_UNIX; + } + + /// The type of a UNIX domain endpoint. + typedef basic_endpoint endpoint; + + /// The UNIX domain socket type. + typedef basic_datagram_socket socket; +}; + +} // namespace local +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_LOCAL_DATAGRAM_PROTOCOL_HPP diff --git a/boost/asio/local/detail/endpoint.hpp b/boost/asio/local/detail/endpoint.hpp new file mode 100644 index 0000000..294fb95 --- /dev/null +++ b/boost/asio/local/detail/endpoint.hpp @@ -0,0 +1,141 @@ +// +// local/detail/endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Derived from a public domain implementation written by Daniel Casimiro. +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_LOCAL_DETAIL_ENDPOINT_HPP +#define BOOST_ASIO_LOCAL_DETAIL_ENDPOINT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace local { +namespace detail { + +// Helper class for implementing a UNIX domain endpoint. +class endpoint +{ +public: + // Default constructor. + BOOST_ASIO_DECL endpoint(); + + // Construct an endpoint using the specified path name. + BOOST_ASIO_DECL endpoint(const char* path_name); + + // Construct an endpoint using the specified path name. + BOOST_ASIO_DECL endpoint(const std::string& path_name); + + #if defined(BOOST_ASIO_HAS_STRING_VIEW) + // Construct an endpoint using the specified path name. + BOOST_ASIO_DECL endpoint(string_view path_name); + #endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + + // Copy constructor. + endpoint(const endpoint& other) + : data_(other.data_), + path_length_(other.path_length_) + { + } + + // Assign from another endpoint. + endpoint& operator=(const endpoint& other) + { + data_ = other.data_; + path_length_ = other.path_length_; + return *this; + } + + // Get the underlying endpoint in the native type. + boost::asio::detail::socket_addr_type* data() + { + return &data_.base; + } + + // Get the underlying endpoint in the native type. + const boost::asio::detail::socket_addr_type* data() const + { + return &data_.base; + } + + // Get the underlying size of the endpoint in the native type. + std::size_t size() const + { + return path_length_ + + offsetof(boost::asio::detail::sockaddr_un_type, sun_path); + } + + // Set the underlying size of the endpoint in the native type. + BOOST_ASIO_DECL void resize(std::size_t size); + + // Get the capacity of the endpoint in the native type. + std::size_t capacity() const + { + return sizeof(boost::asio::detail::sockaddr_un_type); + } + + // Get the path associated with the endpoint. + BOOST_ASIO_DECL std::string path() const; + + // Set the path associated with the endpoint. + BOOST_ASIO_DECL void path(const char* p); + + // Set the path associated with the endpoint. + BOOST_ASIO_DECL void path(const std::string& p); + + // Compare two endpoints for equality. + BOOST_ASIO_DECL friend bool operator==( + const endpoint& e1, const endpoint& e2); + + // Compare endpoints for ordering. + BOOST_ASIO_DECL friend bool operator<( + const endpoint& e1, const endpoint& e2); + +private: + // The underlying UNIX socket address. + union data_union + { + boost::asio::detail::socket_addr_type base; + boost::asio::detail::sockaddr_un_type local; + } data_; + + // The length of the path associated with the endpoint. + std::size_t path_length_; + + // Initialise with a specified path. + BOOST_ASIO_DECL void init(const char* path, std::size_t path_length); +}; + +} // namespace detail +} // namespace local +} // namespace asio +} // namespace boost + +#include + +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +#endif // BOOST_ASIO_LOCAL_DETAIL_ENDPOINT_HPP diff --git a/boost/asio/local/detail/impl/endpoint.ipp b/boost/asio/local/detail/impl/endpoint.ipp new file mode 100644 index 0000000..51ce2cf --- /dev/null +++ b/boost/asio/local/detail/impl/endpoint.ipp @@ -0,0 +1,138 @@ +// +// local/detail/impl/endpoint.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Derived from a public domain implementation written by Daniel Casimiro. +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP +#define BOOST_ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace local { +namespace detail { + +endpoint::endpoint() +{ + init("", 0); +} + +endpoint::endpoint(const char* path_name) +{ + using namespace std; // For strlen. + init(path_name, strlen(path_name)); +} + +endpoint::endpoint(const std::string& path_name) +{ + init(path_name.data(), path_name.length()); +} + +#if defined(BOOST_ASIO_HAS_STRING_VIEW) +endpoint::endpoint(string_view path_name) +{ + init(path_name.data(), path_name.length()); +} +#endif // defined(BOOST_ASIO_HAS_STRING_VIEW) + +void endpoint::resize(std::size_t new_size) +{ + if (new_size > sizeof(boost::asio::detail::sockaddr_un_type)) + { + boost::system::error_code ec(boost::asio::error::invalid_argument); + boost::asio::detail::throw_error(ec); + } + else if (new_size == 0) + { + path_length_ = 0; + } + else + { + path_length_ = new_size + - offsetof(boost::asio::detail::sockaddr_un_type, sun_path); + + // The path returned by the operating system may be NUL-terminated. + if (path_length_ > 0 && data_.local.sun_path[path_length_ - 1] == 0) + --path_length_; + } +} + +std::string endpoint::path() const +{ + return std::string(data_.local.sun_path, path_length_); +} + +void endpoint::path(const char* p) +{ + using namespace std; // For strlen. + init(p, strlen(p)); +} + +void endpoint::path(const std::string& p) +{ + init(p.data(), p.length()); +} + +bool operator==(const endpoint& e1, const endpoint& e2) +{ + return e1.path() == e2.path(); +} + +bool operator<(const endpoint& e1, const endpoint& e2) +{ + return e1.path() < e2.path(); +} + +void endpoint::init(const char* path_name, std::size_t path_length) +{ + if (path_length > sizeof(data_.local.sun_path) - 1) + { + // The buffer is not large enough to store this address. + boost::system::error_code ec(boost::asio::error::name_too_long); + boost::asio::detail::throw_error(ec); + } + + using namespace std; // For memcpy. + data_.local = boost::asio::detail::sockaddr_un_type(); + data_.local.sun_family = AF_UNIX; + if (path_length > 0) + memcpy(data_.local.sun_path, path_name, path_length); + path_length_ = path_length; + + // NUL-terminate normal path names. Names that start with a NUL are in the + // UNIX domain protocol's "abstract namespace" and are not NUL-terminated. + if (path_length > 0 && data_.local.sun_path[0] == 0) + data_.local.sun_path[path_length] = 0; +} + +} // namespace detail +} // namespace local +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + +#endif // BOOST_ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP diff --git a/boost/asio/local/stream_protocol.hpp b/boost/asio/local/stream_protocol.hpp new file mode 100644 index 0000000..4fe0de5 --- /dev/null +++ b/boost/asio/local/stream_protocol.hpp @@ -0,0 +1,92 @@ +// +// local/stream_protocol.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_LOCAL_STREAM_PROTOCOL_HPP +#define BOOST_ASIO_LOCAL_STREAM_PROTOCOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) \ + || defined(GENERATING_DOCUMENTATION) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace local { + +/// Encapsulates the flags needed for stream-oriented UNIX sockets. +/** + * The boost::asio::local::stream_protocol class contains flags necessary for + * stream-oriented UNIX domain sockets. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Safe. + * + * @par Concepts: + * Protocol. + */ +class stream_protocol +{ +public: + /// Obtain an identifier for the type of the protocol. + int type() const + { + return SOCK_STREAM; + } + + /// Obtain an identifier for the protocol. + int protocol() const + { + return 0; + } + + /// Obtain an identifier for the protocol family. + int family() const + { + return AF_UNIX; + } + + /// The type of a UNIX domain endpoint. + typedef basic_endpoint endpoint; + + /// The UNIX domain socket type. + typedef basic_stream_socket socket; + + /// The UNIX domain acceptor type. + typedef basic_socket_acceptor acceptor; + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + /// The UNIX domain iostream type. + typedef basic_socket_iostream iostream; +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +}; + +} // namespace local +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_LOCAL_STREAM_PROTOCOL_HPP diff --git a/boost/asio/packaged_task.hpp b/boost/asio/packaged_task.hpp new file mode 100644 index 0000000..0985e6d --- /dev/null +++ b/boost/asio/packaged_task.hpp @@ -0,0 +1,128 @@ +// +// packaged_task.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_PACKAGED_TASK_HPP +#define BOOST_ASIO_PACKAGED_TASK_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS) \ + || defined(GENERATING_DOCUMENTATION) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +#if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) \ + || defined(GENERATING_DOCUMENTATION) + +/// Partial specialisation of @c async_result for @c std::packaged_task. +template +class async_result, Signature> +{ +public: + /// The packaged task is the concrete completion handler type. + typedef std::packaged_task completion_handler_type; + + /// The return type of the initiating function is the future obtained from + /// the packaged task. + typedef std::future return_type; + + /// The constructor extracts the future from the packaged task. + explicit async_result(completion_handler_type& h) + : future_(h.get_future()) + { + } + + /// Returns the packaged task's future. + return_type get() + { + return std::move(future_); + } + +private: + return_type future_; +}; + +#else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + +template +struct async_result, Signature> +{ + typedef std::packaged_task completion_handler_type; + typedef std::future return_type; + + explicit async_result(completion_handler_type& h) + : future_(h.get_future()) + { + } + + return_type get() + { + return std::move(future_); + } + +private: + return_type future_; +}; + +#define BOOST_ASIO_PRIVATE_ASYNC_RESULT_DEF(n) \ + template \ + class async_result< \ + std::packaged_task, Signature> \ + { \ + public: \ + typedef std::packaged_task< \ + Result(BOOST_ASIO_VARIADIC_TARGS(n))> \ + completion_handler_type; \ + \ + typedef std::future return_type; \ + \ + explicit async_result(completion_handler_type& h) \ + : future_(h.get_future()) \ + { \ + } \ + \ + return_type get() \ + { \ + return std::move(future_); \ + } \ + \ + private: \ + return_type future_; \ + }; \ + /**/ + BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_ASYNC_RESULT_DEF) +#undef BOOST_ASIO_PRIVATE_ASYNC_RESULT_DEF + +#endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) + // || defined(GENERATING_DOCUMENTATION) + +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_PACKAGED_TASK_HPP diff --git a/boost/asio/placeholders.hpp b/boost/asio/placeholders.hpp new file mode 100644 index 0000000..3640bd6 --- /dev/null +++ b/boost/asio/placeholders.hpp @@ -0,0 +1,153 @@ +// +// placeholders.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_PLACEHOLDERS_HPP +#define BOOST_ASIO_PLACEHOLDERS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_BOOST_BIND) +# include +#endif // defined(BOOST_ASIO_HAS_BOOST_BIND) + +#include + +namespace boost { +namespace asio { +namespace placeholders { + +#if defined(GENERATING_DOCUMENTATION) + +/// An argument placeholder, for use with boost::bind(), that corresponds to +/// the error argument of a handler for any of the asynchronous functions. +unspecified error; + +/// An argument placeholder, for use with boost::bind(), that corresponds to +/// the bytes_transferred argument of a handler for asynchronous functions such +/// as boost::asio::basic_stream_socket::async_write_some or +/// boost::asio::async_write. +unspecified bytes_transferred; + +/// An argument placeholder, for use with boost::bind(), that corresponds to +/// the iterator argument of a handler for asynchronous functions such as +/// boost::asio::async_connect. +unspecified iterator; + +/// An argument placeholder, for use with boost::bind(), that corresponds to +/// the results argument of a handler for asynchronous functions such as +/// boost::asio::basic_resolver::async_resolve. +unspecified results; + +/// An argument placeholder, for use with boost::bind(), that corresponds to +/// the results argument of a handler for asynchronous functions such as +/// boost::asio::async_connect. +unspecified endpoint; + +/// An argument placeholder, for use with boost::bind(), that corresponds to +/// the signal_number argument of a handler for asynchronous functions such as +/// boost::asio::signal_set::async_wait. +unspecified signal_number; + +#elif defined(BOOST_ASIO_HAS_BOOST_BIND) +# if defined(__BORLANDC__) || defined(__GNUC__) + +inline boost::arg<1> error() +{ + return boost::arg<1>(); +} + +inline boost::arg<2> bytes_transferred() +{ + return boost::arg<2>(); +} + +inline boost::arg<2> iterator() +{ + return boost::arg<2>(); +} + +inline boost::arg<2> results() +{ + return boost::arg<2>(); +} + +inline boost::arg<2> endpoint() +{ + return boost::arg<2>(); +} + +inline boost::arg<2> signal_number() +{ + return boost::arg<2>(); +} + +# else + +namespace detail +{ + template + struct placeholder + { + static boost::arg& get() + { + static boost::arg result; + return result; + } + }; +} + +# if defined(BOOST_ASIO_MSVC) && (BOOST_ASIO_MSVC < 1400) + +static boost::arg<1>& error + = boost::asio::placeholders::detail::placeholder<1>::get(); +static boost::arg<2>& bytes_transferred + = boost::asio::placeholders::detail::placeholder<2>::get(); +static boost::arg<2>& iterator + = boost::asio::placeholders::detail::placeholder<2>::get(); +static boost::arg<2>& results + = boost::asio::placeholders::detail::placeholder<2>::get(); +static boost::arg<2>& endpoint + = boost::asio::placeholders::detail::placeholder<2>::get(); +static boost::arg<2>& signal_number + = boost::asio::placeholders::detail::placeholder<2>::get(); + +# else + +namespace +{ + boost::arg<1>& error + = boost::asio::placeholders::detail::placeholder<1>::get(); + boost::arg<2>& bytes_transferred + = boost::asio::placeholders::detail::placeholder<2>::get(); + boost::arg<2>& iterator + = boost::asio::placeholders::detail::placeholder<2>::get(); + boost::arg<2>& results + = boost::asio::placeholders::detail::placeholder<2>::get(); + boost::arg<2>& endpoint + = boost::asio::placeholders::detail::placeholder<2>::get(); + boost::arg<2>& signal_number + = boost::asio::placeholders::detail::placeholder<2>::get(); +} // namespace + +# endif +# endif +#endif + +} // namespace placeholders +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_PLACEHOLDERS_HPP diff --git a/boost/asio/posix/basic_descriptor.hpp b/boost/asio/posix/basic_descriptor.hpp new file mode 100644 index 0000000..301c618 --- /dev/null +++ b/boost/asio/posix/basic_descriptor.hpp @@ -0,0 +1,672 @@ +// +// posix/basic_descriptor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_POSIX_BASIC_DESCRIPTOR_HPP +#define BOOST_ASIO_POSIX_BASIC_DESCRIPTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ + || defined(GENERATING_DOCUMENTATION) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_MOVE) +# include +#endif // defined(BOOST_ASIO_HAS_MOVE) + +#include + +namespace boost { +namespace asio { +namespace posix { + +/// Provides POSIX descriptor functionality. +/** + * The posix::basic_descriptor class template provides the ability to wrap a + * POSIX descriptor. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_descriptor + : public descriptor_base +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// The native representation of a descriptor. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef detail::reactive_descriptor_service::native_handle_type + native_handle_type; +#endif + + /// A descriptor is always the lowest layer. + typedef basic_descriptor lowest_layer_type; + + /// Construct a descriptor without opening it. + /** + * This constructor creates a descriptor without opening it. + * + * @param ex The I/O executor that the descriptor will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * descriptor. + */ + explicit basic_descriptor(const executor_type& ex) + : impl_(ex) + { + } + + /// Construct a descriptor without opening it. + /** + * This constructor creates a descriptor without opening it. + * + * @param context An execution context which provides the I/O executor that + * the descriptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the descriptor. + */ + template + explicit basic_descriptor(ExecutionContext& context, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + } + + /// Construct a descriptor on an existing native descriptor. + /** + * This constructor creates a descriptor object to hold an existing native + * descriptor. + * + * @param ex The I/O executor that the descriptor will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * descriptor. + * + * @param native_descriptor A native descriptor. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_descriptor(const executor_type& ex, + const native_handle_type& native_descriptor) + : impl_(ex) + { + boost::system::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + native_descriptor, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + + /// Construct a descriptor on an existing native descriptor. + /** + * This constructor creates a descriptor object to hold an existing native + * descriptor. + * + * @param context An execution context which provides the I/O executor that + * the descriptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the descriptor. + * + * @param native_descriptor A native descriptor. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_descriptor(ExecutionContext& context, + const native_handle_type& native_descriptor, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + boost::system::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + native_descriptor, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a descriptor from another. + /** + * This constructor moves a descriptor from one object to another. + * + * @param other The other descriptor object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_descriptor(const executor_type&) + * constructor. + */ + basic_descriptor(basic_descriptor&& other) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign a descriptor from another. + /** + * This assignment operator moves a descriptor from one object to another. + * + * @param other The other descriptor object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_descriptor(const executor_type&) + * constructor. + */ + basic_descriptor& operator=(basic_descriptor&& other) + { + impl_ = std::move(other.impl_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return impl_.get_executor(); + } + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * layers. Since a descriptor cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A reference to the lowest layer in the stack of layers. Ownership + * is not transferred to the caller. + */ + lowest_layer_type& lowest_layer() + { + return *this; + } + + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since a descriptor cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } + + /// Assign an existing native descriptor to the descriptor. + /* + * This function opens the descriptor to hold an existing native descriptor. + * + * @param native_descriptor A native descriptor. + * + * @throws boost::system::system_error Thrown on failure. + */ + void assign(const native_handle_type& native_descriptor) + { + boost::system::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), + native_descriptor, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + + /// Assign an existing native descriptor to the descriptor. + /* + * This function opens the descriptor to hold an existing native descriptor. + * + * @param native_descriptor A native descriptor. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& native_descriptor, + boost::system::error_code& ec) + { + impl_.get_service().assign( + impl_.get_implementation(), native_descriptor, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the descriptor is open. + bool is_open() const + { + return impl_.get_service().is_open(impl_.get_implementation()); + } + + /// Close the descriptor. + /** + * This function is used to close the descriptor. Any asynchronous read or + * write operations will be cancelled immediately, and will complete with the + * boost::asio::error::operation_aborted error. + * + * @throws boost::system::system_error Thrown on failure. Note that, even if + * the function indicates an error, the underlying descriptor is closed. + */ + void close() + { + boost::system::error_code ec; + impl_.get_service().close(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "close"); + } + + /// Close the descriptor. + /** + * This function is used to close the descriptor. Any asynchronous read or + * write operations will be cancelled immediately, and will complete with the + * boost::asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. Note that, even if + * the function indicates an error, the underlying descriptor is closed. + */ + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) + { + impl_.get_service().close(impl_.get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get the native descriptor representation. + /** + * This function may be used to obtain the underlying representation of the + * descriptor. This is intended to allow access to native descriptor + * functionality that is not otherwise provided. + */ + native_handle_type native_handle() + { + return impl_.get_service().native_handle(impl_.get_implementation()); + } + + /// Release ownership of the native descriptor implementation. + /** + * This function may be used to obtain the underlying representation of the + * descriptor. After calling this function, @c is_open() returns false. The + * caller is responsible for closing the descriptor. + * + * All outstanding asynchronous read or write operations will finish + * immediately, and the handlers for cancelled operations will be passed the + * boost::asio::error::operation_aborted error. + */ + native_handle_type release() + { + return impl_.get_service().release(impl_.get_implementation()); + } + + /// Cancel all asynchronous operations associated with the descriptor. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. + * + * @throws boost::system::system_error Thrown on failure. + */ + void cancel() + { + boost::system::error_code ec; + impl_.get_service().cancel(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the descriptor. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) + { + impl_.get_service().cancel(impl_.get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Perform an IO control command on the descriptor. + /** + * This function is used to execute an IO control command on the descriptor. + * + * @param command The IO control command to be performed on the descriptor. + * + * @throws boost::system::system_error Thrown on failure. + * + * @sa IoControlCommand @n + * boost::asio::posix::descriptor_base::bytes_readable @n + * boost::asio::posix::descriptor_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * boost::asio::posix::stream_descriptor descriptor(my_context); + * ... + * boost::asio::posix::stream_descriptor::bytes_readable command; + * descriptor.io_control(command); + * std::size_t bytes_readable = command.get(); + * @endcode + */ + template + void io_control(IoControlCommand& command) + { + boost::system::error_code ec; + impl_.get_service().io_control(impl_.get_implementation(), command, ec); + boost::asio::detail::throw_error(ec, "io_control"); + } + + /// Perform an IO control command on the descriptor. + /** + * This function is used to execute an IO control command on the descriptor. + * + * @param command The IO control command to be performed on the descriptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa IoControlCommand @n + * boost::asio::posix::descriptor_base::bytes_readable @n + * boost::asio::posix::descriptor_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * boost::asio::posix::stream_descriptor descriptor(my_context); + * ... + * boost::asio::posix::stream_descriptor::bytes_readable command; + * boost::system::error_code ec; + * descriptor.io_control(command, ec); + * if (ec) + * { + * // An error occurred. + * } + * std::size_t bytes_readable = command.get(); + * @endcode + */ + template + BOOST_ASIO_SYNC_OP_VOID io_control(IoControlCommand& command, + boost::system::error_code& ec) + { + impl_.get_service().io_control(impl_.get_implementation(), command, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Gets the non-blocking mode of the descriptor. + /** + * @returns @c true if the descriptor's synchronous operations will fail with + * boost::asio::error::would_block if they are unable to perform the requested + * operation immediately. If @c false, synchronous operations will block + * until complete. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * boost::asio::error::would_block. + */ + bool non_blocking() const + { + return impl_.get_service().non_blocking(impl_.get_implementation()); + } + + /// Sets the non-blocking mode of the descriptor. + /** + * @param mode If @c true, the descriptor's synchronous operations will fail + * with boost::asio::error::would_block if they are unable to perform the + * requested operation immediately. If @c false, synchronous operations will + * block until complete. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * boost::asio::error::would_block. + */ + void non_blocking(bool mode) + { + boost::system::error_code ec; + impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); + boost::asio::detail::throw_error(ec, "non_blocking"); + } + + /// Sets the non-blocking mode of the descriptor. + /** + * @param mode If @c true, the descriptor's synchronous operations will fail + * with boost::asio::error::would_block if they are unable to perform the + * requested operation immediately. If @c false, synchronous operations will + * block until complete. + * + * @param ec Set to indicate what error occurred, if any. + * + * @note The non-blocking mode has no effect on the behaviour of asynchronous + * operations. Asynchronous operations will never fail with the error + * boost::asio::error::would_block. + */ + BOOST_ASIO_SYNC_OP_VOID non_blocking( + bool mode, boost::system::error_code& ec) + { + impl_.get_service().non_blocking(impl_.get_implementation(), mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Gets the non-blocking mode of the native descriptor implementation. + /** + * This function is used to retrieve the non-blocking mode of the underlying + * native descriptor. This mode has no effect on the behaviour of the + * descriptor object's synchronous operations. + * + * @returns @c true if the underlying descriptor is in non-blocking mode and + * direct system calls may fail with boost::asio::error::would_block (or the + * equivalent system error). + * + * @note The current non-blocking mode is cached by the descriptor object. + * Consequently, the return value may be incorrect if the non-blocking mode + * was set directly on the native descriptor. + */ + bool native_non_blocking() const + { + return impl_.get_service().native_non_blocking( + impl_.get_implementation()); + } + + /// Sets the non-blocking mode of the native descriptor implementation. + /** + * This function is used to modify the non-blocking mode of the underlying + * native descriptor. It has no effect on the behaviour of the descriptor + * object's synchronous operations. + * + * @param mode If @c true, the underlying descriptor is put into non-blocking + * mode and direct system calls may fail with boost::asio::error::would_block + * (or the equivalent system error). + * + * @throws boost::system::system_error Thrown on failure. If the @c mode is + * @c false, but the current value of @c non_blocking() is @c true, this + * function fails with boost::asio::error::invalid_argument, as the + * combination does not make sense. + */ + void native_non_blocking(bool mode) + { + boost::system::error_code ec; + impl_.get_service().native_non_blocking( + impl_.get_implementation(), mode, ec); + boost::asio::detail::throw_error(ec, "native_non_blocking"); + } + + /// Sets the non-blocking mode of the native descriptor implementation. + /** + * This function is used to modify the non-blocking mode of the underlying + * native descriptor. It has no effect on the behaviour of the descriptor + * object's synchronous operations. + * + * @param mode If @c true, the underlying descriptor is put into non-blocking + * mode and direct system calls may fail with boost::asio::error::would_block + * (or the equivalent system error). + * + * @param ec Set to indicate what error occurred, if any. If the @c mode is + * @c false, but the current value of @c non_blocking() is @c true, this + * function fails with boost::asio::error::invalid_argument, as the + * combination does not make sense. + */ + BOOST_ASIO_SYNC_OP_VOID native_non_blocking( + bool mode, boost::system::error_code& ec) + { + impl_.get_service().native_non_blocking( + impl_.get_implementation(), mode, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Wait for the descriptor to become ready to read, ready to write, or to + /// have pending error conditions. + /** + * This function is used to perform a blocking wait for a descriptor to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired descriptor state. + * + * @par Example + * Waiting for a descriptor to become readable. + * @code + * boost::asio::posix::stream_descriptor descriptor(my_context); + * ... + * descriptor.wait(boost::asio::posix::stream_descriptor::wait_read); + * @endcode + */ + void wait(wait_type w) + { + boost::system::error_code ec; + impl_.get_service().wait(impl_.get_implementation(), w, ec); + boost::asio::detail::throw_error(ec, "wait"); + } + + /// Wait for the descriptor to become ready to read, ready to write, or to + /// have pending error conditions. + /** + * This function is used to perform a blocking wait for a descriptor to enter + * a ready to read, write or error condition state. + * + * @param w Specifies the desired descriptor state. + * + * @param ec Set to indicate what error occurred, if any. + * + * @par Example + * Waiting for a descriptor to become readable. + * @code + * boost::asio::posix::stream_descriptor descriptor(my_context); + * ... + * boost::system::error_code ec; + * descriptor.wait(boost::asio::posix::stream_descriptor::wait_read, ec); + * @endcode + */ + BOOST_ASIO_SYNC_OP_VOID wait(wait_type w, boost::system::error_code& ec) + { + impl_.get_service().wait(impl_.get_implementation(), w, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Asynchronously wait for the descriptor to become ready to read, ready to + /// write, or to have pending error conditions. + /** + * This function is used to perform an asynchronous wait for a descriptor to + * enter a ready to read, write or error condition state. + * + * @param w Specifies the desired descriptor state. + * + * @param handler The handler to be called when the wait operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error // Result of operation + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * @code + * void wait_handler(const boost::system::error_code& error) + * { + * if (!error) + * { + * // Wait succeeded. + * } + * } + * + * ... + * + * boost::asio::posix::stream_descriptor descriptor(my_context); + * ... + * descriptor.async_wait( + * boost::asio::posix::stream_descriptor::wait_read, + * wait_handler); + * @endcode + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + void (boost::system::error_code)) + async_wait(wait_type w, BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + { + return async_initiate( + initiate_async_wait(), handler, this, w); + } + +protected: + /// Protected destructor to prevent deletion through this type. + /** + * This function destroys the descriptor, cancelling any outstanding + * asynchronous wait operations associated with the descriptor as if by + * calling @c cancel. + */ + ~basic_descriptor() + { + } + + detail::io_object_impl impl_; + +private: + // Disallow copying and assignment. + basic_descriptor(const basic_descriptor&) BOOST_ASIO_DELETED; + basic_descriptor& operator=(const basic_descriptor&) BOOST_ASIO_DELETED; + + struct initiate_async_wait + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler, + basic_descriptor* self, wait_type w) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WaitHandler. + BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_wait( + self->impl_.get_implementation(), w, handler2.value, + self->impl_.get_implementation_executor()); + } + }; +}; + +} // namespace posix +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_POSIX_BASIC_DESCRIPTOR_HPP diff --git a/boost/asio/posix/basic_stream_descriptor.hpp b/boost/asio/posix/basic_stream_descriptor.hpp new file mode 100644 index 0000000..0098802 --- /dev/null +++ b/boost/asio/posix/basic_stream_descriptor.hpp @@ -0,0 +1,426 @@ +// +// posix/basic_stream_descriptor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP +#define BOOST_ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ + || defined(GENERATING_DOCUMENTATION) + +namespace boost { +namespace asio { +namespace posix { + +/// Provides stream-oriented descriptor functionality. +/** + * The posix::basic_stream_descriptor class template provides asynchronous and + * blocking stream-oriented descriptor functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Concepts: + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. + */ +template +class basic_stream_descriptor + : public basic_descriptor +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// The native representation of a descriptor. + typedef typename basic_descriptor::native_handle_type + native_handle_type; + + /// Construct a stream descriptor without opening it. + /** + * This constructor creates a stream descriptor without opening it. The + * descriptor needs to be opened and then connected or accepted before data + * can be sent or received on it. + * + * @param ex The I/O executor that the descriptor will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * descriptor. + */ + explicit basic_stream_descriptor(const executor_type& ex) + : basic_descriptor(ex) + { + } + + /// Construct a stream descriptor without opening it. + /** + * This constructor creates a stream descriptor without opening it. The + * descriptor needs to be opened and then connected or accepted before data + * can be sent or received on it. + * + * @param context An execution context which provides the I/O executor that + * the descriptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the descriptor. + */ + template + explicit basic_stream_descriptor(ExecutionContext& context, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_descriptor(context) + { + } + + /// Construct a stream descriptor on an existing native descriptor. + /** + * This constructor creates a stream descriptor object to hold an existing + * native descriptor. + * + * @param ex The I/O executor that the descriptor will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * descriptor. + * + * @param native_descriptor The new underlying descriptor implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_stream_descriptor(const executor_type& ex, + const native_handle_type& native_descriptor) + : basic_descriptor(ex, native_descriptor) + { + } + + /// Construct a stream descriptor on an existing native descriptor. + /** + * This constructor creates a stream descriptor object to hold an existing + * native descriptor. + * + * @param context An execution context which provides the I/O executor that + * the descriptor will use, by default, to dispatch handlers for any + * asynchronous operations performed on the descriptor. + * + * @param native_descriptor The new underlying descriptor implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_stream_descriptor(ExecutionContext& context, + const native_handle_type& native_descriptor, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_descriptor(context, native_descriptor) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a stream descriptor from another. + /** + * This constructor moves a stream descriptor from one object to another. + * + * @param other The other stream descriptor object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_descriptor(const executor_type&) + * constructor. + */ + basic_stream_descriptor(basic_stream_descriptor&& other) + : descriptor(std::move(other)) + { + } + + /// Move-assign a stream descriptor from another. + /** + * This assignment operator moves a stream descriptor from one object to + * another. + * + * @param other The other stream descriptor object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_descriptor(const executor_type&) + * constructor. + */ + basic_stream_descriptor& operator=(basic_stream_descriptor&& other) + { + descriptor::operator=(std::move(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Write some data to the descriptor. + /** + * This function is used to write data to the stream descriptor. The function + * call will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the descriptor. + * + * @returns The number of bytes written. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * descriptor.write_some(boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t write_some(const ConstBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().write_some( + this->impl_.get_implementation(), buffers, ec); + boost::asio::detail::throw_error(ec, "write_some"); + return s; + } + + /// Write some data to the descriptor. + /** + * This function is used to write data to the stream descriptor. The function + * call will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the descriptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. Returns 0 if an error occurred. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + */ + template + std::size_t write_some(const ConstBufferSequence& buffers, + boost::system::error_code& ec) + { + return this->impl_.get_service().write_some( + this->impl_.get_implementation(), buffers, ec); + } + + /// Start an asynchronous write. + /** + * This function is used to asynchronously write data to the stream + * descriptor. The function call always returns immediately. + * + * @param buffers One or more data buffers to be written to the descriptor. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes written. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The write operation may not transmit all of the data to the peer. + * Consider using the @ref async_write function if you need to ensure that all + * data is written before the asynchronous operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * descriptor.async_write_some(boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_write_some(const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + return async_initiate( + initiate_async_write_some(), handler, this, buffers); + } + + /// Read some data from the descriptor. + /** + * This function is used to read data from the stream descriptor. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @returns The number of bytes read. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * descriptor.read_some(boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t read_some(const MutableBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().read_some( + this->impl_.get_implementation(), buffers, ec); + boost::asio::detail::throw_error(ec, "read_some"); + return s; + } + + /// Read some data from the descriptor. + /** + * This function is used to read data from the stream descriptor. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. Returns 0 if an error occurred. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + */ + template + std::size_t read_some(const MutableBufferSequence& buffers, + boost::system::error_code& ec) + { + return this->impl_.get_service().read_some( + this->impl_.get_implementation(), buffers, ec); + } + + /// Start an asynchronous read. + /** + * This function is used to asynchronously read data from the stream + * descriptor. The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes read. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The read operation may not read all of the requested number of bytes. + * Consider using the @ref async_read function if you need to ensure that the + * requested amount of data is read before the asynchronous operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * descriptor.async_read_some(boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_read_some(const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + return async_initiate( + initiate_async_read_some(), handler, this, buffers); + } + +private: + struct initiate_async_write_some + { + template + void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + basic_stream_descriptor* self, + const ConstBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_write_some( + self->impl_.get_implementation(), buffers, handler2.value, + self->impl_.get_implementation_executor()); + } + }; + + struct initiate_async_read_some + { + template + void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + basic_stream_descriptor* self, + const MutableBufferSequence& buffers) const + { + // If you get an error on the following line it means that your handler + // does not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + detail::non_const_lvalue handler2(handler); + self->impl_.get_service().async_read_some( + self->impl_.get_implementation(), buffers, handler2.value, + self->impl_.get_implementation_executor()); + } + }; +}; + +} // namespace posix +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP diff --git a/boost/asio/posix/descriptor.hpp b/boost/asio/posix/descriptor.hpp new file mode 100644 index 0000000..d7aa928 --- /dev/null +++ b/boost/asio/posix/descriptor.hpp @@ -0,0 +1,39 @@ +// +// posix/descriptor.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_POSIX_DESCRIPTOR_HPP +#define BOOST_ASIO_POSIX_DESCRIPTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ + || defined(GENERATING_DOCUMENTATION) + +#include + +namespace boost { +namespace asio { +namespace posix { + +/// Typedef for the typical usage of basic_descriptor. +typedef basic_descriptor<> descriptor; + +} // namespace posix +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_POSIX_DESCRIPTOR_HPP diff --git a/boost/asio/posix/descriptor_base.hpp b/boost/asio/posix/descriptor_base.hpp new file mode 100644 index 0000000..ff7d4c9 --- /dev/null +++ b/boost/asio/posix/descriptor_base.hpp @@ -0,0 +1,92 @@ +// +// posix/descriptor_base.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_POSIX_DESCRIPTOR_BASE_HPP +#define BOOST_ASIO_POSIX_DESCRIPTOR_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ + || defined(GENERATING_DOCUMENTATION) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace posix { + +/// The descriptor_base class is used as a base for the descriptor class as a +/// place to define the associated IO control commands. +class descriptor_base +{ +public: + /// Wait types. + /** + * For use with descriptor::wait() and descriptor::async_wait(). + */ + enum wait_type + { + /// Wait for a descriptor to become ready to read. + wait_read, + + /// Wait for a descriptor to become ready to write. + wait_write, + + /// Wait for a descriptor to have error conditions pending. + wait_error + }; + + /// IO control command to get the amount of data that can be read without + /// blocking. + /** + * Implements the FIONREAD IO control command. + * + * @par Example + * @code + * boost::asio::posix::stream_descriptor descriptor(my_context); + * ... + * boost::asio::descriptor_base::bytes_readable command(true); + * descriptor.io_control(command); + * std::size_t bytes_readable = command.get(); + * @endcode + * + * @par Concepts: + * IoControlCommand. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined bytes_readable; +#else + typedef boost::asio::detail::io_control::bytes_readable bytes_readable; +#endif + +protected: + /// Protected destructor to prevent deletion through this type. + ~descriptor_base() + { + } +}; + +} // namespace posix +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_POSIX_DESCRIPTOR_BASE_HPP diff --git a/boost/asio/posix/stream_descriptor.hpp b/boost/asio/posix/stream_descriptor.hpp new file mode 100644 index 0000000..035cf3c --- /dev/null +++ b/boost/asio/posix/stream_descriptor.hpp @@ -0,0 +1,39 @@ +// +// posix/stream_descriptor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_POSIX_STREAM_DESCRIPTOR_HPP +#define BOOST_ASIO_POSIX_STREAM_DESCRIPTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ + || defined(GENERATING_DOCUMENTATION) + +#include + +namespace boost { +namespace asio { +namespace posix { + +/// Typedef for the typical usage of a stream-oriented descriptor. +typedef basic_stream_descriptor<> stream_descriptor; + +} // namespace posix +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_POSIX_STREAM_DESCRIPTOR_HPP diff --git a/boost/asio/post.hpp b/boost/asio/post.hpp new file mode 100644 index 0000000..0fbdbf0 --- /dev/null +++ b/boost/asio/post.hpp @@ -0,0 +1,115 @@ +// +// post.hpp +// ~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_POST_HPP +#define BOOST_ASIO_POST_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +/// Submits a completion token or function object for execution. +/** + * This function submits an object for execution using the object's associated + * executor. The function object is queued for execution, and is never called + * from the current thread prior to returning from post(). + * + * The use of @c post(), rather than @ref defer(), indicates the caller's + * preference that the function object be eagerly queued for execution. + * + * This function has the following effects: + * + * @li Constructs a function object handler of type @c Handler, initialized + * with handler(forward(token)). + * + * @li Constructs an object @c result of type async_result, + * initializing the object as result(handler). + * + * @li Obtains the handler's associated executor object @c ex by performing + * get_associated_executor(handler). + * + * @li Obtains the handler's associated allocator object @c alloc by performing + * get_associated_allocator(handler). + * + * @li Performs ex.post(std::move(handler), alloc). + * + * @li Returns result.get(). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( + BOOST_ASIO_MOVE_ARG(CompletionToken) token); + +/// Submits a completion token or function object for execution. +/** + * This function submits an object for execution using the specified executor. + * The function object is queued for execution, and is never called from the + * current thread prior to returning from post(). + * + * The use of @c post(), rather than @ref defer(), indicates the caller's + * preference that the function object be eagerly queued for execution. + * + * This function has the following effects: + * + * @li Constructs a function object handler of type @c Handler, initialized + * with handler(forward(token)). + * + * @li Constructs an object @c result of type async_result, + * initializing the object as result(handler). + * + * @li Obtains the handler's associated executor object @c ex1 by performing + * get_associated_executor(handler). + * + * @li Creates a work object @c w by performing make_work(ex1). + * + * @li Obtains the handler's associated allocator object @c alloc by performing + * get_associated_allocator(handler). + * + * @li Constructs a function object @c f with a function call operator that + * performs ex1.dispatch(std::move(handler), alloc) followed by + * w.reset(). + * + * @li Performs Executor(ex).post(std::move(f), alloc). + * + * @li Returns result.get(). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( + const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if::value>::type* = 0); + +/// Submits a completion token or function object for execution. +/** + * @returns post(ctx.get_executor(), forward(token)). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(CompletionToken, void()) post( + ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, + typename enable_if::value>::type* = 0); + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // BOOST_ASIO_POST_HPP diff --git a/boost/asio/read.hpp b/boost/asio/read.hpp new file mode 100644 index 0000000..3c48686 --- /dev/null +++ b/boost/asio/read.hpp @@ -0,0 +1,1245 @@ +// +// read.hpp +// ~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_READ_HPP +#define BOOST_ASIO_READ_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +# include +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +#include + +namespace boost { +namespace asio { + +/** + * @defgroup read boost::asio::read + * + * @brief The @c read function is a composed operation that reads a certain + * amount of data from a stream before returning. + */ +/*@{*/ + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The supplied buffers are full. That is, the bytes transferred is equal to + * the sum of the buffer sizes. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers One or more buffers into which the data will be read. The sum + * of the buffer sizes indicates the maximum number of bytes to read from the + * stream. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code boost::asio::read(s, boost::asio::buffer(data, size)); @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + * + * @note This overload is equivalent to calling: + * @code boost::asio::read( + * s, buffers, + * boost::asio::transfer_all()); @endcode + */ +template +std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + typename enable_if< + is_mutable_buffer_sequence::value + >::type* = 0); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The supplied buffers are full. That is, the bytes transferred is equal to + * the sum of the buffer sizes. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers One or more buffers into which the data will be read. The sum + * of the buffer sizes indicates the maximum number of bytes to read from the + * stream. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes transferred. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code boost::asio::read(s, boost::asio::buffer(data, size), ec); @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + * + * @note This overload is equivalent to calling: + * @code boost::asio::read( + * s, buffers, + * boost::asio::transfer_all(), ec); @endcode + */ +template +std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + boost::system::error_code& ec, + typename enable_if< + is_mutable_buffer_sequence::value + >::type* = 0); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The supplied buffers are full. That is, the bytes transferred is equal to + * the sum of the buffer sizes. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers One or more buffers into which the data will be read. The sum + * of the buffer sizes indicates the maximum number of bytes to read from the + * stream. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest read_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's read_some function. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code boost::asio::read(s, boost::asio::buffer(data, size), + * boost::asio::transfer_at_least(32)); @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ +template +std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, + typename enable_if< + is_mutable_buffer_sequence::value + >::type* = 0); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The supplied buffers are full. That is, the bytes transferred is equal to + * the sum of the buffer sizes. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers One or more buffers into which the data will be read. The sum + * of the buffer sizes indicates the maximum number of bytes to read from the + * stream. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest read_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's read_some function. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. + */ +template +std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_mutable_buffer_sequence::value + >::type* = 0); + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note This overload is equivalent to calling: + * @code boost::asio::read( + * s, buffers, + * boost::asio::transfer_all()); @endcode + */ +template +std::size_t read(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The supplied buffer is full (that is, it has reached maximum size). + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes transferred. + * + * @note This overload is equivalent to calling: + * @code boost::asio::read( + * s, buffers, + * boost::asio::transfer_all(), ec); @endcode + */ +template +std::size_t read(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest read_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's read_some function. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + */ +template +std::size_t read(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest read_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's read_some function. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. + */ +template +std::size_t read(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The supplied buffer is full (that is, it has reached maximum size). + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param b The basic_streambuf object into which the data will be read. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note This overload is equivalent to calling: + * @code boost::asio::read( + * s, b, + * boost::asio::transfer_all()); @endcode + */ +template +std::size_t read(SyncReadStream& s, basic_streambuf& b); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The supplied buffer is full (that is, it has reached maximum size). + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param b The basic_streambuf object into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes transferred. + * + * @note This overload is equivalent to calling: + * @code boost::asio::read( + * s, b, + * boost::asio::transfer_all(), ec); @endcode + */ +template +std::size_t read(SyncReadStream& s, basic_streambuf& b, + boost::system::error_code& ec); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The supplied buffer is full (that is, it has reached maximum size). + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param b The basic_streambuf object into which the data will be read. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest read_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's read_some function. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + */ +template +std::size_t read(SyncReadStream& s, basic_streambuf& b, + CompletionCondition completion_condition); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The supplied buffer is full (that is, it has reached maximum size). + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param b The basic_streambuf object into which the data will be read. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest read_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's read_some function. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. + */ +template +std::size_t read(SyncReadStream& s, basic_streambuf& b, + CompletionCondition completion_condition, boost::system::error_code& ec); + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note This overload is equivalent to calling: + * @code boost::asio::read( + * s, buffers, + * boost::asio::transfer_all()); @endcode + */ +template +std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The supplied buffer is full (that is, it has reached maximum size). + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes transferred. + * + * @note This overload is equivalent to calling: + * @code boost::asio::read( + * s, buffers, + * boost::asio::transfer_all(), ec); @endcode + */ +template +std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest read_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's read_some function. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + */ +template +std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +/// Attempt to read a certain amount of data from a stream before returning. +/** + * This function is used to read a certain number of bytes of data from a + * stream. The call will block until one of the following conditions is true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest read_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's read_some function. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. + */ +template +std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +/*@}*/ +/** + * @defgroup async_read boost::asio::async_read + * + * @brief The @c async_read function is a composed asynchronous operation that + * reads a certain amount of data from a stream before completion. + */ +/*@{*/ + +/// Start an asynchronous operation to read a certain amount of data from a +/// stream. +/** + * This function is used to asynchronously read a certain number of bytes of + * data from a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions is + * true: + * + * @li The supplied buffers are full. That is, the bytes transferred is equal to + * the sum of the buffer sizes. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other read operations (such + * as async_read, the stream's async_read_some function, or any other composed + * operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers One or more buffers into which the data will be read. The sum + * of the buffer sizes indicates the maximum number of bytes to read from the + * stream. Although the buffers object may be copied as necessary, ownership of + * the underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes copied into the + * // buffers. If an error occurred, + * // this will be the number of + * // bytes successfully transferred + * // prior to the error. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * boost::asio::async_read(s, boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + * + * @note This overload is equivalent to calling: + * @code boost::asio::async_read( + * s, buffers, + * boost::asio::transfer_all(), + * handler); @endcode + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_mutable_buffer_sequence::value + >::type* = 0); + +/// Start an asynchronous operation to read a certain amount of data from a +/// stream. +/** + * This function is used to asynchronously read a certain number of bytes of + * data from a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions is + * true: + * + * @li The supplied buffers are full. That is, the bytes transferred is equal to + * the sum of the buffer sizes. + * + * @li The completion_condition function object returns 0. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers One or more buffers into which the data will be read. The sum + * of the buffer sizes indicates the maximum number of bytes to read from the + * stream. Although the buffers object may be copied as necessary, ownership of + * the underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest async_read_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's async_read_some function. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes copied into the + * // buffers. If an error occurred, + * // this will be the number of + * // bytes successfully transferred + * // prior to the error. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code boost::asio::async_read(s, + * boost::asio::buffer(data, size), + * boost::asio::transfer_at_least(32), + * handler); @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_mutable_buffer_sequence::value + >::type* = 0); + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Start an asynchronous operation to read a certain amount of data from a +/// stream. +/** + * This function is used to asynchronously read a certain number of bytes of + * data from a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions is + * true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other read operations (such + * as async_read, the stream's async_read_some function, or any other composed + * operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes copied into the + * // buffers. If an error occurred, + * // this will be the number of + * // bytes successfully transferred + * // prior to the error. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note This overload is equivalent to calling: + * @code boost::asio::async_read( + * s, buffers, + * boost::asio::transfer_all(), + * handler); @endcode + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +/// Start an asynchronous operation to read a certain amount of data from a +/// stream. +/** + * This function is used to asynchronously read a certain number of bytes of + * data from a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions is + * true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other read operations (such + * as async_read, the stream's async_read_some function, or any other composed + * operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest async_read_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's async_read_some function. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes copied into the + * // buffers. If an error occurred, + * // this will be the number of + * // bytes successfully transferred + * // prior to the error. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +/// Start an asynchronous operation to read a certain amount of data from a +/// stream. +/** + * This function is used to asynchronously read a certain number of bytes of + * data from a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions is + * true: + * + * @li The supplied buffer is full (that is, it has reached maximum size). + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other read operations (such + * as async_read, the stream's async_read_some function, or any other composed + * operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param b A basic_streambuf object into which the data will be read. Ownership + * of the streambuf is retained by the caller, which must guarantee that it + * remains valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes copied into the + * // buffers. If an error occurred, + * // this will be the number of + * // bytes successfully transferred + * // prior to the error. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note This overload is equivalent to calling: + * @code boost::asio::async_read( + * s, b, + * boost::asio::transfer_all(), + * handler); @endcode + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, basic_streambuf& b, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + +/// Start an asynchronous operation to read a certain amount of data from a +/// stream. +/** + * This function is used to asynchronously read a certain number of bytes of + * data from a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions is + * true: + * + * @li The supplied buffer is full (that is, it has reached maximum size). + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other read operations (such + * as async_read, the stream's async_read_some function, or any other composed + * operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param b A basic_streambuf object into which the data will be read. Ownership + * of the streambuf is retained by the caller, which must guarantee that it + * remains valid until the handler is called. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest async_read_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's async_read_some function. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes copied into the + * // buffers. If an error occurred, + * // this will be the number of + * // bytes successfully transferred + * // prior to the error. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, basic_streambuf& b, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Start an asynchronous operation to read a certain amount of data from a +/// stream. +/** + * This function is used to asynchronously read a certain number of bytes of + * data from a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions is + * true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other read operations (such + * as async_read, the stream's async_read_some function, or any other composed + * operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes copied into the + * // buffers. If an error occurred, + * // this will be the number of + * // bytes successfully transferred + * // prior to the error. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note This overload is equivalent to calling: + * @code boost::asio::async_read( + * s, buffers, + * boost::asio::transfer_all(), + * handler); @endcode + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +/// Start an asynchronous operation to read a certain amount of data from a +/// stream. +/** + * This function is used to asynchronously read a certain number of bytes of + * data from a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions is + * true: + * + * @li The specified dynamic buffer sequence is full (that is, it has reached + * maximum size). + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other read operations (such + * as async_read, the stream's async_read_some function, or any other composed + * operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest async_read_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's async_read_some function. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes copied into the + * // buffers. If an error occurred, + * // this will be the number of + * // bytes successfully transferred + * // prior to the error. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +/*@}*/ + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // BOOST_ASIO_READ_HPP diff --git a/boost/asio/read_at.hpp b/boost/asio/read_at.hpp new file mode 100644 index 0000000..8319feb --- /dev/null +++ b/boost/asio/read_at.hpp @@ -0,0 +1,673 @@ +// +// read_at.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_READ_AT_HPP +#define BOOST_ASIO_READ_AT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +# include +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +#include + +namespace boost { +namespace asio { + +/** + * @defgroup read_at boost::asio::read_at + * + * @brief The @c read_at function is a composed operation that reads a certain + * amount of data at the specified offset before returning. + */ +/*@{*/ + +/// Attempt to read a certain amount of data at the specified offset before +/// returning. +/** + * This function is used to read a certain number of bytes of data from a + * random access device at the specified offset. The call will block until one + * of the following conditions is true: + * + * @li The supplied buffers are full. That is, the bytes transferred is equal to + * the sum of the buffer sizes. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the device's + * read_some_at function. + * + * @param d The device from which the data is to be read. The type must support + * the SyncRandomAccessReadDevice concept. + * + * @param offset The offset at which the data will be read. + * + * @param buffers One or more buffers into which the data will be read. The sum + * of the buffer sizes indicates the maximum number of bytes to read from the + * device. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code boost::asio::read_at(d, 42, boost::asio::buffer(data, size)); @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + * + * @note This overload is equivalent to calling: + * @code boost::asio::read_at( + * d, 42, buffers, + * boost::asio::transfer_all()); @endcode + */ +template +std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers); + +/// Attempt to read a certain amount of data at the specified offset before +/// returning. +/** + * This function is used to read a certain number of bytes of data from a + * random access device at the specified offset. The call will block until one + * of the following conditions is true: + * + * @li The supplied buffers are full. That is, the bytes transferred is equal to + * the sum of the buffer sizes. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the device's + * read_some_at function. + * + * @param d The device from which the data is to be read. The type must support + * the SyncRandomAccessReadDevice concept. + * + * @param offset The offset at which the data will be read. + * + * @param buffers One or more buffers into which the data will be read. The sum + * of the buffer sizes indicates the maximum number of bytes to read from the + * device. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes transferred. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code boost::asio::read_at(d, 42, + * boost::asio::buffer(data, size), ec); @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + * + * @note This overload is equivalent to calling: + * @code boost::asio::read_at( + * d, 42, buffers, + * boost::asio::transfer_all(), ec); @endcode + */ +template +std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, + boost::system::error_code& ec); + +/// Attempt to read a certain amount of data at the specified offset before +/// returning. +/** + * This function is used to read a certain number of bytes of data from a + * random access device at the specified offset. The call will block until one + * of the following conditions is true: + * + * @li The supplied buffers are full. That is, the bytes transferred is equal to + * the sum of the buffer sizes. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the device's + * read_some_at function. + * + * @param d The device from which the data is to be read. The type must support + * the SyncRandomAccessReadDevice concept. + * + * @param offset The offset at which the data will be read. + * + * @param buffers One or more buffers into which the data will be read. The sum + * of the buffer sizes indicates the maximum number of bytes to read from the + * device. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest read_some_at operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the device's read_some_at function. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code boost::asio::read_at(d, 42, boost::asio::buffer(data, size), + * boost::asio::transfer_at_least(32)); @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ +template +std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, + CompletionCondition completion_condition); + +/// Attempt to read a certain amount of data at the specified offset before +/// returning. +/** + * This function is used to read a certain number of bytes of data from a + * random access device at the specified offset. The call will block until one + * of the following conditions is true: + * + * @li The supplied buffers are full. That is, the bytes transferred is equal to + * the sum of the buffer sizes. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the device's + * read_some_at function. + * + * @param d The device from which the data is to be read. The type must support + * the SyncRandomAccessReadDevice concept. + * + * @param offset The offset at which the data will be read. + * + * @param buffers One or more buffers into which the data will be read. The sum + * of the buffer sizes indicates the maximum number of bytes to read from the + * device. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest read_some_at operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the device's read_some_at function. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. + */ +template +std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, boost::system::error_code& ec); + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +/// Attempt to read a certain amount of data at the specified offset before +/// returning. +/** + * This function is used to read a certain number of bytes of data from a + * random access device at the specified offset. The call will block until one + * of the following conditions is true: + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the device's + * read_some_at function. + * + * @param d The device from which the data is to be read. The type must support + * the SyncRandomAccessReadDevice concept. + * + * @param offset The offset at which the data will be read. + * + * @param b The basic_streambuf object into which the data will be read. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note This overload is equivalent to calling: + * @code boost::asio::read_at( + * d, 42, b, + * boost::asio::transfer_all()); @endcode + */ +template +std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, basic_streambuf& b); + +/// Attempt to read a certain amount of data at the specified offset before +/// returning. +/** + * This function is used to read a certain number of bytes of data from a + * random access device at the specified offset. The call will block until one + * of the following conditions is true: + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the device's + * read_some_at function. + * + * @param d The device from which the data is to be read. The type must support + * the SyncRandomAccessReadDevice concept. + * + * @param offset The offset at which the data will be read. + * + * @param b The basic_streambuf object into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes transferred. + * + * @note This overload is equivalent to calling: + * @code boost::asio::read_at( + * d, 42, b, + * boost::asio::transfer_all(), ec); @endcode + */ +template +std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, basic_streambuf& b, + boost::system::error_code& ec); + +/// Attempt to read a certain amount of data at the specified offset before +/// returning. +/** + * This function is used to read a certain number of bytes of data from a + * random access device at the specified offset. The call will block until one + * of the following conditions is true: + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the device's + * read_some_at function. + * + * @param d The device from which the data is to be read. The type must support + * the SyncRandomAccessReadDevice concept. + * + * @param offset The offset at which the data will be read. + * + * @param b The basic_streambuf object into which the data will be read. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest read_some_at operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the device's read_some_at function. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + */ +template +std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, basic_streambuf& b, + CompletionCondition completion_condition); + +/// Attempt to read a certain amount of data at the specified offset before +/// returning. +/** + * This function is used to read a certain number of bytes of data from a + * random access device at the specified offset. The call will block until one + * of the following conditions is true: + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the device's + * read_some_at function. + * + * @param d The device from which the data is to be read. The type must support + * the SyncRandomAccessReadDevice concept. + * + * @param offset The offset at which the data will be read. + * + * @param b The basic_streambuf object into which the data will be read. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest read_some_at operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the device's read_some_at function. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. + */ +template +std::size_t read_at(SyncRandomAccessReadDevice& d, + uint64_t offset, basic_streambuf& b, + CompletionCondition completion_condition, boost::system::error_code& ec); + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +/*@}*/ +/** + * @defgroup async_read_at boost::asio::async_read_at + * + * @brief The @c async_read_at function is a composed asynchronous operation + * that reads a certain amount of data at the specified offset. + */ +/*@{*/ + +/// Start an asynchronous operation to read a certain amount of data at the +/// specified offset. +/** + * This function is used to asynchronously read a certain number of bytes of + * data from a random access device at the specified offset. The function call + * always returns immediately. The asynchronous operation will continue until + * one of the following conditions is true: + * + * @li The supplied buffers are full. That is, the bytes transferred is equal to + * the sum of the buffer sizes. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the device's + * async_read_some_at function. + * + * @param d The device from which the data is to be read. The type must support + * the AsyncRandomAccessReadDevice concept. + * + * @param offset The offset at which the data will be read. + * + * @param buffers One or more buffers into which the data will be read. The sum + * of the buffer sizes indicates the maximum number of bytes to read from the + * device. Although the buffers object may be copied as necessary, ownership of + * the underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // Number of bytes copied into the buffers. If an error + * // occurred, this will be the number of bytes successfully + * // transferred prior to the error. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * boost::asio::async_read_at(d, 42, boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + * + * @note This overload is equivalent to calling: + * @code boost::asio::async_read_at( + * d, 42, buffers, + * boost::asio::transfer_all(), + * handler); @endcode + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, + const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + +/// Start an asynchronous operation to read a certain amount of data at the +/// specified offset. +/** + * This function is used to asynchronously read a certain number of bytes of + * data from a random access device at the specified offset. The function call + * always returns immediately. The asynchronous operation will continue until + * one of the following conditions is true: + * + * @li The supplied buffers are full. That is, the bytes transferred is equal to + * the sum of the buffer sizes. + * + * @li The completion_condition function object returns 0. + * + * @param d The device from which the data is to be read. The type must support + * the AsyncRandomAccessReadDevice concept. + * + * @param offset The offset at which the data will be read. + * + * @param buffers One or more buffers into which the data will be read. The sum + * of the buffer sizes indicates the maximum number of bytes to read from the + * device. Although the buffers object may be copied as necessary, ownership of + * the underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest async_read_some_at operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the device's async_read_some_at function. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // Number of bytes copied into the buffers. If an error + * // occurred, this will be the number of bytes successfully + * // transferred prior to the error. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code boost::asio::async_read_at(d, 42, + * boost::asio::buffer(data, size), + * boost::asio::transfer_at_least(32), + * handler); @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_at(AsyncRandomAccessReadDevice& d, + uint64_t offset, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +/// Start an asynchronous operation to read a certain amount of data at the +/// specified offset. +/** + * This function is used to asynchronously read a certain number of bytes of + * data from a random access device at the specified offset. The function call + * always returns immediately. The asynchronous operation will continue until + * one of the following conditions is true: + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the device's + * async_read_some_at function. + * + * @param d The device from which the data is to be read. The type must support + * the AsyncRandomAccessReadDevice concept. + * + * @param offset The offset at which the data will be read. + * + * @param b A basic_streambuf object into which the data will be read. Ownership + * of the streambuf is retained by the caller, which must guarantee that it + * remains valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // Number of bytes copied into the buffers. If an error + * // occurred, this will be the number of bytes successfully + * // transferred prior to the error. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note This overload is equivalent to calling: + * @code boost::asio::async_read_at( + * d, 42, b, + * boost::asio::transfer_all(), + * handler); @endcode + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, + basic_streambuf& b, BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + +/// Start an asynchronous operation to read a certain amount of data at the +/// specified offset. +/** + * This function is used to asynchronously read a certain number of bytes of + * data from a random access device at the specified offset. The function call + * always returns immediately. The asynchronous operation will continue until + * one of the following conditions is true: + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the device's + * async_read_some_at function. + * + * @param d The device from which the data is to be read. The type must support + * the AsyncRandomAccessReadDevice concept. + * + * @param offset The offset at which the data will be read. + * + * @param b A basic_streambuf object into which the data will be read. Ownership + * of the streambuf is retained by the caller, which must guarantee that it + * remains valid until the handler is called. + * + * @param completion_condition The function object to be called to determine + * whether the read operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest async_read_some_at operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the device's async_read_some_at function. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // Number of bytes copied into the buffers. If an error + * // occurred, this will be the number of bytes successfully + * // transferred prior to the error. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_at(AsyncRandomAccessReadDevice& d, + uint64_t offset, basic_streambuf& b, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +/*@}*/ + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // BOOST_ASIO_READ_AT_HPP diff --git a/boost/asio/read_until.hpp b/boost/asio/read_until.hpp new file mode 100644 index 0000000..96ed6a7 --- /dev/null +++ b/boost/asio/read_until.hpp @@ -0,0 +1,2797 @@ +// +// read_until.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_READ_UNTIL_HPP +#define BOOST_ASIO_READ_UNTIL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +# include +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +#include + +namespace boost { +namespace asio { + +namespace detail +{ + char (&has_result_type_helper(...))[2]; + + template + char has_result_type_helper(T*, typename T::result_type* = 0); + + template + struct has_result_type + { + enum { value = (sizeof((has_result_type_helper)((T*)(0))) == 1) }; + }; +} // namespace detail + +/// Type trait used to determine whether a type can be used as a match condition +/// function with read_until and async_read_until. +template +struct is_match_condition +{ +#if defined(GENERATING_DOCUMENTATION) + /// The value member is true if the type may be used as a match condition. + static const bool value; +#else + enum + { + value = boost::asio::is_function< + typename boost::asio::remove_pointer::type>::value + || detail::has_result_type::value + }; +#endif +}; + +/** + * @defgroup read_until boost::asio::read_until + * + * @brief The @c read_until function is a composed operation that reads data + * into a dynamic buffer sequence, or into a streambuf, until it contains a + * delimiter, matches a regular expression, or a function object indicates a + * match. + */ +/*@{*/ + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter character. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + * + * @par Example + * To read data into a @c std::string until a newline is encountered: + * @code std::string data; + * std::string n = boost::asio::read_until(s, + * boost::asio::dynamic_buffer(data), '\n'); + * std::string line = data.substr(0, n); + * data.erase(0, n); @endcode + * After the @c read_until operation completes successfully, the string @c data + * contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c b as + * follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. + */ +template +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, char delim, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter character. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. Returns 0 if an error occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + */ +template +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + char delim, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter string. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + * + * @par Example + * To read data into a @c std::string until a CR-LF sequence is encountered: + * @code std::string data; + * std::string n = boost::asio::read_until(s, + * boost::asio::dynamic_buffer(data), "\r\n"); + * std::string line = data.substr(0, n); + * data.erase(0, n); @endcode + * After the @c read_until operation completes successfully, the string @c data + * contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c b as + * follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. + */ +template +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_STRING_VIEW_PARAM delim, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter string. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. Returns 0 if an error occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + */ +template +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_STRING_VIEW_PARAM delim, + boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if defined(BOOST_ASIO_HAS_BOOST_REGEX) \ + || defined(GENERATING_DOCUMENTATION) + +/// Read data into a dynamic buffer sequence until some part of the data it +/// contains matches a regular expression. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains some data + * that matches a regular expression. The call will block until one of the + * following conditions is true: + * + * @li A substring of the dynamic buffer sequence's get area matches the + * regular expression. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains data that matches the regular expression, the function returns + * immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param expr The regular expression. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the substring that matches the regular expression. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the regular + * expression. An application will typically leave that data in the dynamic + * buffer sequence for a subsequent read_until operation to examine. + * + * @par Example + * To read data into a @c std::string until a CR-LF sequence is encountered: + * @code std::string data; + * std::string n = boost::asio::read_until(s, + * boost::asio::dynamic_buffer(data), boost::regex("\r\n")); + * std::string line = data.substr(0, n); + * data.erase(0, n); @endcode + * After the @c read_until operation completes successfully, the string @c data + * contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c b as + * follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. + */ +template +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + const boost::regex& expr, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +/// Read data into a dynamic buffer sequence until some part of the data it +/// contains matches a regular expression. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains some data + * that matches a regular expression. The call will block until one of the + * following conditions is true: + * + * @li A substring of the dynamic buffer sequence's get area matches the + * regular expression. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains data that matches the regular expression, the function returns + * immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param expr The regular expression. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the substring that matches the regular expression. Returns 0 + * if an error occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the regular + * expression. An application will typically leave that data in the dynamic + * buffer sequence for a subsequent read_until operation to examine. + */ +template +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + const boost::regex& expr, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) + // || defined(GENERATING_DOCUMENTATION) + +/// Read data into a dynamic buffer sequence until a function object indicates a +/// match. + +/** + * This function is used to read data into the specified dynamic buffer + * sequence until a user-defined match condition function object, when applied + * to the data contained in the dynamic buffer sequence, indicates a successful + * match. The call will block until one of the following conditions is true: + * + * @li The match condition function object returns a std::pair where the second + * element evaluates to true. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the match condition function object already indicates + * a match, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param match_condition The function object to be called to determine whether + * a match exists. The signature of the function object must be: + * @code pair match_condition(iterator begin, iterator end); + * @endcode + * where @c iterator represents the type: + * @code buffers_iterator + * @endcode + * The iterator parameters @c begin and @c end define the range of bytes to be + * scanned to determine whether there is a match. The @c first member of the + * return value is an iterator marking one-past-the-end of the bytes that have + * been consumed by the match function. This iterator is used to calculate the + * @c begin parameter for any subsequent invocation of the match condition. The + * @c second member of the return value is true if a match has been found, false + * otherwise. + * + * @returns The number of bytes in the dynamic_buffer's get area that + * have been fully consumed by the match function. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the function object. + * An application will typically leave that data in the dynamic buffer sequence + * for a subsequent read_until operation to examine. + + * @note The default implementation of the @c is_match_condition type trait + * evaluates to true for function pointers and function objects with a + * @c result_type typedef. It must be specialised for other user-defined + * function objects. + * + * @par Examples + * To read data into a dynamic buffer sequence until whitespace is encountered: + * @code typedef boost::asio::buffers_iterator< + * boost::asio::const_buffers_1> iterator; + * + * std::pair + * match_whitespace(iterator begin, iterator end) + * { + * iterator i = begin; + * while (i != end) + * if (std::isspace(*i++)) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * ... + * std::string data; + * boost::asio::read_until(s, data, match_whitespace); + * @endcode + * + * To read data into a @c std::string until a matching character is found: + * @code class match_char + * { + * public: + * explicit match_char(char c) : c_(c) {} + * + * template + * std::pair operator()( + * Iterator begin, Iterator end) const + * { + * Iterator i = begin; + * while (i != end) + * if (c_ == *i++) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * + * private: + * char c_; + * }; + * + * namespace asio { + * template <> struct is_match_condition + * : public boost::true_type {}; + * } // namespace asio + * ... + * std::string data; + * boost::asio::read_until(s, data, match_char('a')); + * @endcode + */ +template +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + MatchCondition match_condition, + typename enable_if< + is_match_condition::value + && is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +/// Read data into a dynamic buffer sequence until a function object indicates a +/// match. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until a user-defined match condition function object, when applied + * to the data contained in the dynamic buffer sequence, indicates a successful + * match. The call will block until one of the following conditions is true: + * + * @li The match condition function object returns a std::pair where the second + * element evaluates to true. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the match condition function object already indicates + * a match, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param match_condition The function object to be called to determine whether + * a match exists. The signature of the function object must be: + * @code pair match_condition(iterator begin, iterator end); + * @endcode + * where @c iterator represents the type: + * @code buffers_iterator + * @endcode + * The iterator parameters @c begin and @c end define the range of bytes to be + * scanned to determine whether there is a match. The @c first member of the + * return value is an iterator marking one-past-the-end of the bytes that have + * been consumed by the match function. This iterator is used to calculate the + * @c begin parameter for any subsequent invocation of the match condition. The + * @c second member of the return value is true if a match has been found, false + * otherwise. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area that + * have been fully consumed by the match function. Returns 0 if an error + * occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the function object. + * An application will typically leave that data in the dynamic buffer sequence + * for a subsequent read_until operation to examine. + * + * @note The default implementation of the @c is_match_condition type trait + * evaluates to true for function pointers and function objects with a + * @c result_type typedef. It must be specialised for other user-defined + * function objects. + */ +template +std::size_t read_until(SyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + MatchCondition match_condition, boost::system::error_code& ec, + typename enable_if< + is_match_condition::value + && is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +/// Read data into a streambuf until it contains a specified delimiter. +/** + * This function is used to read data into the specified streambuf until the + * streambuf's get area contains the specified delimiter. The call will block + * until one of the following conditions is true: + * + * @li The get area of the streambuf contains the specified delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the streambuf's get area already contains the + * delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param b A streambuf object into which the data will be read. + * + * @param delim The delimiter character. + * + * @returns The number of bytes in the streambuf's get area up to and including + * the delimiter. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note After a successful read_until operation, the streambuf may contain + * additional data beyond the delimiter. An application will typically leave + * that data in the streambuf for a subsequent read_until operation to examine. + * + * @par Example + * To read data into a streambuf until a newline is encountered: + * @code boost::asio::streambuf b; + * boost::asio::read_until(s, b, '\n'); + * std::istream is(&b); + * std::string line; + * std::getline(is, line); @endcode + * After the @c read_until operation completes successfully, the buffer @c b + * contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode + * The call to @c std::getline then extracts the data up to and including the + * newline (which is discarded), so that the string @c line contains: + * @code { 'a', 'b', ..., 'c' } @endcode + * The remaining data is left in the buffer @c b as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. + */ +template +std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, char delim); + +/// Read data into a streambuf until it contains a specified delimiter. +/** + * This function is used to read data into the specified streambuf until the + * streambuf's get area contains the specified delimiter. The call will block + * until one of the following conditions is true: + * + * @li The get area of the streambuf contains the specified delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the streambuf's get area already contains the + * delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param b A streambuf object into which the data will be read. + * + * @param delim The delimiter character. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the streambuf's get area up to and including + * the delimiter. Returns 0 if an error occurred. + * + * @note After a successful read_until operation, the streambuf may contain + * additional data beyond the delimiter. An application will typically leave + * that data in the streambuf for a subsequent read_until operation to examine. + */ +template +std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, char delim, + boost::system::error_code& ec); + +/// Read data into a streambuf until it contains a specified delimiter. +/** + * This function is used to read data into the specified streambuf until the + * streambuf's get area contains the specified delimiter. The call will block + * until one of the following conditions is true: + * + * @li The get area of the streambuf contains the specified delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the streambuf's get area already contains the + * delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param b A streambuf object into which the data will be read. + * + * @param delim The delimiter string. + * + * @returns The number of bytes in the streambuf's get area up to and including + * the delimiter. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note After a successful read_until operation, the streambuf may contain + * additional data beyond the delimiter. An application will typically leave + * that data in the streambuf for a subsequent read_until operation to examine. + * + * @par Example + * To read data into a streambuf until a newline is encountered: + * @code boost::asio::streambuf b; + * boost::asio::read_until(s, b, "\r\n"); + * std::istream is(&b); + * std::string line; + * std::getline(is, line); @endcode + * After the @c read_until operation completes successfully, the buffer @c b + * contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c std::getline then extracts the data up to and including the + * newline (which is discarded), so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r' } @endcode + * The remaining data is left in the buffer @c b as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. + */ +template +std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, + BOOST_ASIO_STRING_VIEW_PARAM delim); + +/// Read data into a streambuf until it contains a specified delimiter. +/** + * This function is used to read data into the specified streambuf until the + * streambuf's get area contains the specified delimiter. The call will block + * until one of the following conditions is true: + * + * @li The get area of the streambuf contains the specified delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the streambuf's get area already contains the + * delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param b A streambuf object into which the data will be read. + * + * @param delim The delimiter string. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the streambuf's get area up to and including + * the delimiter. Returns 0 if an error occurred. + * + * @note After a successful read_until operation, the streambuf may contain + * additional data beyond the delimiter. An application will typically leave + * that data in the streambuf for a subsequent read_until operation to examine. + */ +template +std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, + BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec); + +#if defined(BOOST_ASIO_HAS_BOOST_REGEX) \ + || defined(GENERATING_DOCUMENTATION) + +/// Read data into a streambuf until some part of the data it contains matches +/// a regular expression. +/** + * This function is used to read data into the specified streambuf until the + * streambuf's get area contains some data that matches a regular expression. + * The call will block until one of the following conditions is true: + * + * @li A substring of the streambuf's get area matches the regular expression. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the streambuf's get area already contains data that + * matches the regular expression, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param b A streambuf object into which the data will be read. + * + * @param expr The regular expression. + * + * @returns The number of bytes in the streambuf's get area up to and including + * the substring that matches the regular expression. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note After a successful read_until operation, the streambuf may contain + * additional data beyond that which matched the regular expression. An + * application will typically leave that data in the streambuf for a subsequent + * read_until operation to examine. + * + * @par Example + * To read data into a streambuf until a CR-LF sequence is encountered: + * @code boost::asio::streambuf b; + * boost::asio::read_until(s, b, boost::regex("\r\n")); + * std::istream is(&b); + * std::string line; + * std::getline(is, line); @endcode + * After the @c read_until operation completes successfully, the buffer @c b + * contains the data which matched the regular expression: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c std::getline then extracts the data up to and including the + * newline (which is discarded), so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r' } @endcode + * The remaining data is left in the buffer @c b as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. + */ +template +std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, const boost::regex& expr); + +/// Read data into a streambuf until some part of the data it contains matches +/// a regular expression. +/** + * This function is used to read data into the specified streambuf until the + * streambuf's get area contains some data that matches a regular expression. + * The call will block until one of the following conditions is true: + * + * @li A substring of the streambuf's get area matches the regular expression. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the streambuf's get area already contains data that + * matches the regular expression, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param b A streambuf object into which the data will be read. + * + * @param expr The regular expression. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the streambuf's get area up to and including + * the substring that matches the regular expression. Returns 0 if an error + * occurred. + * + * @note After a successful read_until operation, the streambuf may contain + * additional data beyond that which matched the regular expression. An + * application will typically leave that data in the streambuf for a subsequent + * read_until operation to examine. + */ +template +std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, const boost::regex& expr, + boost::system::error_code& ec); + +#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) + // || defined(GENERATING_DOCUMENTATION) + +/// Read data into a streambuf until a function object indicates a match. +/** + * This function is used to read data into the specified streambuf until a + * user-defined match condition function object, when applied to the data + * contained in the streambuf, indicates a successful match. The call will + * block until one of the following conditions is true: + * + * @li The match condition function object returns a std::pair where the second + * element evaluates to true. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the match condition function object already indicates + * a match, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param b A streambuf object into which the data will be read. + * + * @param match_condition The function object to be called to determine whether + * a match exists. The signature of the function object must be: + * @code pair match_condition(iterator begin, iterator end); + * @endcode + * where @c iterator represents the type: + * @code buffers_iterator::const_buffers_type> + * @endcode + * The iterator parameters @c begin and @c end define the range of bytes to be + * scanned to determine whether there is a match. The @c first member of the + * return value is an iterator marking one-past-the-end of the bytes that have + * been consumed by the match function. This iterator is used to calculate the + * @c begin parameter for any subsequent invocation of the match condition. The + * @c second member of the return value is true if a match has been found, false + * otherwise. + * + * @returns The number of bytes in the streambuf's get area that have been fully + * consumed by the match function. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note After a successful read_until operation, the streambuf may contain + * additional data beyond that which matched the function object. An application + * will typically leave that data in the streambuf for a subsequent read_until + * operation to examine. + * + * @note The default implementation of the @c is_match_condition type trait + * evaluates to true for function pointers and function objects with a + * @c result_type typedef. It must be specialised for other user-defined + * function objects. + * + * @par Examples + * To read data into a streambuf until whitespace is encountered: + * @code typedef boost::asio::buffers_iterator< + * boost::asio::streambuf::const_buffers_type> iterator; + * + * std::pair + * match_whitespace(iterator begin, iterator end) + * { + * iterator i = begin; + * while (i != end) + * if (std::isspace(*i++)) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * ... + * boost::asio::streambuf b; + * boost::asio::read_until(s, b, match_whitespace); + * @endcode + * + * To read data into a streambuf until a matching character is found: + * @code class match_char + * { + * public: + * explicit match_char(char c) : c_(c) {} + * + * template + * std::pair operator()( + * Iterator begin, Iterator end) const + * { + * Iterator i = begin; + * while (i != end) + * if (c_ == *i++) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * + * private: + * char c_; + * }; + * + * namespace asio { + * template <> struct is_match_condition + * : public boost::true_type {}; + * } // namespace asio + * ... + * boost::asio::streambuf b; + * boost::asio::read_until(s, b, match_char('a')); + * @endcode + */ +template +std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, MatchCondition match_condition, + typename enable_if::value>::type* = 0); + +/// Read data into a streambuf until a function object indicates a match. +/** + * This function is used to read data into the specified streambuf until a + * user-defined match condition function object, when applied to the data + * contained in the streambuf, indicates a successful match. The call will + * block until one of the following conditions is true: + * + * @li The match condition function object returns a std::pair where the second + * element evaluates to true. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the match condition function object already indicates + * a match, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param b A streambuf object into which the data will be read. + * + * @param match_condition The function object to be called to determine whether + * a match exists. The signature of the function object must be: + * @code pair match_condition(iterator begin, iterator end); + * @endcode + * where @c iterator represents the type: + * @code buffers_iterator::const_buffers_type> + * @endcode + * The iterator parameters @c begin and @c end define the range of bytes to be + * scanned to determine whether there is a match. The @c first member of the + * return value is an iterator marking one-past-the-end of the bytes that have + * been consumed by the match function. This iterator is used to calculate the + * @c begin parameter for any subsequent invocation of the match condition. The + * @c second member of the return value is true if a match has been found, false + * otherwise. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the streambuf's get area that have been fully + * consumed by the match function. Returns 0 if an error occurred. + * + * @note After a successful read_until operation, the streambuf may contain + * additional data beyond that which matched the function object. An application + * will typically leave that data in the streambuf for a subsequent read_until + * operation to examine. + * + * @note The default implementation of the @c is_match_condition type trait + * evaluates to true for function pointers and function objects with a + * @c result_type typedef. It must be specialised for other user-defined + * function objects. + */ +template +std::size_t read_until(SyncReadStream& s, + boost::asio::basic_streambuf& b, + MatchCondition match_condition, boost::system::error_code& ec, + typename enable_if::value>::type* = 0); + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter character. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + * + * @par Example + * To read data into a @c std::string until a newline is encountered: + * @code std::string data; + * std::string n = boost::asio::read_until(s, + * boost::asio::dynamic_buffer(data), '\n'); + * std::string line = data.substr(0, n); + * data.erase(0, n); @endcode + * After the @c read_until operation completes successfully, the string @c data + * contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c b as + * follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. + */ +template +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, char delim, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter character. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. Returns 0 if an error occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + */ +template +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + char delim, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter string. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + * + * @par Example + * To read data into a @c std::string until a CR-LF sequence is encountered: + * @code std::string data; + * std::string n = boost::asio::read_until(s, + * boost::asio::dynamic_buffer(data), "\r\n"); + * std::string line = data.substr(0, n); + * data.erase(0, n); @endcode + * After the @c read_until operation completes successfully, the string @c data + * contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c b as + * follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. + */ +template +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + BOOST_ASIO_STRING_VIEW_PARAM delim, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +/// Read data into a dynamic buffer sequence until it contains a specified +/// delimiter. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains the specified + * delimiter. The call will block until one of the following conditions is + * true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains the delimiter, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * + * @param delim The delimiter string. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the delimiter. Returns 0 if an error occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond the delimiter. An application will + * typically leave that data in the dynamic buffer sequence for a subsequent + * read_until operation to examine. + */ +template +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if defined(BOOST_ASIO_HAS_BOOST_REGEX) \ + || defined(GENERATING_DOCUMENTATION) + +/// Read data into a dynamic buffer sequence until some part of the data it +/// contains matches a regular expression. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains some data + * that matches a regular expression. The call will block until one of the + * following conditions is true: + * + * @li A substring of the dynamic buffer sequence's get area matches the + * regular expression. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains data that matches the regular expression, the function returns + * immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param expr The regular expression. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the substring that matches the regular expression. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the regular + * expression. An application will typically leave that data in the dynamic + * buffer sequence for a subsequent read_until operation to examine. + * + * @par Example + * To read data into a @c std::string until a CR-LF sequence is encountered: + * @code std::string data; + * std::string n = boost::asio::read_until(s, + * boost::asio::dynamic_buffer(data), boost::regex("\r\n")); + * std::string line = data.substr(0, n); + * data.erase(0, n); @endcode + * After the @c read_until operation completes successfully, the string @c data + * contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c b as + * follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c read_until operation. + */ +template +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + const boost::regex& expr, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +/// Read data into a dynamic buffer sequence until some part of the data it +/// contains matches a regular expression. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until the dynamic buffer sequence's get area contains some data + * that matches a regular expression. The call will block until one of the + * following conditions is true: + * + * @li A substring of the dynamic buffer sequence's get area matches the + * regular expression. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the dynamic buffer sequence's get area already + * contains data that matches the regular expression, the function returns + * immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param expr The regular expression. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area up to + * and including the substring that matches the regular expression. Returns 0 + * if an error occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the regular + * expression. An application will typically leave that data in the dynamic + * buffer sequence for a subsequent read_until operation to examine. + */ +template +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + const boost::regex& expr, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) + // || defined(GENERATING_DOCUMENTATION) + +/// Read data into a dynamic buffer sequence until a function object indicates a +/// match. + +/** + * This function is used to read data into the specified dynamic buffer + * sequence until a user-defined match condition function object, when applied + * to the data contained in the dynamic buffer sequence, indicates a successful + * match. The call will block until one of the following conditions is true: + * + * @li The match condition function object returns a std::pair where the second + * element evaluates to true. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the match condition function object already indicates + * a match, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param match_condition The function object to be called to determine whether + * a match exists. The signature of the function object must be: + * @code pair match_condition(iterator begin, iterator end); + * @endcode + * where @c iterator represents the type: + * @code buffers_iterator + * @endcode + * The iterator parameters @c begin and @c end define the range of bytes to be + * scanned to determine whether there is a match. The @c first member of the + * return value is an iterator marking one-past-the-end of the bytes that have + * been consumed by the match function. This iterator is used to calculate the + * @c begin parameter for any subsequent invocation of the match condition. The + * @c second member of the return value is true if a match has been found, false + * otherwise. + * + * @returns The number of bytes in the dynamic_buffer's get area that + * have been fully consumed by the match function. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the function object. + * An application will typically leave that data in the dynamic buffer sequence + * for a subsequent read_until operation to examine. + + * @note The default implementation of the @c is_match_condition type trait + * evaluates to true for function pointers and function objects with a + * @c result_type typedef. It must be specialised for other user-defined + * function objects. + * + * @par Examples + * To read data into a dynamic buffer sequence until whitespace is encountered: + * @code typedef boost::asio::buffers_iterator< + * boost::asio::const_buffers_1> iterator; + * + * std::pair + * match_whitespace(iterator begin, iterator end) + * { + * iterator i = begin; + * while (i != end) + * if (std::isspace(*i++)) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * ... + * std::string data; + * boost::asio::read_until(s, data, match_whitespace); + * @endcode + * + * To read data into a @c std::string until a matching character is found: + * @code class match_char + * { + * public: + * explicit match_char(char c) : c_(c) {} + * + * template + * std::pair operator()( + * Iterator begin, Iterator end) const + * { + * Iterator i = begin; + * while (i != end) + * if (c_ == *i++) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * + * private: + * char c_; + * }; + * + * namespace asio { + * template <> struct is_match_condition + * : public boost::true_type {}; + * } // namespace asio + * ... + * std::string data; + * boost::asio::read_until(s, data, match_char('a')); + * @endcode + */ +template +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + MatchCondition match_condition, + typename enable_if< + is_match_condition::value + && is_dynamic_buffer_v2::value + >::type* = 0); + +/// Read data into a dynamic buffer sequence until a function object indicates a +/// match. +/** + * This function is used to read data into the specified dynamic buffer + * sequence until a user-defined match condition function object, when applied + * to the data contained in the dynamic buffer sequence, indicates a successful + * match. The call will block until one of the following conditions is true: + * + * @li The match condition function object returns a std::pair where the second + * element evaluates to true. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * read_some function. If the match condition function object already indicates + * a match, the function returns immediately. + * + * @param s The stream from which the data is to be read. The type must support + * the SyncReadStream concept. + * + * @param buffers A dynamic buffer sequence into which the data will be read. + * + * @param match_condition The function object to be called to determine whether + * a match exists. The signature of the function object must be: + * @code pair match_condition(iterator begin, iterator end); + * @endcode + * where @c iterator represents the type: + * @code buffers_iterator + * @endcode + * The iterator parameters @c begin and @c end define the range of bytes to be + * scanned to determine whether there is a match. The @c first member of the + * return value is an iterator marking one-past-the-end of the bytes that have + * been consumed by the match function. This iterator is used to calculate the + * @c begin parameter for any subsequent invocation of the match condition. The + * @c second member of the return value is true if a match has been found, false + * otherwise. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes in the dynamic buffer sequence's get area that + * have been fully consumed by the match function. Returns 0 if an error + * occurred. + * + * @note After a successful read_until operation, the dynamic buffer sequence + * may contain additional data beyond that which matched the function object. + * An application will typically leave that data in the dynamic buffer sequence + * for a subsequent read_until operation to examine. + * + * @note The default implementation of the @c is_match_condition type trait + * evaluates to true for function pointers and function objects with a + * @c result_type typedef. It must be specialised for other user-defined + * function objects. + */ +template +std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, + MatchCondition match_condition, boost::system::error_code& ec, + typename enable_if< + is_match_condition::value + && is_dynamic_buffer_v2::value + >::type* = 0); + +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +/*@}*/ +/** + * @defgroup async_read_until boost::asio::async_read_until + * + * @brief The @c async_read_until function is a composed asynchronous operation + * that reads data into a dynamic buffer sequence, or into a streambuf, until + * it contains a delimiter, matches a regular expression, or a function object + * indicates a match. + */ +/*@{*/ + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until it contains a specified delimiter. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until the dynamic buffer sequence's get area contains the + * specified delimiter. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a composed operation. If + * the dynamic buffer sequence's get area already contains the delimiter, this + * asynchronous operation completes immediately. The program must ensure that + * the stream performs no other read operations (such as async_read, + * async_read_until, the stream's async_read_some function, or any other + * composed operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param delim The delimiter character. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // The number of bytes in the dynamic buffer sequence's + * // get area up to and including the delimiter. + * // 0 if an error occurred. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond the delimiter. An application + * will typically leave that data in the dynamic buffer sequence for a + * subsequent async_read_until operation to examine. + * + * @par Example + * To asynchronously read data into a @c std::string until a newline is + * encountered: + * @code std::string data; + * ... + * void handler(const boost::system::error_code& e, std::size_t size) + * { + * if (!e) + * { + * std::string line = data.substr(0, n); + * data.erase(0, n); + * ... + * } + * } + * ... + * boost::asio::async_read_until(s, data, '\n', handler); @endcode + * After the @c async_read_until operation completes successfully, the buffer + * @c data contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c data + * as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until it contains a specified delimiter. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until the dynamic buffer sequence's get area contains the + * specified delimiter. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a composed operation. If + * the dynamic buffer sequence's get area already contains the delimiter, this + * asynchronous operation completes immediately. The program must ensure that + * the stream performs no other read operations (such as async_read, + * async_read_until, the stream's async_read_some function, or any other + * composed operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param delim The delimiter string. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // The number of bytes in the dynamic buffer sequence's + * // get area up to and including the delimiter. + * // 0 if an error occurred. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond the delimiter. An application + * will typically leave that data in the dynamic buffer sequence for a + * subsequent async_read_until operation to examine. + * + * @par Example + * To asynchronously read data into a @c std::string until a CR-LF sequence is + * encountered: + * @code std::string data; + * ... + * void handler(const boost::system::error_code& e, std::size_t size) + * { + * if (!e) + * { + * std::string line = data.substr(0, n); + * data.erase(0, n); + * ... + * } + * } + * ... + * boost::asio::async_read_until(s, data, "\r\n", handler); @endcode + * After the @c async_read_until operation completes successfully, the string + * @c data contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the string @c data + * as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_STRING_VIEW_PARAM delim, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if defined(BOOST_ASIO_HAS_BOOST_REGEX) \ + || defined(GENERATING_DOCUMENTATION) + +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until some part of its data matches a regular expression. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until the dynamic buffer sequence's get area contains some + * data that matches a regular expression. The function call always returns + * immediately. The asynchronous operation will continue until one of the + * following conditions is true: + * + * @li A substring of the dynamic buffer sequence's get area matches the regular + * expression. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a composed operation. If + * the dynamic buffer sequence's get area already contains data that matches + * the regular expression, this asynchronous operation completes immediately. + * The program must ensure that the stream performs no other read operations + * (such as async_read, async_read_until, the stream's async_read_some + * function, or any other composed operations that perform reads) until this + * operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param expr The regular expression. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // The number of bytes in the dynamic buffer + * // sequence's get area up to and including the + * // substring that matches the regular expression. + * // 0 if an error occurred. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond that which matched the regular + * expression. An application will typically leave that data in the dynamic + * buffer sequence for a subsequent async_read_until operation to examine. + * + * @par Example + * To asynchronously read data into a @c std::string until a CR-LF sequence is + * encountered: + * @code std::string data; + * ... + * void handler(const boost::system::error_code& e, std::size_t size) + * { + * if (!e) + * { + * std::string line = data.substr(0, n); + * data.erase(0, n); + * ... + * } + * } + * ... + * boost::asio::async_read_until(s, data, + * boost::regex("\r\n"), handler); @endcode + * After the @c async_read_until operation completes successfully, the string + * @c data contains the data which matched the regular expression: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the match, + * so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the string @c data + * as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + const boost::regex& expr, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) + // || defined(GENERATING_DOCUMENTATION) + +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until a function object indicates a match. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until a user-defined match condition function object, when + * applied to the data contained in the dynamic buffer sequence, indicates a + * successful match. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li The match condition function object returns a std::pair where the second + * element evaluates to true. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a composed operation. If + * the match condition function object already indicates a match, this + * asynchronous operation completes immediately. The program must ensure that + * the stream performs no other read operations (such as async_read, + * async_read_until, the stream's async_read_some function, or any other + * composed operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param match_condition The function object to be called to determine whether + * a match exists. The signature of the function object must be: + * @code pair match_condition(iterator begin, iterator end); + * @endcode + * where @c iterator represents the type: + * @code buffers_iterator + * @endcode + * The iterator parameters @c begin and @c end define the range of bytes to be + * scanned to determine whether there is a match. The @c first member of the + * return value is an iterator marking one-past-the-end of the bytes that have + * been consumed by the match function. This iterator is used to calculate the + * @c begin parameter for any subsequent invocation of the match condition. The + * @c second member of the return value is true if a match has been found, false + * otherwise. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // The number of bytes in the dynamic buffer sequence's + * // get area that have been fully consumed by the match + * // function. O if an error occurred. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond that which matched the function + * object. An application will typically leave that data in the dynamic buffer + * sequence for a subsequent async_read_until operation to examine. + * + * @note The default implementation of the @c is_match_condition type trait + * evaluates to true for function pointers and function objects with a + * @c result_type typedef. It must be specialised for other user-defined + * function objects. + * + * @par Examples + * To asynchronously read data into a @c std::string until whitespace is + * encountered: + * @code typedef boost::asio::buffers_iterator< + * boost::asio::const_buffers_1> iterator; + * + * std::pair + * match_whitespace(iterator begin, iterator end) + * { + * iterator i = begin; + * while (i != end) + * if (std::isspace(*i++)) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * ... + * void handler(const boost::system::error_code& e, std::size_t size); + * ... + * std::string data; + * boost::asio::async_read_until(s, data, match_whitespace, handler); + * @endcode + * + * To asynchronously read data into a @c std::string until a matching character + * is found: + * @code class match_char + * { + * public: + * explicit match_char(char c) : c_(c) {} + * + * template + * std::pair operator()( + * Iterator begin, Iterator end) const + * { + * Iterator i = begin; + * while (i != end) + * if (c_ == *i++) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * + * private: + * char c_; + * }; + * + * namespace asio { + * template <> struct is_match_condition + * : public boost::true_type {}; + * } // namespace asio + * ... + * void handler(const boost::system::error_code& e, std::size_t size); + * ... + * std::string data; + * boost::asio::async_read_until(s, data, match_char('a'), handler); + * @endcode + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_match_condition::value + && is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +/// Start an asynchronous operation to read data into a streambuf until it +/// contains a specified delimiter. +/** + * This function is used to asynchronously read data into the specified + * streambuf until the streambuf's get area contains the specified delimiter. + * The function call always returns immediately. The asynchronous operation + * will continue until one of the following conditions is true: + * + * @li The get area of the streambuf contains the specified delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a composed operation. If + * the streambuf's get area already contains the delimiter, this asynchronous + * operation completes immediately. The program must ensure that the stream + * performs no other read operations (such as async_read, async_read_until, the + * stream's async_read_some function, or any other composed operations that + * perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param b A streambuf object into which the data will be read. Ownership of + * the streambuf is retained by the caller, which must guarantee that it remains + * valid until the handler is called. + * + * @param delim The delimiter character. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // The number of bytes in the streambuf's get + * // area up to and including the delimiter. + * // 0 if an error occurred. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note After a successful async_read_until operation, the streambuf may + * contain additional data beyond the delimiter. An application will typically + * leave that data in the streambuf for a subsequent async_read_until operation + * to examine. + * + * @par Example + * To asynchronously read data into a streambuf until a newline is encountered: + * @code boost::asio::streambuf b; + * ... + * void handler(const boost::system::error_code& e, std::size_t size) + * { + * if (!e) + * { + * std::istream is(&b); + * std::string line; + * std::getline(is, line); + * ... + * } + * } + * ... + * boost::asio::async_read_until(s, b, '\n', handler); @endcode + * After the @c async_read_until operation completes successfully, the buffer + * @c b contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode + * The call to @c std::getline then extracts the data up to and including the + * newline (which is discarded), so that the string @c line contains: + * @code { 'a', 'b', ..., 'c' } @endcode + * The remaining data is left in the buffer @c b as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf& b, + char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + +/// Start an asynchronous operation to read data into a streambuf until it +/// contains a specified delimiter. +/** + * This function is used to asynchronously read data into the specified + * streambuf until the streambuf's get area contains the specified delimiter. + * The function call always returns immediately. The asynchronous operation + * will continue until one of the following conditions is true: + * + * @li The get area of the streambuf contains the specified delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a composed operation. If + * the streambuf's get area already contains the delimiter, this asynchronous + * operation completes immediately. The program must ensure that the stream + * performs no other read operations (such as async_read, async_read_until, the + * stream's async_read_some function, or any other composed operations that + * perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param b A streambuf object into which the data will be read. Ownership of + * the streambuf is retained by the caller, which must guarantee that it remains + * valid until the handler is called. + * + * @param delim The delimiter string. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // The number of bytes in the streambuf's get + * // area up to and including the delimiter. + * // 0 if an error occurred. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note After a successful async_read_until operation, the streambuf may + * contain additional data beyond the delimiter. An application will typically + * leave that data in the streambuf for a subsequent async_read_until operation + * to examine. + * + * @par Example + * To asynchronously read data into a streambuf until a newline is encountered: + * @code boost::asio::streambuf b; + * ... + * void handler(const boost::system::error_code& e, std::size_t size) + * { + * if (!e) + * { + * std::istream is(&b); + * std::string line; + * std::getline(is, line); + * ... + * } + * } + * ... + * boost::asio::async_read_until(s, b, "\r\n", handler); @endcode + * After the @c async_read_until operation completes successfully, the buffer + * @c b contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c std::getline then extracts the data up to and including the + * newline (which is discarded), so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r' } @endcode + * The remaining data is left in the buffer @c b as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf& b, + BOOST_ASIO_STRING_VIEW_PARAM delim, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + +#if defined(BOOST_ASIO_HAS_BOOST_REGEX) \ + || defined(GENERATING_DOCUMENTATION) + +/// Start an asynchronous operation to read data into a streambuf until some +/// part of its data matches a regular expression. +/** + * This function is used to asynchronously read data into the specified + * streambuf until the streambuf's get area contains some data that matches a + * regular expression. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li A substring of the streambuf's get area matches the regular expression. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a composed operation. If + * the streambuf's get area already contains data that matches the regular + * expression, this asynchronous operation completes immediately. The program + * must ensure that the stream performs no other read operations (such as + * async_read, async_read_until, the stream's async_read_some function, or any + * other composed operations that perform reads) until this operation + * completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param b A streambuf object into which the data will be read. Ownership of + * the streambuf is retained by the caller, which must guarantee that it remains + * valid until the handler is called. + * + * @param expr The regular expression. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // The number of bytes in the streambuf's get + * // area up to and including the substring + * // that matches the regular. expression. + * // 0 if an error occurred. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note After a successful async_read_until operation, the streambuf may + * contain additional data beyond that which matched the regular expression. An + * application will typically leave that data in the streambuf for a subsequent + * async_read_until operation to examine. + * + * @par Example + * To asynchronously read data into a streambuf until a CR-LF sequence is + * encountered: + * @code boost::asio::streambuf b; + * ... + * void handler(const boost::system::error_code& e, std::size_t size) + * { + * if (!e) + * { + * std::istream is(&b); + * std::string line; + * std::getline(is, line); + * ... + * } + * } + * ... + * boost::asio::async_read_until(s, b, boost::regex("\r\n"), handler); @endcode + * After the @c async_read_until operation completes successfully, the buffer + * @c b contains the data which matched the regular expression: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c std::getline then extracts the data up to and including the + * newline (which is discarded), so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r' } @endcode + * The remaining data is left in the buffer @c b as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf& b, const boost::regex& expr, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler); + +#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) + // || defined(GENERATING_DOCUMENTATION) + +/// Start an asynchronous operation to read data into a streambuf until a +/// function object indicates a match. +/** + * This function is used to asynchronously read data into the specified + * streambuf until a user-defined match condition function object, when applied + * to the data contained in the streambuf, indicates a successful match. The + * function call always returns immediately. The asynchronous operation will + * continue until one of the following conditions is true: + * + * @li The match condition function object returns a std::pair where the second + * element evaluates to true. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a composed operation. If + * the match condition function object already indicates a match, this + * asynchronous operation completes immediately. The program must ensure that + * the stream performs no other read operations (such as async_read, + * async_read_until, the stream's async_read_some function, or any other + * composed operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param b A streambuf object into which the data will be read. + * + * @param match_condition The function object to be called to determine whether + * a match exists. The signature of the function object must be: + * @code pair match_condition(iterator begin, iterator end); + * @endcode + * where @c iterator represents the type: + * @code buffers_iterator::const_buffers_type> + * @endcode + * The iterator parameters @c begin and @c end define the range of bytes to be + * scanned to determine whether there is a match. The @c first member of the + * return value is an iterator marking one-past-the-end of the bytes that have + * been consumed by the match function. This iterator is used to calculate the + * @c begin parameter for any subsequent invocation of the match condition. The + * @c second member of the return value is true if a match has been found, false + * otherwise. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // The number of bytes in the streambuf's get + * // area that have been fully consumed by the + * // match function. O if an error occurred. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note After a successful async_read_until operation, the streambuf may + * contain additional data beyond that which matched the function object. An + * application will typically leave that data in the streambuf for a subsequent + * async_read_until operation to examine. + * + * @note The default implementation of the @c is_match_condition type trait + * evaluates to true for function pointers and function objects with a + * @c result_type typedef. It must be specialised for other user-defined + * function objects. + * + * @par Examples + * To asynchronously read data into a streambuf until whitespace is encountered: + * @code typedef boost::asio::buffers_iterator< + * boost::asio::streambuf::const_buffers_type> iterator; + * + * std::pair + * match_whitespace(iterator begin, iterator end) + * { + * iterator i = begin; + * while (i != end) + * if (std::isspace(*i++)) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * ... + * void handler(const boost::system::error_code& e, std::size_t size); + * ... + * boost::asio::streambuf b; + * boost::asio::async_read_until(s, b, match_whitespace, handler); + * @endcode + * + * To asynchronously read data into a streambuf until a matching character is + * found: + * @code class match_char + * { + * public: + * explicit match_char(char c) : c_(c) {} + * + * template + * std::pair operator()( + * Iterator begin, Iterator end) const + * { + * Iterator i = begin; + * while (i != end) + * if (c_ == *i++) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * + * private: + * char c_; + * }; + * + * namespace asio { + * template <> struct is_match_condition + * : public boost::true_type {}; + * } // namespace asio + * ... + * void handler(const boost::system::error_code& e, std::size_t size); + * ... + * boost::asio::streambuf b; + * boost::asio::async_read_until(s, b, match_char('a'), handler); + * @endcode + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, + boost::asio::basic_streambuf& b, + MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if::value>::type* = 0); + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until it contains a specified delimiter. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until the dynamic buffer sequence's get area contains the + * specified delimiter. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a composed operation. If + * the dynamic buffer sequence's get area already contains the delimiter, this + * asynchronous operation completes immediately. The program must ensure that + * the stream performs no other read operations (such as async_read, + * async_read_until, the stream's async_read_some function, or any other + * composed operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param delim The delimiter character. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // The number of bytes in the dynamic buffer sequence's + * // get area up to and including the delimiter. + * // 0 if an error occurred. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond the delimiter. An application + * will typically leave that data in the dynamic buffer sequence for a + * subsequent async_read_until operation to examine. + * + * @par Example + * To asynchronously read data into a @c std::string until a newline is + * encountered: + * @code std::string data; + * ... + * void handler(const boost::system::error_code& e, std::size_t size) + * { + * if (!e) + * { + * std::string line = data.substr(0, n); + * data.erase(0, n); + * ... + * } + * } + * ... + * boost::asio::async_read_until(s, data, '\n', handler); @endcode + * After the @c async_read_until operation completes successfully, the buffer + * @c data contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the buffer @c data + * as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, + char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until it contains a specified delimiter. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until the dynamic buffer sequence's get area contains the + * specified delimiter. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li The get area of the dynamic buffer sequence contains the specified + * delimiter. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a composed operation. If + * the dynamic buffer sequence's get area already contains the delimiter, this + * asynchronous operation completes immediately. The program must ensure that + * the stream performs no other read operations (such as async_read, + * async_read_until, the stream's async_read_some function, or any other + * composed operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param delim The delimiter string. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // The number of bytes in the dynamic buffer sequence's + * // get area up to and including the delimiter. + * // 0 if an error occurred. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond the delimiter. An application + * will typically leave that data in the dynamic buffer sequence for a + * subsequent async_read_until operation to examine. + * + * @par Example + * To asynchronously read data into a @c std::string until a CR-LF sequence is + * encountered: + * @code std::string data; + * ... + * void handler(const boost::system::error_code& e, std::size_t size) + * { + * if (!e) + * { + * std::string line = data.substr(0, n); + * data.erase(0, n); + * ... + * } + * } + * ... + * boost::asio::async_read_until(s, data, "\r\n", handler); @endcode + * After the @c async_read_until operation completes successfully, the string + * @c data contains the delimiter: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the + * delimiter, so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the string @c data + * as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, + BOOST_ASIO_STRING_VIEW_PARAM delim, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if defined(BOOST_ASIO_HAS_BOOST_REGEX) \ + || defined(GENERATING_DOCUMENTATION) + +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until some part of its data matches a regular expression. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until the dynamic buffer sequence's get area contains some + * data that matches a regular expression. The function call always returns + * immediately. The asynchronous operation will continue until one of the + * following conditions is true: + * + * @li A substring of the dynamic buffer sequence's get area matches the regular + * expression. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a composed operation. If + * the dynamic buffer sequence's get area already contains data that matches + * the regular expression, this asynchronous operation completes immediately. + * The program must ensure that the stream performs no other read operations + * (such as async_read, async_read_until, the stream's async_read_some + * function, or any other composed operations that perform reads) until this + * operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param expr The regular expression. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // The number of bytes in the dynamic buffer + * // sequence's get area up to and including the + * // substring that matches the regular expression. + * // 0 if an error occurred. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond that which matched the regular + * expression. An application will typically leave that data in the dynamic + * buffer sequence for a subsequent async_read_until operation to examine. + * + * @par Example + * To asynchronously read data into a @c std::string until a CR-LF sequence is + * encountered: + * @code std::string data; + * ... + * void handler(const boost::system::error_code& e, std::size_t size) + * { + * if (!e) + * { + * std::string line = data.substr(0, n); + * data.erase(0, n); + * ... + * } + * } + * ... + * boost::asio::async_read_until(s, data, + * boost::regex("\r\n"), handler); @endcode + * After the @c async_read_until operation completes successfully, the string + * @c data contains the data which matched the regular expression: + * @code { 'a', 'b', ..., 'c', '\r', '\n', 'd', 'e', ... } @endcode + * The call to @c substr then extracts the data up to and including the match, + * so that the string @c line contains: + * @code { 'a', 'b', ..., 'c', '\r', '\n' } @endcode + * After the call to @c erase, the remaining data is left in the string @c data + * as follows: + * @code { 'd', 'e', ... } @endcode + * This data may be the start of a new line, to be extracted by a subsequent + * @c async_read_until operation. + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, + const boost::regex& expr, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +#endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) + // || defined(GENERATING_DOCUMENTATION) + +/// Start an asynchronous operation to read data into a dynamic buffer sequence +/// until a function object indicates a match. +/** + * This function is used to asynchronously read data into the specified dynamic + * buffer sequence until a user-defined match condition function object, when + * applied to the data contained in the dynamic buffer sequence, indicates a + * successful match. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li The match condition function object returns a std::pair where the second + * element evaluates to true. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_read_some function, and is known as a composed operation. If + * the match condition function object already indicates a match, this + * asynchronous operation completes immediately. The program must ensure that + * the stream performs no other read operations (such as async_read, + * async_read_until, the stream's async_read_some function, or any other + * composed operations that perform reads) until this operation completes. + * + * @param s The stream from which the data is to be read. The type must support + * the AsyncReadStream concept. + * + * @param buffers The dynamic buffer sequence into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param match_condition The function object to be called to determine whether + * a match exists. The signature of the function object must be: + * @code pair match_condition(iterator begin, iterator end); + * @endcode + * where @c iterator represents the type: + * @code buffers_iterator + * @endcode + * The iterator parameters @c begin and @c end define the range of bytes to be + * scanned to determine whether there is a match. The @c first member of the + * return value is an iterator marking one-past-the-end of the bytes that have + * been consumed by the match function. This iterator is used to calculate the + * @c begin parameter for any subsequent invocation of the match condition. The + * @c second member of the return value is true if a match has been found, false + * otherwise. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // The number of bytes in the dynamic buffer sequence's + * // get area that have been fully consumed by the match + * // function. O if an error occurred. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note After a successful async_read_until operation, the dynamic buffer + * sequence may contain additional data beyond that which matched the function + * object. An application will typically leave that data in the dynamic buffer + * sequence for a subsequent async_read_until operation to examine. + * + * @note The default implementation of the @c is_match_condition type trait + * evaluates to true for function pointers and function objects with a + * @c result_type typedef. It must be specialised for other user-defined + * function objects. + * + * @par Examples + * To asynchronously read data into a @c std::string until whitespace is + * encountered: + * @code typedef boost::asio::buffers_iterator< + * boost::asio::const_buffers_1> iterator; + * + * std::pair + * match_whitespace(iterator begin, iterator end) + * { + * iterator i = begin; + * while (i != end) + * if (std::isspace(*i++)) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * ... + * void handler(const boost::system::error_code& e, std::size_t size); + * ... + * std::string data; + * boost::asio::async_read_until(s, data, match_whitespace, handler); + * @endcode + * + * To asynchronously read data into a @c std::string until a matching character + * is found: + * @code class match_char + * { + * public: + * explicit match_char(char c) : c_(c) {} + * + * template + * std::pair operator()( + * Iterator begin, Iterator end) const + * { + * Iterator i = begin; + * while (i != end) + * if (c_ == *i++) + * return std::make_pair(i, true); + * return std::make_pair(i, false); + * } + * + * private: + * char c_; + * }; + * + * namespace asio { + * template <> struct is_match_condition + * : public boost::true_type {}; + * } // namespace asio + * ... + * void handler(const boost::system::error_code& e, std::size_t size); + * ... + * std::string data; + * boost::asio::async_read_until(s, data, match_char('a'), handler); + * @endcode + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) +async_read_until(AsyncReadStream& s, DynamicBuffer_v2 buffers, + MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, + typename enable_if< + is_match_condition::value + && is_dynamic_buffer_v2::value + >::type* = 0); + +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +/*@}*/ + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // BOOST_ASIO_READ_UNTIL_HPP diff --git a/boost/asio/redirect_error.hpp b/boost/asio/redirect_error.hpp new file mode 100644 index 0000000..f4563a5 --- /dev/null +++ b/boost/asio/redirect_error.hpp @@ -0,0 +1,68 @@ +// +// redirect_error.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_REDIRECT_ERROR_HPP +#define BOOST_ASIO_REDIRECT_ERROR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +/// Completion token type used to specify that an error produced by an +/// asynchronous operation is captured to an error_code variable. +/** + * The redirect_error_t class is used to indicate that any error_code produced + * by an asynchronous operation is captured to a specified variable. + */ +template +class redirect_error_t +{ +public: + /// Constructor. + template + redirect_error_t(BOOST_ASIO_MOVE_ARG(T) completion_token, + boost::system::error_code& ec) + : token_(BOOST_ASIO_MOVE_CAST(T)(completion_token)), + ec_(ec) + { + } + +//private: + CompletionToken token_; + boost::system::error_code& ec_; +}; + +/// Create a completion token to capture error_code values to a variable. +template +inline redirect_error_t::type> redirect_error( + BOOST_ASIO_MOVE_ARG(CompletionToken) completion_token, + boost::system::error_code& ec) +{ + return redirect_error_t::type>( + BOOST_ASIO_MOVE_CAST(CompletionToken)(completion_token), ec); +} + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // BOOST_ASIO_REDIRECT_ERROR_HPP diff --git a/boost/asio/serial_port.hpp b/boost/asio/serial_port.hpp new file mode 100644 index 0000000..b0960d8 --- /dev/null +++ b/boost/asio/serial_port.hpp @@ -0,0 +1,38 @@ +// +// serial_port.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_SERIAL_PORT_HPP +#define BOOST_ASIO_SERIAL_PORT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ + || defined(GENERATING_DOCUMENTATION) + +#include + +namespace boost { +namespace asio { + +/// Typedef for the typical usage of a serial port. +typedef basic_serial_port<> serial_port; + +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_SERIAL_PORT_HPP diff --git a/boost/asio/serial_port_base.hpp b/boost/asio/serial_port_base.hpp new file mode 100644 index 0000000..f902af1 --- /dev/null +++ b/boost/asio/serial_port_base.hpp @@ -0,0 +1,169 @@ +// +// serial_port_base.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_SERIAL_PORT_BASE_HPP +#define BOOST_ASIO_SERIAL_PORT_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ + || defined(GENERATING_DOCUMENTATION) + +#if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) +# include +#endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) + +#include +#include + +#if defined(GENERATING_DOCUMENTATION) +# define BOOST_ASIO_OPTION_STORAGE implementation_defined +#elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) +# define BOOST_ASIO_OPTION_STORAGE DCB +#else +# define BOOST_ASIO_OPTION_STORAGE termios +#endif + +#include + +namespace boost { +namespace asio { + +/// The serial_port_base class is used as a base for the basic_serial_port class +/// template so that we have a common place to define the serial port options. +class serial_port_base +{ +public: + /// Serial port option to permit changing the baud rate. + /** + * Implements changing the baud rate for a given serial port. + */ + class baud_rate + { + public: + explicit baud_rate(unsigned int rate = 0); + unsigned int value() const; + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID store( + BOOST_ASIO_OPTION_STORAGE& storage, + boost::system::error_code& ec) const; + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID load( + const BOOST_ASIO_OPTION_STORAGE& storage, + boost::system::error_code& ec); + private: + unsigned int value_; + }; + + /// Serial port option to permit changing the flow control. + /** + * Implements changing the flow control for a given serial port. + */ + class flow_control + { + public: + enum type { none, software, hardware }; + BOOST_ASIO_DECL explicit flow_control(type t = none); + type value() const; + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID store( + BOOST_ASIO_OPTION_STORAGE& storage, + boost::system::error_code& ec) const; + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID load( + const BOOST_ASIO_OPTION_STORAGE& storage, + boost::system::error_code& ec); + private: + type value_; + }; + + /// Serial port option to permit changing the parity. + /** + * Implements changing the parity for a given serial port. + */ + class parity + { + public: + enum type { none, odd, even }; + BOOST_ASIO_DECL explicit parity(type t = none); + type value() const; + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID store( + BOOST_ASIO_OPTION_STORAGE& storage, + boost::system::error_code& ec) const; + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID load( + const BOOST_ASIO_OPTION_STORAGE& storage, + boost::system::error_code& ec); + private: + type value_; + }; + + /// Serial port option to permit changing the number of stop bits. + /** + * Implements changing the number of stop bits for a given serial port. + */ + class stop_bits + { + public: + enum type { one, onepointfive, two }; + BOOST_ASIO_DECL explicit stop_bits(type t = one); + type value() const; + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID store( + BOOST_ASIO_OPTION_STORAGE& storage, + boost::system::error_code& ec) const; + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID load( + const BOOST_ASIO_OPTION_STORAGE& storage, + boost::system::error_code& ec); + private: + type value_; + }; + + /// Serial port option to permit changing the character size. + /** + * Implements changing the character size for a given serial port. + */ + class character_size + { + public: + BOOST_ASIO_DECL explicit character_size(unsigned int t = 8); + unsigned int value() const; + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID store( + BOOST_ASIO_OPTION_STORAGE& storage, + boost::system::error_code& ec) const; + BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID load( + const BOOST_ASIO_OPTION_STORAGE& storage, + boost::system::error_code& ec); + private: + unsigned int value_; + }; + +protected: + /// Protected destructor to prevent deletion through this type. + ~serial_port_base() + { + } +}; + +} // namespace asio +} // namespace boost + +#include + +#undef BOOST_ASIO_OPTION_STORAGE + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_SERIAL_PORT_BASE_HPP diff --git a/boost/asio/signal_set.hpp b/boost/asio/signal_set.hpp new file mode 100644 index 0000000..29cfd1b --- /dev/null +++ b/boost/asio/signal_set.hpp @@ -0,0 +1,30 @@ +// +// signal_set.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_SIGNAL_SET_HPP +#define BOOST_ASIO_SIGNAL_SET_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +namespace boost { +namespace asio { + +/// Typedef for the typical usage of a signal set. +typedef basic_signal_set<> signal_set; + +} // namespace asio +} // namespace boost + +#endif // BOOST_ASIO_SIGNAL_SET_HPP diff --git a/boost/asio/socket_base.hpp b/boost/asio/socket_base.hpp new file mode 100644 index 0000000..c19f8d2 --- /dev/null +++ b/boost/asio/socket_base.hpp @@ -0,0 +1,561 @@ +// +// socket_base.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_SOCKET_BASE_HPP +#define BOOST_ASIO_SOCKET_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +/// The socket_base class is used as a base for the basic_stream_socket and +/// basic_datagram_socket class templates so that we have a common place to +/// define the shutdown_type and enum. +class socket_base +{ +public: + /// Different ways a socket may be shutdown. + enum shutdown_type + { +#if defined(GENERATING_DOCUMENTATION) + /// Shutdown the receive side of the socket. + shutdown_receive = implementation_defined, + + /// Shutdown the send side of the socket. + shutdown_send = implementation_defined, + + /// Shutdown both send and receive on the socket. + shutdown_both = implementation_defined +#else + shutdown_receive = BOOST_ASIO_OS_DEF(SHUT_RD), + shutdown_send = BOOST_ASIO_OS_DEF(SHUT_WR), + shutdown_both = BOOST_ASIO_OS_DEF(SHUT_RDWR) +#endif + }; + + /// Bitmask type for flags that can be passed to send and receive operations. + typedef int message_flags; + +#if defined(GENERATING_DOCUMENTATION) + /// Peek at incoming data without removing it from the input queue. + static const int message_peek = implementation_defined; + + /// Process out-of-band data. + static const int message_out_of_band = implementation_defined; + + /// Specify that the data should not be subject to routing. + static const int message_do_not_route = implementation_defined; + + /// Specifies that the data marks the end of a record. + static const int message_end_of_record = implementation_defined; +#else + BOOST_ASIO_STATIC_CONSTANT(int, + message_peek = BOOST_ASIO_OS_DEF(MSG_PEEK)); + BOOST_ASIO_STATIC_CONSTANT(int, + message_out_of_band = BOOST_ASIO_OS_DEF(MSG_OOB)); + BOOST_ASIO_STATIC_CONSTANT(int, + message_do_not_route = BOOST_ASIO_OS_DEF(MSG_DONTROUTE)); + BOOST_ASIO_STATIC_CONSTANT(int, + message_end_of_record = BOOST_ASIO_OS_DEF(MSG_EOR)); +#endif + + /// Wait types. + /** + * For use with basic_socket::wait() and basic_socket::async_wait(). + */ + enum wait_type + { + /// Wait for a socket to become ready to read. + wait_read, + + /// Wait for a socket to become ready to write. + wait_write, + + /// Wait for a socket to have error conditions pending. + wait_error + }; + + /// Socket option to permit sending of broadcast messages. + /** + * Implements the SOL_SOCKET/SO_BROADCAST socket option. + * + * @par Examples + * Setting the option: + * @code + * boost::asio::ip::udp::socket socket(my_context); + * ... + * boost::asio::socket_base::broadcast option(true); + * socket.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * boost::asio::ip::udp::socket socket(my_context); + * ... + * boost::asio::socket_base::broadcast option; + * socket.get_option(option); + * bool is_set = option.value(); + * @endcode + * + * @par Concepts: + * Socket_Option, Boolean_Socket_Option. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined broadcast; +#else + typedef boost::asio::detail::socket_option::boolean< + BOOST_ASIO_OS_DEF(SOL_SOCKET), BOOST_ASIO_OS_DEF(SO_BROADCAST)> + broadcast; +#endif + + /// Socket option to enable socket-level debugging. + /** + * Implements the SOL_SOCKET/SO_DEBUG socket option. + * + * @par Examples + * Setting the option: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::socket_base::debug option(true); + * socket.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::socket_base::debug option; + * socket.get_option(option); + * bool is_set = option.value(); + * @endcode + * + * @par Concepts: + * Socket_Option, Boolean_Socket_Option. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined debug; +#else + typedef boost::asio::detail::socket_option::boolean< + BOOST_ASIO_OS_DEF(SOL_SOCKET), BOOST_ASIO_OS_DEF(SO_DEBUG)> debug; +#endif + + /// Socket option to prevent routing, use local interfaces only. + /** + * Implements the SOL_SOCKET/SO_DONTROUTE socket option. + * + * @par Examples + * Setting the option: + * @code + * boost::asio::ip::udp::socket socket(my_context); + * ... + * boost::asio::socket_base::do_not_route option(true); + * socket.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * boost::asio::ip::udp::socket socket(my_context); + * ... + * boost::asio::socket_base::do_not_route option; + * socket.get_option(option); + * bool is_set = option.value(); + * @endcode + * + * @par Concepts: + * Socket_Option, Boolean_Socket_Option. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined do_not_route; +#else + typedef boost::asio::detail::socket_option::boolean< + BOOST_ASIO_OS_DEF(SOL_SOCKET), BOOST_ASIO_OS_DEF(SO_DONTROUTE)> + do_not_route; +#endif + + /// Socket option to send keep-alives. + /** + * Implements the SOL_SOCKET/SO_KEEPALIVE socket option. + * + * @par Examples + * Setting the option: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::socket_base::keep_alive option(true); + * socket.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::socket_base::keep_alive option; + * socket.get_option(option); + * bool is_set = option.value(); + * @endcode + * + * @par Concepts: + * Socket_Option, Boolean_Socket_Option. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined keep_alive; +#else + typedef boost::asio::detail::socket_option::boolean< + BOOST_ASIO_OS_DEF(SOL_SOCKET), BOOST_ASIO_OS_DEF(SO_KEEPALIVE)> keep_alive; +#endif + + /// Socket option for the send buffer size of a socket. + /** + * Implements the SOL_SOCKET/SO_SNDBUF socket option. + * + * @par Examples + * Setting the option: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::socket_base::send_buffer_size option(8192); + * socket.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::socket_base::send_buffer_size option; + * socket.get_option(option); + * int size = option.value(); + * @endcode + * + * @par Concepts: + * Socket_Option, Integer_Socket_Option. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined send_buffer_size; +#else + typedef boost::asio::detail::socket_option::integer< + BOOST_ASIO_OS_DEF(SOL_SOCKET), BOOST_ASIO_OS_DEF(SO_SNDBUF)> + send_buffer_size; +#endif + + /// Socket option for the send low watermark. + /** + * Implements the SOL_SOCKET/SO_SNDLOWAT socket option. + * + * @par Examples + * Setting the option: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::socket_base::send_low_watermark option(1024); + * socket.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::socket_base::send_low_watermark option; + * socket.get_option(option); + * int size = option.value(); + * @endcode + * + * @par Concepts: + * Socket_Option, Integer_Socket_Option. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined send_low_watermark; +#else + typedef boost::asio::detail::socket_option::integer< + BOOST_ASIO_OS_DEF(SOL_SOCKET), BOOST_ASIO_OS_DEF(SO_SNDLOWAT)> + send_low_watermark; +#endif + + /// Socket option for the receive buffer size of a socket. + /** + * Implements the SOL_SOCKET/SO_RCVBUF socket option. + * + * @par Examples + * Setting the option: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::socket_base::receive_buffer_size option(8192); + * socket.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::socket_base::receive_buffer_size option; + * socket.get_option(option); + * int size = option.value(); + * @endcode + * + * @par Concepts: + * Socket_Option, Integer_Socket_Option. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined receive_buffer_size; +#else + typedef boost::asio::detail::socket_option::integer< + BOOST_ASIO_OS_DEF(SOL_SOCKET), BOOST_ASIO_OS_DEF(SO_RCVBUF)> + receive_buffer_size; +#endif + + /// Socket option for the receive low watermark. + /** + * Implements the SOL_SOCKET/SO_RCVLOWAT socket option. + * + * @par Examples + * Setting the option: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::socket_base::receive_low_watermark option(1024); + * socket.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::socket_base::receive_low_watermark option; + * socket.get_option(option); + * int size = option.value(); + * @endcode + * + * @par Concepts: + * Socket_Option, Integer_Socket_Option. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined receive_low_watermark; +#else + typedef boost::asio::detail::socket_option::integer< + BOOST_ASIO_OS_DEF(SOL_SOCKET), BOOST_ASIO_OS_DEF(SO_RCVLOWAT)> + receive_low_watermark; +#endif + + /// Socket option to allow the socket to be bound to an address that is + /// already in use. + /** + * Implements the SOL_SOCKET/SO_REUSEADDR socket option. + * + * @par Examples + * Setting the option: + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::socket_base::reuse_address option(true); + * acceptor.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::socket_base::reuse_address option; + * acceptor.get_option(option); + * bool is_set = option.value(); + * @endcode + * + * @par Concepts: + * Socket_Option, Boolean_Socket_Option. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined reuse_address; +#else + typedef boost::asio::detail::socket_option::boolean< + BOOST_ASIO_OS_DEF(SOL_SOCKET), BOOST_ASIO_OS_DEF(SO_REUSEADDR)> + reuse_address; +#endif + + /// Socket option to specify whether the socket lingers on close if unsent + /// data is present. + /** + * Implements the SOL_SOCKET/SO_LINGER socket option. + * + * @par Examples + * Setting the option: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::socket_base::linger option(true, 30); + * socket.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::socket_base::linger option; + * socket.get_option(option); + * bool is_set = option.enabled(); + * unsigned short timeout = option.timeout(); + * @endcode + * + * @par Concepts: + * Socket_Option, Linger_Socket_Option. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined linger; +#else + typedef boost::asio::detail::socket_option::linger< + BOOST_ASIO_OS_DEF(SOL_SOCKET), BOOST_ASIO_OS_DEF(SO_LINGER)> + linger; +#endif + + /// Socket option for putting received out-of-band data inline. + /** + * Implements the SOL_SOCKET/SO_OOBINLINE socket option. + * + * @par Examples + * Setting the option: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::socket_base::out_of_band_inline option(true); + * socket.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::socket_base::out_of_band_inline option; + * socket.get_option(option); + * bool value = option.value(); + * @endcode + * + * @par Concepts: + * Socket_Option, Boolean_Socket_Option. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined out_of_band_inline; +#else + typedef boost::asio::detail::socket_option::boolean< + BOOST_ASIO_OS_DEF(SOL_SOCKET), BOOST_ASIO_OS_DEF(SO_OOBINLINE)> + out_of_band_inline; +#endif + + /// Socket option to report aborted connections on accept. + /** + * Implements a custom socket option that determines whether or not an accept + * operation is permitted to fail with boost::asio::error::connection_aborted. + * By default the option is false. + * + * @par Examples + * Setting the option: + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::socket_base::enable_connection_aborted option(true); + * acceptor.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * boost::asio::ip::tcp::acceptor acceptor(my_context); + * ... + * boost::asio::socket_base::enable_connection_aborted option; + * acceptor.get_option(option); + * bool is_set = option.value(); + * @endcode + * + * @par Concepts: + * Socket_Option, Boolean_Socket_Option. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined enable_connection_aborted; +#else + typedef boost::asio::detail::socket_option::boolean< + boost::asio::detail::custom_socket_option_level, + boost::asio::detail::enable_connection_aborted_option> + enable_connection_aborted; +#endif + + /// IO control command to get the amount of data that can be read without + /// blocking. + /** + * Implements the FIONREAD IO control command. + * + * @par Example + * @code + * boost::asio::ip::tcp::socket socket(my_context); + * ... + * boost::asio::socket_base::bytes_readable command(true); + * socket.io_control(command); + * std::size_t bytes_readable = command.get(); + * @endcode + * + * @par Concepts: + * IO_Control_Command, Size_IO_Control_Command. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined bytes_readable; +#else + typedef boost::asio::detail::io_control::bytes_readable bytes_readable; +#endif + + /// The maximum length of the queue of pending incoming connections. +#if defined(GENERATING_DOCUMENTATION) + static const int max_listen_connections = implementation_defined; +#else + BOOST_ASIO_STATIC_CONSTANT(int, max_listen_connections + = BOOST_ASIO_OS_DEF(SOMAXCONN)); +#endif + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use max_listen_connections.) The maximum length of the queue + /// of pending incoming connections. +#if defined(GENERATING_DOCUMENTATION) + static const int max_connections = implementation_defined; +#else + BOOST_ASIO_STATIC_CONSTANT(int, max_connections + = BOOST_ASIO_OS_DEF(SOMAXCONN)); +#endif +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + +protected: + /// Protected destructor to prevent deletion through this type. + ~socket_base() + { + } +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_SOCKET_BASE_HPP diff --git a/boost/asio/steady_timer.hpp b/boost/asio/steady_timer.hpp new file mode 100644 index 0000000..5c88e97 --- /dev/null +++ b/boost/asio/steady_timer.hpp @@ -0,0 +1,44 @@ +// +// steady_timer.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_STEADY_TIMER_HPP +#define BOOST_ASIO_STEADY_TIMER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) + +#include +#include + +namespace boost { +namespace asio { + +/// Typedef for a timer based on the steady clock. +/** + * This typedef uses the C++11 @c <chrono> standard library facility, if + * available. Otherwise, it may use the Boost.Chrono library. To explicitly + * utilise Boost.Chrono, use the basic_waitable_timer template directly: + * @code + * typedef basic_waitable_timer timer; + * @endcode + */ +typedef basic_waitable_timer steady_timer; + +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_STEADY_TIMER_HPP diff --git a/boost/asio/strand.hpp b/boost/asio/strand.hpp new file mode 100644 index 0000000..d08801b --- /dev/null +++ b/boost/asio/strand.hpp @@ -0,0 +1,315 @@ +// +// strand.hpp +// ~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_STRAND_HPP +#define BOOST_ASIO_STRAND_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +/// Provides serialised function invocation for any executor type. +template +class strand +{ +public: + /// The type of the underlying executor. + typedef Executor inner_executor_type; + + /// Default constructor. + /** + * This constructor is only valid if the underlying executor type is default + * constructible. + */ + strand() + : executor_(), + impl_(use_service( + executor_.context()).create_implementation()) + { + } + + /// Construct a strand for the specified executor. + explicit strand(const Executor& e) + : executor_(e), + impl_(use_service( + executor_.context()).create_implementation()) + { + } + + /// Copy constructor. + strand(const strand& other) BOOST_ASIO_NOEXCEPT + : executor_(other.executor_), + impl_(other.impl_) + { + } + + /// Converting constructor. + /** + * This constructor is only valid if the @c OtherExecutor type is convertible + * to @c Executor. + */ + template + strand( + const strand& other) BOOST_ASIO_NOEXCEPT + : executor_(other.executor_), + impl_(other.impl_) + { + } + + /// Assignment operator. + strand& operator=(const strand& other) BOOST_ASIO_NOEXCEPT + { + executor_ = other.executor_; + impl_ = other.impl_; + return *this; + } + + /// Converting assignment operator. + /** + * This assignment operator is only valid if the @c OtherExecutor type is + * convertible to @c Executor. + */ + template + strand& operator=( + const strand& other) BOOST_ASIO_NOEXCEPT + { + executor_ = other.executor_; + impl_ = other.impl_; + return *this; + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move constructor. + strand(strand&& other) BOOST_ASIO_NOEXCEPT + : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)), + impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_)) + { + } + + /// Converting move constructor. + /** + * This constructor is only valid if the @c OtherExecutor type is convertible + * to @c Executor. + */ + template + strand(strand&& other) BOOST_ASIO_NOEXCEPT + : executor_(BOOST_ASIO_MOVE_CAST(OtherExecutor)(other)), + impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_)) + { + } + + /// Move assignment operator. + strand& operator=(strand&& other) BOOST_ASIO_NOEXCEPT + { + executor_ = BOOST_ASIO_MOVE_CAST(Executor)(other); + impl_ = BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_); + return *this; + } + + /// Converting move assignment operator. + /** + * This assignment operator is only valid if the @c OtherExecutor type is + * convertible to @c Executor. + */ + template + strand& operator=( + const strand&& other) BOOST_ASIO_NOEXCEPT + { + executor_ = BOOST_ASIO_MOVE_CAST(OtherExecutor)(other); + impl_ = BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Destructor. + ~strand() + { + } + + /// Obtain the underlying executor. + inner_executor_type get_inner_executor() const BOOST_ASIO_NOEXCEPT + { + return executor_; + } + + /// Obtain the underlying execution context. + execution_context& context() const BOOST_ASIO_NOEXCEPT + { + return executor_.context(); + } + + /// Inform the strand that it has some outstanding work to do. + /** + * The strand delegates this call to its underlying executor. + */ + void on_work_started() const BOOST_ASIO_NOEXCEPT + { + executor_.on_work_started(); + } + + /// Inform the strand that some work is no longer outstanding. + /** + * The strand delegates this call to its underlying executor. + */ + void on_work_finished() const BOOST_ASIO_NOEXCEPT + { + executor_.on_work_finished(); + } + + /// Request the strand to invoke the given function object. + /** + * This function is used to ask the strand to execute the given function + * object on its underlying executor. The function object will be executed + * inside this function if the strand is not otherwise busy and if the + * underlying executor's @c dispatch() function is also able to execute the + * function before returning. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template + void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const + { + detail::strand_executor_service::dispatch(impl_, + executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a); + } + + /// Request the strand to invoke the given function object. + /** + * This function is used to ask the executor to execute the given function + * object. The function object will never be executed inside this function. + * Instead, it will be scheduled by the underlying executor's defer function. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template + void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const + { + detail::strand_executor_service::post(impl_, + executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a); + } + + /// Request the strand to invoke the given function object. + /** + * This function is used to ask the executor to execute the given function + * object. The function object will never be executed inside this function. + * Instead, it will be scheduled by the underlying executor's defer function. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template + void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const + { + detail::strand_executor_service::defer(impl_, + executor_, BOOST_ASIO_MOVE_CAST(Function)(f), a); + } + + /// Determine whether the strand is running in the current thread. + /** + * @return @c true if the current thread is executing a function that was + * submitted to the strand using post(), dispatch() or defer(). Otherwise + * returns @c false. + */ + bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT + { + return detail::strand_executor_service::running_in_this_thread(impl_); + } + + /// Compare two strands for equality. + /** + * Two strands are equal if they refer to the same ordered, non-concurrent + * state. + */ + friend bool operator==(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT + { + return a.impl_ == b.impl_; + } + + /// Compare two strands for inequality. + /** + * Two strands are equal if they refer to the same ordered, non-concurrent + * state. + */ + friend bool operator!=(const strand& a, const strand& b) BOOST_ASIO_NOEXCEPT + { + return a.impl_ != b.impl_; + } + +private: + Executor executor_; + typedef detail::strand_executor_service::implementation_type + implementation_type; + implementation_type impl_; +}; + +/** @defgroup make_strand boost::asio::make_strand + * + * @brief The boost::asio::make_strand function creates a @ref strand object for + * an executor or execution context. + */ +/*@{*/ + +/// Create a @ref strand object for an executor. +template +inline strand make_strand(const Executor& ex, + typename enable_if::value>::type* = 0) +{ + return strand(ex); +} + +/// Create a @ref strand object for an execution context. +template +inline strand +make_strand(ExecutionContext& ctx, + typename enable_if< + is_convertible::value>::type* = 0) +{ + return strand(ctx.get_executor()); +} + +/*@}*/ + +} // namespace asio +} // namespace boost + +#include + +// If both io_context.hpp and strand.hpp have been included, automatically +// include the header file needed for the io_context::strand class. +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +# if defined(BOOST_ASIO_IO_CONTEXT_HPP) +# include +# endif // defined(BOOST_ASIO_IO_CONTEXT_HPP) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +#endif // BOOST_ASIO_STRAND_HPP diff --git a/boost/asio/streambuf.hpp b/boost/asio/streambuf.hpp new file mode 100644 index 0000000..a66600d --- /dev/null +++ b/boost/asio/streambuf.hpp @@ -0,0 +1,35 @@ +// +// streambuf.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_STREAMBUF_HPP +#define BOOST_ASIO_STREAMBUF_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +#include + +namespace boost { +namespace asio { + +/// Typedef for the typical usage of basic_streambuf. +typedef basic_streambuf<> streambuf; + +} // namespace asio +} // namespace boost + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) + +#endif // BOOST_ASIO_STREAMBUF_HPP diff --git a/boost/asio/system_context.hpp b/boost/asio/system_context.hpp new file mode 100644 index 0000000..96d29f4 --- /dev/null +++ b/boost/asio/system_context.hpp @@ -0,0 +1,83 @@ +// +// system_context.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_SYSTEM_CONTEXT_HPP +#define BOOST_ASIO_SYSTEM_CONTEXT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +class system_executor; + +/// The executor context for the system executor. +class system_context : public execution_context +{ +public: + /// The executor type associated with the context. + typedef system_executor executor_type; + + /// Destructor shuts down all threads in the system thread pool. + BOOST_ASIO_DECL ~system_context(); + + /// Obtain an executor for the context. + executor_type get_executor() BOOST_ASIO_NOEXCEPT; + + /// Signal all threads in the system thread pool to stop. + BOOST_ASIO_DECL void stop(); + + /// Determine whether the system thread pool has been stopped. + BOOST_ASIO_DECL bool stopped() const BOOST_ASIO_NOEXCEPT; + + /// Join all threads in the system thread pool. + BOOST_ASIO_DECL void join(); + +#if defined(GENERATING_DOCUMENTATION) +private: +#endif // defined(GENERATING_DOCUMENTATION) + // Constructor creates all threads in the system thread pool. + BOOST_ASIO_DECL system_context(); + +private: + friend class system_executor; + + struct thread_function; + + // Helper function to create the underlying scheduler. + BOOST_ASIO_DECL detail::scheduler& add_scheduler(detail::scheduler* s); + + // The underlying scheduler. + detail::scheduler& scheduler_; + + // The threads in the system thread pool. + detail::thread_group threads_; +}; + +} // namespace asio +} // namespace boost + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_SYSTEM_CONTEXT_HPP diff --git a/boost/asio/system_executor.hpp b/boost/asio/system_executor.hpp new file mode 100644 index 0000000..5125046 --- /dev/null +++ b/boost/asio/system_executor.hpp @@ -0,0 +1,131 @@ +// +// system_executor.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_SYSTEM_EXECUTOR_HPP +#define BOOST_ASIO_SYSTEM_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { + +class system_context; + +/// An executor that uses arbitrary threads. +/** + * The system executor represents an execution context where functions are + * permitted to run on arbitrary threads. The post() and defer() functions + * schedule the function to run on an unspecified system thread pool, and + * dispatch() invokes the function immediately. + */ +class system_executor +{ +public: + /// Obtain the underlying execution context. + system_context& context() const BOOST_ASIO_NOEXCEPT; + + /// Inform the executor that it has some outstanding work to do. + /** + * For the system executor, this is a no-op. + */ + void on_work_started() const BOOST_ASIO_NOEXCEPT + { + } + + /// Inform the executor that some work is no longer outstanding. + /** + * For the system executor, this is a no-op. + */ + void on_work_finished() const BOOST_ASIO_NOEXCEPT + { + } + + /// Request the system executor to invoke the given function object. + /** + * This function is used to ask the executor to execute the given function + * object. The function object will always be executed inside this function. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template + void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Request the system executor to invoke the given function object. + /** + * This function is used to ask the executor to execute the given function + * object. The function object will never be executed inside this function. + * Instead, it will be scheduled to run on an unspecified system thread pool. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template + void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Request the system executor to invoke the given function object. + /** + * This function is used to ask the executor to execute the given function + * object. The function object will never be executed inside this function. + * Instead, it will be scheduled to run on an unspecified system thread pool. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template + void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Compare two executors for equality. + /** + * System executors always compare equal. + */ + friend bool operator==(const system_executor&, + const system_executor&) BOOST_ASIO_NOEXCEPT + { + return true; + } + + /// Compare two executors for inequality. + /** + * System executors always compare equal. + */ + friend bool operator!=(const system_executor&, + const system_executor&) BOOST_ASIO_NOEXCEPT + { + return false; + } +}; + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // BOOST_ASIO_SYSTEM_EXECUTOR_HPP diff --git a/boost/asio/system_timer.hpp b/boost/asio/system_timer.hpp new file mode 100644 index 0000000..880feac --- /dev/null +++ b/boost/asio/system_timer.hpp @@ -0,0 +1,44 @@ +// +// system_timer.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_SYSTEM_TIMER_HPP +#define BOOST_ASIO_SYSTEM_TIMER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) + +#include +#include + +namespace boost { +namespace asio { + +/// Typedef for a timer based on the system clock. +/** + * This typedef uses the C++11 @c <chrono> standard library facility, if + * available. Otherwise, it may use the Boost.Chrono library. To explicitly + * utilise Boost.Chrono, use the basic_waitable_timer template directly: + * @code + * typedef basic_waitable_timer timer; + * @endcode + */ +typedef basic_waitable_timer system_timer; + +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_SYSTEM_TIMER_HPP diff --git a/boost/asio/this_coro.hpp b/boost/asio/this_coro.hpp new file mode 100644 index 0000000..19c50b2 --- /dev/null +++ b/boost/asio/this_coro.hpp @@ -0,0 +1,47 @@ +// +// this_coro.hpp +// ~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_THIS_CORO_HPP +#define BOOST_ASIO_THIS_CORO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#include + +namespace boost { +namespace asio { +namespace this_coro { + +/// Awaitable type that returns the executor of the current coroutine. +struct executor_t +{ + BOOST_ASIO_CONSTEXPR executor_t() + { + } +}; + +/// Awaitable object that returns the executor of the current coroutine. +#if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr executor_t executor; +#elif defined(BOOST_ASIO_MSVC) +__declspec(selectany) executor_t executor; +#endif + +} // namespace this_coro +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_THIS_CORO_HPP diff --git a/boost/asio/thread_pool.hpp b/boost/asio/thread_pool.hpp new file mode 100644 index 0000000..765fa2a --- /dev/null +++ b/boost/asio/thread_pool.hpp @@ -0,0 +1,237 @@ +// +// thread_pool.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_THREAD_POOL_HPP +#define BOOST_ASIO_THREAD_POOL_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace asio { + +/// A simple fixed-size thread pool. +/** + * The thread pool class is an execution context where functions are permitted + * to run on one of a fixed number of threads. + * + * @par Submitting tasks to the pool + * + * To submit functions to the thread_pool, use the @ref boost::asio::dispatch, + * @ref boost::asio::post or @ref boost::asio::defer free functions. + * + * For example: + * + * @code void my_task() + * { + * ... + * } + * + * ... + * + * // Launch the pool with four threads. + * boost::asio::thread_pool pool(4); + * + * // Submit a function to the pool. + * boost::asio::post(pool, my_task); + * + * // Submit a lambda object to the pool. + * boost::asio::post(pool, + * []() + * { + * ... + * }); + * + * // Wait for all tasks in the pool to complete. + * pool.join(); @endcode + */ +class thread_pool + : public execution_context +{ +public: + class executor_type; + + /// Constructs a pool with an automatically determined number of threads. + BOOST_ASIO_DECL thread_pool(); + + /// Constructs a pool with a specified number of threads. + BOOST_ASIO_DECL thread_pool(std::size_t num_threads); + + /// Destructor. + /** + * Automatically stops and joins the pool, if not explicitly done beforehand. + */ + BOOST_ASIO_DECL ~thread_pool(); + + /// Obtains the executor associated with the pool. + executor_type get_executor() BOOST_ASIO_NOEXCEPT; + + /// Stops the threads. + /** + * This function stops the threads as soon as possible. As a result of calling + * @c stop(), pending function objects may be never be invoked. + */ + BOOST_ASIO_DECL void stop(); + + /// Joins the threads. + /** + * This function blocks until the threads in the pool have completed. If @c + * stop() is not called prior to @c join(), the @c join() call will wait + * until the pool has no more outstanding work. + */ + BOOST_ASIO_DECL void join(); + +private: + friend class executor_type; + struct thread_function; + + // Helper function to create the underlying scheduler. + BOOST_ASIO_DECL detail::scheduler& add_scheduler(detail::scheduler* s); + + // The underlying scheduler. + detail::scheduler& scheduler_; + + // The threads in the pool. + detail::thread_group threads_; +}; + +/// Executor used to submit functions to a thread pool. +class thread_pool::executor_type +{ +public: + /// Obtain the underlying execution context. + thread_pool& context() const BOOST_ASIO_NOEXCEPT; + + /// Inform the thread pool that it has some outstanding work to do. + /** + * This function is used to inform the thread pool that some work has begun. + * This ensures that the thread pool's join() function will not return while + * the work is underway. + */ + void on_work_started() const BOOST_ASIO_NOEXCEPT; + + /// Inform the thread pool that some work is no longer outstanding. + /** + * This function is used to inform the thread pool that some work has + * finished. Once the count of unfinished work reaches zero, the thread + * pool's join() function is permitted to exit. + */ + void on_work_finished() const BOOST_ASIO_NOEXCEPT; + + /// Request the thread pool to invoke the given function object. + /** + * This function is used to ask the thread pool to execute the given function + * object. If the current thread belongs to the pool, @c dispatch() executes + * the function before returning. Otherwise, the function will be scheduled + * to run on the thread pool. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template + void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Request the thread pool to invoke the given function object. + /** + * This function is used to ask the thread pool to execute the given function + * object. The function object will never be executed inside @c post(). + * Instead, it will be scheduled to run on the thread pool. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template + void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Request the thread pool to invoke the given function object. + /** + * This function is used to ask the thread pool to execute the given function + * object. The function object will never be executed inside @c defer(). + * Instead, it will be scheduled to run on the thread pool. + * + * If the current thread belongs to the thread pool, @c defer() will delay + * scheduling the function object until the current thread returns control to + * the pool. + * + * @param f The function object to be called. The executor will make + * a copy of the handler object as required. The function signature of the + * function object must be: @code void function(); @endcode + * + * @param a An allocator that may be used by the executor to allocate the + * internal storage needed for function invocation. + */ + template + void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const; + + /// Determine whether the thread pool is running in the current thread. + /** + * @return @c true if the current thread belongs to the pool. Otherwise + * returns @c false. + */ + bool running_in_this_thread() const BOOST_ASIO_NOEXCEPT; + + /// Compare two executors for equality. + /** + * Two executors are equal if they refer to the same underlying thread pool. + */ + friend bool operator==(const executor_type& a, + const executor_type& b) BOOST_ASIO_NOEXCEPT + { + return &a.pool_ == &b.pool_; + } + + /// Compare two executors for inequality. + /** + * Two executors are equal if they refer to the same underlying thread pool. + */ + friend bool operator!=(const executor_type& a, + const executor_type& b) BOOST_ASIO_NOEXCEPT + { + return &a.pool_ != &b.pool_; + } + +private: + friend class thread_pool; + + // Constructor. + explicit executor_type(thread_pool& p) : pool_(p) {} + + // The underlying thread pool. + thread_pool& pool_; +}; + +} // namespace asio +} // namespace boost + +#include + +#include +#if defined(BOOST_ASIO_HEADER_ONLY) +# include +#endif // defined(BOOST_ASIO_HEADER_ONLY) + +#endif // BOOST_ASIO_THREAD_POOL_HPP diff --git a/boost/asio/time_traits.hpp b/boost/asio/time_traits.hpp new file mode 100644 index 0000000..b161f46 --- /dev/null +++ b/boost/asio/time_traits.hpp @@ -0,0 +1,88 @@ +// +// time_traits.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_TIME_TRAITS_HPP +#define BOOST_ASIO_TIME_TRAITS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include // Must come before posix_time. + +#if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ + || defined(GENERATING_DOCUMENTATION) + +#include + +#include + +namespace boost { +namespace asio { + +/// Time traits suitable for use with the deadline timer. +template +struct time_traits; + +/// Time traits specialised for posix_time. +template <> +struct time_traits +{ + /// The time type. + typedef boost::posix_time::ptime time_type; + + /// The duration type. + typedef boost::posix_time::time_duration duration_type; + + /// Get the current time. + static time_type now() + { +#if defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK) + return boost::posix_time::microsec_clock::universal_time(); +#else // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK) + return boost::posix_time::second_clock::universal_time(); +#endif // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK) + } + + /// Add a duration to a time. + static time_type add(const time_type& t, const duration_type& d) + { + return t + d; + } + + /// Subtract one time from another. + static duration_type subtract(const time_type& t1, const time_type& t2) + { + return t1 - t2; + } + + /// Test whether one time is less than another. + static bool less_than(const time_type& t1, const time_type& t2) + { + return t1 < t2; + } + + /// Convert to POSIX duration type. + static boost::posix_time::time_duration to_posix_duration( + const duration_type& d) + { + return d; + } +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_TIME_TRAITS_HPP diff --git a/boost/asio/use_awaitable.hpp b/boost/asio/use_awaitable.hpp new file mode 100644 index 0000000..8764b3d --- /dev/null +++ b/boost/asio/use_awaitable.hpp @@ -0,0 +1,73 @@ +// +// use_awaitable.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_USE_AWAITABLE_HPP +#define BOOST_ASIO_USE_AWAITABLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) + +#include + +#include + +namespace boost { +namespace asio { + +/// A completion token that represents the currently executing coroutine. +/** + * The @c use_awaitable_t class, with its value @c use_awaitable, is used to + * represent the currently executing coroutine. This completion token may be + * passed as a handler to an asynchronous operation. For example: + * + * @code awaitable my_coroutine() + * { + * std::size_t n = co_await my_socket.async_read_some(buffer, use_awaitable); + * ... + * } @endcode + * + * When used with co_await, the initiating function (@c async_read_some in the + * above example) suspends the current coroutine. The coroutine is resumed when + * the asynchronous operation completes, and the result of the operation is + * returned. + */ +template +struct use_awaitable_t +{ + BOOST_ASIO_CONSTEXPR use_awaitable_t() + { + } +}; + +/// A completion token object that represents the currently executing coroutine. +/** + * See the documentation for boost::asio::use_awaitable_t for a usage example. + */ +#if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr use_awaitable_t<> use_awaitable; +#elif defined(BOOST_ASIO_MSVC) +__declspec(selectany) use_awaitable_t<> use_awaitable; +#endif + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_USE_AWAITABLE_HPP diff --git a/boost/asio/use_future.hpp b/boost/asio/use_future.hpp new file mode 100644 index 0000000..45497ef --- /dev/null +++ b/boost/asio/use_future.hpp @@ -0,0 +1,162 @@ +// +// use_future.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_USE_FUTURE_HPP +#define BOOST_ASIO_USE_FUTURE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS) \ + || defined(GENERATING_DOCUMENTATION) + +#include +#include + +#include + +namespace boost { +namespace asio { +namespace detail { + +template +class packaged_token; + +template +class packaged_handler; + +} // namespace detail + +/// Class used to specify that an asynchronous operation should return a future. +/** + * The use_future_t class is used to indicate that an asynchronous operation + * should return a std::future object. A use_future_t object may be passed as a + * handler to an asynchronous operation, typically using the special value @c + * boost::asio::use_future. For example: + * + * @code std::future my_future + * = my_socket.async_read_some(my_buffer, boost::asio::use_future); @endcode + * + * The initiating function (async_read_some in the above example) returns a + * future that will receive the result of the operation. If the operation + * completes with an error_code indicating failure, it is converted into a + * system_error and passed back to the caller via the future. + */ +template > +class use_future_t +{ +public: + /// The allocator type. The allocator is used when constructing the + /// @c std::promise object for a given asynchronous operation. + typedef Allocator allocator_type; + + /// Construct using default-constructed allocator. + BOOST_ASIO_CONSTEXPR use_future_t() + { + } + + /// Construct using specified allocator. + explicit use_future_t(const Allocator& allocator) + : allocator_(allocator) + { + } + +#if !defined(BOOST_ASIO_NO_DEPRECATED) + /// (Deprecated: Use rebind().) Specify an alternate allocator. + template + use_future_t operator[](const OtherAllocator& allocator) const + { + return use_future_t(allocator); + } +#endif // !defined(BOOST_ASIO_NO_DEPRECATED) + + /// Specify an alternate allocator. + template + use_future_t rebind(const OtherAllocator& allocator) const + { + return use_future_t(allocator); + } + + /// Obtain allocator. + allocator_type get_allocator() const + { + return allocator_; + } + + /// Wrap a function object in a packaged task. + /** + * The @c package function is used to adapt a function object as a packaged + * task. When this adapter is passed as a completion token to an asynchronous + * operation, the result of the function object is retuned via a std::future. + * + * @par Example + * + * @code std::future fut = + * my_socket.async_read_some(buffer, + * use_future([](boost::system::error_code ec, std::size_t n) + * { + * return ec ? 0 : n; + * })); + * ... + * std::size_t n = fut.get(); @endcode + */ + template +#if defined(GENERATING_DOCUMENTATION) + unspecified +#else // defined(GENERATING_DOCUMENTATION) + detail::packaged_token::type, Allocator> +#endif // defined(GENERATING_DOCUMENTATION) + operator()(BOOST_ASIO_MOVE_ARG(Function) f) const; + +private: + // Helper type to ensure that use_future can be constexpr default-constructed + // even when std::allocator can't be. + struct std_allocator_void + { + BOOST_ASIO_CONSTEXPR std_allocator_void() + { + } + + operator std::allocator() const + { + return std::allocator(); + } + }; + + typename conditional< + is_same, Allocator>::value, + std_allocator_void, Allocator>::type allocator_; +}; + +/// A special value, similar to std::nothrow. +/** + * See the documentation for boost::asio::use_future_t for a usage example. + */ +#if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr use_future_t<> use_future; +#elif defined(BOOST_ASIO_MSVC) +__declspec(selectany) use_future_t<> use_future; +#endif + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_USE_FUTURE_HPP diff --git a/boost/asio/uses_executor.hpp b/boost/asio/uses_executor.hpp new file mode 100644 index 0000000..fb55b67 --- /dev/null +++ b/boost/asio/uses_executor.hpp @@ -0,0 +1,73 @@ +// +// uses_executor.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_USES_EXECUTOR_HPP +#define BOOST_ASIO_USES_EXECUTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#include + +namespace boost { +namespace asio { + +/// A special type, similar to std::nothrow_t, used to disambiguate +/// constructors that accept executor arguments. +/** + * The executor_arg_t struct is an empty structure type used as a unique type + * to disambiguate constructor and function overloading. Specifically, some + * types have constructors with executor_arg_t as the first argument, + * immediately followed by an argument of a type that satisfies the Executor + * type requirements. + */ +struct executor_arg_t +{ + /// Constructor. + BOOST_ASIO_CONSTEXPR executor_arg_t() BOOST_ASIO_NOEXCEPT + { + } +}; + +/// A special value, similar to std::nothrow, used to disambiguate constructors +/// that accept executor arguments. +/** + * See boost::asio::executor_arg_t and boost::asio::uses_executor + * for more information. + */ +#if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) +constexpr executor_arg_t executor_arg; +#elif defined(BOOST_ASIO_MSVC) +__declspec(selectany) executor_arg_t executor_arg; +#endif + +/// The uses_executor trait detects whether a type T has an associated executor +/// that is convertible from type Executor. +/** + * Meets the BinaryTypeTrait requirements. The Asio library provides a + * definition that is derived from false_type. A program may specialize this + * template to derive from true_type for a user-defined type T that can be + * constructed with an executor, where the first argument of a constructor has + * type executor_arg_t and the second argument is convertible from type + * Executor. + */ +template +struct uses_executor : false_type {}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_USES_EXECUTOR_HPP diff --git a/boost/asio/version.hpp b/boost/asio/version.hpp new file mode 100644 index 0000000..b93824d --- /dev/null +++ b/boost/asio/version.hpp @@ -0,0 +1,23 @@ +// +// version.hpp +// ~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_VERSION_HPP +#define BOOST_ASIO_VERSION_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +// BOOST_ASIO_VERSION % 100 is the sub-minor version +// BOOST_ASIO_VERSION / 100 % 1000 is the minor version +// BOOST_ASIO_VERSION / 100000 is the major version +#define BOOST_ASIO_VERSION 101401 // 1.14.1 + +#endif // BOOST_ASIO_VERSION_HPP diff --git a/boost/asio/wait_traits.hpp b/boost/asio/wait_traits.hpp new file mode 100644 index 0000000..66719f2 --- /dev/null +++ b/boost/asio/wait_traits.hpp @@ -0,0 +1,58 @@ +// +// wait_traits.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_WAIT_TRAITS_HPP +#define BOOST_ASIO_WAIT_TRAITS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +namespace boost { +namespace asio { + +/// Wait traits suitable for use with the basic_waitable_timer class template. +template +struct wait_traits +{ + /// Convert a clock duration into a duration used for waiting. + /** + * @returns @c d. + */ + static typename Clock::duration to_wait_duration( + const typename Clock::duration& d) + { + return d; + } + + /// Convert a clock duration into a duration used for waiting. + /** + * @returns @c d. + */ + static typename Clock::duration to_wait_duration( + const typename Clock::time_point& t) + { + typename Clock::time_point now = Clock::now(); + if (now + (Clock::duration::max)() < t) + return (Clock::duration::max)(); + if (now + (Clock::duration::min)() > t) + return (Clock::duration::min)(); + return t - now; + } +}; + +} // namespace asio +} // namespace boost + +#include + +#endif // BOOST_ASIO_WAIT_TRAITS_HPP diff --git a/boost/asio/windows/basic_object_handle.hpp b/boost/asio/windows/basic_object_handle.hpp new file mode 100644 index 0000000..9519bc7 --- /dev/null +++ b/boost/asio/windows/basic_object_handle.hpp @@ -0,0 +1,398 @@ +// +// windows/basic_object_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2011 Boris Schaeling (boris@highscore.de) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_WINDOWS_BASIC_OBJECT_HANDLE_HPP +#define BOOST_ASIO_WINDOWS_BASIC_OBJECT_HANDLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) \ + || defined(GENERATING_DOCUMENTATION) + +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_MOVE) +# include +#endif // defined(BOOST_ASIO_HAS_MOVE) + +#include + +namespace boost { +namespace asio { +namespace windows { + +/// Provides object-oriented handle functionality. +/** + * The windows::basic_object_handle class provides asynchronous and blocking + * object-oriented handle functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_object_handle +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// The native representation of a handle. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef boost::asio::detail::win_object_handle_service::native_handle_type + native_handle_type; +#endif + + /// An object handle is always the lowest layer. + typedef basic_object_handle lowest_layer_type; + + /// Construct an object handle without opening it. + /** + * This constructor creates an object handle without opening it. + * + * @param ex The I/O executor that the object handle will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * object handle. + */ + explicit basic_object_handle(const executor_type& ex) + : impl_(ex) + { + } + + /// Construct an object handle without opening it. + /** + * This constructor creates an object handle without opening it. + * + * @param context An execution context which provides the I/O executor that + * the object handle will use, by default, to dispatch handlers for any + * asynchronous operations performed on the object handle. + */ + template + explicit basic_object_handle(ExecutionContext& context, + typename enable_if< + is_convertible::value, + basic_object_handle + >::type* = 0) + : impl_(context) + { + } + + /// Construct an object handle on an existing native handle. + /** + * This constructor creates an object handle object to hold an existing native + * handle. + * + * @param ex The I/O executor that the object handle will use, by default, to + * dispatch handlers for any asynchronous operations performed on the + * object handle. + * + * @param native_handle The new underlying handle implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_object_handle(const executor_type& ex, + const native_handle_type& native_handle) + : impl_(ex) + { + boost::system::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), native_handle, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + + /// Construct an object handle on an existing native handle. + /** + * This constructor creates an object handle object to hold an existing native + * handle. + * + * @param context An execution context which provides the I/O executor that + * the object handle will use, by default, to dispatch handlers for any + * asynchronous operations performed on the object handle. + * + * @param native_handle The new underlying handle implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_object_handle(ExecutionContext& context, + const native_handle_type& native_handle, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + boost::system::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), native_handle, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct an object handle from another. + /** + * This constructor moves an object handle from one object to another. + * + * @param other The other object handle object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_object_handle(const executor_type&) + * constructor. + */ + basic_object_handle(basic_object_handle&& other) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign an object handle from another. + /** + * This assignment operator moves an object handle from one object to another. + * + * @param other The other object handle object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_object_handle(const executor_type&) + * constructor. + */ + basic_object_handle& operator=(basic_object_handle&& other) + { + impl_ = std::move(other.impl_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return impl_.get_executor(); + } + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * layers. Since an object handle cannot contain any further layers, it simply + * returns a reference to itself. + * + * @return A reference to the lowest layer in the stack of layers. Ownership + * is not transferred to the caller. + */ + lowest_layer_type& lowest_layer() + { + return *this; + } + + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since an object handle cannot contain any further layers, it simply + * returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } + + /// Assign an existing native handle to the handle. + /* + * This function opens the handle to hold an existing native handle. + * + * @param handle A native handle. + * + * @throws boost::system::system_error Thrown on failure. + */ + void assign(const native_handle_type& handle) + { + boost::system::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), handle, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + + /// Assign an existing native handle to the handle. + /* + * This function opens the handle to hold an existing native handle. + * + * @param handle A native handle. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& handle, + boost::system::error_code& ec) + { + impl_.get_service().assign(impl_.get_implementation(), handle, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the handle is open. + bool is_open() const + { + return impl_.get_service().is_open(impl_.get_implementation()); + } + + /// Close the handle. + /** + * This function is used to close the handle. Any asynchronous read or write + * operations will be cancelled immediately, and will complete with the + * boost::asio::error::operation_aborted error. + * + * @throws boost::system::system_error Thrown on failure. + */ + void close() + { + boost::system::error_code ec; + impl_.get_service().close(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "close"); + } + + /// Close the handle. + /** + * This function is used to close the handle. Any asynchronous read or write + * operations will be cancelled immediately, and will complete with the + * boost::asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) + { + impl_.get_service().close(impl_.get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get the native handle representation. + /** + * This function may be used to obtain the underlying representation of the + * handle. This is intended to allow access to native handle functionality + * that is not otherwise provided. + */ + native_handle_type native_handle() + { + return impl_.get_service().native_handle(impl_.get_implementation()); + } + + /// Cancel all asynchronous operations associated with the handle. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. + * + * @throws boost::system::system_error Thrown on failure. + */ + void cancel() + { + boost::system::error_code ec; + impl_.get_service().cancel(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the handle. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) + { + impl_.get_service().cancel(impl_.get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Perform a blocking wait on the object handle. + /** + * This function is used to wait for the object handle to be set to the + * signalled state. This function blocks and does not return until the object + * handle has been set to the signalled state. + * + * @throws boost::system::system_error Thrown on failure. + */ + void wait() + { + boost::system::error_code ec; + impl_.get_service().wait(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "wait"); + } + + /// Perform a blocking wait on the object handle. + /** + * This function is used to wait for the object handle to be set to the + * signalled state. This function blocks and does not return until the object + * handle has been set to the signalled state. + * + * @param ec Set to indicate what error occurred, if any. + */ + void wait(boost::system::error_code& ec) + { + impl_.get_service().wait(impl_.get_implementation(), ec); + } + + /// Start an asynchronous wait on the object handle. + /** + * This function is be used to initiate an asynchronous wait against the + * object handle. It always returns immediately. + * + * @param handler The handler to be called when the object handle is set to + * the signalled state. Copies will be made of the handler as required. The + * function signature of the handler must be: + * @code void handler( + * const boost::system::error_code& error // Result of operation. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WaitHandler, + void (boost::system::error_code)) + async_wait(BOOST_ASIO_MOVE_ARG(WaitHandler) handler) + { + boost::asio::async_completion init(handler); + + impl_.get_service().async_wait(impl_.get_implementation(), + init.completion_handler, impl_.get_implementation_executor()); + + return init.result.get(); + } + +private: + // Disallow copying and assignment. + basic_object_handle(const basic_object_handle&) BOOST_ASIO_DELETED; + basic_object_handle& operator=(const basic_object_handle&) BOOST_ASIO_DELETED; + + boost::asio::detail::io_object_impl< + boost::asio::detail::win_object_handle_service, Executor> impl_; +}; + +} // namespace windows +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_WINDOWS_BASIC_OBJECT_HANDLE_HPP diff --git a/boost/asio/windows/basic_overlapped_handle.hpp b/boost/asio/windows/basic_overlapped_handle.hpp new file mode 100644 index 0000000..ccce21f --- /dev/null +++ b/boost/asio/windows/basic_overlapped_handle.hpp @@ -0,0 +1,355 @@ +// +// windows/basic_overlapped_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_WINDOWS_BASIC_OVERLAPPED_HANDLE_HPP +#define BOOST_ASIO_WINDOWS_BASIC_OVERLAPPED_HANDLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ + || defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ + || defined(GENERATING_DOCUMENTATION) + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(BOOST_ASIO_HAS_MOVE) +# include +#endif // defined(BOOST_ASIO_HAS_MOVE) + +#include + +namespace boost { +namespace asio { +namespace windows { + +/// Provides Windows handle functionality for objects that support +/// overlapped I/O. +/** + * The windows::overlapped_handle class provides the ability to wrap a Windows + * handle. The underlying object referred to by the handle must support + * overlapped I/O. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_overlapped_handle +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// The native representation of a handle. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef boost::asio::detail::win_iocp_handle_service::native_handle_type + native_handle_type; +#endif + + /// An overlapped_handle is always the lowest layer. + typedef basic_overlapped_handle lowest_layer_type; + + /// Construct an overlapped handle without opening it. + /** + * This constructor creates an overlapped handle without opening it. + * + * @param ex The I/O executor that the overlapped handle will use, by default, + * to dispatch handlers for any asynchronous operations performed on the + * overlapped handle. + */ + explicit basic_overlapped_handle(const executor_type& ex) + : impl_(ex) + { + } + + /// Construct an overlapped handle without opening it. + /** + * This constructor creates an overlapped handle without opening it. + * + * @param context An execution context which provides the I/O executor that + * the overlapped handle will use, by default, to dispatch handlers for any + * asynchronous operations performed on the overlapped handle. + */ + template + explicit basic_overlapped_handle(ExecutionContext& context, + typename enable_if< + is_convertible::value, + basic_overlapped_handle + >::type* = 0) + : impl_(context) + { + } + + /// Construct an overlapped handle on an existing native handle. + /** + * This constructor creates an overlapped handle object to hold an existing + * native handle. + * + * @param ex The I/O executor that the overlapped handle will use, by default, + * to dispatch handlers for any asynchronous operations performed on the + * overlapped handle. + * + * @param native_handle The new underlying handle implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_overlapped_handle(const executor_type& ex, + const native_handle_type& native_handle) + : impl_(ex) + { + boost::system::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), native_handle, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + + /// Construct an overlapped handle on an existing native handle. + /** + * This constructor creates an overlapped handle object to hold an existing + * native handle. + * + * @param context An execution context which provides the I/O executor that + * the overlapped handle will use, by default, to dispatch handlers for any + * asynchronous operations performed on the overlapped handle. + * + * @param native_handle The new underlying handle implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_overlapped_handle(ExecutionContext& context, + const native_handle_type& native_handle, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context) + { + boost::system::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), native_handle, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct an overlapped handle from another. + /** + * This constructor moves a handle from one object to another. + * + * @param other The other overlapped handle object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c overlapped_handle(const executor_type&) + * constructor. + */ + basic_overlapped_handle(basic_overlapped_handle&& other) + : impl_(std::move(other.impl_)) + { + } + + /// Move-assign an overlapped handle from another. + /** + * This assignment operator moves a handle from one object to another. + * + * @param other The other overlapped handle object from which the move will + * occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c overlapped_handle(const executor_type&) + * constructor. + */ + basic_overlapped_handle& operator=(basic_overlapped_handle&& other) + { + impl_ = std::move(other.impl_); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Get the executor associated with the object. + executor_type get_executor() BOOST_ASIO_NOEXCEPT + { + return impl_.get_executor(); + } + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * layers. Since an overlapped_handle cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A reference to the lowest layer in the stack of layers. Ownership + * is not transferred to the caller. + */ + lowest_layer_type& lowest_layer() + { + return *this; + } + + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since an overlapped_handle cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } + + /// Assign an existing native handle to the handle. + /* + * This function opens the handle to hold an existing native handle. + * + * @param handle A native handle. + * + * @throws boost::system::system_error Thrown on failure. + */ + void assign(const native_handle_type& handle) + { + boost::system::error_code ec; + impl_.get_service().assign(impl_.get_implementation(), handle, ec); + boost::asio::detail::throw_error(ec, "assign"); + } + + /// Assign an existing native handle to the handle. + /* + * This function opens the handle to hold an existing native handle. + * + * @param handle A native handle. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& handle, + boost::system::error_code& ec) + { + impl_.get_service().assign(impl_.get_implementation(), handle, ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Determine whether the handle is open. + bool is_open() const + { + return impl_.get_service().is_open(impl_.get_implementation()); + } + + /// Close the handle. + /** + * This function is used to close the handle. Any asynchronous read or write + * operations will be cancelled immediately, and will complete with the + * boost::asio::error::operation_aborted error. + * + * @throws boost::system::system_error Thrown on failure. + */ + void close() + { + boost::system::error_code ec; + impl_.get_service().close(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "close"); + } + + /// Close the handle. + /** + * This function is used to close the handle. Any asynchronous read or write + * operations will be cancelled immediately, and will complete with the + * boost::asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) + { + impl_.get_service().close(impl_.get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + + /// Get the native handle representation. + /** + * This function may be used to obtain the underlying representation of the + * handle. This is intended to allow access to native handle functionality + * that is not otherwise provided. + */ + native_handle_type native_handle() + { + return impl_.get_service().native_handle(impl_.get_implementation()); + } + + /// Cancel all asynchronous operations associated with the handle. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. + * + * @throws boost::system::system_error Thrown on failure. + */ + void cancel() + { + boost::system::error_code ec; + impl_.get_service().cancel(impl_.get_implementation(), ec); + boost::asio::detail::throw_error(ec, "cancel"); + } + + /// Cancel all asynchronous operations associated with the handle. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the handlers for cancelled operations will be + * passed the boost::asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) + { + impl_.get_service().cancel(impl_.get_implementation(), ec); + BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); + } + +protected: + /// Protected destructor to prevent deletion through this type. + /** + * This function destroys the handle, cancelling any outstanding asynchronous + * wait operations associated with the handle as if by calling @c cancel. + */ + ~basic_overlapped_handle() + { + } + + boost::asio::detail::io_object_impl< + boost::asio::detail::win_iocp_handle_service, Executor> impl_; + +private: + // Disallow copying and assignment. + basic_overlapped_handle(const basic_overlapped_handle&) BOOST_ASIO_DELETED; + basic_overlapped_handle& operator=( + const basic_overlapped_handle&) BOOST_ASIO_DELETED; +}; + +} // namespace windows +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) + // || defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_WINDOWS_BASIC_OVERLAPPED_HANDLE_HPP diff --git a/boost/asio/windows/basic_random_access_handle.hpp b/boost/asio/windows/basic_random_access_handle.hpp new file mode 100644 index 0000000..5f0d6d4 --- /dev/null +++ b/boost/asio/windows/basic_random_access_handle.hpp @@ -0,0 +1,429 @@ +// +// windows/basic_random_access_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP +#define BOOST_ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ + || defined(GENERATING_DOCUMENTATION) + +#include + +namespace boost { +namespace asio { +namespace windows { + +/// Provides random-access handle functionality. +/** + * The windows::basic_random_access_handle class provides asynchronous and + * blocking random-access handle functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_random_access_handle + : public basic_overlapped_handle +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// The native representation of a handle. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef boost::asio::detail::win_iocp_handle_service::native_handle_type + native_handle_type; +#endif + + /// Construct a random-access handle without opening it. + /** + * This constructor creates a random-access handle without opening it. + * + * @param ex The I/O executor that the random-access handle will use, by + * default, to dispatch handlers for any asynchronous operations performed on + * the random-access handle. + */ + explicit basic_random_access_handle(const executor_type& ex) + : basic_overlapped_handle(ex) + { + } + + /// Construct a random-access handle without opening it. + /** + * This constructor creates a random-access handle without opening it. The + * handle needs to be opened or assigned before data can be sent or received + * on it. + * + * @param context An execution context which provides the I/O executor that + * the random-access handle will use, by default, to dispatch handlers for any + * asynchronous operations performed on the random-access handle. + */ + template + explicit basic_random_access_handle(ExecutionContext& context, + typename enable_if< + is_convertible::value, + basic_random_access_handle + >::type* = 0) + : basic_overlapped_handle(context) + { + } + + /// Construct a random-access handle on an existing native handle. + /** + * This constructor creates a random-access handle object to hold an existing + * native handle. + * + * @param ex The I/O executor that the random-access handle will use, by + * default, to dispatch handlers for any asynchronous operations performed on + * the random-access handle. + * + * @param handle The new underlying handle implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_random_access_handle(const executor_type& ex, + const native_handle_type& handle) + : basic_overlapped_handle(ex, handle) + { + } + + /// Construct a random-access handle on an existing native handle. + /** + * This constructor creates a random-access handle object to hold an existing + * native handle. + * + * @param context An execution context which provides the I/O executor that + * the random-access handle will use, by default, to dispatch handlers for any + * asynchronous operations performed on the random-access handle. + * + * @param handle The new underlying handle implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_random_access_handle(ExecutionContext& context, + const native_handle_type& handle, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_overlapped_handle(context, handle) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a random-access handle from another. + /** + * This constructor moves a random-access handle from one object to another. + * + * @param other The other random-access handle object from which the + * move will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_random_access_handle(const executor_type&) + * constructor. + */ + basic_random_access_handle(basic_random_access_handle&& other) + : basic_overlapped_handle(std::move(other)) + { + } + + /// Move-assign a random-access handle from another. + /** + * This assignment operator moves a random-access handle from one object to + * another. + * + * @param other The other random-access handle object from which the + * move will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_random_access_handle(const executor_type&) + * constructor. + */ + basic_random_access_handle& operator=(basic_random_access_handle&& other) + { + basic_overlapped_handle::operator=(std::move(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Write some data to the handle at the specified offset. + /** + * This function is used to write data to the random-access handle. The + * function call will block until one or more bytes of the data has been + * written successfully, or until an error occurs. + * + * @param offset The offset at which the data will be written. + * + * @param buffers One or more data buffers to be written to the handle. + * + * @returns The number of bytes written. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The write_some_at operation may not write all of the data. Consider + * using the @ref write_at function if you need to ensure that all data is + * written before the blocking operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * handle.write_some_at(42, boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t write_some_at(uint64_t offset, + const ConstBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().write_some_at( + this->impl_.get_implementation(), offset, buffers, ec); + boost::asio::detail::throw_error(ec, "write_some_at"); + return s; + } + + /// Write some data to the handle at the specified offset. + /** + * This function is used to write data to the random-access handle. The + * function call will block until one or more bytes of the data has been + * written successfully, or until an error occurs. + * + * @param offset The offset at which the data will be written. + * + * @param buffers One or more data buffers to be written to the handle. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. Returns 0 if an error occurred. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write_at function if you need to ensure that + * all data is written before the blocking operation completes. + */ + template + std::size_t write_some_at(uint64_t offset, + const ConstBufferSequence& buffers, boost::system::error_code& ec) + { + return this->impl_.get_service().write_some_at( + this->impl_.get_implementation(), offset, buffers, ec); + } + + /// Start an asynchronous write at the specified offset. + /** + * This function is used to asynchronously write data to the random-access + * handle. The function call always returns immediately. + * + * @param offset The offset at which the data will be written. + * + * @param buffers One or more data buffers to be written to the handle. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes written. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The write operation may not transmit all of the data to the peer. + * Consider using the @ref async_write_at function if you need to ensure that + * all data is written before the asynchronous operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * handle.async_write_some_at(42, boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_write_some_at(uint64_t offset, + const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + boost::asio::async_completion init(handler); + + this->impl_.get_service().async_write_some_at( + this->impl_.get_implementation(), offset, + buffers, init.completion_handler, + this->impl_.get_implementation_executor()); + + return init.result.get(); + } + + /// Read some data from the handle at the specified offset. + /** + * This function is used to read data from the random-access handle. The + * function call will block until one or more bytes of data has been read + * successfully, or until an error occurs. + * + * @param offset The offset at which the data will be read. + * + * @param buffers One or more buffers into which the data will be read. + * + * @returns The number of bytes read. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read_at function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * handle.read_some_at(42, boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t read_some_at(uint64_t offset, + const MutableBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().read_some_at( + this->impl_.get_implementation(), offset, buffers, ec); + boost::asio::detail::throw_error(ec, "read_some_at"); + return s; + } + + /// Read some data from the handle at the specified offset. + /** + * This function is used to read data from the random-access handle. The + * function call will block until one or more bytes of data has been read + * successfully, or until an error occurs. + * + * @param offset The offset at which the data will be read. + * + * @param buffers One or more buffers into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. Returns 0 if an error occurred. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read_at function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + */ + template + std::size_t read_some_at(uint64_t offset, + const MutableBufferSequence& buffers, boost::system::error_code& ec) + { + return this->impl_.get_service().read_some_at( + this->impl_.get_implementation(), offset, buffers, ec); + } + + /// Start an asynchronous read at the specified offset. + /** + * This function is used to asynchronously read data from the random-access + * handle. The function call always returns immediately. + * + * @param offset The offset at which the data will be read. + * + * @param buffers One or more buffers into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes read. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The read operation may not read all of the requested number of bytes. + * Consider using the @ref async_read_at function if you need to ensure that + * the requested amount of data is read before the asynchronous operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * handle.async_read_some_at(42, boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_read_some_at(uint64_t offset, + const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + boost::asio::async_completion init(handler); + + this->impl_.get_service().async_read_some_at( + this->impl_.get_implementation(), offset, + buffers, init.completion_handler, + this->impl_.get_implementation_executor()); + + return init.result.get(); + } +}; + +} // namespace windows +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP diff --git a/boost/asio/windows/basic_stream_handle.hpp b/boost/asio/windows/basic_stream_handle.hpp new file mode 100644 index 0000000..f8d50d5 --- /dev/null +++ b/boost/asio/windows/basic_stream_handle.hpp @@ -0,0 +1,413 @@ +// +// windows/basic_stream_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP +#define BOOST_ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include + +#if defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ + || defined(GENERATING_DOCUMENTATION) + +#include + +namespace boost { +namespace asio { +namespace windows { + +/// Provides stream-oriented handle functionality. +/** + * The windows::basic_stream_handle class provides asynchronous and blocking + * stream-oriented handle functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Concepts: + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. + */ +template +class basic_stream_handle + : public basic_overlapped_handle +{ +public: + /// The type of the executor associated with the object. + typedef Executor executor_type; + + /// The native representation of a handle. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_handle_type; +#else + typedef boost::asio::detail::win_iocp_handle_service::native_handle_type + native_handle_type; +#endif + + /// Construct a stream handle without opening it. + /** + * This constructor creates a stream handle without opening it. + * + * @param ex The I/O executor that the stream handle will use, by default, to + * dispatch handlers for any asynchronous operations performed on the stream + * handle. + */ + explicit basic_stream_handle(const executor_type& ex) + : basic_overlapped_handle(ex) + { + } + + /// Construct a stream handle without opening it. + /** + * This constructor creates a stream handle without opening it. The handle + * needs to be opened or assigned before data can be sent or received on it. + * + * @param context An execution context which provides the I/O executor that + * the stream handle will use, by default, to dispatch handlers for any + * asynchronous operations performed on the stream handle. + */ + template + explicit basic_stream_handle(ExecutionContext& context, + typename enable_if< + is_convertible::value, + basic_stream_handle + >::type* = 0) + : basic_overlapped_handle(context) + { + } + + /// Construct a stream handle on an existing native handle. + /** + * This constructor creates a stream handle object to hold an existing native + * handle. + * + * @param ex The I/O executor that the stream handle will use, by default, to + * dispatch handlers for any asynchronous operations performed on the stream + * handle. + * + * @param handle The new underlying handle implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + basic_stream_handle(const executor_type& ex, const native_handle_type& handle) + : basic_overlapped_handle(ex, handle) + { + } + + /// Construct a stream handle on an existing native handle. + /** + * This constructor creates a stream handle object to hold an existing native + * handle. + * + * @param context An execution context which provides the I/O executor that + * the stream handle will use, by default, to dispatch handlers for any + * asynchronous operations performed on the stream handle. + * + * @param handle The new underlying handle implementation. + * + * @throws boost::system::system_error Thrown on failure. + */ + template + basic_stream_handle(ExecutionContext& context, + const native_handle_type& handle, + typename enable_if< + is_convertible::value + >::type* = 0) + : basic_overlapped_handle(context, handle) + { + } + +#if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + /// Move-construct a stream handle from another. + /** + * This constructor moves a stream handle from one object to another. + * + * @param other The other stream handle object from which the move + * will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_handle(const executor_type&) + * constructor. + */ + basic_stream_handle(basic_stream_handle&& other) + : basic_overlapped_handle(std::move(other)) + { + } + + /// Move-assign a stream handle from another. + /** + * This assignment operator moves a stream handle from one object to + * another. + * + * @param other The other stream handle object from which the move will occur. + * + * @note Following the move, the moved-from object is in the same state as if + * constructed using the @c basic_stream_handle(const executor_type&) + * constructor. + */ + basic_stream_handle& operator=(basic_stream_handle&& other) + { + basic_overlapped_handle::operator=(std::move(other)); + return *this; + } +#endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) + + /// Write some data to the handle. + /** + * This function is used to write data to the stream handle. The function call + * will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the handle. + * + * @returns The number of bytes written. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * handle.write_some(boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t write_some(const ConstBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().write_some( + this->impl_.get_implementation(), buffers, ec); + boost::asio::detail::throw_error(ec, "write_some"); + return s; + } + + /// Write some data to the handle. + /** + * This function is used to write data to the stream handle. The function call + * will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the handle. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. Returns 0 if an error occurred. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + */ + template + std::size_t write_some(const ConstBufferSequence& buffers, + boost::system::error_code& ec) + { + return this->impl_.get_service().write_some( + this->impl_.get_implementation(), buffers, ec); + } + + /// Start an asynchronous write. + /** + * This function is used to asynchronously write data to the stream handle. + * The function call always returns immediately. + * + * @param buffers One or more data buffers to be written to the handle. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes written. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The write operation may not transmit all of the data to the peer. + * Consider using the @ref async_write function if you need to ensure that all + * data is written before the asynchronous operation completes. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * handle.async_write_some(boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) + async_write_some(const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a WriteHandler. + BOOST_ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check; + + boost::asio::async_completion init(handler); + + this->impl_.get_service().async_write_some( + this->impl_.get_implementation(), + buffers, init.completion_handler, + this->impl_.get_implementation_executor()); + + return init.result.get(); + } + + /// Read some data from the handle. + /** + * This function is used to read data from the stream handle. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @returns The number of bytes read. + * + * @throws boost::system::system_error Thrown on failure. An error code of + * boost::asio::error::eof indicates that the connection was closed by the + * peer. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * handle.read_some(boost::asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t read_some(const MutableBufferSequence& buffers) + { + boost::system::error_code ec; + std::size_t s = this->impl_.get_service().read_some( + this->impl_.get_implementation(), buffers, ec); + boost::asio::detail::throw_error(ec, "read_some"); + return s; + } + + /// Read some data from the handle. + /** + * This function is used to read data from the stream handle. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. Returns 0 if an error occurred. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + */ + template + std::size_t read_some(const MutableBufferSequence& buffers, + boost::system::error_code& ec) + { + return this->impl_.get_service().read_some( + this->impl_.get_implementation(), buffers, ec); + } + + /// Start an asynchronous read. + /** + * This function is used to asynchronously read data from the stream handle. + * The function call always returns immediately. + * + * @param buffers One or more buffers into which the data will be read. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the read operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes read. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @note The read operation may not read all of the requested number of bytes. + * Consider using the @ref async_read function if you need to ensure that the + * requested amount of data is read before the asynchronous operation + * completes. + * + * @par Example + * To read into a single data buffer use the @ref buffer function as follows: + * @code + * handle.async_read_some(boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + BOOST_ASIO_INITFN_RESULT_TYPE(ReadHandler, + void (boost::system::error_code, std::size_t)) + async_read_some(const MutableBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(ReadHandler) handler) + { + // If you get an error on the following line it means that your handler does + // not meet the documented type requirements for a ReadHandler. + BOOST_ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check; + + boost::asio::async_completion init(handler); + + this->impl_.get_service().async_read_some( + this->impl_.get_implementation(), + buffers, init.completion_handler, + this->impl_.get_implementation_executor()); + + return init.result.get(); + } +}; + +} // namespace windows +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP diff --git a/boost/asio/windows/object_handle.hpp b/boost/asio/windows/object_handle.hpp new file mode 100644 index 0000000..6cde166 --- /dev/null +++ b/boost/asio/windows/object_handle.hpp @@ -0,0 +1,40 @@ +// +// windows/object_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2011 Boris Schaeling (boris@highscore.de) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_WINDOWS_OBJECT_HANDLE_HPP +#define BOOST_ASIO_WINDOWS_OBJECT_HANDLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) \ + || defined(GENERATING_DOCUMENTATION) + +#include + +namespace boost { +namespace asio { +namespace windows { + +/// Typedef for the typical usage of an object handle. +typedef basic_object_handle<> object_handle; + +} // namespace windows +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_WINDOWS_OBJECT_HANDLE_HPP diff --git a/boost/asio/windows/overlapped_handle.hpp b/boost/asio/windows/overlapped_handle.hpp new file mode 100644 index 0000000..e87e7b3 --- /dev/null +++ b/boost/asio/windows/overlapped_handle.hpp @@ -0,0 +1,41 @@ +// +// windows/overlapped_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_WINDOWS_OVERLAPPED_HANDLE_HPP +#define BOOST_ASIO_WINDOWS_OVERLAPPED_HANDLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ + || defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ + || defined(GENERATING_DOCUMENTATION) + +#include + +namespace boost { +namespace asio { +namespace windows { + +/// Typedef for the typical usage of an overlapped handle. +typedef basic_overlapped_handle<> overlapped_handle; + +} // namespace windows +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) + // || defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_WINDOWS_OVERLAPPED_HANDLE_HPP diff --git a/boost/asio/windows/overlapped_ptr.hpp b/boost/asio/windows/overlapped_ptr.hpp new file mode 100644 index 0000000..a891248 --- /dev/null +++ b/boost/asio/windows/overlapped_ptr.hpp @@ -0,0 +1,145 @@ +// +// windows/overlapped_ptr.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_WINDOWS_OVERLAPPED_PTR_HPP +#define BOOST_ASIO_WINDOWS_OVERLAPPED_PTR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) \ + || defined(GENERATING_DOCUMENTATION) + +#include +#include +#include + +#include + +namespace boost { +namespace asio { +namespace windows { + +/// Wraps a handler to create an OVERLAPPED object for use with overlapped I/O. +/** + * A special-purpose smart pointer used to wrap an application handler so that + * it can be passed as the LPOVERLAPPED argument to overlapped I/O functions. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +class overlapped_ptr + : private noncopyable +{ +public: + /// Construct an empty overlapped_ptr. + overlapped_ptr() + : impl_() + { + } + + /// Construct an overlapped_ptr to contain the specified handler. + template + explicit overlapped_ptr(ExecutionContext& context, + BOOST_ASIO_MOVE_ARG(Handler) handler, + typename enable_if< + is_convertible::value + >::type* = 0) + : impl_(context.get_executor(), BOOST_ASIO_MOVE_CAST(Handler)(handler)) + { + } + + /// Construct an overlapped_ptr to contain the specified handler. + template + explicit overlapped_ptr(const Executor& ex, + BOOST_ASIO_MOVE_ARG(Handler) handler, + typename enable_if< + is_executor::value + >::type* = 0) + : impl_(ex, BOOST_ASIO_MOVE_CAST(Handler)(handler)) + { + } + + /// Destructor automatically frees the OVERLAPPED object unless released. + ~overlapped_ptr() + { + } + + /// Reset to empty. + void reset() + { + impl_.reset(); + } + + /// Reset to contain the specified handler, freeing any current OVERLAPPED + /// object. + template + void reset(ExecutionContext& context, BOOST_ASIO_MOVE_ARG(Handler) handler, + typename enable_if< + is_convertible::value + >::type* = 0) + { + impl_.reset(context.get_executor(), BOOST_ASIO_MOVE_CAST(Handler)(handler)); + } + + /// Reset to contain the specified handler, freeing any current OVERLAPPED + /// object. + template + void reset(const Executor& ex, BOOST_ASIO_MOVE_ARG(Handler) handler, + typename enable_if< + is_executor::value + >::type* = 0) + { + impl_.reset(ex, BOOST_ASIO_MOVE_CAST(Handler)(handler)); + } + + /// Get the contained OVERLAPPED object. + OVERLAPPED* get() + { + return impl_.get(); + } + + /// Get the contained OVERLAPPED object. + const OVERLAPPED* get() const + { + return impl_.get(); + } + + /// Release ownership of the OVERLAPPED object. + OVERLAPPED* release() + { + return impl_.release(); + } + + /// Post completion notification for overlapped operation. Releases ownership. + void complete(const boost::system::error_code& ec, + std::size_t bytes_transferred) + { + impl_.complete(ec, bytes_transferred); + } + +private: + detail::win_iocp_overlapped_ptr impl_; +}; + +} // namespace windows +} // namespace asio +} // namespace boost + +#include + +#endif // defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_WINDOWS_OVERLAPPED_PTR_HPP diff --git a/boost/asio/windows/random_access_handle.hpp b/boost/asio/windows/random_access_handle.hpp new file mode 100644 index 0000000..77ae022 --- /dev/null +++ b/boost/asio/windows/random_access_handle.hpp @@ -0,0 +1,39 @@ +// +// windows/random_access_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_HPP +#define BOOST_ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ + || defined(GENERATING_DOCUMENTATION) + +#include + +namespace boost { +namespace asio { +namespace windows { + +/// Typedef for the typical usage of a random-access handle. +typedef basic_random_access_handle<> random_access_handle; + +} // namespace windows +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_WINDOWS_RANDOM_ACCESS_HANDLE_HPP diff --git a/boost/asio/windows/stream_handle.hpp b/boost/asio/windows/stream_handle.hpp new file mode 100644 index 0000000..56e7db0 --- /dev/null +++ b/boost/asio/windows/stream_handle.hpp @@ -0,0 +1,39 @@ +// +// windows/stream_handle.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_WINDOWS_STREAM_HANDLE_HPP +#define BOOST_ASIO_WINDOWS_STREAM_HANDLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include + +#if defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ + || defined(GENERATING_DOCUMENTATION) + +#include + +namespace boost { +namespace asio { +namespace windows { + +/// Typedef for the typical usage of a stream-oriented handle. +typedef basic_stream_handle<> stream_handle; + +} // namespace windows +} // namespace asio +} // namespace boost + +#endif // defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) + // || defined(GENERATING_DOCUMENTATION) + +#endif // BOOST_ASIO_WINDOWS_STREAM_HANDLE_HPP diff --git a/boost/asio/write.hpp b/boost/asio/write.hpp new file mode 100644 index 0000000..041f163 --- /dev/null +++ b/boost/asio/write.hpp @@ -0,0 +1,1219 @@ +// +// write.hpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_WRITE_HPP +#define BOOST_ASIO_WRITE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +# include +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +#include + +namespace boost { +namespace asio { + +/** + * @defgroup write boost::asio::write + * + * @brief The @c write function is a composed operation that writes a certain + * amount of data to a stream before returning. + */ +/*@{*/ + +/// Write all of the supplied data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied buffers has been written. That is, the + * bytes transferred is equal to the sum of the buffer sizes. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers One or more buffers containing the data to be written. The sum + * of the buffer sizes indicates the maximum number of bytes to write to the + * stream. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code boost::asio::write(s, boost::asio::buffer(data, size)); @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + * + * @note This overload is equivalent to calling: + * @code boost::asio::write( + * s, buffers, + * boost::asio::transfer_all()); @endcode + */ +template +std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + typename enable_if< + is_const_buffer_sequence::value + >::type* = 0); + +/// Write all of the supplied data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied buffers has been written. That is, the + * bytes transferred is equal to the sum of the buffer sizes. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers One or more buffers containing the data to be written. The sum + * of the buffer sizes indicates the maximum number of bytes to write to the + * stream. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes transferred. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code boost::asio::write(s, boost::asio::buffer(data, size), ec); @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + * + * @note This overload is equivalent to calling: + * @code boost::asio::write( + * s, buffers, + * boost::asio::transfer_all(), ec); @endcode + */ +template +std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + boost::system::error_code& ec, + typename enable_if< + is_const_buffer_sequence::value + >::type* = 0); + +/// Write a certain amount of data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied buffers has been written. That is, the + * bytes transferred is equal to the sum of the buffer sizes. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers One or more buffers containing the data to be written. The sum + * of the buffer sizes indicates the maximum number of bytes to write to the + * stream. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest write_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's write_some function. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code boost::asio::write(s, boost::asio::buffer(data, size), + * boost::asio::transfer_at_least(32)); @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ +template +std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, + typename enable_if< + is_const_buffer_sequence::value + >::type* = 0); + +/// Write a certain amount of data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied buffers has been written. That is, the + * bytes transferred is equal to the sum of the buffer sizes. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers One or more buffers containing the data to be written. The sum + * of the buffer sizes indicates the maximum number of bytes to write to the + * stream. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest write_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's write_some function. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. + */ +template +std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_const_buffer_sequence::value + >::type* = 0); + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Write all of the supplied data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note This overload is equivalent to calling: + * @code boost::asio::write( + * s, buffers, + * boost::asio::transfer_all()); @endcode + */ +template +std::size_t write(SyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +/// Write all of the supplied data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes transferred. + * + * @note This overload is equivalent to calling: + * @code boost::asio::write( + * s, buffers, + * boost::asio::transfer_all(), ec); @endcode + */ +template +std::size_t write(SyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +/// Write a certain amount of data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest write_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's write_some function. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + */ +template +std::size_t write(SyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +/// Write a certain amount of data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest write_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's write_some function. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. + */ +template +std::size_t write(SyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +/// Write all of the supplied data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied basic_streambuf has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param b The basic_streambuf object from which data will be written. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note This overload is equivalent to calling: + * @code boost::asio::write( + * s, b, + * boost::asio::transfer_all()); @endcode + */ +template +std::size_t write(SyncWriteStream& s, basic_streambuf& b); + +/// Write all of the supplied data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied basic_streambuf has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param b The basic_streambuf object from which data will be written. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes transferred. + * + * @note This overload is equivalent to calling: + * @code boost::asio::write( + * s, b, + * boost::asio::transfer_all(), ec); @endcode + */ +template +std::size_t write(SyncWriteStream& s, basic_streambuf& b, + boost::system::error_code& ec); + +/// Write a certain amount of data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied basic_streambuf has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param b The basic_streambuf object from which data will be written. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest write_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's write_some function. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + */ +template +std::size_t write(SyncWriteStream& s, basic_streambuf& b, + CompletionCondition completion_condition); + +/// Write a certain amount of data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied basic_streambuf has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param b The basic_streambuf object from which data will be written. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest write_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's write_some function. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. + */ +template +std::size_t write(SyncWriteStream& s, basic_streambuf& b, + CompletionCondition completion_condition, boost::system::error_code& ec); + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Write all of the supplied data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note This overload is equivalent to calling: + * @code boost::asio::write( + * s, buffers, + * boost::asio::transfer_all()); @endcode + */ +template +std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +/// Write all of the supplied data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes transferred. + * + * @note This overload is equivalent to calling: + * @code boost::asio::write( + * s, buffers, + * boost::asio::transfer_all(), ec); @endcode + */ +template +std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +/// Write a certain amount of data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest write_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's write_some function. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + */ +template +std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +/// Write a certain amount of data to a stream before returning. +/** + * This function is used to write a certain number of bytes of data to a stream. + * The call will block until one of the following conditions is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * write_some function. + * + * @param s The stream to which the data is to be written. The type must support + * the SyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Successfully written data is automatically consumed from the buffers. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest write_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's write_some function. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. + */ +template +std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, boost::system::error_code& ec, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +/*@}*/ +/** + * @defgroup async_write boost::asio::async_write + * + * @brief The @c async_write function is a composed asynchronous operation that + * writes a certain amount of data to a stream before completion. + */ +/*@{*/ + +/// Start an asynchronous operation to write all of the supplied data to a +/// stream. +/** + * This function is used to asynchronously write a certain number of bytes of + * data to a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li All of the data in the supplied buffers has been written. That is, the + * bytes transferred is equal to the sum of the buffer sizes. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_write_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other write operations (such + * as async_write, the stream's async_write_some function, or any other composed + * operations that perform writes) until this operation completes. + * + * @param s The stream to which the data is to be written. The type must support + * the AsyncWriteStream concept. + * + * @param buffers One or more buffers containing the data to be written. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes written from the + * // buffers. If an error occurred, + * // this will be less than the sum + * // of the buffer sizes. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * boost::asio::async_write(s, boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_const_buffer_sequence::value + >::type* = 0); + +/// Start an asynchronous operation to write a certain amount of data to a +/// stream. +/** + * This function is used to asynchronously write a certain number of bytes of + * data to a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li All of the data in the supplied buffers has been written. That is, the + * bytes transferred is equal to the sum of the buffer sizes. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_write_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other write operations (such + * as async_write, the stream's async_write_some function, or any other composed + * operations that perform writes) until this operation completes. + * + * @param s The stream to which the data is to be written. The type must support + * the AsyncWriteStream concept. + * + * @param buffers One or more buffers containing the data to be written. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest async_write_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's async_write_some function. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes written from the + * // buffers. If an error occurred, + * // this will be less than the sum + * // of the buffer sizes. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code boost::asio::async_write(s, + * boost::asio::buffer(data, size), + * boost::asio::transfer_at_least(32), + * handler); @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_const_buffer_sequence::value + >::type* = 0); + +#if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Start an asynchronous operation to write all of the supplied data to a +/// stream. +/** + * This function is used to asynchronously write a certain number of bytes of + * data to a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_write_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other write operations (such + * as async_write, the stream's async_write_some function, or any other composed + * operations that perform writes) until this operation completes. + * + * @param s The stream to which the data is to be written. The type must support + * the AsyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. Successfully written + * data is automatically consumed from the buffers. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes written from the + * // buffers. If an error occurred, + * // this will be less than the sum + * // of the buffer sizes. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +/// Start an asynchronous operation to write a certain amount of data to a +/// stream. +/** + * This function is used to asynchronously write a certain number of bytes of + * data to a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_write_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other write operations (such + * as async_write, the stream's async_write_some function, or any other composed + * operations that perform writes) until this operation completes. + * + * @param s The stream to which the data is to be written. The type must support + * the AsyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. Successfully written + * data is automatically consumed from the buffers. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest async_write_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's async_write_some function. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes written from the + * // buffers. If an error occurred, + * // this will be less than the sum + * // of the buffer sizes. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, + BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer_v1::type>::value + && !is_dynamic_buffer_v2::type>::value + >::type* = 0); + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +/// Start an asynchronous operation to write all of the supplied data to a +/// stream. +/** + * This function is used to asynchronously write a certain number of bytes of + * data to a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li All of the data in the supplied basic_streambuf has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_write_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other write operations (such + * as async_write, the stream's async_write_some function, or any other composed + * operations that perform writes) until this operation completes. + * + * @param s The stream to which the data is to be written. The type must support + * the AsyncWriteStream concept. + * + * @param b A basic_streambuf object from which data will be written. Ownership + * of the streambuf is retained by the caller, which must guarantee that it + * remains valid until the handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes written from the + * // buffers. If an error occurred, + * // this will be less than the sum + * // of the buffer sizes. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, basic_streambuf& b, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler); + +/// Start an asynchronous operation to write a certain amount of data to a +/// stream. +/** + * This function is used to asynchronously write a certain number of bytes of + * data to a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li All of the data in the supplied basic_streambuf has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_write_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other write operations (such + * as async_write, the stream's async_write_some function, or any other composed + * operations that perform writes) until this operation completes. + * + * @param s The stream to which the data is to be written. The type must support + * the AsyncWriteStream concept. + * + * @param b A basic_streambuf object from which data will be written. Ownership + * of the streambuf is retained by the caller, which must guarantee that it + * remains valid until the handler is called. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest async_write_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's async_write_some function. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes written from the + * // buffers. If an error occurred, + * // this will be less than the sum + * // of the buffer sizes. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, basic_streambuf& b, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler); + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) +#endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) + +/// Start an asynchronous operation to write all of the supplied data to a +/// stream. +/** + * This function is used to asynchronously write a certain number of bytes of + * data to a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_write_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other write operations (such + * as async_write, the stream's async_write_some function, or any other composed + * operations that perform writes) until this operation completes. + * + * @param s The stream to which the data is to be written. The type must support + * the AsyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. Successfully written + * data is automatically consumed from the buffers. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes written from the + * // buffers. If an error occurred, + * // this will be less than the sum + * // of the buffer sizes. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +/// Start an asynchronous operation to write a certain amount of data to a +/// stream. +/** + * This function is used to asynchronously write a certain number of bytes of + * data to a stream. The function call always returns immediately. The + * asynchronous operation will continue until one of the following conditions + * is true: + * + * @li All of the data in the supplied dynamic buffer sequence has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the stream's + * async_write_some function, and is known as a composed operation. The + * program must ensure that the stream performs no other write operations (such + * as async_write, the stream's async_write_some function, or any other composed + * operations that perform writes) until this operation completes. + * + * @param s The stream to which the data is to be written. The type must support + * the AsyncWriteStream concept. + * + * @param buffers The dynamic buffer sequence from which data will be written. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. Successfully written + * data is automatically consumed from the buffers. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest async_write_some operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's async_write_some function. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * const boost::system::error_code& error, // Result of operation. + * + * std::size_t bytes_transferred // Number of bytes written from the + * // buffers. If an error occurred, + * // this will be less than the sum + * // of the buffer sizes. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler, + typename enable_if< + is_dynamic_buffer_v2::value + >::type* = 0); + +/*@}*/ + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // BOOST_ASIO_WRITE_HPP diff --git a/boost/asio/write_at.hpp b/boost/asio/write_at.hpp new file mode 100644 index 0000000..d874327 --- /dev/null +++ b/boost/asio/write_at.hpp @@ -0,0 +1,681 @@ +// +// write_at.hpp +// ~~~~~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BOOST_ASIO_WRITE_AT_HPP +#define BOOST_ASIO_WRITE_AT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +# include +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +#include + +namespace boost { +namespace asio { + +/** + * @defgroup write_at boost::asio::write_at + * + * @brief The @c write_at function is a composed operation that writes a + * certain amount of data at a specified offset before returning. + */ +/*@{*/ + +/// Write all of the supplied data at the specified offset before returning. +/** + * This function is used to write a certain number of bytes of data to a random + * access device at a specified offset. The call will block until one of the + * following conditions is true: + * + * @li All of the data in the supplied buffers has been written. That is, the + * bytes transferred is equal to the sum of the buffer sizes. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the device's + * write_some_at function. + * + * @param d The device to which the data is to be written. The type must support + * the SyncRandomAccessWriteDevice concept. + * + * @param offset The offset at which the data will be written. + * + * @param buffers One or more buffers containing the data to be written. The sum + * of the buffer sizes indicates the maximum number of bytes to write to the + * device. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code boost::asio::write_at(d, 42, boost::asio::buffer(data, size)); @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + * + * @note This overload is equivalent to calling: + * @code boost::asio::write_at( + * d, offset, buffers, + * boost::asio::transfer_all()); @endcode + */ +template +std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers); + +/// Write all of the supplied data at the specified offset before returning. +/** + * This function is used to write a certain number of bytes of data to a random + * access device at a specified offset. The call will block until one of the + * following conditions is true: + * + * @li All of the data in the supplied buffers has been written. That is, the + * bytes transferred is equal to the sum of the buffer sizes. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the device's + * write_some_at function. + * + * @param d The device to which the data is to be written. The type must support + * the SyncRandomAccessWriteDevice concept. + * + * @param offset The offset at which the data will be written. + * + * @param buffers One or more buffers containing the data to be written. The sum + * of the buffer sizes indicates the maximum number of bytes to write to the + * device. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes transferred. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code boost::asio::write_at(d, 42, + * boost::asio::buffer(data, size), ec); @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + * + * @note This overload is equivalent to calling: + * @code boost::asio::write_at( + * d, offset, buffers, + * boost::asio::transfer_all(), ec); @endcode + */ +template +std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, + boost::system::error_code& ec); + +/// Write a certain amount of data at a specified offset before returning. +/** + * This function is used to write a certain number of bytes of data to a random + * access device at a specified offset. The call will block until one of the + * following conditions is true: + * + * @li All of the data in the supplied buffers has been written. That is, the + * bytes transferred is equal to the sum of the buffer sizes. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the device's + * write_some_at function. + * + * @param d The device to which the data is to be written. The type must support + * the SyncRandomAccessWriteDevice concept. + * + * @param offset The offset at which the data will be written. + * + * @param buffers One or more buffers containing the data to be written. The sum + * of the buffer sizes indicates the maximum number of bytes to write to the + * device. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest write_some_at operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the device's write_some_at function. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code boost::asio::write_at(d, 42, boost::asio::buffer(data, size), + * boost::asio::transfer_at_least(32)); @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ +template +std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, + CompletionCondition completion_condition); + +/// Write a certain amount of data at a specified offset before returning. +/** + * This function is used to write a certain number of bytes of data to a random + * access device at a specified offset. The call will block until one of the + * following conditions is true: + * + * @li All of the data in the supplied buffers has been written. That is, the + * bytes transferred is equal to the sum of the buffer sizes. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the device's + * write_some_at function. + * + * @param d The device to which the data is to be written. The type must support + * the SyncRandomAccessWriteDevice concept. + * + * @param offset The offset at which the data will be written. + * + * @param buffers One or more buffers containing the data to be written. The sum + * of the buffer sizes indicates the maximum number of bytes to write to the + * device. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest write_some_at operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the device's write_some_at function. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. + */ +template +std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, boost::system::error_code& ec); + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +/// Write all of the supplied data at the specified offset before returning. +/** + * This function is used to write a certain number of bytes of data to a random + * access device at a specified offset. The call will block until one of the + * following conditions is true: + * + * @li All of the data in the supplied basic_streambuf has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the device's + * write_some_at function. + * + * @param d The device to which the data is to be written. The type must support + * the SyncRandomAccessWriteDevice concept. + * + * @param offset The offset at which the data will be written. + * + * @param b The basic_streambuf object from which data will be written. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + * + * @note This overload is equivalent to calling: + * @code boost::asio::write_at( + * d, 42, b, + * boost::asio::transfer_all()); @endcode + */ +template +std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, basic_streambuf& b); + +/// Write all of the supplied data at the specified offset before returning. +/** + * This function is used to write a certain number of bytes of data to a random + * access device at a specified offset. The call will block until one of the + * following conditions is true: + * + * @li All of the data in the supplied basic_streambuf has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the device's + * write_some_at function. + * + * @param d The device to which the data is to be written. The type must support + * the SyncRandomAccessWriteDevice concept. + * + * @param offset The offset at which the data will be written. + * + * @param b The basic_streambuf object from which data will be written. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes transferred. + * + * @note This overload is equivalent to calling: + * @code boost::asio::write_at( + * d, 42, b, + * boost::asio::transfer_all(), ec); @endcode + */ +template +std::size_t write_at(SyncRandomAccessWriteDevice& d, + uint64_t offset, basic_streambuf& b, + boost::system::error_code& ec); + +/// Write a certain amount of data at a specified offset before returning. +/** + * This function is used to write a certain number of bytes of data to a random + * access device at a specified offset. The call will block until one of the + * following conditions is true: + * + * @li All of the data in the supplied basic_streambuf has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the device's + * write_some_at function. + * + * @param d The device to which the data is to be written. The type must support + * the SyncRandomAccessWriteDevice concept. + * + * @param offset The offset at which the data will be written. + * + * @param b The basic_streambuf object from which data will be written. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest write_some_at operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the device's write_some_at function. + * + * @returns The number of bytes transferred. + * + * @throws boost::system::system_error Thrown on failure. + */ +template +std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, + basic_streambuf& b, CompletionCondition completion_condition); + +/// Write a certain amount of data at a specified offset before returning. +/** + * This function is used to write a certain number of bytes of data to a random + * access device at a specified offset. The call will block until one of the + * following conditions is true: + * + * @li All of the data in the supplied basic_streambuf has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the device's + * write_some_at function. + * + * @param d The device to which the data is to be written. The type must support + * the SyncRandomAccessWriteDevice concept. + * + * @param offset The offset at which the data will be written. + * + * @param b The basic_streambuf object from which data will be written. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest write_some_at operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the device's write_some_at function. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. + */ +template +std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, + basic_streambuf& b, CompletionCondition completion_condition, + boost::system::error_code& ec); + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +/*@}*/ +/** + * @defgroup async_write_at boost::asio::async_write_at + * + * @brief The @c async_write_at function is a composed asynchronous operation + * that writes a certain amount of data at the specified offset before + * completion. + */ +/*@{*/ + +/// Start an asynchronous operation to write all of the supplied data at the +/// specified offset. +/** + * This function is used to asynchronously write a certain number of bytes of + * data to a random access device at a specified offset. The function call + * always returns immediately. The asynchronous operation will continue until + * one of the following conditions is true: + * + * @li All of the data in the supplied buffers has been written. That is, the + * bytes transferred is equal to the sum of the buffer sizes. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the device's + * async_write_some_at function, and is known as a composed operation. + * The program must ensure that the device performs no overlapping + * write operations (such as async_write_at, the device's async_write_some_at + * function, or any other composed operations that perform writes) until this + * operation completes. Operations are overlapping if the regions defined by + * their offsets, and the numbers of bytes to write, intersect. + * + * @param d The device to which the data is to be written. The type must support + * the AsyncRandomAccessWriteDevice concept. + * + * @param offset The offset at which the data will be written. + * + * @param buffers One or more buffers containing the data to be written. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of + * the handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // Number of bytes written from the buffers. If an error + * // occurred, this will be less than the sum of the buffer sizes. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code + * boost::asio::async_write_at(d, 42, boost::asio::buffer(data, size), handler); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, + const ConstBufferSequence& buffers, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler); + +/// Start an asynchronous operation to write a certain amount of data at the +/// specified offset. +/** + * This function is used to asynchronously write a certain number of bytes of + * data to a random access device at a specified offset. The function call + * always returns immediately. The asynchronous operation will continue until + * one of the following conditions is true: + * + * @li All of the data in the supplied buffers has been written. That is, the + * bytes transferred is equal to the sum of the buffer sizes. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the device's + * async_write_some_at function, and is known as a composed operation. + * The program must ensure that the device performs no overlapping + * write operations (such as async_write_at, the device's async_write_some_at + * function, or any other composed operations that perform writes) until this + * operation completes. Operations are overlapping if the regions defined by + * their offsets, and the numbers of bytes to write, intersect. + * + * @param d The device to which the data is to be written. The type must support + * the AsyncRandomAccessWriteDevice concept. + * + * @param offset The offset at which the data will be written. + * + * @param buffers One or more buffers containing the data to be written. + * Although the buffers object may be copied as necessary, ownership of the + * underlying memory blocks is retained by the caller, which must guarantee + * that they remain valid until the handler is called. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest async_write_some_at operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the device's async_write_some_at function. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // Number of bytes written from the buffers. If an error + * // occurred, this will be less than the sum of the buffer sizes. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + * + * @par Example + * To write a single data buffer use the @ref buffer function as follows: + * @code boost::asio::async_write_at(d, 42, + * boost::asio::buffer(data, size), + * boost::asio::transfer_at_least(32), + * handler); @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write_at(AsyncRandomAccessWriteDevice& d, + uint64_t offset, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler); + +#if !defined(BOOST_ASIO_NO_EXTENSIONS) +#if !defined(BOOST_ASIO_NO_IOSTREAM) + +/// Start an asynchronous operation to write all of the supplied data at the +/// specified offset. +/** + * This function is used to asynchronously write a certain number of bytes of + * data to a random access device at a specified offset. The function call + * always returns immediately. The asynchronous operation will continue until + * one of the following conditions is true: + * + * @li All of the data in the supplied basic_streambuf has been written. + * + * @li An error occurred. + * + * This operation is implemented in terms of zero or more calls to the device's + * async_write_some_at function, and is known as a composed operation. + * The program must ensure that the device performs no overlapping + * write operations (such as async_write_at, the device's async_write_some_at + * function, or any other composed operations that perform writes) until this + * operation completes. Operations are overlapping if the regions defined by + * their offsets, and the numbers of bytes to write, intersect. + * + * @param d The device to which the data is to be written. The type must support + * the AsyncRandomAccessWriteDevice concept. + * + * @param offset The offset at which the data will be written. + * + * @param b A basic_streambuf object from which data will be written. Ownership + * of the streambuf is retained by the caller, which must guarantee that it + * remains valid until the handler is called. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // Number of bytes written from the buffers. If an error + * // occurred, this will be less than the sum of the buffer sizes. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, + basic_streambuf& b, BOOST_ASIO_MOVE_ARG(WriteHandler) handler); + +/// Start an asynchronous operation to write a certain amount of data at the +/// specified offset. +/** + * This function is used to asynchronously write a certain number of bytes of + * data to a random access device at a specified offset. The function call + * always returns immediately. The asynchronous operation will continue until + * one of the following conditions is true: + * + * @li All of the data in the supplied basic_streambuf has been written. + * + * @li The completion_condition function object returns 0. + * + * This operation is implemented in terms of zero or more calls to the device's + * async_write_some_at function, and is known as a composed operation. + * The program must ensure that the device performs no overlapping + * write operations (such as async_write_at, the device's async_write_some_at + * function, or any other composed operations that perform writes) until this + * operation completes. Operations are overlapping if the regions defined by + * their offsets, and the numbers of bytes to write, intersect. + * + * @param d The device to which the data is to be written. The type must support + * the AsyncRandomAccessWriteDevice concept. + * + * @param offset The offset at which the data will be written. + * + * @param b A basic_streambuf object from which data will be written. Ownership + * of the streambuf is retained by the caller, which must guarantee that it + * remains valid until the handler is called. + * + * @param completion_condition The function object to be called to determine + * whether the write operation is complete. The signature of the function object + * must be: + * @code std::size_t completion_condition( + * // Result of latest async_write_some_at operation. + * const boost::system::error_code& error, + * + * // Number of bytes transferred so far. + * std::size_t bytes_transferred + * ); @endcode + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the device's async_write_some_at function. + * + * @param handler The handler to be called when the write operation completes. + * Copies will be made of the handler as required. The function signature of the + * handler must be: + * @code void handler( + * // Result of operation. + * const boost::system::error_code& error, + * + * // Number of bytes written from the buffers. If an error + * // occurred, this will be less than the sum of the buffer sizes. + * std::size_t bytes_transferred + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. On + * immediate completion, invocation of the handler will be performed in a + * manner equivalent to using boost::asio::post(). + */ +template +BOOST_ASIO_INITFN_RESULT_TYPE(WriteHandler, + void (boost::system::error_code, std::size_t)) +async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, + basic_streambuf& b, CompletionCondition completion_condition, + BOOST_ASIO_MOVE_ARG(WriteHandler) handler); + +#endif // !defined(BOOST_ASIO_NO_IOSTREAM) +#endif // !defined(BOOST_ASIO_NO_EXTENSIONS) + +/*@}*/ + +} // namespace asio +} // namespace boost + +#include + +#include + +#endif // BOOST_ASIO_WRITE_AT_HPP diff --git a/boost/bind/bind.hpp b/boost/bind/bind.hpp index 4cedc5e..711e000 100644 --- a/boost/bind/bind.hpp +++ b/boost/bind/bind.hpp @@ -2136,7 +2136,7 @@ template struct mf #undef BOOST_MEM_FN_CC #undef BOOST_MEM_FN_NAME -#ifdef BOOST_MEM_FN_ENABLE_CDECL +#if defined(BOOST_MEM_FN_ENABLE_CDECL) && !defined(_M_X64) #define BOOST_MEM_FN_NAME(X) inner_##X##_cdecl #define BOOST_MEM_FN_CC __cdecl @@ -61,7 +61,7 @@ template struct mf #endif -#ifdef BOOST_MEM_FN_ENABLE_STDCALL +#if defined(BOOST_MEM_FN_ENABLE_STDCALL) && !defined(_M_X64) #define BOOST_MEM_FN_NAME(X) inner_##X##_stdcall #define BOOST_MEM_FN_CC __stdcall @@ -73,7 +73,7 @@ template struct mf #endif -#ifdef BOOST_MEM_FN_ENABLE_FASTCALL +#if defined(BOOST_MEM_FN_ENABLE_FASTCALL) && !defined(_M_X64) #define BOOST_MEM_FN_NAME(X) inner_##X##_fastcall #define BOOST_MEM_FN_CC __fastcall @@ -102,7 +102,7 @@ template<> struct mf #undef BOOST_MEM_FN_CC #undef BOOST_MEM_FN_NAME -#ifdef BOOST_MEM_FN_ENABLE_CDECL +#if defined(BOOST_MEM_FN_ENABLE_CDECL) && !defined(_M_X64) #define BOOST_MEM_FN_NAME(X) inner_##X##_cdecl #define BOOST_MEM_FN_CC __cdecl @@ -155,7 +155,7 @@ template<> struct mf #undef BOOST_MEM_FN_NAME2 #undef BOOST_MEM_FN_CC -#ifdef BOOST_MEM_FN_ENABLE_CDECL +#if defined(BOOST_MEM_FN_ENABLE_CDECL) && !defined(_M_X64) #define BOOST_MEM_FN_NAME(X) X##_cdecl #define BOOST_MEM_FN_NAME2(X) inner_##X##_cdecl @@ -217,7 +217,7 @@ namespace _mfi #undef BOOST_MEM_FN_CC #undef BOOST_MEM_FN_NAME -#ifdef BOOST_MEM_FN_ENABLE_CDECL +#if defined(BOOST_MEM_FN_ENABLE_CDECL) && !defined(_M_X64) #define BOOST_MEM_FN_NAME(X) X##_cdecl #define BOOST_MEM_FN_CC __cdecl @@ -229,7 +229,7 @@ namespace _mfi #endif -#ifdef BOOST_MEM_FN_ENABLE_STDCALL +#if defined(BOOST_MEM_FN_ENABLE_STDCALL) && !defined(_M_X64) #define BOOST_MEM_FN_NAME(X) X##_stdcall #define BOOST_MEM_FN_CC __stdcall @@ -241,7 +241,7 @@ namespace _mfi #endif -#ifdef BOOST_MEM_FN_ENABLE_FASTCALL +#if defined(BOOST_MEM_FN_ENABLE_FASTCALL) && !defined(_M_X64) #define BOOST_MEM_FN_NAME(X) X##_fastcall #define BOOST_MEM_FN_CC __fastcall @@ -270,7 +270,7 @@ namespace _mfi #undef BOOST_MEM_FN_NAME #undef BOOST_MEM_FN_CC -#ifdef BOOST_MEM_FN_ENABLE_CDECL +#if defined(BOOST_MEM_FN_ENABLE_CDECL) && !defined(_M_X64) #define BOOST_MEM_FN_NAME(X) X##_cdecl #define BOOST_MEM_FN_CC __cdecl @@ -282,7 +282,7 @@ namespace _mfi #endif -#ifdef BOOST_MEM_FN_ENABLE_STDCALL +#if defined(BOOST_MEM_FN_ENABLE_STDCALL) && !defined(_M_X64) #define BOOST_MEM_FN_NAME(X) X##_stdcall #define BOOST_MEM_FN_CC __stdcall @@ -294,7 +294,7 @@ namespace _mfi #endif -#ifdef BOOST_MEM_FN_ENABLE_FASTCALL +#if defined(BOOST_MEM_FN_ENABLE_FASTCALL) && !defined(_M_X64) #define BOOST_MEM_FN_NAME(X) X##_fastcall #define BOOST_MEM_FN_CC __fastcall diff --git a/boost/blank.hpp b/boost/blank.hpp index d0fe5ab..918723c 100644 --- a/boost/blank.hpp +++ b/boost/blank.hpp @@ -20,7 +20,7 @@ #include "boost/detail/templated_streams.hpp" #endif // BOOST_NO_IOSTREAM -#include "boost/mpl/bool.hpp" +#include "boost/type_traits/integral_constant.hpp" #include "boost/type_traits/is_empty.hpp" #include "boost/type_traits/is_pod.hpp" #include "boost/type_traits/is_stateless.hpp" @@ -36,19 +36,19 @@ struct blank template <> struct is_pod< blank > - : mpl::true_ + : boost::true_type { }; template <> struct is_empty< blank > - : mpl::true_ + : boost::true_type { }; template <> struct is_stateless< blank > - : mpl::true_ + : boost::true_type { }; diff --git a/boost/cerrno.hpp b/boost/cerrno.hpp new file mode 100644 index 0000000..57278f5 --- /dev/null +++ b/boost/cerrno.hpp @@ -0,0 +1,331 @@ +// Boost cerrno.hpp header -------------------------------------------------// + +// Copyright Beman Dawes 2005. +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See library home page at http://www.boost.org/libs/system + +#ifndef BOOST_SYSTEM_CERRNO_HPP +#define BOOST_SYSTEM_CERRNO_HPP + +#include + +// supply errno values likely to be missing, particularly on Windows + +#ifndef EAFNOSUPPORT +#define EAFNOSUPPORT 9901 +#endif + +#ifndef EADDRINUSE +#define EADDRINUSE 9902 +#endif + +#ifndef EADDRNOTAVAIL +#define EADDRNOTAVAIL 9903 +#endif + +#ifndef EISCONN +#define EISCONN 9904 +#endif + +#ifndef EBADMSG +#define EBADMSG 9905 +#endif + +#ifndef ECONNABORTED +#define ECONNABORTED 9906 +#endif + +#ifndef EALREADY +#define EALREADY 9907 +#endif + +#ifndef ECONNREFUSED +#define ECONNREFUSED 9908 +#endif + +#ifndef ECONNRESET +#define ECONNRESET 9909 +#endif + +#ifndef EDESTADDRREQ +#define EDESTADDRREQ 9910 +#endif + +#ifndef EHOSTUNREACH +#define EHOSTUNREACH 9911 +#endif + +#ifndef EIDRM +#define EIDRM 9912 +#endif + +#ifndef EMSGSIZE +#define EMSGSIZE 9913 +#endif + +#ifndef ENETDOWN +#define ENETDOWN 9914 +#endif + +#ifndef ENETRESET +#define ENETRESET 9915 +#endif + +#ifndef ENETUNREACH +#define ENETUNREACH 9916 +#endif + +#ifndef ENOBUFS +#define ENOBUFS 9917 +#endif + +#ifndef ENOLINK +#define ENOLINK 9918 +#endif + +#ifndef ENODATA +#define ENODATA 9919 +#endif + +#ifndef ENOMSG +#define ENOMSG 9920 +#endif + +#ifndef ENOPROTOOPT +#define ENOPROTOOPT 9921 +#endif + +#ifndef ENOSR +#define ENOSR 9922 +#endif + +#ifndef ENOTSOCK +#define ENOTSOCK 9923 +#endif + +#ifndef ENOSTR +#define ENOSTR 9924 +#endif + +#ifndef ENOTCONN +#define ENOTCONN 9925 +#endif + +#ifndef ENOTSUP +#define ENOTSUP 9926 +#endif + +#ifndef ECANCELED +#define ECANCELED 9927 +#endif + +#ifndef EINPROGRESS +#define EINPROGRESS 9928 +#endif + +#ifndef EOPNOTSUPP +#define EOPNOTSUPP 9929 +#endif + +#ifndef EWOULDBLOCK +#define EWOULDBLOCK 9930 +#endif + +#ifndef EOWNERDEAD +#define EOWNERDEAD 9931 +#endif + +#ifndef EPROTO +#define EPROTO 9932 +#endif + +#ifndef EPROTONOSUPPORT +#define EPROTONOSUPPORT 9933 +#endif + +#ifndef ENOTRECOVERABLE +#define ENOTRECOVERABLE 9934 +#endif + +#ifndef ETIME +#define ETIME 9935 +#endif + +#ifndef ETXTBSY +#define ETXTBSY 9936 +#endif + +#ifndef ETIMEDOUT +#define ETIMEDOUT 9938 +#endif + +#ifndef ELOOP +#define ELOOP 9939 +#endif + +#ifndef EOVERFLOW +#define EOVERFLOW 9940 +#endif + +#ifndef EPROTOTYPE +#define EPROTOTYPE 9941 +#endif + +#ifndef ENOSYS +#define ENOSYS 9942 +#endif + +#ifndef EINVAL +#define EINVAL 9943 +#endif + +#ifndef ERANGE +#define ERANGE 9944 +#endif + +#ifndef EILSEQ +#define EILSEQ 9945 +#endif + +// Windows Mobile doesn't appear to define these: + +#ifndef E2BIG +#define E2BIG 9946 +#endif + +#ifndef EDOM +#define EDOM 9947 +#endif + +#ifndef EFAULT +#define EFAULT 9948 +#endif + +#ifndef EBADF +#define EBADF 9949 +#endif + +#ifndef EPIPE +#define EPIPE 9950 +#endif + +#ifndef EXDEV +#define EXDEV 9951 +#endif + +#ifndef EBUSY +#define EBUSY 9952 +#endif + +#ifndef ENOTEMPTY +#define ENOTEMPTY 9953 +#endif + +#ifndef ENOEXEC +#define ENOEXEC 9954 +#endif + +#ifndef EEXIST +#define EEXIST 9955 +#endif + +#ifndef EFBIG +#define EFBIG 9956 +#endif + +#ifndef ENAMETOOLONG +#define ENAMETOOLONG 9957 +#endif + +#ifndef ENOTTY +#define ENOTTY 9958 +#endif + +#ifndef EINTR +#define EINTR 9959 +#endif + +#ifndef ESPIPE +#define ESPIPE 9960 +#endif + +#ifndef EIO +#define EIO 9961 +#endif + +#ifndef EISDIR +#define EISDIR 9962 +#endif + +#ifndef ECHILD +#define ECHILD 9963 +#endif + +#ifndef ENOLCK +#define ENOLCK 9964 +#endif + +#ifndef ENOSPC +#define ENOSPC 9965 +#endif + +#ifndef ENXIO +#define ENXIO 9966 +#endif + +#ifndef ENODEV +#define ENODEV 9967 +#endif + +#ifndef ENOENT +#define ENOENT 9968 +#endif + +#ifndef ESRCH +#define ESRCH 9969 +#endif + +#ifndef ENOTDIR +#define ENOTDIR 9970 +#endif + +#ifndef ENOMEM +#define ENOMEM 9971 +#endif + +#ifndef EPERM +#define EPERM 9972 +#endif + +#ifndef EACCES +#define EACCES 9973 +#endif + +#ifndef EROFS +#define EROFS 9974 +#endif + +#ifndef EDEADLK +#define EDEADLK 9975 +#endif + +#ifndef EAGAIN +#define EAGAIN 9976 +#endif + +#ifndef ENFILE +#define ENFILE 9977 +#endif + +#ifndef EMFILE +#define EMFILE 9978 +#endif + +#ifndef EMLINK +#define EMLINK 9979 +#endif + +#endif // include guard diff --git a/boost/chrono/chrono.hpp b/boost/chrono/chrono.hpp new file mode 100644 index 0000000..ebc29d8 --- /dev/null +++ b/boost/chrono/chrono.hpp @@ -0,0 +1,15 @@ +// chrono.hpp --------------------------------------------------------------// + +// Copyright 2009-2011 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHRONO_CHRONO_HPP +#define BOOST_CHRONO_CHRONO_HPP + +#include +#include +#include + +#endif // BOOST_CHRONO_CHRONO_HPP diff --git a/boost/chrono/clock_string.hpp b/boost/chrono/clock_string.hpp new file mode 100644 index 0000000..af025f2 --- /dev/null +++ b/boost/chrono/clock_string.hpp @@ -0,0 +1,25 @@ +// +// (C) Copyright 2010-2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). +// + +#ifndef BOOST_CHRONO_CLOCK_STRING_HPP +#define BOOST_CHRONO_CLOCK_STRING_HPP + +#include + +namespace boost +{ + namespace chrono + { + + template + struct clock_string; + + } // chrono + +} // boost + +#endif // BOOST_CHRONO_CLOCK_STRING_HPP diff --git a/boost/chrono/config.hpp b/boost/chrono/config.hpp new file mode 100644 index 0000000..1045ba3 --- /dev/null +++ b/boost/chrono/config.hpp @@ -0,0 +1,216 @@ +// boost/chrono/config.hpp -------------------------------------------------// + +// Copyright Beman Dawes 2003, 2006, 2008 +// Copyright 2009-2011 Vicente J. Botet Escriba +// Copyright (c) Microsoft Corporation 2014 + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/chrono for documentation. + +#ifndef BOOST_CHRONO_CONFIG_HPP +#define BOOST_CHRONO_CONFIG_HPP + +#include +#include + +#if !defined BOOST_CHRONO_VERSION +#define BOOST_CHRONO_VERSION 1 +#else +#if BOOST_CHRONO_VERSION!=1 && BOOST_CHRONO_VERSION!=2 +#error "BOOST_CHRONO_VERSION must be 1 or 2" +#endif +#endif + +#if defined(BOOST_CHRONO_SOURCE) && !defined(BOOST_USE_WINDOWS_H) +#define BOOST_USE_WINDOWS_H +#endif + +#if ! defined BOOST_CHRONO_PROVIDES_DATE_IO_FOR_SYSTEM_CLOCK_TIME_POINT \ + && ! defined BOOST_CHRONO_DONT_PROVIDE_DATE_IO_FOR_SYSTEM_CLOCK_TIME_POINT + +# define BOOST_CHRONO_PROVIDES_DATE_IO_FOR_SYSTEM_CLOCK_TIME_POINT + +#endif + +// BOOST_CHRONO_POSIX_API, BOOST_CHRONO_MAC_API, or BOOST_CHRONO_WINDOWS_API +// can be defined by the user to specify which API should be used + +#if defined(BOOST_CHRONO_WINDOWS_API) +# warning Boost.Chrono will use the Windows API +#elif defined(BOOST_CHRONO_MAC_API) +# warning Boost.Chrono will use the Mac API +#elif defined(BOOST_CHRONO_POSIX_API) +# warning Boost.Chrono will use the POSIX API +#endif + +# if defined( BOOST_CHRONO_WINDOWS_API ) && defined( BOOST_CHRONO_POSIX_API ) +# error both BOOST_CHRONO_WINDOWS_API and BOOST_CHRONO_POSIX_API are defined +# elif defined( BOOST_CHRONO_WINDOWS_API ) && defined( BOOST_CHRONO_MAC_API ) +# error both BOOST_CHRONO_WINDOWS_API and BOOST_CHRONO_MAC_API are defined +# elif defined( BOOST_CHRONO_MAC_API ) && defined( BOOST_CHRONO_POSIX_API ) +# error both BOOST_CHRONO_MAC_API and BOOST_CHRONO_POSIX_API are defined +# elif !defined( BOOST_CHRONO_WINDOWS_API ) && !defined( BOOST_CHRONO_MAC_API ) && !defined( BOOST_CHRONO_POSIX_API ) +# if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) +# define BOOST_CHRONO_WINDOWS_API +# elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) +# define BOOST_CHRONO_MAC_API +# else +# define BOOST_CHRONO_POSIX_API +# endif +# endif + +# if defined( BOOST_CHRONO_WINDOWS_API ) +# ifndef UNDER_CE +# define BOOST_CHRONO_HAS_PROCESS_CLOCKS +# endif +# define BOOST_CHRONO_HAS_CLOCK_STEADY +# if BOOST_PLAT_WINDOWS_DESKTOP +# define BOOST_CHRONO_HAS_THREAD_CLOCK +# endif +# define BOOST_CHRONO_THREAD_CLOCK_IS_STEADY true +# endif + +# if defined( BOOST_CHRONO_MAC_API ) +# define BOOST_CHRONO_HAS_PROCESS_CLOCKS +# define BOOST_CHRONO_HAS_CLOCK_STEADY +# define BOOST_CHRONO_HAS_THREAD_CLOCK +# define BOOST_CHRONO_THREAD_CLOCK_IS_STEADY true +# endif + +# if defined( BOOST_CHRONO_POSIX_API ) +# define BOOST_CHRONO_HAS_PROCESS_CLOCKS +# include //to check for CLOCK_REALTIME and CLOCK_MONOTONIC and _POSIX_THREAD_CPUTIME +# if defined(CLOCK_MONOTONIC) +# define BOOST_CHRONO_HAS_CLOCK_STEADY +# endif +# if defined(_POSIX_THREAD_CPUTIME) && !defined(BOOST_DISABLE_THREADS) +# define BOOST_CHRONO_HAS_THREAD_CLOCK +# define BOOST_CHRONO_THREAD_CLOCK_IS_STEADY true +# endif +# if defined(CLOCK_THREAD_CPUTIME_ID) && !defined(BOOST_DISABLE_THREADS) +# define BOOST_CHRONO_HAS_THREAD_CLOCK +# define BOOST_CHRONO_THREAD_CLOCK_IS_STEADY true +# endif +# if defined(sun) || defined(__sun) +# undef BOOST_CHRONO_HAS_THREAD_CLOCK +# undef BOOST_CHRONO_THREAD_CLOCK_IS_STEADY +# endif +# if (defined(__HP_aCC) || defined(__GNUC__)) && defined(__hpux) +# undef BOOST_CHRONO_HAS_THREAD_CLOCK +# undef BOOST_CHRONO_THREAD_CLOCK_IS_STEADY +# endif +# if defined(__VXWORKS__) +# undef BOOST_CHRONO_HAS_PROCESS_CLOCKS +# endif +# endif + +#if defined(BOOST_CHRONO_THREAD_DISABLED) && defined(BOOST_CHRONO_HAS_THREAD_CLOCK) +#undef BOOST_CHRONO_HAS_THREAD_CLOCK +#undef BOOST_CHRONO_THREAD_CLOCK_IS_STEADY +#endif + +// unicode support ------------------------------// + +#if defined(BOOST_NO_CXX11_UNICODE_LITERALS) || defined(BOOST_NO_CXX11_CHAR16_T) || defined(BOOST_NO_CXX11_CHAR32_T) +//~ #define BOOST_CHRONO_HAS_UNICODE_SUPPORT +#else +#define BOOST_CHRONO_HAS_UNICODE_SUPPORT 1 +#endif + +#ifndef BOOST_CHRONO_LIB_CONSTEXPR +#if defined( BOOST_NO_CXX11_NUMERIC_LIMITS ) +#define BOOST_CHRONO_LIB_CONSTEXPR +#elif defined(_LIBCPP_VERSION) && !defined(_LIBCPP_CONSTEXPR) + #define BOOST_CHRONO_LIB_CONSTEXPR +#else + #define BOOST_CHRONO_LIB_CONSTEXPR BOOST_CONSTEXPR +#endif +#endif + +#if defined( BOOST_NO_CXX11_NUMERIC_LIMITS ) +# define BOOST_CHRONO_LIB_NOEXCEPT_OR_THROW throw() +#else +#ifdef BOOST_NO_CXX11_NOEXCEPT +# define BOOST_CHRONO_LIB_NOEXCEPT_OR_THROW throw() +#else +# define BOOST_CHRONO_LIB_NOEXCEPT_OR_THROW noexcept +#endif +#endif + +#if defined BOOST_CHRONO_PROVIDE_HYBRID_ERROR_HANDLING \ + && defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +#error "BOOST_CHRONO_PROVIDE_HYBRID_ERROR_HANDLING && BOOST_CHRONO_PROVIDE_HYBRID_ERROR_HANDLING defined" +#endif + +#if defined BOOST_CHRONO_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 \ + && defined BOOST_CHRONO_DONT_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 +#error "BOOST_CHRONO_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 && BOOST_CHRONO_DONT_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 defined" +#endif + +#if ! defined BOOST_CHRONO_PROVIDE_HYBRID_ERROR_HANDLING \ + && ! defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +#define BOOST_CHRONO_PROVIDE_HYBRID_ERROR_HANDLING +#endif + +#if (BOOST_CHRONO_VERSION == 2) +#if ! defined BOOST_CHRONO_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 \ + && ! defined BOOST_CHRONO_DONT_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 +#define BOOST_CHRONO_DONT_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 +#endif +#endif + +#ifdef BOOST_CHRONO_HEADER_ONLY +#define BOOST_CHRONO_INLINE inline +#define BOOST_CHRONO_STATIC inline +#define BOOST_CHRONO_DECL + +#else +#define BOOST_CHRONO_INLINE +#define BOOST_CHRONO_STATIC static + +// enable dynamic linking on Windows ---------------------------------------// + +// we need to import/export our code only if the user has specifically +// asked for it by defining either BOOST_ALL_DYN_LINK if they want all boost +// libraries to be dynamically linked, or BOOST_CHRONO_DYN_LINK +// if they want just this one to be dynamically liked: +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CHRONO_DYN_LINK) +// export if this is our own source, otherwise import: +#ifdef BOOST_CHRONO_SOURCE +# define BOOST_CHRONO_DECL BOOST_SYMBOL_EXPORT +#else +# define BOOST_CHRONO_DECL BOOST_SYMBOL_IMPORT +#endif // BOOST_CHRONO_SOURCE +#endif // DYN_LINK +// +// if BOOST_CHRONO_DECL isn't defined yet define it now: +#ifndef BOOST_CHRONO_DECL +#define BOOST_CHRONO_DECL +#endif + + + +// enable automatic library variant selection ------------------------------// + +#if !defined(BOOST_CHRONO_SOURCE) && !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_CHRONO_NO_LIB) +// +// Set the name of our library; this will get undef'ed by auto_link.hpp +// once it's done with it: +// +#define BOOST_LIB_NAME boost_chrono +// +// If we're importing code from a dll, then tell auto_link.hpp about it: +// +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CHRONO_DYN_LINK) +# define BOOST_DYN_LINK +#endif +// +// And include the header that does the work: +// +#include +#endif // auto-linking disabled +#endif // BOOST_CHRONO_HEADER_ONLY +#endif // BOOST_CHRONO_CONFIG_HPP + diff --git a/boost/chrono/detail/inlined/chrono.hpp b/boost/chrono/detail/inlined/chrono.hpp new file mode 100644 index 0000000..3bad546 --- /dev/null +++ b/boost/chrono/detail/inlined/chrono.hpp @@ -0,0 +1,46 @@ +// chrono.cpp --------------------------------------------------------------// + +// Copyright Beman Dawes 2008 +// Copyright Vicente J. Botet Escriba 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHRONO_DETAIL_INLINED_CHRONO_HPP +#define BOOST_CHRONO_DETAIL_INLINED_CHRONO_HPP + +#include +#include +#if defined BOOST_CHRONO_PROVIDE_HYBRID_ERROR_HANDLING +#include +#endif +#include +#include + +//----------------------------------------------------------------------------// +// // +// Platform-specific Implementations // +// // +//----------------------------------------------------------------------------// + +//----------------------------------------------------------------------------// +// Windows // +//----------------------------------------------------------------------------// +#if defined(BOOST_CHRONO_WINDOWS_API) +#include + +//----------------------------------------------------------------------------// +// Mac // +//----------------------------------------------------------------------------// +#elif defined(BOOST_CHRONO_MAC_API) +#include + +//----------------------------------------------------------------------------// +// POSIX // +//----------------------------------------------------------------------------// +#elif defined(BOOST_CHRONO_POSIX_API) +#include + +#endif // POSIX + +#endif diff --git a/boost/chrono/detail/inlined/mac/chrono.hpp b/boost/chrono/detail/inlined/mac/chrono.hpp new file mode 100644 index 0000000..9bf6c2b --- /dev/null +++ b/boost/chrono/detail/inlined/mac/chrono.hpp @@ -0,0 +1,242 @@ +// mac/chrono.cpp --------------------------------------------------------------// + +// Copyright Beman Dawes 2008 +// Copyright 2009-2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + + +//----------------------------------------------------------------------------// +// Mac // +//----------------------------------------------------------------------------// + +#include //for gettimeofday and timeval +#include // mach_absolute_time, mach_timebase_info_data_t +#include + +namespace boost +{ +namespace chrono +{ + +// system_clock + +// gettimeofday is the most precise "system time" available on this platform. +// It returns the number of microseconds since New Years 1970 in a struct called timeval +// which has a field for seconds and a field for microseconds. +// Fill in the timeval and then convert that to the time_point +system_clock::time_point +system_clock::now() BOOST_NOEXCEPT +{ + timeval tv; + gettimeofday(&tv, 0); + return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec)); +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +system_clock::time_point +system_clock::now(system::error_code & ec) +{ + timeval tv; + gettimeofday(&tv, 0); + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec)); +} +#endif +// Take advantage of the fact that on this platform time_t is nothing but +// an integral count of seconds since New Years 1970 (same epoch as timeval). +// Just get the duration out of the time_point and truncate it to seconds. +time_t +system_clock::to_time_t(const time_point& t) BOOST_NOEXCEPT +{ + return time_t(duration_cast(t.time_since_epoch()).count()); +} + +// Just turn the time_t into a count of seconds and construct a time_point with it. +system_clock::time_point +system_clock::from_time_t(time_t t) BOOST_NOEXCEPT +{ + return system_clock::time_point(seconds(t)); +} + +namespace chrono_detail +{ + +// steady_clock + +// Note, in this implementation steady_clock and high_resolution_clock +// are the same clock. They are both based on mach_absolute_time(). +// mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of +// nanoseconds since the computer booted up. MachInfo.numer and MachInfo.denom +// are run time constants supplied by the OS. This clock has no relationship +// to the Gregorian calendar. It's main use is as a high resolution timer. + +// MachInfo.numer / MachInfo.denom is often 1 on the latest equipment. Specialize +// for that case as an optimization. +BOOST_CHRONO_STATIC +steady_clock::rep +steady_simplified() +{ + return mach_absolute_time(); +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +BOOST_CHRONO_STATIC +steady_clock::rep +steady_simplified_ec(system::error_code & ec) +{ + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return mach_absolute_time(); +} +#endif + +BOOST_CHRONO_STATIC +double +compute_steady_factor(kern_return_t& err) +{ + mach_timebase_info_data_t MachInfo; + err = mach_timebase_info(&MachInfo); + if ( err != 0 ) { + return 0; + } + return static_cast(MachInfo.numer) / MachInfo.denom; +} + +BOOST_CHRONO_STATIC +steady_clock::rep +steady_full() +{ + kern_return_t err; + const double factor = chrono_detail::compute_steady_factor(err); + if (err != 0) + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + return static_cast(mach_absolute_time() * factor); +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +BOOST_CHRONO_STATIC +steady_clock::rep +steady_full_ec(system::error_code & ec) +{ + kern_return_t err; + const double factor = chrono_detail::compute_steady_factor(err); + if (err != 0) + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + err, + ::boost::system::system_category(), + "chrono::steady_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return steady_clock::rep(); + } + } + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return static_cast(mach_absolute_time() * factor); +} +#endif + +typedef steady_clock::rep (*FP)(); +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +typedef steady_clock::rep (*FP_ec)(system::error_code &); +#endif + +BOOST_CHRONO_STATIC +FP +init_steady_clock(kern_return_t & err) +{ + mach_timebase_info_data_t MachInfo; + err = mach_timebase_info(&MachInfo); + if ( err != 0 ) + { + return 0; + } + + if (MachInfo.numer == MachInfo.denom) + { + return &chrono_detail::steady_simplified; + } + return &chrono_detail::steady_full; +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +BOOST_CHRONO_STATIC +FP_ec +init_steady_clock_ec(kern_return_t & err) +{ + mach_timebase_info_data_t MachInfo; + err = mach_timebase_info(&MachInfo); + if ( err != 0 ) + { + return 0; + } + + if (MachInfo.numer == MachInfo.denom) + { + return &chrono_detail::steady_simplified_ec; + } + return &chrono_detail::steady_full_ec; +} +#endif +} + +steady_clock::time_point +steady_clock::now() BOOST_NOEXCEPT +{ + kern_return_t err; + chrono_detail::FP fp = chrono_detail::init_steady_clock(err); + if ( err != 0 ) + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + return time_point(duration(fp())); +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +steady_clock::time_point +steady_clock::now(system::error_code & ec) +{ + kern_return_t err; + chrono_detail::FP_ec fp = chrono_detail::init_steady_clock_ec(err); + if ( err != 0 ) + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + err, + ::boost::system::system_category(), + "chrono::steady_clock" )); + } + else + { + ec.assign( err, ::boost::system::system_category() ); + return time_point(); + } + } + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(duration(fp(ec))); +} +#endif +} // namespace chrono +} // namespace boost diff --git a/boost/chrono/detail/inlined/mac/process_cpu_clocks.hpp b/boost/chrono/detail/inlined/mac/process_cpu_clocks.hpp new file mode 100644 index 0000000..29fe86c --- /dev/null +++ b/boost/chrono/detail/inlined/mac/process_cpu_clocks.hpp @@ -0,0 +1,356 @@ +// boost process_cpu_clocks.cpp -----------------------------------------------------------// + +// Copyright Beman Dawes 1994, 2006, 2008 +// Copyright Vicente J. Botet Escriba 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/chrono for documentation. + +//--------------------------------------------------------------------------------------// + +#include +#include +#include + +#include //for gettimeofday and timeval +#include //for times +# include + +namespace boost +{ + namespace chrono + { + namespace chrono_detail + { + + inline long tick_factor() // multiplier to convert ticks + // to nanoseconds; -1 if unknown + { + long factor = 0; + if (!factor) + { + if ((factor = ::sysconf(_SC_CLK_TCK)) <= 0) + factor = -1; + else + { + BOOST_ASSERT(factor <= 1000000000l); // doesn't handle large ticks + factor = 1000000000l / factor; // compute factor + if (!factor) + factor = -1; + } + } + return factor; + } + } + + + process_real_cpu_clock::time_point process_real_cpu_clock::now() BOOST_NOEXCEPT + { +#if 1 + tms tm; + clock_t c = ::times(&tm); + if (c == clock_t(-1)) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + return time_point(nanoseconds(c * factor)); + } else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + } + return time_point(); +#else + clock_t c = ::clock(); + if (c == clock_t(-1)) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + return time_point(nanoseconds(c * factor)); + } else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + } + return time_point(); +#endif + } + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + process_real_cpu_clock::time_point process_real_cpu_clock::now(system::error_code & ec) + { + +#if 1 + tms tm; + clock_t c = ::times(&tm); + if (c == clock_t(-1)) // error + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_real_cpu_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(nanoseconds(c * factor)); + } else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_real_cpu_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } + } +#else + clock_t c = ::clock(); + if (c == clock_t(-1)) // error + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_real_cpu_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(nanoseconds(c * factor)); + } else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_real_cpu_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } + } +#endif + + } +#endif + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + process_user_cpu_clock::time_point process_user_cpu_clock::now(system::error_code & ec) + { + tms tm; + clock_t c = ::times(&tm); + if (c == clock_t(-1)) // error + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_user_cpu_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(nanoseconds((tm.tms_utime + tm.tms_cutime) * factor)); + } else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_user_cpu_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } + } + } +#endif + + process_user_cpu_clock::time_point process_user_cpu_clock::now() BOOST_NOEXCEPT + { + tms tm; + clock_t c = ::times(&tm); + if (c == clock_t(-1)) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + return time_point(nanoseconds((tm.tms_utime + tm.tms_cutime) + * factor)); + } else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + } + return time_point(); + } + process_system_cpu_clock::time_point process_system_cpu_clock::now() BOOST_NOEXCEPT + { + tms tm; + clock_t c = ::times(&tm); + if (c == clock_t(-1)) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + return time_point(nanoseconds((tm.tms_stime + tm.tms_cstime) + * factor)); + } else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + } + return time_point(); + } + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + process_system_cpu_clock::time_point process_system_cpu_clock::now(system::error_code & ec) + { + tms tm; + clock_t c = ::times(&tm); + if (c == clock_t(-1)) // error + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_system_cpu_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(nanoseconds((tm.tms_stime + tm.tms_cstime) * factor)); + } else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_system_cpu_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } + } + } +#endif + + process_cpu_clock::time_point process_cpu_clock::now() BOOST_NOEXCEPT + { + tms tm; + clock_t c = ::times(&tm); + if (c == clock_t(-1)) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + time_point::rep + r(c * factor, (tm.tms_utime + tm.tms_cutime) * factor, (tm.tms_stime + + tm.tms_cstime) * factor); + return time_point(duration(r)); + } else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + } + return time_point(); + } + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + process_cpu_clock::time_point process_cpu_clock::now(system::error_code & ec) + { + + tms tm; + clock_t c = ::times(&tm); + if (c == clock_t(-1)) // error + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + time_point::rep + r(c * factor, (tm.tms_utime + tm.tms_cutime) * factor, (tm.tms_stime + + tm.tms_cstime) * factor); + return time_point(duration(r)); + } else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } + } + + } +#endif + + } +} diff --git a/boost/chrono/detail/inlined/mac/thread_clock.hpp b/boost/chrono/detail/inlined/mac/thread_clock.hpp new file mode 100644 index 0000000..74b820a --- /dev/null +++ b/boost/chrono/detail/inlined/mac/thread_clock.hpp @@ -0,0 +1,92 @@ +// boost thread_clock.cpp -----------------------------------------------------------// + +// Copyright Beman Dawes 1994, 2006, 2008 +// Copyright Vicente J. Botet Escriba 2009-2011 +// Copyright Christopher Brown 2013 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/chrono for documentation. + +//--------------------------------------------------------------------------------------// + +#include +#include +#include +#include + +# include +# include + +namespace boost { namespace chrono { + + thread_clock::time_point thread_clock::now( ) BOOST_NOEXCEPT + { + // get the thread port (borrowing pthread's reference) + mach_port_t port = pthread_mach_thread_np(pthread_self()); + + // get the thread info + thread_basic_info_data_t info; + mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT; + if ( thread_info(port, THREAD_BASIC_INFO, (thread_info_t)&info, &count) != KERN_SUCCESS ) + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + return time_point(); + } + + // convert to nanoseconds + duration user = duration( + static_cast( info.user_time.seconds ) * 1000000000 + + static_cast(info.user_time.microseconds ) * 1000); + + duration system = duration( + static_cast( info.system_time.seconds ) * 1000000000 + + static_cast( info.system_time.microseconds ) * 1000); + + return time_point( user + system ); + } + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + thread_clock::time_point thread_clock::now( system::error_code & ec ) + { + // get the thread port (borrowing pthread's reference) + mach_port_t port = pthread_mach_thread_np(pthread_self()); + + // get the thread info + thread_basic_info_data_t info; + mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT; + if ( thread_info(port, THREAD_BASIC_INFO, (thread_info_t)&info, &count) != KERN_SUCCESS ) + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + EINVAL, + ::boost::system::system_category(), + "chrono::thread_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + + // convert to nanoseconds + duration user = duration( + static_cast( info.user_time.seconds ) * 1000000000 + + static_cast(info.user_time.microseconds ) * 1000); + + duration system = duration( + static_cast( info.system_time.seconds ) * 1000000000 + + static_cast( info.system_time.microseconds ) * 1000); + + return time_point( user + system ); + } +#endif +} } diff --git a/boost/chrono/detail/inlined/posix/chrono.hpp b/boost/chrono/detail/inlined/posix/chrono.hpp new file mode 100644 index 0000000..8baac39 --- /dev/null +++ b/boost/chrono/detail/inlined/posix/chrono.hpp @@ -0,0 +1,141 @@ +// posix/chrono.cpp --------------------------------------------------------------// + +// Copyright Beman Dawes 2008 +// Copyright Vicente J. Botet Escriba 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +//----------------------------------------------------------------------------// +// POSIX // +//----------------------------------------------------------------------------// + +#include // for clock_gettime +#include +#include + +namespace boost +{ +namespace chrono +{ + + system_clock::time_point system_clock::now() BOOST_NOEXCEPT + { + timespec ts; + if ( ::clock_gettime( CLOCK_REALTIME, &ts ) ) + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + + return time_point(duration( + static_cast( ts.tv_sec ) * 1000000000 + ts.tv_nsec)); + } + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + system_clock::time_point system_clock::now(system::error_code & ec) + { + timespec ts; + if ( ::clock_gettime( CLOCK_REALTIME, &ts ) ) + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::system_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(duration( + static_cast( ts.tv_sec ) * 1000000000 + ts.tv_nsec)); + } +#endif + + std::time_t system_clock::to_time_t(const system_clock::time_point& t) BOOST_NOEXCEPT + { + return static_cast( t.time_since_epoch().count() / 1000000000 ); + } + + system_clock::time_point system_clock::from_time_t(std::time_t t) BOOST_NOEXCEPT + { + return time_point(duration(static_cast(t) * 1000000000)); + } + +#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY + + steady_clock::time_point steady_clock::now() BOOST_NOEXCEPT + { + timespec ts; +#if BOOST_OS_CYGWIN + // lack of thread safety in high resolution timer initialization + // can lead to a timespec of zero without an error; was reported + // to the cygwin mailing list and can be removed once fixed + do + { +#endif + if ( ::clock_gettime( CLOCK_MONOTONIC, &ts ) ) + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } +#if BOOST_OS_CYGWIN + } while (ts.tv_sec == 0 && ts.tv_nsec == 0); +#endif + return time_point(duration( + static_cast( ts.tv_sec ) * 1000000000 + ts.tv_nsec)); + } + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + steady_clock::time_point steady_clock::now(system::error_code & ec) + { + timespec ts; +#if BOOST_OS_CYGWIN + // lack of thread safety in high resolution timer initialization + // can lead to a timespec of zero without an error; was reported + // to the cygwin mailing list and can be removed once fixed + do + { +#endif + if ( ::clock_gettime( CLOCK_MONOTONIC, &ts ) ) + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::steady_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } +#if BOOST_OS_CYGWIN + } while (ts.tv_sec == 0 && ts.tv_nsec == 0); +#endif + + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(duration( + static_cast( ts.tv_sec ) * 1000000000 + ts.tv_nsec)); + } +#endif +#endif + +} // namespace chrono +} // namespace boost + + diff --git a/boost/chrono/detail/inlined/posix/process_cpu_clocks.hpp b/boost/chrono/detail/inlined/posix/process_cpu_clocks.hpp new file mode 100644 index 0000000..f9a9e12 --- /dev/null +++ b/boost/chrono/detail/inlined/posix/process_cpu_clocks.hpp @@ -0,0 +1,354 @@ +// boost process_cpu_clocks.cpp -----------------------------------------------------------// + +// Copyright Beman Dawes 1994, 2006, 2008 +// Copyright Vicente J. Botet Escriba 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/chrono for documentation. + +//--------------------------------------------------------------------------------------// + +#include +#include +#include + +#include +#include +#include // for clock_gettime + + +namespace boost { namespace chrono { +namespace chrono_detail +{ + inline nanoseconds::rep tick_factor() // multiplier to convert ticks + // to nanoseconds; -1 if unknown + { + long factor = 0; + if ( !factor ) + { + if ( (factor = ::sysconf( _SC_CLK_TCK )) <= 0 ) + factor = -1; + else + { + BOOST_ASSERT( factor <= 1000000000l ); // doesn't handle large ticks + factor = 1000000000l / factor; // compute factor + if ( !factor ) factor = -1; + } + } + return factor; + } +} + +process_real_cpu_clock::time_point process_real_cpu_clock::now() BOOST_NOEXCEPT +{ + tms tm; + clock_t c = ::times( &tm ); + if ( c == clock_t(-1) ) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + else + { + if ( chrono_detail::tick_factor() != -1 ) + { + return time_point( + nanoseconds(c*chrono_detail::tick_factor())); + } + else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + } + return time_point(); +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +process_real_cpu_clock::time_point process_real_cpu_clock::now( + system::error_code & ec) +{ + + tms tm; + clock_t c = ::times( &tm ); + if ( c == clock_t(-1) ) // error + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::process_real_cpu_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + else + { + if ( chrono_detail::tick_factor() != -1 ) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point( + nanoseconds(c*chrono_detail::tick_factor())); + } + else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::process_real_cpu_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + } +} +#endif + +process_user_cpu_clock::time_point process_user_cpu_clock::now() BOOST_NOEXCEPT +{ + tms tm; + clock_t c = ::times( &tm ); + if ( c == clock_t(-1) ) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + else + { + if ( chrono_detail::tick_factor() != -1 ) + { + return time_point( + nanoseconds((tm.tms_utime + tm.tms_cutime)*chrono_detail::tick_factor())); + } + else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + } + return time_point(); +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +process_user_cpu_clock::time_point process_user_cpu_clock::now( + system::error_code & ec) +{ + tms tm; + clock_t c = ::times( &tm ); + if ( c == clock_t(-1) ) // error + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::process_user_cpu_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + else + { + if ( chrono_detail::tick_factor() != -1 ) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point( + nanoseconds((tm.tms_utime + tm.tms_cutime)*chrono_detail::tick_factor())); + } + else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::process_user_cpu_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + } +} +#endif + +process_system_cpu_clock::time_point process_system_cpu_clock::now() BOOST_NOEXCEPT +{ + tms tm; + clock_t c = ::times( &tm ); + if ( c == clock_t(-1) ) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + return time_point(); + } + else + { + if ( chrono_detail::tick_factor() != -1 ) + { + return time_point( + nanoseconds((tm.tms_stime + tm.tms_cstime)*chrono_detail::tick_factor())); + } + else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + return time_point(); + } + } +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +process_system_cpu_clock::time_point process_system_cpu_clock::now( + system::error_code & ec) +{ + tms tm; + clock_t c = ::times( &tm ); + if ( c == clock_t(-1) ) // error + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::process_system_cpu_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + else + { + if ( chrono_detail::tick_factor() != -1 ) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point( + nanoseconds((tm.tms_stime + tm.tms_cstime)*chrono_detail::tick_factor())); + } + else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::process_system_cpu_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + } +} +#endif + +process_cpu_clock::time_point process_cpu_clock::now() BOOST_NOEXCEPT +{ + tms tm; + clock_t c = ::times( &tm ); + if ( c == clock_t(-1) ) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + else + { + nanoseconds::rep factor = chrono_detail::tick_factor(); + if ( factor != -1 ) + { + time_point::rep r( + c*factor, + (tm.tms_utime + tm.tms_cutime)*factor, + (tm.tms_stime + tm.tms_cstime)*factor); + return time_point(duration(r)); + } + else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + } + return time_point(); +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +process_cpu_clock::time_point process_cpu_clock::now( + system::error_code & ec ) +{ + tms tm; + clock_t c = ::times( &tm ); + if ( c == clock_t(-1) ) // error + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::process_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + else + { + if ( chrono_detail::tick_factor() != -1 ) + { + time_point::rep r( + c*chrono_detail::tick_factor(), + (tm.tms_utime + tm.tms_cutime)*chrono_detail::tick_factor(), + (tm.tms_stime + tm.tms_cstime)*chrono_detail::tick_factor()); + return time_point(duration(r)); + } + else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::process_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + } + +} +#endif + +} } diff --git a/boost/chrono/detail/inlined/posix/thread_clock.hpp b/boost/chrono/detail/inlined/posix/thread_clock.hpp new file mode 100644 index 0000000..a2a2d9c --- /dev/null +++ b/boost/chrono/detail/inlined/posix/thread_clock.hpp @@ -0,0 +1,92 @@ +// boost thread_clock.cpp -----------------------------------------------------------// + +// Copyright Beman Dawes 1994, 2006, 2008 +// Copyright Vicente J. Botet Escriba 2009-2011 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/chrono for documentation. + +//--------------------------------------------------------------------------------------// + +#include +#include +#include +#include + +#if !defined(__VXWORKS__) +# include +#endif +# include +# include + +namespace boost { namespace chrono { + + thread_clock::time_point thread_clock::now( ) BOOST_NOEXCEPT + { + struct timespec ts; +#if defined CLOCK_THREAD_CPUTIME_ID + // get the timespec associated to the thread clock + if ( ::clock_gettime( CLOCK_THREAD_CPUTIME_ID, &ts ) ) +#else + // get the current thread + pthread_t pth=pthread_self(); + // get the clock_id associated to the current thread + clockid_t clock_id; + pthread_getcpuclockid(pth, &clock_id); + // get the timespec associated to the thread clock + if ( ::clock_gettime( clock_id, &ts ) ) +#endif + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + + // transform to nanoseconds + return time_point(duration( + static_cast( ts.tv_sec ) * 1000000000 + ts.tv_nsec)); + + } + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + thread_clock::time_point thread_clock::now( system::error_code & ec ) + { + struct timespec ts; +#if defined CLOCK_THREAD_CPUTIME_ID + // get the timespec associated to the thread clock + if ( ::clock_gettime( CLOCK_THREAD_CPUTIME_ID, &ts ) ) +#else + // get the current thread + pthread_t pth=pthread_self(); + // get the clock_id associated to the current thread + clockid_t clock_id; + pthread_getcpuclockid(pth, &clock_id); + // get the timespec associated to the thread clock + if ( ::clock_gettime( clock_id, &ts ) ) +#endif + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::thread_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + // transform to nanoseconds + return time_point(duration( + static_cast( ts.tv_sec ) * 1000000000 + ts.tv_nsec)); + + } +#endif +} } diff --git a/boost/chrono/detail/inlined/process_cpu_clocks.hpp b/boost/chrono/detail/inlined/process_cpu_clocks.hpp new file mode 100644 index 0000000..fad6036 --- /dev/null +++ b/boost/chrono/detail/inlined/process_cpu_clocks.hpp @@ -0,0 +1,46 @@ +// boost process_cpu_clocks.cpp -----------------------------------------------------------// + +// Copyright 2009-2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/chrono for documentation. + +//--------------------------------------------------------------------------------------// +#ifndef BOOST_CHRONO_DETAIL_INLINED_PROCESS_CPU_CLOCKS_HPP +#define BOOST_CHRONO_DETAIL_INLINED_PROCESS_CPU_CLOCKS_HPP + + +#include +#if defined(BOOST_CHRONO_HAS_PROCESS_CLOCKS) + +#include +#include +#include +#if defined BOOST_CHRONO_PROVIDE_HYBRID_ERROR_HANDLING +#include +#endif +//----------------------------------------------------------------------------// +// Windows // +//----------------------------------------------------------------------------// +#if defined(BOOST_CHRONO_WINDOWS_API) +#include + +//----------------------------------------------------------------------------// +// Mac // +//----------------------------------------------------------------------------// +#elif defined(BOOST_CHRONO_MAC_API) +#include + +//----------------------------------------------------------------------------// +// POSIX // +//----------------------------------------------------------------------------// +#elif defined(BOOST_CHRONO_POSIX_API) +#include + +#endif // POSIX + +#endif + +#endif diff --git a/boost/chrono/detail/inlined/thread_clock.hpp b/boost/chrono/detail/inlined/thread_clock.hpp new file mode 100644 index 0000000..e4f8317 --- /dev/null +++ b/boost/chrono/detail/inlined/thread_clock.hpp @@ -0,0 +1,46 @@ +// boost thread_clock.cpp -----------------------------------------------------------// + +// Copyright 2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/chrono for documentation. + +//--------------------------------------------------------------------------------------// +#ifndef BOOST_CHRONO_DETAIL_INLINED_THREAD_CLOCK_HPP +#define BOOST_CHRONO_DETAIL_INLINED_THREAD_CLOCK_HPP + +#include +#include +#if defined(BOOST_CHRONO_HAS_THREAD_CLOCK) +#include +#include +#if defined BOOST_CHRONO_PROVIDE_HYBRID_ERROR_HANDLING +#include +#endif +#include +#include + +//----------------------------------------------------------------------------// +// Windows // +//----------------------------------------------------------------------------// +#if defined(BOOST_CHRONO_WINDOWS_API) +#include + +//----------------------------------------------------------------------------// +// Mac // +//----------------------------------------------------------------------------// +#elif defined(BOOST_CHRONO_MAC_API) +#include + +//----------------------------------------------------------------------------// +// POSIX // +//----------------------------------------------------------------------------// +#elif defined(BOOST_CHRONO_POSIX_API) +#include + +#endif // POSIX + +#endif +#endif diff --git a/boost/chrono/detail/inlined/win/chrono.hpp b/boost/chrono/detail/inlined/win/chrono.hpp new file mode 100644 index 0000000..570dc02 --- /dev/null +++ b/boost/chrono/detail/inlined/win/chrono.hpp @@ -0,0 +1,150 @@ +// win/chrono.cpp --------------------------------------------------------------// + +// Copyright Beman Dawes 2008 +// Copyright 2009-2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +//----------------------------------------------------------------------------// +// Windows // +//----------------------------------------------------------------------------// +#ifndef BOOST_CHRONO_DETAIL_INLINED_WIN_CHRONO_HPP +#define BOOST_CHRONO_DETAIL_INLINED_WIN_CHRONO_HPP + +#include +#include +#include +#include + +namespace boost +{ +namespace chrono +{ +namespace chrono_detail +{ + + BOOST_CHRONO_INLINE double get_nanosecs_per_tic() BOOST_NOEXCEPT + { + boost::winapi::LARGE_INTEGER_ freq; + if ( !boost::winapi::QueryPerformanceFrequency( &freq ) ) + return 0.0L; + return double(1000000000.0L / freq.QuadPart); + } + +} + + steady_clock::time_point steady_clock::now() BOOST_NOEXCEPT + { + double nanosecs_per_tic = chrono_detail::get_nanosecs_per_tic(); + + boost::winapi::LARGE_INTEGER_ pcount; + if ( nanosecs_per_tic <= 0.0L ) + { + BOOST_ASSERT(0 && "Boost::Chrono - get_nanosecs_per_tic Internal Error"); + return steady_clock::time_point(); + } + unsigned times=0; + while ( ! boost::winapi::QueryPerformanceCounter( &pcount ) ) + { + if ( ++times > 3 ) + { + BOOST_ASSERT(0 && "Boost::Chrono - QueryPerformanceCounter Internal Error"); + return steady_clock::time_point(); + } + } + + return steady_clock::time_point(steady_clock::duration( + static_cast((nanosecs_per_tic) * pcount.QuadPart))); + } + + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + steady_clock::time_point steady_clock::now( system::error_code & ec ) + { + double nanosecs_per_tic = chrono_detail::get_nanosecs_per_tic(); + + boost::winapi::LARGE_INTEGER_ pcount; + if ( (nanosecs_per_tic <= 0.0L) + || (!boost::winapi::QueryPerformanceCounter( &pcount )) ) + { + boost::winapi::DWORD_ cause = + ((nanosecs_per_tic <= 0.0L) + ? ERROR_NOT_SUPPORTED + : boost::winapi::GetLastError()); + if (::boost::chrono::is_throws(ec)) { + boost::throw_exception( + system::system_error( + cause, + ::boost::system::system_category(), + "chrono::steady_clock" )); + } + else + { + ec.assign( cause, ::boost::system::system_category() ); + return steady_clock::time_point(duration(0)); + } + } + + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(duration( + static_cast(nanosecs_per_tic * pcount.QuadPart))); + } +#endif + + BOOST_CHRONO_INLINE + system_clock::time_point system_clock::now() BOOST_NOEXCEPT + { + boost::winapi::FILETIME_ ft; + boost::winapi::GetSystemTimeAsFileTime( &ft ); // never fails + return system_clock::time_point( + system_clock::duration( + ((static_cast<__int64>( ft.dwHighDateTime ) << 32) | ft.dwLowDateTime) + - 116444736000000000LL + //- (134775LL*864000000000LL) + ) + ); + } + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + BOOST_CHRONO_INLINE + system_clock::time_point system_clock::now( system::error_code & ec ) + { + boost::winapi::FILETIME_ ft; + boost::winapi::GetSystemTimeAsFileTime( &ft ); // never fails + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return system_clock::time_point( + system_clock::duration( + ((static_cast<__int64>( ft.dwHighDateTime ) << 32) | ft.dwLowDateTime) + - 116444736000000000LL + //- (134775LL*864000000000LL) + )); + } +#endif + + BOOST_CHRONO_INLINE + std::time_t system_clock::to_time_t(const system_clock::time_point& t) BOOST_NOEXCEPT + { + __int64 temp = t.time_since_epoch().count(); + temp /= 10000000; + return static_cast( temp ); + } + + BOOST_CHRONO_INLINE + system_clock::time_point system_clock::from_time_t(std::time_t t) BOOST_NOEXCEPT + { + __int64 temp = t; + temp *= 10000000; + return time_point(duration(temp)); + } + +} // namespace chrono +} // namespace boost + +#endif diff --git a/boost/chrono/detail/inlined/win/process_cpu_clocks.hpp b/boost/chrono/detail/inlined/win/process_cpu_clocks.hpp new file mode 100644 index 0000000..a3a838a --- /dev/null +++ b/boost/chrono/detail/inlined/win/process_cpu_clocks.hpp @@ -0,0 +1,281 @@ +// boost process_timer.cpp -----------------------------------------------------------// + +// Copyright Beman Dawes 1994, 2006, 2008 +// Copyright 2009-2010 Vicente J. Botet Escriba +// Copyright (c) Microsoft Corporation 2014 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/chrono for documentation. + +//--------------------------------------------------------------------------------------// +#ifndef BOOST_CHRONO_DETAIL_INLINED_WIN_PROCESS_CLOCK_HPP +#define BOOST_CHRONO_DETAIL_INLINED_WIN_PROCESS_CLOCK_HPP + +#include +#include +#include +#include +#include + +#include +#include +#if BOOST_PLAT_WINDOWS_DESKTOP +#include +#endif + +namespace boost +{ +namespace chrono +{ + +process_real_cpu_clock::time_point process_real_cpu_clock::now() BOOST_NOEXCEPT +{ + clock_t c = ::clock(); + if ( c == clock_t(-1) ) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + typedef ratio_divide >::type R; + return time_point( + duration(static_cast(c)*R::num/R::den) + ); +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +process_real_cpu_clock::time_point process_real_cpu_clock::now( + system::error_code & ec) +{ + clock_t c = ::clock(); + if ( c == clock_t(-1) ) // error + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::process_real_cpu_clock" )); + } + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + typedef ratio_divide >::type R; + return time_point( + duration(static_cast(c)*R::num/R::den) + ); +} +#endif + +#if BOOST_PLAT_WINDOWS_DESKTOP +process_user_cpu_clock::time_point process_user_cpu_clock::now() BOOST_NOEXCEPT +{ + + // note that Windows uses 100 nanosecond ticks for FILETIME + boost::detail::winapi::FILETIME_ creation, exit, user_time, system_time; + + if ( boost::detail::winapi::GetProcessTimes( + boost::detail::winapi::GetCurrentProcess(), &creation, &exit, + &system_time, &user_time ) ) + { + return time_point(duration( + ((static_cast(user_time.dwHighDateTime) << 32) + | user_time.dwLowDateTime) * 100 + )); + } + else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + return time_point(); + } + +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +process_user_cpu_clock::time_point process_user_cpu_clock::now( + system::error_code & ec) +{ + + // note that Windows uses 100 nanosecond ticks for FILETIME + boost::detail::winapi::FILETIME_ creation, exit, user_time, system_time; + + if ( boost::detail::winapi::GetProcessTimes( + boost::detail::winapi::GetCurrentProcess(), &creation, &exit, + &system_time, &user_time ) ) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(duration( + ((static_cast(user_time.dwHighDateTime) << 32) + | user_time.dwLowDateTime) * 100 + )); + } + else + { + boost::detail::winapi::DWORD_ cause = boost::detail::winapi::GetLastError(); + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + cause, + ::boost::system::system_category(), + "chrono::process_user_cpu_clock" )); + } + else + { + ec.assign( cause, ::boost::system::system_category() ); + return time_point(); + } + } + +} +#endif + +process_system_cpu_clock::time_point process_system_cpu_clock::now() BOOST_NOEXCEPT +{ + + // note that Windows uses 100 nanosecond ticks for FILETIME + boost::detail::winapi::FILETIME_ creation, exit, user_time, system_time; + + if ( boost::detail::winapi::GetProcessTimes( + boost::detail::winapi::GetCurrentProcess(), &creation, &exit, + &system_time, &user_time ) ) + { + return time_point(duration( + ((static_cast(system_time.dwHighDateTime) << 32) + | system_time.dwLowDateTime) * 100 + )); + } + else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + return time_point(); + } + +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +process_system_cpu_clock::time_point process_system_cpu_clock::now( + system::error_code & ec) +{ + + // note that Windows uses 100 nanosecond ticks for FILETIME + boost::detail::winapi::FILETIME_ creation, exit, user_time, system_time; + + if ( boost::detail::winapi::GetProcessTimes( + boost::detail::winapi::GetCurrentProcess(), &creation, &exit, + &system_time, &user_time ) ) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(duration( + ((static_cast(system_time.dwHighDateTime) << 32) + | system_time.dwLowDateTime) * 100 + )); + } + else + { + boost::detail::winapi::DWORD_ cause = boost::detail::winapi::GetLastError(); + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + cause, + ::boost::system::system_category(), + "chrono::process_system_cpu_clock" )); + } + else + { + ec.assign( cause, ::boost::system::system_category() ); + return time_point(); + } + } + +} +#endif + +process_cpu_clock::time_point process_cpu_clock::now() BOOST_NOEXCEPT +{ + + // note that Windows uses 100 nanosecond ticks for FILETIME + boost::detail::winapi::FILETIME_ creation, exit, user_time, system_time; + + if ( boost::detail::winapi::GetProcessTimes( + boost::detail::winapi::GetCurrentProcess(), &creation, &exit, + &system_time, &user_time ) ) + { + time_point::rep r(process_real_cpu_clock::now().time_since_epoch().count() + , + ((static_cast(user_time.dwHighDateTime) << 32) + | user_time.dwLowDateTime + ) * 100, + ((static_cast(system_time.dwHighDateTime) << 32) + | system_time.dwLowDateTime + ) * 100 + ); + return time_point(duration(r)); + } + else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + return time_point(); + } + +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +process_cpu_clock::time_point process_cpu_clock::now( + system::error_code & ec ) +{ + + // note that Windows uses 100 nanosecond ticks for FILETIME + boost::detail::winapi::FILETIME_ creation, exit, user_time, system_time; + + if ( boost::detail::winapi::GetProcessTimes( + boost::detail::winapi::GetCurrentProcess(), &creation, &exit, + &system_time, &user_time ) ) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + time_point::rep r(process_real_cpu_clock::now().time_since_epoch().count() + , + ((static_cast(user_time.dwHighDateTime) << 32) + | user_time.dwLowDateTime + ) * 100, + ((static_cast(system_time.dwHighDateTime) << 32) + | system_time.dwLowDateTime + ) * 100 + ); + return time_point(duration(r)); + } + else + { + boost::detail::winapi::DWORD_ cause = boost::detail::winapi::GetLastError(); + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + cause, + ::boost::system::system_category(), + "chrono::process_cpu_clock" )); + } + else + { + ec.assign( cause, ::boost::system::system_category() ); + return time_point(); + } + } + +} +#endif +#endif +} // namespace chrono +} // namespace boost + +#endif diff --git a/boost/chrono/detail/inlined/win/thread_clock.hpp b/boost/chrono/detail/inlined/win/thread_clock.hpp new file mode 100644 index 0000000..776e5b4 --- /dev/null +++ b/boost/chrono/detail/inlined/win/thread_clock.hpp @@ -0,0 +1,103 @@ +// boost thread_clock.cpp -----------------------------------------------------------// + +// Copyright 2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/chrono for documentation. + +//--------------------------------------------------------------------------------------// +#ifndef BOOST_CHRONO_DETAIL_INLINED_WIN_THREAD_CLOCK_HPP +#define BOOST_CHRONO_DETAIL_INLINED_WIN_THREAD_CLOCK_HPP + +#include +#include +#include +#include + +#include +#include +#include + +namespace boost +{ +namespace chrono +{ + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +thread_clock::time_point thread_clock::now( system::error_code & ec ) +{ + // note that Windows uses 100 nanosecond ticks for FILETIME + boost::detail::winapi::FILETIME_ creation, exit, user_time, system_time; + + if ( boost::detail::winapi::GetThreadTimes( + boost::detail::winapi::GetCurrentThread (), &creation, &exit, + &system_time, &user_time ) ) + { + duration user = duration( + ((static_cast(user_time.dwHighDateTime) << 32) + | user_time.dwLowDateTime) * 100 ); + + duration system = duration( + ((static_cast(system_time.dwHighDateTime) << 32) + | system_time.dwLowDateTime) * 100 ); + + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(system+user); + + } + else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + boost::detail::winapi::GetLastError(), + ::boost::system::system_category(), + "chrono::thread_clock" )); + } + else + { + ec.assign( boost::detail::winapi::GetLastError(), ::boost::system::system_category() ); + return thread_clock::time_point(duration(0)); + } + } +} +#endif + +thread_clock::time_point thread_clock::now() BOOST_NOEXCEPT +{ + + // note that Windows uses 100 nanosecond ticks for FILETIME + boost::detail::winapi::FILETIME_ creation, exit, user_time, system_time; + + if ( boost::detail::winapi::GetThreadTimes( + boost::detail::winapi::GetCurrentThread (), &creation, &exit, + &system_time, &user_time ) ) + { + duration user = duration( + ((static_cast(user_time.dwHighDateTime) << 32) + | user_time.dwLowDateTime) * 100 ); + + duration system = duration( + ((static_cast(system_time.dwHighDateTime) << 32) + | system_time.dwLowDateTime) * 100 ); + + return time_point(system+user); + } + else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + return time_point(); + } + +} + +} // namespace chrono +} // namespace boost + +#endif diff --git a/boost/chrono/detail/is_evenly_divisible_by.hpp b/boost/chrono/detail/is_evenly_divisible_by.hpp new file mode 100644 index 0000000..960a208 --- /dev/null +++ b/boost/chrono/detail/is_evenly_divisible_by.hpp @@ -0,0 +1,31 @@ +// is_evenly_divisible_by.hpp --------------------------------------------------------------// + +// Copyright 2009-2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHRONO_DETAIL_IS_EVENLY_DIVISIBLE_BY_HPP +#define BOOST_CHRONO_DETAIL_IS_EVENLY_DIVISIBLE_BY_HPP + +#include + +#include +#include + +namespace boost { +namespace chrono { +namespace chrono_detail { + +// template +// struct is_evenly_divisible_by : public boost::mpl::bool_ < ratio_divide::type::den == 1 > +// {}; + template + struct is_evenly_divisible_by : public boost::ratio_detail::is_evenly_divisible_by + {}; + +} // namespace chrono_detail +} // namespace detail +} // namespace chrono + +#endif // BOOST_CHRONO_DETAIL_IS_EVENLY_DIVISIBLE_BY_HPP diff --git a/boost/chrono/detail/static_assert.hpp b/boost/chrono/detail/static_assert.hpp new file mode 100644 index 0000000..8615194 --- /dev/null +++ b/boost/chrono/detail/static_assert.hpp @@ -0,0 +1,30 @@ +// static_assert.hpp --------------------------------------------------------------// + +// Copyright 2009-2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + + +#ifndef BOOST_CHRONO_DETAIL_STATIC_ASSERT_HPP +#define BOOST_CHRONO_DETAIL_STATIC_ASSERT_HPP + +#include + +#ifndef BOOST_NO_CXX11_STATIC_ASSERT +#define BOOST_CHRONO_STATIC_ASSERT(CND, MSG, TYPES) static_assert(CND,MSG) +#elif defined(BOOST_CHRONO_USES_STATIC_ASSERT) +#include +#define BOOST_CHRONO_STATIC_ASSERT(CND, MSG, TYPES) BOOST_STATIC_ASSERT(CND) +#elif defined(BOOST_CHRONO_USES_MPL_ASSERT) +#include +#include +#define BOOST_CHRONO_STATIC_ASSERT(CND, MSG, TYPES) \ + BOOST_MPL_ASSERT_MSG(boost::mpl::bool_< (CND) >::type::value, MSG, TYPES) +#else +//~ #elif defined(BOOST_CHRONO_USES_ARRAY_ASSERT) +#define BOOST_CHRONO_STATIC_ASSERT(CND, MSG, TYPES) static char BOOST_JOIN(boost_chrono_test_,__LINE__)[(CND)?1:-1] +//~ #define BOOST_CHRONO_STATIC_ASSERT(CND, MSG, TYPES) +#endif + +#endif // BOOST_CHRONO_DETAIL_STATIC_ASSERT_HPP diff --git a/boost/chrono/detail/system.hpp b/boost/chrono/detail/system.hpp new file mode 100644 index 0000000..3d82006 --- /dev/null +++ b/boost/chrono/detail/system.hpp @@ -0,0 +1,20 @@ +// Copyright 2009-2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHRONO_DETAIL_SYSTEM_HPP +#define BOOST_CHRONO_DETAIL_SYSTEM_HPP + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + +#include + +namespace boost { +namespace chrono { + inline bool is_throws(system::error_code & ec) { return (&ec==&boost::throws()); } +} +} + +#endif +#endif diff --git a/boost/chrono/duration.hpp b/boost/chrono/duration.hpp new file mode 100644 index 0000000..0a09674 --- /dev/null +++ b/boost/chrono/duration.hpp @@ -0,0 +1,798 @@ +// duration.hpp --------------------------------------------------------------// + +// Copyright 2008 Howard Hinnant +// Copyright 2008 Beman Dawes +// Copyright 2009-2011 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +/* + +This code was derived by Beman Dawes from Howard Hinnant's time2_demo prototype. +Many thanks to Howard for making his code available under the Boost license. +The original code was modified to conform to Boost conventions and to section +20.9 Time utilities [time] of the C++ committee's working paper N2798. +See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf. + +time2_demo contained this comment: + + Much thanks to Andrei Alexandrescu, + Walter Brown, + Peter Dimov, + Jeff Garland, + Terry Golubiewski, + Daniel Krugler, + Anthony Williams. +*/ + + +#ifndef BOOST_CHRONO_DURATION_HPP +#define BOOST_CHRONO_DURATION_HPP + +#include +#include + +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if !defined(BOOST_NO_CXX11_STATIC_ASSERT) || !defined(BOOST_CHRONO_USES_MPL_ASSERT) +#define BOOST_CHRONO_A_DURATION_REPRESENTATION_CAN_NOT_BE_A_DURATION "A duration representation can not be a duration" +#define BOOST_CHRONO_SECOND_TEMPLATE_PARAMETER_OF_DURATION_MUST_BE_A_STD_RATIO "Second template parameter of duration must be a boost::ratio" +#define BOOST_CHRONO_DURATION_PERIOD_MUST_BE_POSITIVE "duration period must be positive" +#define BOOST_CHRONO_SECOND_TEMPLATE_PARAMETER_OF_TIME_POINT_MUST_BE_A_BOOST_CHRONO_DURATION "Second template parameter of time_point must be a boost::chrono::duration" +#endif + +#ifndef BOOST_CHRONO_HEADER_ONLY +// this must occur after all of the includes and before any code appears: +#include // must be the last #include +#endif + +//----------------------------------------------------------------------------// +// // +// 20.9 Time utilities [time] // +// synopsis // +// // +//----------------------------------------------------------------------------// + +namespace boost { +namespace chrono { + + template > + class duration; + + namespace detail + { + template + struct is_duration + : boost::false_type {}; + + template + struct is_duration > + : boost::true_type {}; + + template ::value> + struct duration_divide_result + { + }; + + template ::type>::value)) + && ((boost::is_convertible::type>::value)) + ) + > + struct duration_divide_imp + { + }; + + template + struct duration_divide_imp, Rep2, true> + { + typedef duration::type, Period> type; + }; + + template + struct duration_divide_result, Rep2, false> + : duration_divide_imp, Rep2> + { + }; + +/// + template ::value> + struct duration_divide_result2 + { + }; + + template ::type>::value)) + && ((boost::is_convertible::type>::value)) + ) + > + struct duration_divide_imp2 + { + }; + + template + struct duration_divide_imp2, true> + { + //typedef typename common_type::type type; + typedef double type; + }; + + template + struct duration_divide_result2, false> + : duration_divide_imp2 > + { + }; + +/// + template ::value> + struct duration_modulo_result + { + }; + + template ::type>::value + //&& + boost::is_convertible::type>::value + ) + > + struct duration_modulo_imp + { + }; + + template + struct duration_modulo_imp, Rep2, true> + { + typedef duration::type, Period> type; + }; + + template + struct duration_modulo_result, Rep2, false> + : duration_modulo_imp, Rep2> + { + }; + +} // namespace detail +} // namespace chrono + + +// common_type trait specializations + +template +struct common_type, + chrono::duration >; + + +namespace chrono { + + // customization traits + template struct treat_as_floating_point; + template struct duration_values; + + // convenience typedefs + typedef duration nanoseconds; // at least 64 bits needed + typedef duration microseconds; // at least 55 bits needed + typedef duration milliseconds; // at least 45 bits needed + typedef duration seconds; // at least 35 bits needed + typedef duration > minutes; // at least 29 bits needed + typedef duration > hours; // at least 23 bits needed + +//----------------------------------------------------------------------------// +// duration helpers // +//----------------------------------------------------------------------------// + +namespace detail +{ + + // duration_cast + + // duration_cast is the heart of this whole prototype. It can convert any + // duration to any other. It is also (implicitly) used in converting + // time_points. The conversion is always exact if possible. And it is + // always as efficient as hand written code. If different representations + // are involved, care is taken to never require implicit conversions. + // Instead static_cast is used explicitly for every required conversion. + // If there are a mixture of integral and floating point representations, + // the use of common_type ensures that the most logical "intermediate" + // representation is used. + template + struct duration_cast_aux; + + // When the two periods are the same, all that is left to do is static_cast from + // the source representation to the target representation (which may be a no-op). + // This conversion is always exact as long as the static_cast from the source + // representation to the destination representation is exact. + template + struct duration_cast_aux + { + BOOST_CONSTEXPR ToDuration operator()(const FromDuration& fd) const + { + return ToDuration(static_cast(fd.count())); + } + }; + + // When the numerator of FromPeriod / ToPeriod is 1, then all we need to do is + // divide by the denominator of FromPeriod / ToPeriod. The common_type of + // the two representations is used for the intermediate computation before + // static_cast'ing to the destination. + // This conversion is generally not exact because of the division (but could be + // if you get lucky on the run time value of fd.count()). + template + struct duration_cast_aux + { + BOOST_CONSTEXPR ToDuration operator()(const FromDuration& fd) const + { + typedef typename common_type< + typename ToDuration::rep, + typename FromDuration::rep, + boost::intmax_t>::type C; + return ToDuration(static_cast( + static_cast(fd.count()) / static_cast(Period::den))); + } + }; + + // When the denominator of FromPeriod / ToPeriod is 1, then all we need to do is + // multiply by the numerator of FromPeriod / ToPeriod. The common_type of + // the two representations is used for the intermediate computation before + // static_cast'ing to the destination. + // This conversion is always exact as long as the static_cast's involved are exact. + template + struct duration_cast_aux + { + BOOST_CONSTEXPR ToDuration operator()(const FromDuration& fd) const + { + typedef typename common_type< + typename ToDuration::rep, + typename FromDuration::rep, + boost::intmax_t>::type C; + return ToDuration(static_cast( + static_cast(fd.count()) * static_cast(Period::num))); + } + }; + + // When neither the numerator or denominator of FromPeriod / ToPeriod is 1, then we need to + // multiply by the numerator and divide by the denominator of FromPeriod / ToPeriod. The + // common_type of the two representations is used for the intermediate computation before + // static_cast'ing to the destination. + // This conversion is generally not exact because of the division (but could be + // if you get lucky on the run time value of fd.count()). + template + struct duration_cast_aux + { + BOOST_CONSTEXPR ToDuration operator()(const FromDuration& fd) const + { + typedef typename common_type< + typename ToDuration::rep, + typename FromDuration::rep, + boost::intmax_t>::type C; + return ToDuration(static_cast( + static_cast(fd.count()) * static_cast(Period::num) + / static_cast(Period::den))); + } + }; + + template + struct duration_cast { + typedef typename ratio_divide::type Period; + typedef duration_cast_aux< + FromDuration, + ToDuration, + Period, + Period::num == 1, + Period::den == 1 + > Aux; + BOOST_CONSTEXPR ToDuration operator()(const FromDuration& fd) const + { + return Aux()(fd); + } + }; + +} // namespace detail + +//----------------------------------------------------------------------------// +// // +// 20.9.2 Time-related traits [time.traits] // +// // +//----------------------------------------------------------------------------// +//----------------------------------------------------------------------------// +// 20.9.2.1 treat_as_floating_point [time.traits.is_fp] // +// Probably should have been treat_as_floating_point. Editor notifed. // +//----------------------------------------------------------------------------// + + // Support bidirectional (non-exact) conversions for floating point rep types + // (or user defined rep types which specialize treat_as_floating_point). + template + struct treat_as_floating_point : boost::is_floating_point {}; + +//----------------------------------------------------------------------------// +// 20.9.2.2 duration_values [time.traits.duration_values] // +//----------------------------------------------------------------------------// + +namespace detail { + template ::value> + struct chrono_numeric_limits { + static BOOST_CHRONO_LIB_CONSTEXPR T lowest() BOOST_CHRONO_LIB_NOEXCEPT_OR_THROW {return (std::numeric_limits::min) ();} + }; + + template + struct chrono_numeric_limits { + static BOOST_CHRONO_LIB_CONSTEXPR T lowest() BOOST_CHRONO_LIB_NOEXCEPT_OR_THROW {return (std::numeric_limits::min) ();} + }; + + template <> + struct chrono_numeric_limits { + static BOOST_CHRONO_LIB_CONSTEXPR float lowest() BOOST_CHRONO_LIB_NOEXCEPT_OR_THROW + { + return -(std::numeric_limits::max) (); + } + }; + + template <> + struct chrono_numeric_limits { + static BOOST_CHRONO_LIB_CONSTEXPR double lowest() BOOST_CHRONO_LIB_NOEXCEPT_OR_THROW + { + return -(std::numeric_limits::max) (); + } + }; + + template <> + struct chrono_numeric_limits { + static BOOST_CHRONO_LIB_CONSTEXPR long double lowest() BOOST_CHRONO_LIB_NOEXCEPT_OR_THROW + { + return -(std::numeric_limits::max)(); + } + }; + + template + struct numeric_limits : chrono_numeric_limits::type> + {}; + +} +template +struct duration_values +{ + static BOOST_CONSTEXPR Rep zero() {return Rep(0);} + static BOOST_CHRONO_LIB_CONSTEXPR Rep max BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return (std::numeric_limits::max)(); + } + + static BOOST_CHRONO_LIB_CONSTEXPR Rep min BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return detail::numeric_limits::lowest(); + } +}; + +} // namespace chrono + +//----------------------------------------------------------------------------// +// 20.9.2.3 Specializations of common_type [time.traits.specializations] // +//----------------------------------------------------------------------------// + +template +struct common_type, + chrono::duration > +{ + typedef chrono::duration::type, + typename boost::ratio_gcd::type> type; +}; + + +//----------------------------------------------------------------------------// +// // +// 20.9.3 Class template duration [time.duration] // +// // +//----------------------------------------------------------------------------// + + +namespace chrono { + + template + class BOOST_SYMBOL_VISIBLE duration + { + //BOOST_CHRONO_STATIC_ASSERT(boost::is_integral::value, BOOST_CHRONO_A_DURATION_REPRESENTATION_MUST_BE_INTEGRAL, ()); + BOOST_CHRONO_STATIC_ASSERT(!boost::chrono::detail::is_duration::value, + BOOST_CHRONO_A_DURATION_REPRESENTATION_CAN_NOT_BE_A_DURATION, ()); + BOOST_CHRONO_STATIC_ASSERT(boost::ratio_detail::is_ratio::value, + BOOST_CHRONO_SECOND_TEMPLATE_PARAMETER_OF_DURATION_MUST_BE_A_STD_RATIO, ()); + BOOST_CHRONO_STATIC_ASSERT(Period::num>0, + BOOST_CHRONO_DURATION_PERIOD_MUST_BE_POSITIVE, ()); + public: + typedef Rep rep; + typedef Period period; + private: + rep rep_; + public: + +#if defined BOOST_CHRONO_DURATION_DEFAULTS_TO_ZERO + BOOST_FORCEINLINE BOOST_CONSTEXPR + duration() : rep_(duration_values::zero()) { } +#elif defined BOOST_NO_CXX11_DEFAULTED_FUNCTIONS + BOOST_CONSTEXPR duration() {} +#else + BOOST_CONSTEXPR duration() = default; +#endif + template + BOOST_SYMBOL_VISIBLE BOOST_FORCEINLINE BOOST_CONSTEXPR + explicit duration(const Rep2& r + , typename boost::enable_if < + mpl::and_ < + boost::is_convertible, + mpl::or_ < + treat_as_floating_point, + mpl::and_ < + mpl::not_ < treat_as_floating_point >, + mpl::not_ < treat_as_floating_point > + > + > + > + >::type* = 0 + ) : rep_(r) { } +#if defined BOOST_NO_CXX11_DEFAULTED_FUNCTIONS + duration& operator=(const duration& rhs) + { + if (&rhs != this) rep_= rhs.rep_; + return *this; + } +#else + duration& operator=(const duration& rhs) = default; +#endif + // conversions + template + BOOST_FORCEINLINE BOOST_CONSTEXPR + duration(const duration& d + , typename boost::enable_if < + mpl::or_ < + treat_as_floating_point, + mpl::and_ < + chrono_detail::is_evenly_divisible_by, + mpl::not_ < treat_as_floating_point > + > + > + >::type* = 0 + ) + : rep_(chrono::detail::duration_cast, duration>()(d).count()) {} + + // observer + + BOOST_CONSTEXPR + rep count() const {return rep_;} + + // arithmetic + + BOOST_CONSTEXPR + duration operator+() const {return duration(rep_);;} + BOOST_CONSTEXPR + duration operator-() const {return duration(-rep_);} + duration& operator++() {++rep_; return *this;} + duration operator++(int) {return duration(rep_++);} + duration& operator--() {--rep_; return *this;} + duration operator--(int) {return duration(rep_--);} + + duration& operator+=(const duration& d) + { + rep_ += d.count(); return *this; + } + duration& operator-=(const duration& d) + { + rep_ -= d.count(); return *this; + } + + duration& operator*=(const rep& rhs) {rep_ *= rhs; return *this;} + duration& operator/=(const rep& rhs) {rep_ /= rhs; return *this;} + duration& operator%=(const rep& rhs) {rep_ %= rhs; return *this;} + duration& operator%=(const duration& rhs) + { + rep_ %= rhs.count(); return *this; + } + // 20.9.3.4 duration special values [time.duration.special] + + static BOOST_CONSTEXPR duration zero() + { + return duration(duration_values::zero()); + } + static BOOST_CHRONO_LIB_CONSTEXPR duration min BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return duration((duration_values::min)()); + } + static BOOST_CHRONO_LIB_CONSTEXPR duration max BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return duration((duration_values::max)()); + } + }; + +//----------------------------------------------------------------------------// +// 20.9.3.5 duration non-member arithmetic [time.duration.nonmember] // +//----------------------------------------------------------------------------// + + // Duration + + + template + inline BOOST_CONSTEXPR + typename common_type, duration >::type + operator+(const duration& lhs, + const duration& rhs) + { + typedef typename common_type, + duration >::type common_duration; + return common_duration(common_duration(lhs).count()+common_duration(rhs).count()); + } + + // Duration - + + template + inline BOOST_CONSTEXPR + typename common_type, duration >::type + operator-(const duration& lhs, + const duration& rhs) + { + typedef typename common_type, + duration >::type common_duration; + return common_duration(common_duration(lhs).count()-common_duration(rhs).count()); + } + + // Duration * + + template + inline BOOST_CONSTEXPR + typename boost::enable_if < + mpl::and_ < + boost::is_convertible::type>, + boost::is_convertible::type> + >, + duration::type, Period> + >::type + operator*(const duration& d, const Rep2& s) + { + typedef typename common_type::type common_rep; + typedef duration common_duration; + return common_duration(common_duration(d).count()*static_cast(s)); + } + + template + inline BOOST_CONSTEXPR + typename boost::enable_if < + mpl::and_ < + boost::is_convertible::type>, + boost::is_convertible::type> + >, + duration::type, Period> + >::type + operator*(const Rep1& s, const duration& d) + { + return d * s; + } + + // Duration / + + template + inline BOOST_CONSTEXPR + typename boost::disable_if , + typename boost::chrono::detail::duration_divide_result< + duration, Rep2>::type + >::type + operator/(const duration& d, const Rep2& s) + { + typedef typename common_type::type common_rep; + typedef duration common_duration; + return common_duration(common_duration(d).count()/static_cast(s)); + } + + template + inline BOOST_CONSTEXPR + typename common_type::type + operator/(const duration& lhs, const duration& rhs) + { + typedef typename common_type, + duration >::type common_duration; + return common_duration(lhs).count() / common_duration(rhs).count(); + } + + #ifdef BOOST_CHRONO_EXTENSIONS + template + inline BOOST_CONSTEXPR + typename boost::disable_if , + typename boost::chrono::detail::duration_divide_result2< + Rep1, duration >::type + >::type + operator/(const Rep1& s, const duration& d) + { + typedef typename common_type::type common_rep; + typedef duration common_duration; + return static_cast(s)/common_duration(d).count(); + } + #endif + // Duration % + + template + inline BOOST_CONSTEXPR + typename boost::disable_if , + typename boost::chrono::detail::duration_modulo_result< + duration, Rep2>::type + >::type + operator%(const duration& d, const Rep2& s) + { + typedef typename common_type::type common_rep; + typedef duration common_duration; + return common_duration(common_duration(d).count()%static_cast(s)); + } + + template + inline BOOST_CONSTEXPR + typename common_type, duration >::type + operator%(const duration& lhs, + const duration& rhs) { + typedef typename common_type, + duration >::type common_duration; + + return common_duration(common_duration(lhs).count()%common_duration(rhs).count()); + } + + +//----------------------------------------------------------------------------// +// 20.9.3.6 duration comparisons [time.duration.comparisons] // +//----------------------------------------------------------------------------// + +namespace detail +{ + template + struct duration_eq + { + BOOST_CONSTEXPR bool operator()(const LhsDuration& lhs, const RhsDuration& rhs) const + { + typedef typename common_type::type common_duration; + return common_duration(lhs).count() == common_duration(rhs).count(); + } + }; + + template + struct duration_eq + { + BOOST_CONSTEXPR bool operator()(const LhsDuration& lhs, const LhsDuration& rhs) const + { + return lhs.count() == rhs.count(); + } + }; + + template + struct duration_lt + { + BOOST_CONSTEXPR bool operator()(const LhsDuration& lhs, const RhsDuration& rhs) const + { + typedef typename common_type::type common_duration; + return common_duration(lhs).count() < common_duration(rhs).count(); + } + }; + + template + struct duration_lt + { + BOOST_CONSTEXPR bool operator()(const LhsDuration& lhs, const LhsDuration& rhs) const + { + return lhs.count() < rhs.count(); + } + }; + +} // namespace detail + + // Duration == + + template + inline BOOST_CONSTEXPR + bool + operator==(const duration& lhs, + const duration& rhs) + { + return boost::chrono::detail::duration_eq< + duration, duration >()(lhs, rhs); + } + + // Duration != + + template + inline BOOST_CONSTEXPR + bool + operator!=(const duration& lhs, + const duration& rhs) + { + return !(lhs == rhs); + } + + // Duration < + + template + inline BOOST_CONSTEXPR + bool + operator< (const duration& lhs, + const duration& rhs) + { + return boost::chrono::detail::duration_lt< + duration, duration >()(lhs, rhs); + } + + // Duration > + + template + inline BOOST_CONSTEXPR + bool + operator> (const duration& lhs, + const duration& rhs) + { + return rhs < lhs; + } + + // Duration <= + + template + inline BOOST_CONSTEXPR + bool + operator<=(const duration& lhs, + const duration& rhs) + { + return !(rhs < lhs); + } + + // Duration >= + + template + inline BOOST_CONSTEXPR + bool + operator>=(const duration& lhs, + const duration& rhs) + { + return !(lhs < rhs); + } + +//----------------------------------------------------------------------------// +// 20.9.3.7 duration_cast [time.duration.cast] // +//----------------------------------------------------------------------------// + + // Compile-time select the most efficient algorithm for the conversion... + template + inline BOOST_CONSTEXPR + typename boost::enable_if < + boost::chrono::detail::is_duration, ToDuration>::type + duration_cast(const duration& fd) + { + return boost::chrono::detail::duration_cast< + duration, ToDuration>()(fd); + } + +} // namespace chrono +} // namespace boost + +#ifndef BOOST_CHRONO_HEADER_ONLY +// the suffix header occurs after all of our code: +#include // pops abi_prefix.hpp pragmas +#endif + +#endif // BOOST_CHRONO_DURATION_HPP diff --git a/boost/chrono/process_cpu_clocks.hpp b/boost/chrono/process_cpu_clocks.hpp new file mode 100644 index 0000000..93d3c94 --- /dev/null +++ b/boost/chrono/process_cpu_clocks.hpp @@ -0,0 +1,525 @@ +// boost/chrono/process_cpu_clocks.hpp -----------------------------------------------------------// + +// Copyright 2009-2011 Vicente J. Botet Escriba +// Copyright (c) Microsoft Corporation 2014 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/system for documentation. + +#ifndef BOOST_CHRONO_PROCESS_CPU_CLOCKS_HPP +#define BOOST_CHRONO_PROCESS_CPU_CLOCKS_HPP + +#include + + +#if defined(BOOST_CHRONO_HAS_PROCESS_CLOCKS) + +#include +#include +#include +#include +#include +#include +#include + +#ifndef BOOST_CHRONO_HEADER_ONLY +#include // must be the last #include +#endif + +namespace boost { namespace chrono { + + class BOOST_CHRONO_DECL process_real_cpu_clock { + public: + typedef nanoseconds duration; + typedef duration::rep rep; + typedef duration::period period; + typedef chrono::time_point time_point; + BOOST_STATIC_CONSTEXPR bool is_steady = true; + + static BOOST_CHRONO_INLINE time_point now() BOOST_NOEXCEPT; +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + static BOOST_CHRONO_INLINE time_point now(system::error_code & ec ); +#endif + }; + +#if ! BOOST_OS_WINDOWS || BOOST_PLAT_WINDOWS_DESKTOP + class BOOST_CHRONO_DECL process_user_cpu_clock { + public: + typedef nanoseconds duration; + typedef duration::rep rep; + typedef duration::period period; + typedef chrono::time_point time_point; + BOOST_STATIC_CONSTEXPR bool is_steady = true; + + static BOOST_CHRONO_INLINE time_point now() BOOST_NOEXCEPT; +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + static BOOST_CHRONO_INLINE time_point now(system::error_code & ec ); +#endif + }; + + class BOOST_CHRONO_DECL process_system_cpu_clock { + public: + typedef nanoseconds duration; + typedef duration::rep rep; + typedef duration::period period; + typedef chrono::time_point time_point; + BOOST_STATIC_CONSTEXPR bool is_steady = true; + + static BOOST_CHRONO_INLINE time_point now() BOOST_NOEXCEPT; +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + static BOOST_CHRONO_INLINE time_point now(system::error_code & ec ); +#endif + }; +#endif + + template + struct process_times + : arithmetic, + multiplicative, Rep, + less_than_comparable > > > + { + //typedef process_real_cpu_clock::rep rep; + typedef Rep rep; + process_times() + : real(0) + , user(0) + , system(0){} + +#if ! defined BOOST_CHRONO_DONT_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 + template + explicit process_times( + Rep2 r) + : real(r) + , user(r) + , system(r){} +#endif + template + explicit process_times( + process_times const& rhs) + : real(rhs.real) + , user(rhs.user) + , system(rhs.system){} + process_times( + rep r, + rep u, + rep s) + : real(r) + , user(u) + , system(s){} + + rep real; // real (i.e wall clock) time + rep user; // user cpu time + rep system; // system cpu time + +#if ! defined BOOST_CHRONO_DONT_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 + operator rep() const + { + return real; + } +#endif + template + bool operator==(process_times const& rhs) { + return (real==rhs.real && + user==rhs.user && + system==rhs.system); + } + + process_times& operator+=( + process_times const& rhs) + { + real+=rhs.real; + user+=rhs.user; + system+=rhs.system; + return *this; + } + process_times& operator-=( + process_times const& rhs) + { + real-=rhs.real; + user-=rhs.user; + system-=rhs.system; + return *this; + } + process_times& operator*=( + process_times const& rhs) + { + real*=rhs.real; + user*=rhs.user; + system*=rhs.system; + return *this; + } + process_times& operator*=(rep const& rhs) + { + real*=rhs; + user*=rhs; + system*=rhs; + return *this; + } + process_times& operator/=(process_times const& rhs) + { + real/=rhs.real; + user/=rhs.user; + system/=rhs.system; + return *this; + } + process_times& operator/=(rep const& rhs) + { + real/=rhs; + user/=rhs; + system/=rhs; + return *this; + } + bool operator<(process_times const & rhs) const + { + if (real < rhs.real) return true; + if (real > rhs.real) return false; + if (user < rhs.user) return true; + if (user > rhs.user) return false; + if (system < rhs.system) return true; + else return false; + } + + template + void print(std::basic_ostream& os) const + { + os << "{"<< real <<";"<< user <<";"<< system << "}"; + } + + template + void read(std::basic_istream& is) + { + typedef std::istreambuf_iterator in_iterator; + in_iterator i(is); + in_iterator e; + if (i == e || *i++ != '{') // mandatory '{' + { + is.setstate(is.failbit | is.eofbit); + return; + } + CharT x,y,z; + is >> real >> x >> user >> y >> system >> z; + if (!is.good() || (x != ';')|| (y != ';')|| (z != '}')) + { + is.setstate(is.failbit); + } + } + }; +} +template +struct common_type< + chrono::process_times, + chrono::process_times +> +{ + typedef chrono::process_times::type> type; +}; + +template +struct common_type< + chrono::process_times, + Rep2 +> +{ + typedef chrono::process_times::type> type; +}; + +template +struct common_type< + Rep1, + chrono::process_times +> +{ + typedef chrono::process_times::type> type; +}; + + +namespace chrono +{ + template + inline BOOST_CONSTEXPR + bool + operator==(const duration, Period1>& lhs, + const duration, Period2>& rhs) + { + return boost::chrono::detail::duration_eq< + duration, duration + >()(duration(lhs.count().real), duration(rhs.count().real)); + } + + template + inline BOOST_CONSTEXPR + bool + operator==(const duration, Period1>& lhs, + const duration& rhs) + { + return boost::chrono::detail::duration_eq< + duration, duration >()(duration(lhs.count().real), rhs); + } + + template + inline BOOST_CONSTEXPR + bool + operator==(const duration& lhs, + const duration, Period2>& rhs) + { + return rhs == lhs; + } + + + // Duration < + + template + inline BOOST_CONSTEXPR + bool + operator< (const duration, Period1>& lhs, + const duration& rhs) + { + return boost::chrono::detail::duration_lt< + duration, duration >()(duration(lhs.count().real), rhs); + } + + template + inline BOOST_CONSTEXPR + bool + operator< (const duration& lhs, + const duration, Period2>& rhs) + { + return boost::chrono::detail::duration_lt< + duration, duration >()(lhs, duration(rhs.count().real)); + } + + template + inline BOOST_CONSTEXPR + bool + operator< (const duration, Period1>& lhs, + const duration, Period2>& rhs) + { + return boost::chrono::detail::duration_lt< + duration, duration + >()(duration(lhs.count().real), duration(rhs.count().real)); + } + + + typedef process_times process_cpu_clock_times; +#if ! BOOST_OS_WINDOWS || BOOST_PLAT_WINDOWS_DESKTOP + class BOOST_CHRONO_DECL process_cpu_clock + { + public: + + typedef process_cpu_clock_times times; + typedef boost::chrono::duration duration; + typedef duration::rep rep; + typedef duration::period period; + typedef chrono::time_point time_point; + BOOST_STATIC_CONSTEXPR bool is_steady = true; + + static BOOST_CHRONO_INLINE time_point now() BOOST_NOEXCEPT; +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + static BOOST_CHRONO_INLINE time_point now(system::error_code & ec ); +#endif + }; +#endif + + template + std::basic_ostream& + operator<<(std::basic_ostream& os, + process_times const& rhs) + { + rhs.print(os); + return os; + } + + template + std::basic_istream& + operator>>(std::basic_istream& is, + process_times& rhs) + { + rhs.read(is); + return is; + } + + template + struct duration_values > + { + typedef process_times Res; + public: + static Res zero() + { + return Res(); + } + static Res max BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return Res((std::numeric_limits::max)(), + (std::numeric_limits::max)(), + (std::numeric_limits::max)()); + } + static Res min BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return Res((std::numeric_limits::min)(), + (std::numeric_limits::min)(), + (std::numeric_limits::min)()); + } + }; + + template + struct clock_string + { + static std::basic_string name() + { + static const CharT + u[] = + { 'p', 'r', 'o', 'c', 'e', 's', 's', '_', 'r', 'e', 'a', 'l', '_', 'c', 'l', 'o', 'c', 'k' }; + static const std::basic_string str(u, u + sizeof(u) + / sizeof(u[0])); + return str; + } + static std::basic_string since() + { + const CharT + u[] = + { ' ', 's', 'i', 'n', 'c', 'e', ' ', 'p', 'r', 'o', 'c', 'e', 's', 's', ' ', 's', 't', 'a', 'r', 't', '-', 'u', 'p' }; + const std::basic_string str(u, u + sizeof(u) / sizeof(u[0])); + return str; + } + }; + +#if ! BOOST_OS_WINDOWS || BOOST_PLAT_WINDOWS_DESKTOP + template + struct clock_string + { + static std::basic_string name() + { + static const CharT + u[] = + { 'p', 'r', 'o', 'c', 'e', 's', 's', '_', 'u', 's', 'e', 'r', '_', 'c', 'l', 'o', 'c', 'k' }; + static const std::basic_string str(u, u + sizeof(u) + / sizeof(u[0])); + return str; + } + static std::basic_string since() + { + const CharT + u[] = + { ' ', 's', 'i', 'n', 'c', 'e', ' ', 'p', 'r', 'o', 'c', 'e', 's', 's', ' ', 's', 't', 'a', 'r', 't', '-', 'u', 'p' }; + const std::basic_string str(u, u + sizeof(u) / sizeof(u[0])); + return str; + } + }; + + template + struct clock_string + { + static std::basic_string name() + { + static const CharT + u[] = + { 'p', 'r', 'o', 'c', 'e', 's', 's', '_', 's', 'y', 's', 't', 'e', 'm', '_', 'c', 'l', 'o', 'c', 'k' }; + static const std::basic_string str(u, u + sizeof(u) + / sizeof(u[0])); + return str; + } + static std::basic_string since() + { + const CharT + u[] = + { ' ', 's', 'i', 'n', 'c', 'e', ' ', 'p', 'r', 'o', 'c', 'e', 's', 's', ' ', 's', 't', 'a', 'r', 't', '-', 'u', 'p' }; + const std::basic_string str(u, u + sizeof(u) / sizeof(u[0])); + return str; + } + }; + + template + struct clock_string + { + static std::basic_string name() + { + static const CharT u[] = + { 'p', 'r', 'o', 'c', 'e', 's', 's', '_', 'c', 'l', 'o', 'c', 'k' }; + static const std::basic_string str(u, u + sizeof(u) + / sizeof(u[0])); + return str; + } + static std::basic_string since() + { + const CharT + u[] = + { ' ', 's', 'i', 'n', 'c', 'e', ' ', 'p', 'r', 'o', 'c', 'e', 's', 's', ' ', 's', 't', 'a', 'r', 't', '-', 'u', 'p' }; + const std::basic_string str(u, u + sizeof(u) / sizeof(u[0])); + return str; + } + }; +#endif + +} // namespace chrono +} // namespace boost + +namespace std { + + template + struct numeric_limits > + { + typedef boost::chrono::process_times Res; + + public: + static const bool is_specialized = true; + static Res min BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return Res((std::numeric_limits::min)(), + (std::numeric_limits::min)(), + (std::numeric_limits::min)()); + } + static Res max BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return Res((std::numeric_limits::max)(), + (std::numeric_limits::max)(), + (std::numeric_limits::max)()); + } + static Res lowest() BOOST_NOEXCEPT_OR_NOTHROW + { + return (min)(); + } + static const int digits = std::numeric_limits::digits+ + std::numeric_limits::digits+ + std::numeric_limits::digits; + static const int digits10 = std::numeric_limits::digits10+ + std::numeric_limits::digits10+ + std::numeric_limits::digits10; + static const bool is_signed = Rep::is_signed; + static const bool is_integer = Rep::is_integer; + static const bool is_exact = Rep::is_exact; + static const int radix = 0; + //~ static Res epsilon() throw() { return 0; } + //~ static Res round_error() throw() { return 0; } + //~ static const int min_exponent = 0; + //~ static const int min_exponent10 = 0; + //~ static const int max_exponent = 0; + //~ static const int max_exponent10 = 0; + //~ static const bool has_infinity = false; + //~ static const bool has_quiet_NaN = false; + //~ static const bool has_signaling_NaN = false; + //~ static const float_denorm_style has_denorm = denorm_absent; + //~ static const bool has_denorm_loss = false; + //~ static Res infinity() throw() { return 0; } + //~ static Res quiet_NaN() throw() { return 0; } + //~ static Res signaling_NaN() throw() { return 0; } + //~ static Res denorm_min() throw() { return 0; } + //~ static const bool is_iec559 = false; + //~ static const bool is_bounded = true; + //~ static const bool is_modulo = false; + //~ static const bool traps = false; + //~ static const bool tinyness_before = false; + //~ static const float_round_style round_style = round_toward_zero; + + }; +} + +#ifndef BOOST_CHRONO_HEADER_ONLY +#include // pops abi_prefix.hpp pragmas +#else +#include +#endif +#endif + +#endif // BOOST_CHRONO_PROCESS_CPU_CLOCKS_HPP diff --git a/boost/chrono/system_clocks.hpp b/boost/chrono/system_clocks.hpp new file mode 100644 index 0000000..3087311 --- /dev/null +++ b/boost/chrono/system_clocks.hpp @@ -0,0 +1,233 @@ +// boost/chrono/system_clocks.hpp --------------------------------------------------------------// + +// Copyright 2008 Howard Hinnant +// Copyright 2008 Beman Dawes +// Copyright 2009-2011 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +/* + +This code was derived by Beman Dawes from Howard Hinnant's time2_demo prototype. +Many thanks to Howard for making his code available under the Boost license. +The original code was modified to conform to Boost conventions and to section +20.9 Time utilities [time] of the C++ committee's working paper N2798. +See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf. + +time2_demo contained this comment: + + Much thanks to Andrei Alexandrescu, + Walter Brown, + Peter Dimov, + Jeff Garland, + Terry Golubiewski, + Daniel Krugler, + Anthony Williams. +*/ + +/* + +TODO: + + * Fully implement error handling, with test cases. + * Consider issues raised by Michael Marcin: + + > In the past I've seen QueryPerformanceCounter give incorrect results, + > especially with SpeedStep processors on laptops. This was many years ago and + > might have been fixed by service packs and drivers. + > + > Typically you check the results of QPC against GetTickCount to see if the + > results are reasonable. + > http://support.microsoft.com/kb/274323 + > + > I've also heard of problems with QueryPerformanceCounter in multi-processor + > systems. + > + > I know some people SetThreadAffinityMask to 1 for the current thread call + > their QueryPerformance* functions then restore SetThreadAffinityMask. This + > seems horrible to me because it forces your program to jump to another + > physical processor if it isn't already on cpu0 but they claim it worked well + > in practice because they called the timing functions infrequently. + > + > In the past I have chosen to use timeGetTime with timeBeginPeriod(1) for + > high resolution timers to avoid these issues. + +*/ + +#ifndef BOOST_CHRONO_SYSTEM_CLOCKS_HPP +#define BOOST_CHRONO_SYSTEM_CLOCKS_HPP + +#include +#include +#include +#include +#include + +#include + +# if defined( BOOST_CHRONO_POSIX_API ) +# if ! defined(CLOCK_REALTIME) && ! defined (__hpux__) +# error does not supply CLOCK_REALTIME +# endif +# endif + +#ifdef BOOST_CHRONO_WINDOWS_API +// The system_clock tick is 100 nanoseconds +# define BOOST_SYSTEM_CLOCK_DURATION boost::chrono::duration > +#else +# define BOOST_SYSTEM_CLOCK_DURATION boost::chrono::nanoseconds +#endif + +// this must occur after all of the includes and before any code appears: +#ifndef BOOST_CHRONO_HEADER_ONLY +#include // must be the last #include +#endif + + +//----------------------------------------------------------------------------// +// // +// 20.9 Time utilities [time] // +// synopsis // +// // +//----------------------------------------------------------------------------// + +namespace boost { +namespace chrono { + + // Clocks + class system_clock; +#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY + class steady_clock; +#endif + +#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY + typedef steady_clock high_resolution_clock; // as permitted by [time.clock.hires] +#else + typedef system_clock high_resolution_clock; // as permitted by [time.clock.hires] +#endif + +//----------------------------------------------------------------------------// +// // +// 20.9.5 Clocks [time.clock] // +// // +//----------------------------------------------------------------------------// + +// If you're porting, clocks are the system-specific (non-portable) part. +// You'll need to know how to get the current time and implement that under now(). +// You'll need to know what units (tick period) and representation makes the most +// sense for your clock and set those accordingly. +// If you know how to map this clock to time_t (perhaps your clock is std::time, which +// makes that trivial), then you can fill out system_clock's to_time_t() and from_time_t(). + +//----------------------------------------------------------------------------// +// 20.9.5.1 Class system_clock [time.clock.system] // +//----------------------------------------------------------------------------// + + class BOOST_CHRONO_DECL system_clock + { + public: + typedef BOOST_SYSTEM_CLOCK_DURATION duration; + typedef duration::rep rep; + typedef duration::period period; + typedef chrono::time_point time_point; + BOOST_STATIC_CONSTEXPR bool is_steady = false; + + static BOOST_CHRONO_INLINE time_point now() BOOST_NOEXCEPT; +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + static BOOST_CHRONO_INLINE time_point now(system::error_code & ec); +#endif + + static BOOST_CHRONO_INLINE std::time_t to_time_t(const time_point& t) BOOST_NOEXCEPT; + static BOOST_CHRONO_INLINE time_point from_time_t(std::time_t t) BOOST_NOEXCEPT; + }; + +//----------------------------------------------------------------------------// +// 20.9.5.2 Class steady_clock [time.clock.steady] // +//----------------------------------------------------------------------------// + +// As permitted by [time.clock.steady] +// The class steady_clock is conditionally supported. + +#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY + class BOOST_CHRONO_DECL steady_clock + { + public: + typedef nanoseconds duration; + typedef duration::rep rep; + typedef duration::period period; + typedef chrono::time_point time_point; + BOOST_STATIC_CONSTEXPR bool is_steady = true; + + static BOOST_CHRONO_INLINE time_point now() BOOST_NOEXCEPT; +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + static BOOST_CHRONO_INLINE time_point now(system::error_code & ec); +#endif + }; +#endif +//----------------------------------------------------------------------------// +// 20.9.5.3 Class high_resolution_clock [time.clock.hires] // +//----------------------------------------------------------------------------// + +// As permitted, steady_clock or system_clock is a typedef for high_resolution_clock. +// See synopsis. + + + template + struct clock_string + { + static std::basic_string name() + { + static const CharT u[] = + { 's', 'y', 's', 't', 'e', 'm', '_', 'c', 'l', 'o', 'c', 'k' }; + static const std::basic_string str(u, u + sizeof(u) + / sizeof(u[0])); + return str; + } + static std::basic_string since() + { + static const CharT + u[] = + { ' ', 's', 'i', 'n', 'c', 'e', ' ', 'J', 'a', 'n', ' ', '1', ',', ' ', '1', '9', '7', '0' }; + static const std::basic_string str(u, u + sizeof(u) + / sizeof(u[0])); + return str; + } + }; + +#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY + + template + struct clock_string + { + static std::basic_string name() + { + static const CharT + u[] = + { 's', 't', 'e', 'a', 'd', 'y', '_', 'c', 'l', 'o', 'c', 'k' }; + static const std::basic_string str(u, u + sizeof(u) + / sizeof(u[0])); + return str; + } + static std::basic_string since() + { + const CharT u[] = + { ' ', 's', 'i', 'n', 'c', 'e', ' ', 'b', 'o', 'o', 't' }; + const std::basic_string str(u, u + sizeof(u) / sizeof(u[0])); + return str; + } + }; + +#endif + +} // namespace chrono +} // namespace boost + +#ifndef BOOST_CHRONO_HEADER_ONLY +// the suffix header occurs after all of our code: +#include // pops abi_prefix.hpp pragmas +#else +#include +#endif + +#endif // BOOST_CHRONO_SYSTEM_CLOCKS_HPP diff --git a/boost/chrono/thread_clock.hpp b/boost/chrono/thread_clock.hpp new file mode 100644 index 0000000..207697b --- /dev/null +++ b/boost/chrono/thread_clock.hpp @@ -0,0 +1,75 @@ +// boost/chrono/thread_clock.hpp -----------------------------------------------------------// + +// Copyright 2009-2011 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/system for documentation. + +#include + +#ifndef BOOST_CHRONO_THREAD_CLOCK_HPP +#define BOOST_CHRONO_THREAD_CLOCK_HPP + +#if defined(BOOST_CHRONO_HAS_THREAD_CLOCK) + +#include +#include +#include +#include +#include + +#ifndef BOOST_CHRONO_HEADER_ONLY +#include // must be the last #include +#endif + +namespace boost { namespace chrono { + +class BOOST_CHRONO_DECL thread_clock { +public: + typedef nanoseconds duration; + typedef duration::rep rep; + typedef duration::period period; + typedef chrono::time_point time_point; + BOOST_STATIC_CONSTEXPR bool is_steady = BOOST_CHRONO_THREAD_CLOCK_IS_STEADY; + + static BOOST_CHRONO_INLINE time_point now( ) BOOST_NOEXCEPT; +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + static BOOST_CHRONO_INLINE time_point now( system::error_code & ec ); +#endif +}; + +template +struct clock_string +{ + static std::basic_string name() + { + static const CharT u[] = + { 't', 'h', 'r', 'e', 'a', 'd', '_', + 'c', 'l','o', 'c', 'k'}; + static const std::basic_string str(u, u + sizeof(u)/sizeof(u[0])); + return str; + } + static std::basic_string since() + { + const CharT u[] = + { ' ', 's', 'i', 'n', 'c', 'e', ' ', 't', 'h', 'r', 'e', 'a', 'd', ' ', 's', 't', 'a', 'r', 't', '-', 'u', 'p'}; + const std::basic_string str(u, u + sizeof(u)/sizeof(u[0])); + return str; + } +}; + +} // namespace chrono +} // namespace boost + + +#ifndef BOOST_CHRONO_HEADER_ONLY +#include // pops abi_prefix.hpp pragmas +#else +#include +#endif + +#endif + +#endif // BOOST_CHRONO_THREAD_CLOCK_HPP diff --git a/boost/chrono/time_point.hpp b/boost/chrono/time_point.hpp new file mode 100644 index 0000000..fc23095 --- /dev/null +++ b/boost/chrono/time_point.hpp @@ -0,0 +1,379 @@ +// duration.hpp --------------------------------------------------------------// + +// Copyright 2008 Howard Hinnant +// Copyright 2008 Beman Dawes +// Copyright 2009-2012 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +/* + +This code was derived by Beman Dawes from Howard Hinnant's time2_demo prototype. +Many thanks to Howard for making his code available under the Boost license. +The original code was modified to conform to Boost conventions and to section +20.9 Time utilities [time] of the C++ committee's working paper N2798. +See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf. + +time2_demo contained this comment: + + Much thanks to Andrei Alexandrescu, + Walter Brown, + Peter Dimov, + Jeff Garland, + Terry Golubiewski, + Daniel Krugler, + Anthony Williams. +*/ + + +#ifndef BOOST_CHRONO_TIME_POINT_HPP +#define BOOST_CHRONO_TIME_POINT_HPP + +#include + +#ifndef BOOST_CHRONO_HEADER_ONLY +// this must occur after all of the includes and before any code appears: +#include // must be the last #include +#endif + +//----------------------------------------------------------------------------// +// // +// 20.9 Time utilities [time] // +// synopsis // +// // +//----------------------------------------------------------------------------// + +namespace boost { +namespace chrono { + + template + class time_point; + + +} // namespace chrono + + +// common_type trait specializations + +template + struct common_type, + chrono::time_point >; + + +//----------------------------------------------------------------------------// +// 20.9.2.3 Specializations of common_type [time.traits.specializations] // +//----------------------------------------------------------------------------// + + +template +struct common_type, + chrono::time_point > +{ + typedef chrono::time_point::type> type; +}; + + + +namespace chrono { + + // time_point arithmetic + template + inline BOOST_CONSTEXPR + time_point >::type> + operator+( + const time_point& lhs, + const duration& rhs); + template + inline BOOST_CONSTEXPR + time_point, Duration2>::type> + operator+( + const duration& lhs, + const time_point& rhs); + template + inline BOOST_CONSTEXPR + time_point >::type> + operator-( + const time_point& lhs, + const duration& rhs); + template + inline BOOST_CONSTEXPR + typename common_type::type + operator-( + const time_point& lhs, + const time_point& rhs); + + // time_point comparisons + template + inline BOOST_CONSTEXPR + bool operator==( + const time_point& lhs, + const time_point& rhs); + template + inline BOOST_CONSTEXPR + bool operator!=( + const time_point& lhs, + const time_point& rhs); + template + inline BOOST_CONSTEXPR + bool operator< ( + const time_point& lhs, + const time_point& rhs); + template + inline BOOST_CONSTEXPR + bool operator<=( + const time_point& lhs, + const time_point& rhs); + template + inline BOOST_CONSTEXPR + bool operator> ( + const time_point& lhs, + const time_point& rhs); + template + inline BOOST_CONSTEXPR + bool operator>=( + const time_point& lhs, + const time_point& rhs); + + // time_point_cast + template + inline BOOST_CONSTEXPR + time_point time_point_cast(const time_point& t); + +//----------------------------------------------------------------------------// +// // +// 20.9.4 Class template time_point [time.point] // +// // +//----------------------------------------------------------------------------// + + template + class time_point + { + BOOST_CHRONO_STATIC_ASSERT(boost::chrono::detail::is_duration::value, + BOOST_CHRONO_SECOND_TEMPLATE_PARAMETER_OF_TIME_POINT_MUST_BE_A_BOOST_CHRONO_DURATION, (Duration)); + public: + typedef Clock clock; + typedef Duration duration; + typedef typename duration::rep rep; + typedef typename duration::period period; + typedef Duration difference_type; + + private: + duration d_; + + public: + BOOST_FORCEINLINE BOOST_CONSTEXPR + time_point() : d_(duration::zero()) + {} + BOOST_FORCEINLINE BOOST_CONSTEXPR + explicit time_point(const duration& d) + : d_(d) + {} + + // conversions + template + BOOST_FORCEINLINE BOOST_CONSTEXPR + time_point(const time_point& t + , typename boost::enable_if + < + boost::is_convertible + >::type* = 0 + ) + : d_(t.time_since_epoch()) + { + } + // observer + + BOOST_CONSTEXPR + duration time_since_epoch() const + { + return d_; + } + + // arithmetic + +#ifdef BOOST_CHRONO_EXTENSIONS + BOOST_CONSTEXPR + time_point operator+() const {return *this;} + BOOST_CONSTEXPR + time_point operator-() const {return time_point(-d_);} + time_point& operator++() {++d_; return *this;} + time_point operator++(int) {return time_point(d_++);} + time_point& operator--() {--d_; return *this;} + time_point operator--(int) {return time_point(d_--);} + + time_point& operator+=(const rep& r) {d_ += duration(r); return *this;} + time_point& operator-=(const rep& r) {d_ -= duration(r); return *this;} + +#endif + + time_point& operator+=(const duration& d) {d_ += d; return *this;} + time_point& operator-=(const duration& d) {d_ -= d; return *this;} + + // special values + + static BOOST_CHRONO_LIB_CONSTEXPR time_point + min BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return time_point((duration::min)()); + } + static BOOST_CHRONO_LIB_CONSTEXPR time_point + max BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return time_point((duration::max)()); + } + }; + +//----------------------------------------------------------------------------// +// 20.9.4.5 time_point non-member arithmetic [time.point.nonmember] // +//----------------------------------------------------------------------------// + + // time_point operator+(time_point x, duration y); + + template + inline BOOST_CONSTEXPR + time_point >::type> + operator+(const time_point& lhs, + const duration& rhs) + { + typedef typename common_type >::type CDuration; + typedef time_point< + Clock, + CDuration + > TimeResult; + return TimeResult(lhs.time_since_epoch() + CDuration(rhs)); + } + + // time_point operator+(duration x, time_point y); + + template + inline BOOST_CONSTEXPR + time_point, Duration2>::type> + operator+(const duration& lhs, + const time_point& rhs) + { + return rhs + lhs; + } + + // time_point operator-(time_point x, duration y); + + template + inline BOOST_CONSTEXPR + time_point >::type> + operator-(const time_point& lhs, + const duration& rhs) + { + return lhs + (-rhs); + } + + // duration operator-(time_point x, time_point y); + + template + inline BOOST_CONSTEXPR + typename common_type::type + operator-(const time_point& lhs, + const time_point& rhs) + { + return lhs.time_since_epoch() - rhs.time_since_epoch(); + } + +//----------------------------------------------------------------------------// +// 20.9.4.6 time_point comparisons [time.point.comparisons] // +//----------------------------------------------------------------------------// + + // time_point == + + template + inline BOOST_CONSTEXPR + bool + operator==(const time_point& lhs, + const time_point& rhs) + { + return lhs.time_since_epoch() == rhs.time_since_epoch(); + } + + // time_point != + + template + inline BOOST_CONSTEXPR + bool + operator!=(const time_point& lhs, + const time_point& rhs) + { + return !(lhs == rhs); + } + + // time_point < + + template + inline BOOST_CONSTEXPR + bool + operator<(const time_point& lhs, + const time_point& rhs) + { + return lhs.time_since_epoch() < rhs.time_since_epoch(); + } + + // time_point > + + template + inline BOOST_CONSTEXPR + bool + operator>(const time_point& lhs, + const time_point& rhs) + { + return rhs < lhs; + } + + // time_point <= + + template + inline BOOST_CONSTEXPR + bool + operator<=(const time_point& lhs, + const time_point& rhs) + { + return !(rhs < lhs); + } + + // time_point >= + + template + inline BOOST_CONSTEXPR + bool + operator>=(const time_point& lhs, + const time_point& rhs) + { + return !(lhs < rhs); + } + +//----------------------------------------------------------------------------// +// 20.9.4.7 time_point_cast [time.point.cast] // +//----------------------------------------------------------------------------// + + template + inline BOOST_CONSTEXPR + time_point + time_point_cast(const time_point& t) + { + return time_point( + duration_cast(t.time_since_epoch())); + } + +} // namespace chrono +} // namespace boost + +#ifndef BOOST_CHRONO_HEADER_ONLY +// the suffix header occurs after all of our code: +#include // pops abi_prefix.hpp pragmas +#endif + +#endif // BOOST_CHRONO_TIME_POINT_HPP diff --git a/boost/concept/assert.hpp b/boost/concept/assert.hpp index cf98179..36c3b03 100644 --- a/boost/concept/assert.hpp +++ b/boost/concept/assert.hpp @@ -5,7 +5,7 @@ # define BOOST_CONCEPT_ASSERT_DWA2006430_HPP # include -# include +# include // The old protocol used a constraints() member function in concept // checking classes. If the compiler supports SFINAE, we can detect diff --git a/boost/concept/detail/general.hpp b/boost/concept/detail/general.hpp index 525ea65..eeb0875 100644 --- a/boost/concept/detail/general.hpp +++ b/boost/concept/detail/general.hpp @@ -10,7 +10,7 @@ # ifdef BOOST_OLD_CONCEPT_SUPPORT # include -# include +# include # endif // This implementation works on Comeau and GCC, all the way back to @@ -49,8 +49,8 @@ struct constraint template struct requirement_ - : mpl::if_< - concepts::not_satisfied + : boost::conditional< + concepts::not_satisfied::value , constraint , requirement >::type diff --git a/boost/concept/detail/has_constraints.hpp b/boost/concept/detail/has_constraints.hpp index a309db3..dc2c207 100644 --- a/boost/concept/detail/has_constraints.hpp +++ b/boost/concept/detail/has_constraints.hpp @@ -4,8 +4,8 @@ #ifndef BOOST_CONCEPT_DETAIL_HAS_CONSTRAINTS_DWA2006429_HPP # define BOOST_CONCEPT_DETAIL_HAS_CONSTRAINTS_DWA2006429_HPP -# include -# include +# include +# include # include namespace boost { namespace concepts { @@ -42,7 +42,7 @@ struct not_satisfied BOOST_STATIC_CONSTANT( bool , value = sizeof( detail::has_constraints_((Model*)0) ) == sizeof(detail::yes) ); - typedef mpl::bool_ type; + typedef boost::integral_constant type; }; }} // namespace boost::concepts::detail diff --git a/boost/concept/detail/msvc.hpp b/boost/concept/detail/msvc.hpp index 078dd22..933ac02 100644 --- a/boost/concept/detail/msvc.hpp +++ b/boost/concept/detail/msvc.hpp @@ -10,7 +10,7 @@ # ifdef BOOST_OLD_CONCEPT_SUPPORT # include -# include +# include # endif # ifdef BOOST_MSVC @@ -54,7 +54,7 @@ namespace detail template struct require - : mpl::if_c< + : boost::conditional< not_satisfied::value , detail::constraint # ifndef BOOST_NO_PARTIAL_SPECIALIZATION diff --git a/boost/concept/usage.hpp b/boost/concept/usage.hpp index e73370f..373de63 100644 --- a/boost/concept/usage.hpp +++ b/boost/concept/usage.hpp @@ -5,7 +5,7 @@ # define BOOST_CONCEPT_USAGE_DWA2006919_HPP # include -# include +# include # include namespace boost { namespace concepts { diff --git a/boost/concept_check.hpp b/boost/concept_check.hpp index 25f118b..abbadb7 100644 --- a/boost/concept_check.hpp +++ b/boost/concept_check.hpp @@ -24,9 +24,9 @@ # include # include # include -# include -# include -# include +# include +# include +# include # include # include @@ -301,14 +301,14 @@ namespace boost BOOST_CONCEPT_USAGE(Generator) { test(is_void()); } private: - void test(boost::mpl::false_) + void test(boost::false_type) { // Do we really want a reference here? const Return& r = f(); ignore_unused_variable_warning(r); } - void test(boost::mpl::true_) + void test(boost::true_type) { f(); } @@ -321,22 +321,22 @@ namespace boost BOOST_CONCEPT_USAGE(UnaryFunction) { test(is_void()); } private: - void test(boost::mpl::false_) + void test(boost::false_type) { f(arg); // "priming the pump" this way keeps msvc6 happy (ICE) Return r = f(arg); ignore_unused_variable_warning(r); } - void test(boost::mpl::true_) + void test(boost::true_type) { f(arg); } #if (BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(4) \ && BOOST_WORKAROUND(__GNUC__, > 3))) - // Declare a dummy construktor to make gcc happy. - // It seems the compiler can not generate a sensible constructor when this is instantiated with a refence type. + // Declare a dummy constructor to make gcc happy. + // It seems the compiler can not generate a sensible constructor when this is instantiated with a reference type. // (warning: non-static reference "const double& boost::UnaryFunction::arg" // in class without a constructor [-Wuninitialized]) UnaryFunction(); @@ -350,14 +350,14 @@ namespace boost { BOOST_CONCEPT_USAGE(BinaryFunction) { test(is_void()); } private: - void test(boost::mpl::false_) + void test(boost::false_type) { f(first,second); Return r = f(first, second); // require operator() (void)r; } - void test(boost::mpl::true_) + void test(boost::true_type) { f(first,second); } @@ -365,7 +365,7 @@ namespace boost #if (BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(4) \ && BOOST_WORKAROUND(__GNUC__, > 3))) // Declare a dummy constructor to make gcc happy. - // It seems the compiler can not generate a sensible constructor when this is instantiated with a refence type. + // It seems the compiler can not generate a sensible constructor when this is instantiated with a reference type. // (warning: non-static reference "const double& boost::BinaryFunction::arg" // in class without a constructor [-Wuninitialized]) BinaryFunction(); @@ -385,7 +385,7 @@ namespace boost #if (BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(4) \ && BOOST_WORKAROUND(__GNUC__, > 3))) // Declare a dummy constructor to make gcc happy. - // It seems the compiler can not generate a sensible constructor when this is instantiated with a refence type. + // It seems the compiler can not generate a sensible constructor when this is instantiated with a reference type. // (warning: non-static reference "const double& boost::UnaryPredicate::arg" // in class without a constructor [-Wuninitialized]) UnaryPredicate(); @@ -404,7 +404,7 @@ namespace boost #if (BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(4) \ && BOOST_WORKAROUND(__GNUC__, > 3))) // Declare a dummy constructor to make gcc happy. - // It seems the compiler can not generate a sensible constructor when this is instantiated with a refence type. + // It seems the compiler can not generate a sensible constructor when this is instantiated with a reference type. // (warning: non-static reference "const double& boost::BinaryPredicate::arg" // in class without a constructor [-Wuninitialized]) BinaryPredicate(); @@ -429,7 +429,7 @@ namespace boost #if (BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(4) \ && BOOST_WORKAROUND(__GNUC__, > 3))) // Declare a dummy constructor to make gcc happy. - // It seems the compiler can not generate a sensible constructor when this is instantiated with a refence type. + // It seems the compiler can not generate a sensible constructor when this is instantiated with a reference type. // (warning: non-static reference "const double& boost::Const_BinaryPredicate::arg" // in class without a constructor [-Wuninitialized]) Const_BinaryPredicate(); @@ -734,8 +734,8 @@ namespace boost private: void const_constraints(const C& cc) { - const_reverse_iterator i = cc.rbegin(); - i = cc.rend(); + const_reverse_iterator _i = cc.rbegin(); + _i = cc.rend(); } C c; }; @@ -966,7 +966,7 @@ namespace boost { typedef typename C::key_type key_type; typedef typename C::value_type value_type; - BOOST_MPL_ASSERT((boost::is_same)); + BOOST_STATIC_ASSERT((boost::is_same::value)); } }; @@ -979,7 +979,7 @@ namespace boost typedef typename C::value_type value_type; typedef typename C::mapped_type mapped_type; typedef std::pair required_value_type; - BOOST_MPL_ASSERT((boost::is_same)); + BOOST_STATIC_ASSERT((boost::is_same::value)); } }; diff --git a/boost/config/auto_link.hpp b/boost/config/auto_link.hpp index 271f837..e74f3c1 100644 --- a/boost/config/auto_link.hpp +++ b/boost/config/auto_link.hpp @@ -28,6 +28,9 @@ BOOST_AUTO_LINK_NOMANGLE: Specifies that we should link to BOOST_LIB_NAME.lib, BOOST_AUTO_LINK_TAGGED: Specifies that we link to libraries built with the --layout=tagged option. This is essentially the same as the default name-mangled version, but without the compiler name and version, or the Boost version. Just the build options. +BOOST_AUTO_LINK_SYSTEM: Specifies that we link to libraries built with the --layout=system option. + This is essentially the same as the non-name-mangled version, but with + the prefix to differentiate static and dll builds These macros will be undef'ed at the end of the header, further this header has no include guards - so be sure to include it only once from your library! @@ -96,7 +99,8 @@ BOOST_LIB_VERSION: The Boost version, in the form x_y, for Boost version x.y. #if defined(BOOST_MSVC) \ || defined(__BORLANDC__) \ || (defined(__MWERKS__) && defined(_WIN32) && (__MWERKS__ >= 0x3000)) \ - || (defined(__ICL) && defined(_MSC_EXTENSIONS) && (_MSC_VER >= 1200)) + || (defined(__ICL) && defined(_MSC_EXTENSIONS) && (_MSC_VER >= 1200)) \ + || (defined(BOOST_CLANG) && defined(BOOST_WINDOWS) && defined(_MSC_VER) && (__clang_major__ >= 4)) #ifndef BOOST_VERSION_HPP # include @@ -170,11 +174,16 @@ BOOST_LIB_VERSION: The Boost version, in the form x_y, for Boost version x.y. // vc14: # define BOOST_LIB_TOOLSET "vc140" -# elif defined(BOOST_MSVC) +# elif defined(BOOST_MSVC) && (BOOST_MSVC < 1920) // vc14.1: # define BOOST_LIB_TOOLSET "vc141" +# elif defined(BOOST_MSVC) + + // vc14.2: +# define BOOST_LIB_TOOLSET "vc142" + # elif defined(__BORLANDC__) // CBuilder 6: @@ -195,6 +204,11 @@ BOOST_LIB_VERSION: The Boost version, in the form x_y, for Boost version x.y. // Metrowerks CodeWarrior 9.x # define BOOST_LIB_TOOLSET "cw9" +# elif defined(BOOST_CLANG) && defined(BOOST_WINDOWS) && defined(_MSC_VER) && (__clang_major__ >= 4) + + // Clang on Windows +# define BOOST_LIB_TOOLSET "clangw" BOOST_STRINGIZE(__clang_major__) + # endif #endif // BOOST_LIB_TOOLSET @@ -402,9 +416,14 @@ BOOST_LIB_VERSION: The Boost version, in the form x_y, for Boost version x.y. && defined(BOOST_LIB_VERSION) #ifdef BOOST_AUTO_LINK_TAGGED -# pragma comment(lib, BOOST_LIB_PREFIX BOOST_STRINGIZE(BOOST_LIB_NAME) BOOST_LIB_THREAD_OPT BOOST_LIB_RT_OPT ".lib") +# pragma comment(lib, BOOST_LIB_PREFIX BOOST_STRINGIZE(BOOST_LIB_NAME) BOOST_LIB_THREAD_OPT BOOST_LIB_RT_OPT BOOST_LIB_ARCH_AND_MODEL_OPT ".lib") # ifdef BOOST_LIB_DIAGNOSTIC -# pragma message ("Linking to lib file: " BOOST_LIB_PREFIX BOOST_STRINGIZE(BOOST_LIB_NAME) BOOST_LIB_THREAD_OPT BOOST_LIB_RT_OPT ".lib") +# pragma message ("Linking to lib file: " BOOST_LIB_PREFIX BOOST_STRINGIZE(BOOST_LIB_NAME) BOOST_LIB_THREAD_OPT BOOST_LIB_RT_OPT BOOST_LIB_ARCH_AND_MODEL_OPT ".lib") +# endif +#elif defined(BOOST_AUTO_LINK_SYSTEM) +# pragma comment(lib, BOOST_LIB_PREFIX BOOST_STRINGIZE(BOOST_LIB_NAME) ".lib") +# ifdef BOOST_LIB_DIAGNOSTIC +# pragma message ("Linking to lib file: " BOOST_LIB_PREFIX BOOST_STRINGIZE(BOOST_LIB_NAME) ".lib") # endif #elif defined(BOOST_AUTO_LINK_NOMANGLE) # pragma comment(lib, BOOST_STRINGIZE(BOOST_LIB_NAME) ".lib") diff --git a/boost/config/compiler/borland.hpp b/boost/config/compiler/borland.hpp index cb164f8..beec946 100644 --- a/boost/config/compiler/borland.hpp +++ b/boost/config/compiler/borland.hpp @@ -19,9 +19,9 @@ // last known compiler version: #if (__BORLANDC__ > 0x613) //# if defined(BOOST_ASSERT_CONFIG) -# error "Unknown compiler version - please run the configure tests and report the results" +# error "boost: Unknown compiler version - please run the configure tests and report the results" //# else -//# pragma message( "Unknown compiler version - please run the configure tests and report the results") +//# pragma message( "boost: Unknown compiler version - please run the configure tests and report the results") //# endif #elif (__BORLANDC__ == 0x600) # error "CBuilderX preview compiler is no longer supported" diff --git a/boost/config/compiler/clang.hpp b/boost/config/compiler/clang.hpp index 3d893c6..52b23d9 100644 --- a/boost/config/compiler/clang.hpp +++ b/boost/config/compiler/clang.hpp @@ -57,6 +57,14 @@ # define BOOST_HAS_STDINT_H #endif +#if (defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && !defined(_CRAYC) +#if (__clang_major__ >= 4) && defined(__has_include) +#if __has_include() +# define BOOST_HAS_FLOAT128 +#endif +#endif +#endif + #define BOOST_HAS_NRVO @@ -104,9 +112,9 @@ # define BOOST_SYMBOL_IMPORT __attribute__((__dllimport__)) #else # define BOOST_SYMBOL_EXPORT __attribute__((__visibility__("default"))) +# define BOOST_SYMBOL_VISIBLE __attribute__((__visibility__("default"))) # define BOOST_SYMBOL_IMPORT #endif -#define BOOST_SYMBOL_VISIBLE __attribute__((__visibility__("default"))) // // The BOOST_FALLTHROUGH macro can be used to annotate implicit fall-through diff --git a/boost/config/compiler/codegear.hpp b/boost/config/compiler/codegear.hpp index c2cfe15..52531d2 100644 --- a/boost/config/compiler/codegear.hpp +++ b/boost/config/compiler/codegear.hpp @@ -22,9 +22,9 @@ // last known and checked version is 0x621 #if (__CODEGEARC__ > 0x621) # if defined(BOOST_ASSERT_CONFIG) -# error "Unknown compiler version - please run the configure tests and report the results" +# error "boost: Unknown compiler version - please run the configure tests and report the results" # else -# pragma message( "Unknown compiler version - please run the configure tests and report the results") +# pragma message( "boost: Unknown compiler version - please run the configure tests and report the results") # endif #endif diff --git a/boost/config/compiler/comeau.hpp b/boost/config/compiler/comeau.hpp index 0984160..ca80fac 100644 --- a/boost/config/compiler/comeau.hpp +++ b/boost/config/compiler/comeau.hpp @@ -50,7 +50,7 @@ // last known and checked version is 4245: #if (__COMO_VERSION__ > 4245) # if defined(BOOST_ASSERT_CONFIG) -# error "Unknown compiler version - please run the configure tests and report the results" +# error "boost: Unknown compiler version - please run the configure tests and report the results" # endif #endif diff --git a/boost/config/compiler/digitalmars.hpp b/boost/config/compiler/digitalmars.hpp index 3e9a3ab..1466373 100644 --- a/boost/config/compiler/digitalmars.hpp +++ b/boost/config/compiler/digitalmars.hpp @@ -135,6 +135,6 @@ // last known and checked version is ...: #if (__DMC__ > 0x848) # if defined(BOOST_ASSERT_CONFIG) -# error "Unknown compiler version - please run the configure tests and report the results" +# error "boost: Unknown compiler version - please run the configure tests and report the results" # endif #endif diff --git a/boost/config/compiler/gcc.hpp b/boost/config/compiler/gcc.hpp index 19ccc59..3380ffe 100644 --- a/boost/config/compiler/gcc.hpp +++ b/boost/config/compiler/gcc.hpp @@ -232,7 +232,6 @@ // C++0x features in 4.6.n and later // #if (BOOST_GCC_VERSION < 40600) || !defined(BOOST_GCC_CXX11) -#define BOOST_NO_CXX11_CONSTEXPR #define BOOST_NO_CXX11_DEFAULTED_MOVES #define BOOST_NO_CXX11_NOEXCEPT #define BOOST_NO_CXX11_NULLPTR @@ -243,6 +242,9 @@ // C++0x features in 4.7.n and later // #if (BOOST_GCC_VERSION < 40700) || !defined(BOOST_GCC_CXX11) +// Note that while constexpr is partly supported in gcc-4.6 it's a +// pre-std version with several bugs: +# define BOOST_NO_CXX11_CONSTEXPR # define BOOST_NO_CXX11_FINAL # define BOOST_NO_CXX11_TEMPLATE_ALIASES # define BOOST_NO_CXX11_USER_DEFINED_LITERALS @@ -307,8 +309,8 @@ # define BOOST_FALLTHROUGH __attribute__((fallthrough)) #endif -#ifdef __MINGW32__ -// Currently (June 2017) thread_local is broken on mingw for all current compiler releases, see +#if defined(__MINGW32__) && !defined(__MINGW64__) +// Currently (March 2019) thread_local is broken on mingw for all current 32bit compiler releases, see // https://sourceforge.net/p/mingw-w64/bugs/527/ // Not setting this causes program termination on thread exit. #define BOOST_NO_CXX11_THREAD_LOCAL @@ -325,7 +327,7 @@ // // __builtin_unreachable: -#if BOOST_GCC_VERSION >= 40800 +#if BOOST_GCC_VERSION >= 40500 #define BOOST_UNREACHABLE_RETURN(x) __builtin_unreachable(); #endif @@ -346,14 +348,14 @@ # error "Compiler not configured - please reconfigure" #endif // -// last known and checked version is 7.1: -#if (BOOST_GCC_VERSION > 70100) +// last known and checked version is 8.1: +#if (BOOST_GCC_VERSION > 80100) # if defined(BOOST_ASSERT_CONFIG) # error "Boost.Config is older than your compiler - please check for an updated Boost release." # else // we don't emit warnings here anymore since there are no defect macros defined for // gcc post 3.4, so any failures are gcc regressions... -//# warning "Unknown compiler version - please run the configure tests and report the results" +//# warning "boost: Unknown compiler version - please run the configure tests and report the results" # endif #endif diff --git a/boost/config/compiler/greenhills.hpp b/boost/config/compiler/greenhills.hpp index a76a07c..39112c2 100644 --- a/boost/config/compiler/greenhills.hpp +++ b/boost/config/compiler/greenhills.hpp @@ -21,7 +21,7 @@ // last known and checked version is 0: #if (__ghs > 0) # if defined(BOOST_ASSERT_CONFIG) -# error "Unknown compiler version - please run the configure tests and report the results" +# error "boost: Unknown compiler version - please run the configure tests and report the results" # endif #endif diff --git a/boost/config/compiler/hp_acc.hpp b/boost/config/compiler/hp_acc.hpp index 9df18ea..49d676f 100644 --- a/boost/config/compiler/hp_acc.hpp +++ b/boost/config/compiler/hp_acc.hpp @@ -142,6 +142,6 @@ // last known and checked version for PA-RISC is 38000 #if ((__HP_aCC > 61300) || ((__HP_aCC > 38000) && defined(__hpxstd98))) # if defined(BOOST_ASSERT_CONFIG) -# error "Unknown compiler version - please run the configure tests and report the results" +# error "boost: Unknown compiler version - please run the configure tests and report the results" # endif #endif diff --git a/boost/config/compiler/intel.hpp b/boost/config/compiler/intel.hpp index 0eea05b..f56807d 100644 --- a/boost/config/compiler/intel.hpp +++ b/boost/config/compiler/intel.hpp @@ -46,12 +46,17 @@ #undef BOOST_GCC_VERSION #undef BOOST_GCC_CXX11 #undef BOOST_GCC +#undef BOOST_FALLTHROUGH // Broken in all versions up to 17 (newer versions not tested) #if (__INTEL_COMPILER <= 1700) && !defined(BOOST_NO_CXX14_CONSTEXPR) # define BOOST_NO_CXX14_CONSTEXPR #endif +#if (__INTEL_COMPILER >= 1800) && (__cplusplus >= 201703) +# define BOOST_FALLTHROUGH [[fallthrough]] +#endif + #endif // defined(_MSC_VER) #undef BOOST_COMPILER @@ -558,7 +563,7 @@ template<> struct assert_intrinsic_wchar_t {}; // We don't emit this warning any more, since we have so few // defect macros set anyway (just the one). // -//# pragma message("Unknown compiler version - please run the configure tests and report the results") +//# pragma message("boost: Unknown compiler version - please run the configure tests and report the results") # endif #endif diff --git a/boost/config/compiler/kai.hpp b/boost/config/compiler/kai.hpp index 960d501..0b22ec1 100644 --- a/boost/config/compiler/kai.hpp +++ b/boost/config/compiler/kai.hpp @@ -25,7 +25,7 @@ // last known and checked version is 4001: #if (__KCC_VERSION > 4001) # if defined(BOOST_ASSERT_CONFIG) -# error "Unknown compiler version - please run the configure tests and report the results" +# error "boost: Unknown compiler version - please run the configure tests and report the results" # endif #endif diff --git a/boost/config/compiler/metrowerks.hpp b/boost/config/compiler/metrowerks.hpp index 4bfc01e..0e18e18 100644 --- a/boost/config/compiler/metrowerks.hpp +++ b/boost/config/compiler/metrowerks.hpp @@ -183,7 +183,7 @@ // last known and checked version: #if (__MWERKS__ > 0x3205) # if defined(BOOST_ASSERT_CONFIG) -# error "Unknown compiler version - please run the configure tests and report the results" +# error "boost: Unknown compiler version - please run the configure tests and report the results" # endif #endif diff --git a/boost/config/compiler/mpw.hpp b/boost/config/compiler/mpw.hpp index 2292ada..05c066e 100644 --- a/boost/config/compiler/mpw.hpp +++ b/boost/config/compiler/mpw.hpp @@ -130,7 +130,7 @@ // last known and checked version is 0x890: #if (MPW_CPLUS > 0x890) # if defined(BOOST_ASSERT_CONFIG) -# error "Unknown compiler version - please run the configure tests and report the results" +# error "boost: Unknown compiler version - please run the configure tests and report the results" # endif #endif diff --git a/boost/config/compiler/vacpp.hpp b/boost/config/compiler/vacpp.hpp index cabe844..8e26449 100644 --- a/boost/config/compiler/vacpp.hpp +++ b/boost/config/compiler/vacpp.hpp @@ -56,7 +56,7 @@ // last known and checked version is 1210: #if (__IBMCPP__ > 1210) # if defined(BOOST_ASSERT_CONFIG) -# error "Unknown compiler version - please run the configure tests and report the results" +# error "boost: Unknown compiler version - please run the configure tests and report the results" # endif #endif diff --git a/boost/config/compiler/visualc.hpp b/boost/config/compiler/visualc.hpp index ded7284..e2ea270 100644 --- a/boost/config/compiler/visualc.hpp +++ b/boost/config/compiler/visualc.hpp @@ -43,6 +43,9 @@ # error "Compiler not supported or configured - please reconfigure" #endif +// VS2005 (VC8) docs: __assume has been in Visual C++ for multiple releases +#define BOOST_UNREACHABLE_RETURN(x) __assume(0); + #if _MSC_FULL_VER < 180020827 # define BOOST_NO_FENV_H #endif @@ -202,6 +205,9 @@ #if (_MSC_VER < 1911) || (_MSVC_LANG < 201703) # define BOOST_NO_CXX17_STRUCTURED_BINDINGS # define BOOST_NO_CXX17_IF_CONSTEXPR +// Let the defaults handle these now: +//# define BOOST_NO_CXX17_HDR_OPTIONAL +//# define BOOST_NO_CXX17_HDR_STRING_VIEW #endif // MSVC including version 14 has not yet completely @@ -234,9 +240,11 @@ // Supported from msvc-15.5 onwards: #define BOOST_NO_CXX11_SFINAE_EXPR #endif +#if (_MSC_VER < 1915) || (_MSVC_LANG < 201402) // C++ 14: // Still gives internal compiler error for msvc-15.5: # define BOOST_NO_CXX14_CONSTEXPR +#endif // C++ 17: #if (_MSC_VER < 1912) || (_MSVC_LANG < 201703) #define BOOST_NO_CXX17_INLINE_VARIABLES @@ -284,9 +292,9 @@ # if _MSC_VER < 1400 // Note: I'm not aware of any CE compiler with version 13xx # if defined(BOOST_ASSERT_CONFIG) -# error "Unknown EVC++ compiler version - please run the configure tests and report the results" +# error "boost: Unknown EVC++ compiler version - please run the configure tests and report the results" # else -# pragma message("Unknown EVC++ compiler version - please run the configure tests and report the results") +# pragma message("boost: Unknown EVC++ compiler version - please run the configure tests and report the results") # endif # elif _MSC_VER < 1500 # define BOOST_COMPILER_VERSION evc8 @@ -302,14 +310,14 @@ # define BOOST_COMPILER_VERSION evc14 # else # if defined(BOOST_ASSERT_CONFIG) -# error "Unknown EVC++ compiler version - please run the configure tests and report the results" +# error "boost: Unknown EVC++ compiler version - please run the configure tests and report the results" # else -# pragma message("Unknown EVC++ compiler version - please run the configure tests and report the results") +# pragma message("boost: Unknown EVC++ compiler version - please run the configure tests and report the results") # endif # endif # else # if _MSC_VER < 1200 - // Note: Versions up to 7.0 aren't supported. + // Note: Versions up to 10.0 aren't supported. # define BOOST_COMPILER_VERSION 5.0 # elif _MSC_VER < 1300 # define BOOST_COMPILER_VERSION 6.0 @@ -331,6 +339,8 @@ # define BOOST_COMPILER_VERSION 14.0 # elif _MSC_VER < 1920 # define BOOST_COMPILER_VERSION 14.1 +# elif _MSC_VER < 1930 +# define BOOST_COMPILER_VERSION 14.2 # else # define BOOST_COMPILER_VERSION _MSC_VER # endif @@ -342,8 +352,8 @@ #include // -// last known and checked version is 19.12.25830.2 (VC++ 2017.3): -#if (_MSC_VER > 1912) +// last known and checked version is 19.20.27508 (VC++ 2019 RC3): +#if (_MSC_VER > 1920) # if defined(BOOST_ASSERT_CONFIG) # error "Boost.Config is older than your current compiler version." # elif !defined(BOOST_CONFIG_SUPPRESS_OUTDATED_MESSAGE) diff --git a/boost/config/detail/select_compiler_config.hpp b/boost/config/detail/select_compiler_config.hpp index ced8443..8970dff 100644 --- a/boost/config/detail/select_compiler_config.hpp +++ b/boost/config/detail/select_compiler_config.hpp @@ -39,8 +39,7 @@ // Intel # define BOOST_COMPILER_CONFIG "boost/config/compiler/intel.hpp" -#elif defined __clang__ && !defined(__CUDACC__) && !defined(__ibmxl__) -// when using clang and cuda at same time, you want to appear as gcc +#elif defined __clang__ && !defined(__ibmxl__) // Clang C++ emulates GCC, so it has to appear early. # define BOOST_COMPILER_CONFIG "boost/config/compiler/clang.hpp" diff --git a/boost/config/detail/suffix.hpp b/boost/config/detail/suffix.hpp index 22d31f6..86f6081 100644 --- a/boost/config/detail/suffix.hpp +++ b/boost/config/detail/suffix.hpp @@ -992,6 +992,23 @@ namespace std{ using ::type_info; } #ifndef BOOST_ATTRIBUTE_UNUSED # define BOOST_ATTRIBUTE_UNUSED #endif +// +// [[nodiscard]]: +// +#ifdef __has_cpp_attribute +#if __has_cpp_attribute(nodiscard) +# define BOOST_ATTRIBUTE_NODISCARD [[nodiscard]] +#endif +#if __has_cpp_attribute(no_unique_address) && !(defined(__GNUC__) && (__cplusplus < 201100)) +# define BOOST_ATTRIBUTE_NO_UNIQUE_ADDRESS [[no_unique_address]] +#endif +#endif +#ifndef BOOST_ATTRIBUTE_NODISCARD +# define BOOST_ATTRIBUTE_NODISCARD +#endif +#ifndef BOOST_ATTRIBUTE_NO_UNIQUE_ADDRESS +# define BOOST_ATTRIBUTE_NO_UNIQUE_ADDRESS +#endif #define BOOST_STATIC_CONSTEXPR static BOOST_CONSTEXPR_OR_CONST @@ -1023,6 +1040,23 @@ namespace std{ using ::type_info; } # define BOOST_NO_CXX11_FIXED_LENGTH_VARIADIC_TEMPLATE_EXPANSION_PACKS #endif +// This is a catch all case for obsolete compilers / std libs: +#if !defined(__has_include) +# define BOOST_NO_CXX17_HDR_OPTIONAL +# define BOOST_NO_CXX17_HDR_STRING_VIEW +# define BOOST_NO_CXX17_HDR_VARIANT +#else +#if !__has_include() +# define BOOST_NO_CXX17_HDR_OPTIONAL +#endif +#if !__has_include() +# define BOOST_NO_CXX17_HDR_STRING_VIEW +#endif +#if !__has_include() +# define BOOST_NO_CXX17_HDR_VARIANT +#endif +#endif + // // Finish off with checks for macros that are depricated / no longer supported, // if any of these are set then it's very likely that much of Boost will no diff --git a/boost/config/platform/cygwin.hpp b/boost/config/platform/cygwin.hpp index 6dd7e57..d0052d8 100644 --- a/boost/config/platform/cygwin.hpp +++ b/boost/config/platform/cygwin.hpp @@ -42,8 +42,11 @@ # define BOOST_HAS_STDINT_H #endif +#include +#if (CYGWIN_VERSION_API_MAJOR == 0 && CYGWIN_VERSION_API_MINOR < 231) /// Cygwin has no fenv.h #define BOOST_NO_FENV_H +#endif // Cygwin has it's own which breaks unless the correct compiler flags are used: #ifndef BOOST_NO_CXX14_HDR_SHARED_MUTEX diff --git a/boost/config/platform/vxworks.hpp b/boost/config/platform/vxworks.hpp index a91e4ab..7718acb 100644 --- a/boost/config/platform/vxworks.hpp +++ b/boost/config/platform/vxworks.hpp @@ -12,40 +12,17 @@ // like (GCC 2.96) . Do not even think of getting this to work, // a miserable failure will be guaranteed! // -// Equally, this file has been tested for RTPs (Real Time Processes) -// only, not for DKMs (Downloadable Kernel Modules). These two types -// of executables differ largely in the available functionality of -// the C-library, STL, and so on. A DKM uses a C89 library with no -// wide character support and no guarantee of ANSI C. The same Dinkum +// VxWorks supports C++ linkage in the kernel with +// DKMs (Downloadable Kernel Modules). But, until recently +// the kernel used a C89 library with no +// wide character support and no guarantee of ANSI C. +// Regardless of the C library the same Dinkum // STL library is used in both contexts. // // Similarly the Dinkum abridged STL that supports the loosely specified // embedded C++ standard has not been tested and is unlikely to work // on anything but the simplest library. // ==================================================================== -// -// Additional Configuration -// ------------------------------------------------------------------- -// -// Because of the ordering of include files and other issues the following -// additional definitions worked better outside this file. -// -// When building the log library add the following to the b2 invocation -// define=BOOST_LOG_WITHOUT_IPC -// and -// -DBOOST_LOG_WITHOUT_DEFAULT_FACTORIES -// to your compile options. -// -// When building the test library add -// -DBOOST_TEST_LIMITED_SIGNAL_DETAILS -// to your compile options -// -// When building containers library add -// -DHAVE_MORECORE=0 -// to your c compile options so dlmalloc heap library is compiled -// without brk() calls -// -// ==================================================================== // // Some important information regarding the usage of POSIX semaphores: // ------------------------------------------------------------------- @@ -112,30 +89,20 @@ // -------------------------------- #define BOOST_PLATFORM "vxWorks" -// Special behaviour for DKMs: -#ifdef _WRS_KERNEL - // DKMs do not have the -header, - // but apparently they do have an intrinsic wchar_t meanwhile! -# define BOOST_NO_CWCHAR - - // Lots of wide-functions and -headers are unavailable for DKMs as well: -# define BOOST_NO_CWCTYPE -# define BOOST_NO_SWPRINTF -# define BOOST_NO_STD_WSTRING -# define BOOST_NO_STD_WSTREAMBUF -#endif // Generally available headers: #define BOOST_HAS_UNISTD_H #define BOOST_HAS_STDINT_H #define BOOST_HAS_DIRENT_H -#define BOOST_HAS_SLIST +//#define BOOST_HAS_SLIST // vxWorks does not have installed an iconv-library by default, // so unfortunately no Unicode support from scratch is available! // Thus, instead it is suggested to switch to ICU, as this seems // to be the most complete and portable option... -#define BOOST_LOCALE_WITH_ICU +#ifndef BOOST_LOCALE_WITH_ICU + #define BOOST_LOCALE_WITH_ICU +#endif // Generally available functionality: #define BOOST_HAS_THREADS @@ -170,16 +137,18 @@ # ifndef _POSIX_THREADS # define _POSIX_THREADS 1 # endif +// no sysconf( _SC_PAGESIZE) in kernel +# define BOOST_THREAD_USES_GETPAGESIZE #endif #if (_WRS_VXWORKS_MAJOR < 7) // vxWorks-around: #defines CLOCKS_PER_SEC as sysClkRateGet() but // miserably fails to #include the required to make // sysClkRateGet() available! So we manually include it here. -#ifdef __RTP__ -# include -# include -#endif +# ifdef __RTP__ +# include +# include +# endif // vxWorks-around: In the macros INT32_C(), UINT32_C(), INT64_C() and // UINT64_C() are defined erroneously, yielding not a signed/ @@ -188,30 +157,47 @@ // when trying to define several constants which do not fit into a // long type! We correct them here by redefining. -#include +# include + +// Special behaviour for DKMs: // Some macro-magic to do the job -#define VX_JOIN(X, Y) VX_DO_JOIN(X, Y) -#define VX_DO_JOIN(X, Y) VX_DO_JOIN2(X, Y) -#define VX_DO_JOIN2(X, Y) X##Y +# define VX_JOIN(X, Y) VX_DO_JOIN(X, Y) +# define VX_DO_JOIN(X, Y) VX_DO_JOIN2(X, Y) +# define VX_DO_JOIN2(X, Y) X##Y // Correctly setup the macros -#undef INT32_C -#undef UINT32_C -#undef INT64_C -#undef UINT64_C -#define INT32_C(x) VX_JOIN(x, L) -#define UINT32_C(x) VX_JOIN(x, UL) -#define INT64_C(x) VX_JOIN(x, LL) -#define UINT64_C(x) VX_JOIN(x, ULL) +# undef INT32_C +# undef UINT32_C +# undef INT64_C +# undef UINT64_C +# define INT32_C(x) VX_JOIN(x, L) +# define UINT32_C(x) VX_JOIN(x, UL) +# define INT64_C(x) VX_JOIN(x, LL) +# define UINT64_C(x) VX_JOIN(x, ULL) // #include Libraries required for the following function adaption -#include +# include #endif // _WRS_VXWORKS_MAJOR < 7 #include #include +#if defined(_WRS_KERNEL) && (_CPPLIB_VER < 700) + // recent kernels use Dinkum clib v7.00+ + // with widechar but older kernels + // do not have the -header, + // but apparently they do have an intrinsic wchar_t meanwhile! +# define BOOST_NO_CWCHAR + + // Lots of wide-functions and -headers are unavailable for DKMs as well: +# define BOOST_NO_CWCTYPE +# define BOOST_NO_SWPRINTF +# define BOOST_NO_STD_WSTRING +# define BOOST_NO_STD_WSTREAMBUF +#endif + + // Use C-linkage for the following helper functions #ifdef __cplusplus extern "C" { @@ -253,9 +239,9 @@ inline int truncate(const char *p, off_t l){ } #ifdef __GNUC__ -#define ___unused __attribute__((unused)) +# define ___unused __attribute__((unused)) #else -#define ___unused +# define ___unused #endif // Fake symlink handling by dummy functions: @@ -291,7 +277,7 @@ inline int gettimeofday(struct timeval *tv, void * /*tzv*/) { * to avoid conflict with MPL operator times */ #if (_WRS_VXWORKS_MAJOR < 7) -#ifdef __cplusplus +# ifdef __cplusplus // vxWorks provides neither struct tms nor function times()! // We implement an empty dummy-function, simply setting the user @@ -327,7 +313,7 @@ struct tms{ namespace std { using ::times; } -#endif // __cplusplus +# endif // __cplusplus #endif // _WRS_VXWORKS_MAJOR < 7 @@ -336,16 +322,16 @@ extern "C" void bzero (void *, size_t); // FD_ZERO uses bzero() but does // Put the selfmade functions into the std-namespace, just in case namespace std { -# ifdef __RTP__ +# ifdef __RTP__ using ::getrlimit; using ::setrlimit; -# endif +# endif using ::truncate; using ::symlink; using ::readlink; -#if (_WRS_VXWORKS_MAJOR < 7) +# if (_WRS_VXWORKS_MAJOR < 7) using ::gettimeofday; -#endif +# endif } #endif // __cplusplus @@ -355,10 +341,12 @@ namespace std { // Include signal.h which might contain a typo to be corrected here #include + #if (_WRS_VXWORKS_MAJOR < 7) -#define getpagesize() sysconf(_SC_PAGESIZE) // getpagesize is deprecated anyway! +# define getpagesize() sysconf(_SC_PAGESIZE) // getpagesize is deprecated anyway! inline int lstat(p, b) { return stat(p, b); } // lstat() == stat(), as vxWorks has no symlinks! #endif + #ifndef S_ISSOCK # define S_ISSOCK(mode) ((mode & S_IFMT) == S_IFSOCK) // Is file a socket? #endif @@ -379,7 +367,7 @@ typedef int locale_t; // locale_t is a POSIX-ex // vxWorks 7 adds C++11 support // however it is optional, and does not match exactly the support determined // by examining the Dinkum STL version and GCC version (or ICC and DCC) -#ifndef _WRS_CONFIG_LANG_LIB_CPLUS_CPLUS_USER_2011 +#if !( defined( _WRS_CONFIG_LANG_LIB_CPLUS_CPLUS_USER_2011) || defined(_WRS_CONFIG_LIBCPLUS_STD)) # define BOOST_NO_CXX11_ADDRESSOF // C11 addressof operator on memory location # define BOOST_NO_CXX11_ALLOCATOR # define BOOST_NO_CXX11_ATOMIC_SMART_PTR @@ -408,9 +396,9 @@ typedef int locale_t; // locale_t is a POSIX-ex # define BOOST_NO_CXX11_HDR_UNORDERED_MAP # define BOOST_NO_CXX11_HDR_UNORDERED_SET #else -#ifndef BOOST_SYSTEM_NO_DEPRECATED -# define BOOST_SYSTEM_NO_DEPRECATED // workaround link error in spirit -#endif +# ifndef BOOST_SYSTEM_NO_DEPRECATED +# define BOOST_SYSTEM_NO_DEPRECATED // workaround link error in spirit +# endif #endif @@ -418,6 +406,8 @@ typedef int locale_t; // locale_t is a POSIX-ex #undef NONE // restrict is an iostreams class #undef restrict +// affects some typeof tests +#undef V7 // use fake poll() from Unix layer in ASIO to get full functionality // most libraries will use select() but this define allows 'iostream' functionality @@ -430,4 +420,3 @@ typedef int locale_t; // locale_t is a POSIX-ex # define BOOST_ASIO_DISABLE_SERIAL_PORT #endif - diff --git a/boost/config/stdlib/dinkumware.hpp b/boost/config/stdlib/dinkumware.hpp index e829f08..19c772c 100644 --- a/boost/config/stdlib/dinkumware.hpp +++ b/boost/config/stdlib/dinkumware.hpp @@ -174,6 +174,9 @@ #if !defined(_CPPLIB_VER) || (_CPPLIB_VER < 650) || !defined(BOOST_MSVC) || (BOOST_MSVC < 1910) || !defined(_HAS_CXX17) || (_HAS_CXX17 == 0) # define BOOST_NO_CXX17_STD_APPLY # define BOOST_NO_CXX17_ITERATOR_TRAITS +# define BOOST_NO_CXX17_HDR_STRING_VIEW +# define BOOST_NO_CXX17_HDR_OPTIONAL +# define BOOST_NO_CXX17_HDR_VARIANT #endif #if !defined(_CPPLIB_VER) || (_CPPLIB_VER < 650) || !defined(_HAS_CXX17) || (_HAS_CXX17 == 0) || !defined(_MSVC_STL_UPDATE) || (_MSVC_STL_UPDATE < 201709) # define BOOST_NO_CXX17_STD_INVOKE diff --git a/boost/config/stdlib/libcpp.hpp b/boost/config/stdlib/libcpp.hpp index a051dbb..e5e5c34 100644 --- a/boost/config/stdlib/libcpp.hpp +++ b/boost/config/stdlib/libcpp.hpp @@ -89,6 +89,9 @@ // C++17 features #if (_LIBCPP_VERSION < 4000) || (__cplusplus <= 201402L) # define BOOST_NO_CXX17_STD_APPLY +# define BOOST_NO_CXX17_HDR_OPTIONAL +# define BOOST_NO_CXX17_HDR_STRING_VIEW +# define BOOST_NO_CXX17_HDR_VARIANT #endif #if (_LIBCPP_VERSION > 4000) && (__cplusplus > 201402L) && !defined(_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR) # define BOOST_NO_AUTO_PTR @@ -111,10 +114,16 @@ # define BOOST_NO_CXX11_THREAD_LOCAL #endif -#if defined(__linux__) && !defined(BOOST_NO_CXX11_THREAD_LOCAL) +#if defined(__linux__) && (_LIBCPP_VERSION < 6000) && !defined(BOOST_NO_CXX11_THREAD_LOCAL) // After libc++-dev is installed on Trusty, clang++-libc++ almost works, // except uses of `thread_local` fail with undefined reference to // `__cxa_thread_atexit`. +// +// clang's libc++abi provides an implementation by deferring to the glibc +// implementation, which may or may not be available (it is not on Trusty). +// clang 4's libc++abi will provide an implementation if one is not in glibc +// though, so thread local support should work with clang 4 and above as long +// as libc++abi is linked in. # define BOOST_NO_CXX11_THREAD_LOCAL #endif @@ -128,4 +137,8 @@ # define BOOST_NO_CXX14_HDR_SHARED_MUTEX #endif +#if !defined(BOOST_NO_CXX14_HDR_SHARED_MUTEX) && (_LIBCPP_VERSION < 5000) +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif + // --- end --- diff --git a/boost/config/stdlib/libstdcpp3.hpp b/boost/config/stdlib/libstdcpp3.hpp index f6eab26..9696515 100644 --- a/boost/config/stdlib/libstdcpp3.hpp +++ b/boost/config/stdlib/libstdcpp3.hpp @@ -299,6 +299,9 @@ extern "C" char *gets (char *__s); #if (BOOST_LIBSTDCXX_VERSION < 70100) || (__cplusplus <= 201402L) # define BOOST_NO_CXX17_STD_INVOKE # define BOOST_NO_CXX17_STD_APPLY +# define BOOST_NO_CXX17_HDR_OPTIONAL +# define BOOST_NO_CXX17_HDR_STRING_VIEW +# define BOOST_NO_CXX17_HDR_VARIANT #endif #if defined(__has_include) diff --git a/boost/container/allocator_traits.hpp b/boost/container/allocator_traits.hpp index af32f18..72d90d1 100644 --- a/boost/container/allocator_traits.hpp +++ b/boost/container/allocator_traits.hpp @@ -77,7 +77,7 @@ namespace container { #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED -template +template class small_vector_allocator; namespace allocator_traits_detail { @@ -99,8 +99,8 @@ template struct is_std_allocator< std::allocator > { static const bool value = true; }; -template -struct is_std_allocator< small_vector_allocator< std::allocator > > +template +struct is_std_allocator< small_vector_allocator, Options > > { static const bool value = true; }; template @@ -151,7 +151,7 @@ struct allocator_traits //! Allocator::void_pointer if such a type exists ; otherwise, pointer_traits::rebind. //! typedef see_documentation void_pointer; - //! Allocator::const_void_pointer if such a type exists ; otherwis e, pointer_traits::rebind::rebind::difference_type. @@ -469,6 +469,22 @@ struct allocator_traits #endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) }; +#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + +template +struct real_allocator +{ + typedef AllocatorOrVoid type; +}; + +template +struct real_allocator +{ + typedef new_allocator type; +}; + +#endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + } //namespace container { } //namespace boost { diff --git a/boost/container/container_fwd.hpp b/boost/container/container_fwd.hpp index e4fe6f8..2cfb20a 100644 --- a/boost/container/container_fwd.hpp +++ b/boost/container/container_fwd.hpp @@ -24,6 +24,7 @@ //! - boost::container::vector //! - boost::container::stable_vector //! - boost::container::static_vector +//! - boost::container::small_vector_base //! - boost::container::small_vector //! - boost::container::slist //! - boost::container::list @@ -90,101 +91,105 @@ namespace container { #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED +template +struct pair; + template class new_allocator; template - ,class Options = void> + ,class Allocator = void + ,class Options = void> class vector; template > + ,class Allocator = void > class stable_vector; -template +template < class T + , std::size_t Capacity + , class Options = void> class static_vector; -template < class T, std::size_t N - , class Allocator= new_allocator > +template < class T + , class Allocator = void + , class Options = void > +class small_vector_base; + +template < class T + , std::size_t N + , class Allocator = void + , class Options = void > class small_vector; template > + ,class Allocator = void + ,class Options = void> class deque; template > + ,class Allocator = void > class list; template > + ,class Allocator = void > class slist; template - ,class Allocator = new_allocator + ,class Allocator = void ,class Options = void> class set; template - ,class Allocator = new_allocator + ,class Allocator = void ,class Options = void > class multiset; template - ,class Allocator = new_allocator > + ,class Allocator = void ,class Options = void > class map; template - ,class Allocator = new_allocator > + ,class Allocator = void ,class Options = void > class multimap; template - ,class Allocator = new_allocator > + ,class Allocator = void > class flat_set; template - ,class Allocator = new_allocator > + ,class Allocator = void > class flat_multiset; template - ,class Allocator = new_allocator > > + ,class Allocator = void > class flat_map; template - ,class Allocator = new_allocator > > + ,class Allocator = void > class flat_multimap; template - ,class Allocator = new_allocator > + ,class Allocator = void > class basic_string; -typedef basic_string - - ,new_allocator > -string; - -typedef basic_string - - ,new_allocator > -wstring; +typedef basic_string string; +typedef basic_string wstring; static const std::size_t ADP_nodes_per_block = 256u; static const std::size_t ADP_max_free_blocks = 2u; diff --git a/boost/container/detail/advanced_insert_int.hpp b/boost/container/detail/advanced_insert_int.hpp index fc8a33a..28e7ae9 100644 --- a/boost/container/detail/advanced_insert_int.hpp +++ b/boost/container/detail/advanced_insert_int.hpp @@ -128,11 +128,11 @@ struct insert_value_initialized_n_proxy void copy_n_and_update(Allocator &a, Iterator p, size_type n) const { for (; 0 < n; --n, ++p){ - typename aligned_storage::value>::type stor; - value_type &v = *static_cast(static_cast(stor.data)); - alloc_traits::construct(a, &v); - value_destructor on_exit(a, v); (void)on_exit; - *p = ::boost::move(v); + typename dtl::aligned_storage::value>::type v; + value_type *vp = reinterpret_cast(v.data); + alloc_traits::construct(a, vp); + value_destructor on_exit(a, *vp); (void)on_exit; + *p = ::boost::move(*vp); } } }; @@ -151,11 +151,11 @@ struct insert_default_initialized_n_proxy { if(!is_pod::value){ for (; 0 < n; --n, ++p){ - typename aligned_storage::value>::type stor; - value_type &v = *static_cast(static_cast(stor.data)); - alloc_traits::construct(a, &v, default_init); - value_destructor on_exit(a, v); (void)on_exit; - *p = ::boost::move(v); + typename dtl::aligned_storage::value>::type v; + value_type *vp = reinterpret_cast(v.data); + alloc_traits::construct(a, vp, default_init); + value_destructor on_exit(a, *vp); (void)on_exit; + *p = ::boost::move(*vp); } } } @@ -195,17 +195,17 @@ struct insert_move_proxy typedef typename alloc_traits::size_type size_type; typedef typename alloc_traits::value_type value_type; - explicit insert_move_proxy(value_type &v) + BOOST_CONTAINER_FORCEINLINE explicit insert_move_proxy(value_type &v) : v_(v) {} - void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const + BOOST_CONTAINER_FORCEINLINE void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const { BOOST_ASSERT(n == 1); (void)n; alloc_traits::construct( a, boost::movelib::iterator_to_raw_pointer(p), ::boost::move(v_) ); } - void copy_n_and_update(Allocator &, Iterator p, size_type n) const + BOOST_CONTAINER_FORCEINLINE void copy_n_and_update(Allocator &, Iterator p, size_type n) const { BOOST_ASSERT(n == 1); (void)n; *p = ::boost::move(v_); @@ -288,8 +288,8 @@ struct insert_emplace_proxy void priv_copy_some_and_update(Allocator &a, const index_tuple&, Iterator p, size_type n) { BOOST_ASSERT(n ==1); (void)n; - typename aligned_storage::value>::type v; - value_type *vp = static_cast(static_cast(v.data)); + typename dtl::aligned_storage::value>::type v; + value_type *vp = reinterpret_cast(v.data); alloc_traits::construct(a, vp, ::boost::forward(get(this->args_))...); BOOST_TRY{ @@ -398,9 +398,9 @@ struct insert_emplace_proxy_arg##N\ void copy_n_and_update(Allocator &a, Iterator p, size_type n)\ {\ BOOST_ASSERT(n == 1); (void)n;\ - typename aligned_storage::value>::type v;\ + typename dtl::aligned_storage::value>::type v;\ BOOST_ASSERT((((size_type)(&v)) % alignment_of::value) == 0);\ - value_type *vp = static_cast(static_cast(v.data));\ + value_type *vp = reinterpret_cast(v.data);\ alloc_traits::construct(a, vp BOOST_MOVE_I##N BOOST_MOVE_MFWD##N);\ BOOST_TRY{\ *p = ::boost::move(*vp);\ diff --git a/boost/container/detail/allocator_version_traits.hpp b/boost/container/detail/allocator_version_traits.hpp index 18460bd..d037e0e 100644 --- a/boost/container/detail/allocator_version_traits.hpp +++ b/boost/container/detail/allocator_version_traits.hpp @@ -93,7 +93,8 @@ struct allocator_version_traits { size_type n = holder.size(); typename multiallocation_chain::iterator it = holder.begin(); - while(n--){ + while(n){ + --n; pointer p = boost::intrusive::pointer_traits::pointer_to(*it); ++it; a.deallocate(p, 1); diff --git a/boost/container/detail/compare_functors.hpp b/boost/container/detail/compare_functors.hpp index 28f9093..21f222b 100644 --- a/boost/container/detail/compare_functors.hpp +++ b/boost/container/detail/compare_functors.hpp @@ -19,13 +19,15 @@ # pragma once #endif +#include + namespace boost { namespace container { -template +template class equal_to_value { - typedef typename Allocator::value_type value_type; + typedef ValueType value_type; const value_type &t_; public: @@ -37,7 +39,7 @@ class equal_to_value { return t_ == t; } }; -template +template struct value_to_node_compare : Pred { @@ -52,22 +54,76 @@ struct value_to_node_compare : Pred(pred) {} - bool operator()(const Node &a, const Node &b) const + Ret operator()(const Node &a, const Node &b) const { return static_cast(*this)(a.get_data(), b.get_data()); } - bool operator()(const Node &a) const + Ret operator()(const Node &a) const { return static_cast(*this)(a.get_data()); } - bool operator()(const Node &a, const Node &b) + Ret operator()(const Node &a, const Node &b) { return static_cast(*this)(a.get_data(), b.get_data()); } - bool operator()(const Node &a) + Ret operator()(const Node &a) { return static_cast(*this)(a.get_data()); } predicate_type & predicate() { return static_cast(*this); } const predicate_type & predicate() const { return static_cast(*this); } }; +template +struct key_node_pred + : public boost::intrusive::detail::ebo_functor_holder +{ + BOOST_CONTAINER_FORCEINLINE explicit key_node_pred(const KeyPred &comp) + : base_t(comp) + {} + + typedef boost::intrusive::detail::ebo_functor_holder base_t; + typedef KeyPred key_predicate; + typedef KeyOfValue key_of_value; + typedef typename KeyOfValue::type key_type; + + + BOOST_CONTAINER_FORCEINLINE static const key_type &key_from(const Node &n) + { + return key_of_value()(n.get_data()); + } + + template + BOOST_CONTAINER_FORCEINLINE static const T & + key_from(const T &t) + { return t; } + + BOOST_CONTAINER_FORCEINLINE const key_predicate &key_pred() const + { return static_cast(*this); } + + BOOST_CONTAINER_FORCEINLINE key_predicate &key_pred() + { return static_cast(*this); } + + BOOST_CONTAINER_FORCEINLINE Ret operator()(const key_type &key) const + { return this->key_pred()(key); } + + template + BOOST_CONTAINER_FORCEINLINE Ret operator()(const U &nonkey) const + { return this->key_pred()(this->key_from(nonkey)); } + + BOOST_CONTAINER_FORCEINLINE bool operator()(const key_type &key1, const key_type &key2) const + { return this->key_pred()(key1, key2); } + + template + BOOST_CONTAINER_FORCEINLINE bool operator()(const key_type &key1, const U &nonkey2) const + { return this->key_pred()(key1, this->key_from(nonkey2)); } + + template + BOOST_CONTAINER_FORCEINLINE bool operator()(const U &nonkey1, const key_type &key2) const + { return this->key_pred()(this->key_from(nonkey1), key2); } + + template + BOOST_CONTAINER_FORCEINLINE bool operator()(const U &nonkey1, const V &nonkey2) const + { return this->key_pred()(this->key_from(nonkey1), this->key_from(nonkey2)); } +}; + + } //namespace container { } //namespace boost { diff --git a/boost/container/detail/container_or_allocator_rebind.hpp b/boost/container/detail/container_or_allocator_rebind.hpp index d74df6c..1525e41 100644 --- a/boost/container/detail/container_or_allocator_rebind.hpp +++ b/boost/container/detail/container_or_allocator_rebind.hpp @@ -34,7 +34,11 @@ struct container_or_allocator_rebind_impl template struct container_or_allocator_rebind_impl : allocator_traits::template portable_rebind_alloc +{}; +template +struct container_or_allocator_rebind_impl + : real_allocator {}; template diff --git a/boost/container/detail/container_rebind.hpp b/boost/container/detail/container_rebind.hpp index 0ebb478..0af9b9e 100644 --- a/boost/container/detail/container_rebind.hpp +++ b/boost/container/detail/container_rebind.hpp @@ -19,6 +19,7 @@ #endif #include +#include namespace boost { @@ -33,14 +34,14 @@ namespace dtl { template