?????????? ????????? - ??????????????? - /home/agenciai/public_html/cd38d8/asio.tar
???????
placeholders.hpp 0000644 00000010062 15125530236 0007723 0 ustar 00 // // placeholders.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_BOOST_BIND) # include <boost/bind/arg.hpp> #endif // defined(BOOST_ASIO_HAS_BOOST_BIND) #include <boost/asio/detail/push_options.hpp> 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 <int Number> struct placeholder { static boost::arg<Number>& get() { static boost::arg<Number> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_PLACEHOLDERS_HPP associated_executor.hpp 0000644 00000011701 15125530236 0011314 0 ustar 00 // // associated_executor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/is_executor.hpp> #include <boost/asio/system_executor.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename T, typename E, typename = void> struct associated_executor_impl { typedef void asio_associated_executor_is_unspecialised; typedef E type; static type get(const T&, const E& e = E()) BOOST_ASIO_NOEXCEPT { return e; } }; template <typename T, typename E> struct associated_executor_impl<T, E, typename void_type<typename T::executor_type>::type> { typedef typename T::executor_type type; static type get(const T& t, const E& = 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 <typename T, typename Executor = system_executor> struct associated_executor #if !defined(GENERATING_DOCUMENTATION) : detail::associated_executor_impl<T, Executor> #endif // !defined(GENERATING_DOCUMENTATION) { #if defined(GENERATING_DOCUMENTATION) /// If @c T has a nested type @c executor_type, <tt>T::executor_type</tt>. /// Otherwise @c Executor. typedef see_below type; /// If @c T has a nested type @c executor_type, returns /// <tt>t.get_executor()</tt>. Otherwise returns @c ex. static type get(const T& t, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT; #endif // defined(GENERATING_DOCUMENTATION) }; /// Helper function to obtain an object's associated executor. /** * @returns <tt>associated_executor<T>::get(t)</tt> */ template <typename T> inline typename associated_executor<T>::type get_associated_executor(const T& t) BOOST_ASIO_NOEXCEPT { return associated_executor<T>::get(t); } /// Helper function to obtain an object's associated executor. /** * @returns <tt>associated_executor<T, Executor>::get(t, ex)</tt> */ template <typename T, typename Executor> inline typename associated_executor<T, Executor>::type get_associated_executor(const T& t, const Executor& ex, typename enable_if< is_executor<Executor>::value || execution::is_executor<Executor>::value >::type* = 0) BOOST_ASIO_NOEXCEPT { return associated_executor<T, Executor>::get(t, ex); } /// Helper function to obtain an object's associated executor. /** * @returns <tt>associated_executor<T, typename * ExecutionContext::executor_type>::get(t, ctx.get_executor())</tt> */ template <typename T, typename ExecutionContext> inline typename associated_executor<T, typename ExecutionContext::executor_type>::type get_associated_executor(const T& t, ExecutionContext& ctx, typename enable_if<is_convertible<ExecutionContext&, execution_context&>::value>::type* = 0) BOOST_ASIO_NOEXCEPT { return associated_executor<T, typename ExecutionContext::executor_type>::get(t, ctx.get_executor()); } #if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) template <typename T, typename Executor = system_executor> using associated_executor_t = typename associated_executor<T, Executor>::type; #endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) namespace detail { template <typename T, typename E, typename = void> struct associated_executor_forwarding_base { }; template <typename T, typename E> struct associated_executor_forwarding_base<T, E, typename enable_if< is_same< typename associated_executor<T, E>::asio_associated_executor_is_unspecialised, void >::value >::type> { typedef void asio_associated_executor_is_unspecialised; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_ASSOCIATED_EXECUTOR_HPP local/connect_pair.hpp 0000644 00000006504 15125530236 0011022 0 ustar 00 // // local/connect_pair.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/basic_socket.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/local/basic_endpoint.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace local { /// Create a pair of connected sockets. template <typename Protocol, typename Executor1, typename Executor2> void connect_pair(basic_socket<Protocol, Executor1>& socket1, basic_socket<Protocol, Executor2>& socket2); /// Create a pair of connected sockets. template <typename Protocol, typename Executor1, typename Executor2> BOOST_ASIO_SYNC_OP_VOID connect_pair(basic_socket<Protocol, Executor1>& socket1, basic_socket<Protocol, Executor2>& socket2, boost::system::error_code& ec); template <typename Protocol, typename Executor1, typename Executor2> inline void connect_pair(basic_socket<Protocol, Executor1>& socket1, basic_socket<Protocol, Executor2>& socket2) { boost::system::error_code ec; connect_pair(socket1, socket2, ec); boost::asio::detail::throw_error(ec, "connect_pair"); } template <typename Protocol, typename Executor1, typename Executor2> inline BOOST_ASIO_SYNC_OP_VOID connect_pair( basic_socket<Protocol, Executor1>& socket1, basic_socket<Protocol, Executor2>& socket2, boost::system::error_code& ec) { // Check that this function is only being used with a UNIX domain socket. boost::asio::local::basic_endpoint<Protocol>* tmp = static_cast<typename Protocol::endpoint*>(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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_LOCAL_CONNECT_PAIR_HPP local/basic_endpoint.hpp 0000644 00000013505 15125530236 0011336 0 ustar 00 // // local/basic_endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/local/detail/endpoint.hpp> #if !defined(BOOST_ASIO_NO_IOSTREAM) # include <iosfwd> #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #include <boost/asio/detail/push_options.hpp> 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 <typename Protocol> 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() BOOST_ASIO_NOEXCEPT { } /// 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<Protocol>& e1, const basic_endpoint<Protocol>& e2) { return e1.impl_ == e2.impl_; } /// Compare two endpoints for inequality. friend bool operator!=(const basic_endpoint<Protocol>& e1, const basic_endpoint<Protocol>& e2) { return !(e1.impl_ == e2.impl_); } /// Compare endpoints for ordering. friend bool operator<(const basic_endpoint<Protocol>& e1, const basic_endpoint<Protocol>& e2) { return e1.impl_ < e2.impl_; } /// Compare endpoints for ordering. friend bool operator>(const basic_endpoint<Protocol>& e1, const basic_endpoint<Protocol>& e2) { return e2.impl_ < e1.impl_; } /// Compare endpoints for ordering. friend bool operator<=(const basic_endpoint<Protocol>& e1, const basic_endpoint<Protocol>& e2) { return !(e2 < e1); } /// Compare endpoints for ordering. friend bool operator>=(const basic_endpoint<Protocol>& e1, const basic_endpoint<Protocol>& 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 <typename Elem, typename Traits, typename Protocol> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, const basic_endpoint<Protocol>& endpoint) { os << endpoint.path(); return os; } } // namespace local } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_LOCAL_BASIC_ENDPOINT_HPP local/detail/impl/endpoint.ipp 0000644 00000006653 15125530236 0012407 0 ustar 00 // // local/detail/impl/endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) #include <cstring> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/local/detail/endpoint.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) #endif // BOOST_ASIO_LOCAL_DETAIL_IMPL_ENDPOINT_IPP local/detail/endpoint.hpp 0000644 00000007341 15125530236 0011440 0 ustar 00 // // local/detail/endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) #include <cstddef> #include <string> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/string_view.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/local/detail/impl/endpoint.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) #endif // BOOST_ASIO_LOCAL_DETAIL_ENDPOINT_HPP local/stream_protocol.hpp 0000644 00000004533 15125530236 0011572 0 ustar 00 // // local/stream_protocol.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/basic_socket_acceptor.hpp> #include <boost/asio/basic_socket_iostream.hpp> #include <boost/asio/basic_stream_socket.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/local/basic_endpoint.hpp> #include <boost/asio/detail/push_options.hpp> 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 BOOST_ASIO_NOEXCEPT { return SOCK_STREAM; } /// Obtain an identifier for the protocol. int protocol() const BOOST_ASIO_NOEXCEPT { return 0; } /// Obtain an identifier for the protocol family. int family() const BOOST_ASIO_NOEXCEPT { return AF_UNIX; } /// The type of a UNIX domain endpoint. typedef basic_endpoint<stream_protocol> endpoint; /// The UNIX domain socket type. typedef basic_stream_socket<stream_protocol> socket; /// The UNIX domain acceptor type. typedef basic_socket_acceptor<stream_protocol> acceptor; #if !defined(BOOST_ASIO_NO_IOSTREAM) /// The UNIX domain iostream type. typedef basic_socket_iostream<stream_protocol> iostream; #endif // !defined(BOOST_ASIO_NO_IOSTREAM) }; } // namespace local } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_LOCAL_STREAM_PROTOCOL_HPP local/datagram_protocol.hpp 0000644 00000004002 15125530236 0012046 0 ustar 00 // // local/datagram_protocol.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/basic_datagram_socket.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/local/basic_endpoint.hpp> #include <boost/asio/detail/push_options.hpp> 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 BOOST_ASIO_NOEXCEPT { return SOCK_DGRAM; } /// Obtain an identifier for the protocol. int protocol() const BOOST_ASIO_NOEXCEPT { return 0; } /// Obtain an identifier for the protocol family. int family() const BOOST_ASIO_NOEXCEPT { return AF_UNIX; } /// The type of a UNIX domain endpoint. typedef basic_endpoint<datagram_protocol> endpoint; /// The UNIX domain socket type. typedef basic_datagram_socket<datagram_protocol> socket; }; } // namespace local } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_LOCAL_SOCKETS) // || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_LOCAL_DATAGRAM_PROTOCOL_HPP packaged_task.hpp 0000644 00000006436 15125530236 0010051 0 ustar 00 // // packaged_task.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/future.hpp> #if defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/async_result.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/variadic_templates.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Result, typename... Args, typename Signature> class async_result<std::packaged_task<Result(Args...)>, Signature> { public: /// The packaged task is the concrete completion handler type. typedef std::packaged_task<Result(Args...)> completion_handler_type; /// The return type of the initiating function is the future obtained from /// the packaged task. typedef std::future<Result> 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 <typename Result, typename Signature> struct async_result<std::packaged_task<Result()>, Signature> { typedef std::packaged_task<Result()> completion_handler_type; typedef std::future<Result> 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 <typename Result, \ BOOST_ASIO_VARIADIC_TPARAMS(n), typename Signature> \ class async_result< \ std::packaged_task<Result(BOOST_ASIO_VARIADIC_TARGS(n))>, Signature> \ { \ public: \ typedef std::packaged_task< \ Result(BOOST_ASIO_VARIADIC_TARGS(n))> \ completion_handler_type; \ \ typedef std::future<Result> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS) // || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_PACKAGED_TASK_HPP buffer.hpp 0000644 00000242466 15125530236 0006546 0 ustar 00 // // buffer.hpp // ~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <cstring> #include <limits> #include <stdexcept> #include <string> #include <vector> #include <boost/asio/detail/array_fwd.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/string_view.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/detail/type_traits.hpp> #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 <boost/asio/detail/functional.hpp> #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING #if defined(BOOST_ASIO_HAS_BOOST_WORKAROUND) # include <boost/detail/workaround.hpp> # if !defined(__clang__) # if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) # define BOOST_ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND # endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) # elif BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) # define BOOST_ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND # endif // BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) #endif // defined(BOOST_ASIO_HAS_BOOST_WORKAROUND) #if defined(BOOST_ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) # include <boost/asio/detail/type_traits.hpp> #endif // defined(BOOST_ASIO_ENABLE_ARRAY_BUFFER_WORKAROUND) #include <boost/asio/detail/push_options.hpp> 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<unsigned char*>(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<void()> debug_check) : data_(data), size_(size), debug_check_(debug_check) { } const boost::asio::detail::function<void()>& 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<char*>(data_) + offset; size_ -= offset; return *this; } private: void* data_; std::size_t size_; #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) boost::asio::detail::function<void()> 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<void()> 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<const unsigned char*>(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<void()> debug_check) : data_(data), size_(size), debug_check_(debug_check) { } const boost::asio::detail::function<void()>& 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<const char*>(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<void()> 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<void()> 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 <typename MutableBuffer> inline const mutable_buffer* buffer_sequence_begin(const MutableBuffer& b, typename enable_if< is_convertible<const MutableBuffer*, const mutable_buffer*>::value >::type* = 0) BOOST_ASIO_NOEXCEPT { return static_cast<const mutable_buffer*>(detail::addressof(b)); } /// Get an iterator to the first element in a buffer sequence. template <typename ConstBuffer> inline const const_buffer* buffer_sequence_begin(const ConstBuffer& b, typename enable_if< is_convertible<const ConstBuffer*, const const_buffer*>::value >::type* = 0) BOOST_ASIO_NOEXCEPT { return static_cast<const const_buffer*>(detail::addressof(b)); } #if defined(BOOST_ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) /// Get an iterator to the first element in a buffer sequence. template <typename C> inline auto buffer_sequence_begin(C& c, typename enable_if< !is_convertible<const C*, const mutable_buffer*>::value && !is_convertible<const C*, const const_buffer*>::value >::type* = 0) BOOST_ASIO_NOEXCEPT -> decltype(c.begin()) { return c.begin(); } /// Get an iterator to the first element in a buffer sequence. template <typename C> inline auto buffer_sequence_begin(const C& c, typename enable_if< !is_convertible<const C*, const mutable_buffer*>::value && !is_convertible<const C*, const const_buffer*>::value >::type* = 0) BOOST_ASIO_NOEXCEPT -> decltype(c.begin()) { return c.begin(); } #else // defined(BOOST_ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) template <typename C> inline typename C::iterator buffer_sequence_begin(C& c, typename enable_if< !is_convertible<const C*, const mutable_buffer*>::value && !is_convertible<const C*, const const_buffer*>::value >::type* = 0) BOOST_ASIO_NOEXCEPT { return c.begin(); } template <typename C> inline typename C::const_iterator buffer_sequence_begin(const C& c, typename enable_if< !is_convertible<const C*, const mutable_buffer*>::value && !is_convertible<const C*, const const_buffer*>::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 <typename MutableBuffer> inline const mutable_buffer* buffer_sequence_end(const MutableBuffer& b, typename enable_if< is_convertible<const MutableBuffer*, const mutable_buffer*>::value >::type* = 0) BOOST_ASIO_NOEXCEPT { return static_cast<const mutable_buffer*>(detail::addressof(b)) + 1; } /// Get an iterator to one past the end element in a buffer sequence. template <typename ConstBuffer> inline const const_buffer* buffer_sequence_end(const ConstBuffer& b, typename enable_if< is_convertible<const ConstBuffer*, const const_buffer*>::value >::type* = 0) BOOST_ASIO_NOEXCEPT { return static_cast<const const_buffer*>(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 <typename C> inline auto buffer_sequence_end(C& c, typename enable_if< !is_convertible<const C*, const mutable_buffer*>::value && !is_convertible<const C*, const const_buffer*>::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 <typename C> inline auto buffer_sequence_end(const C& c, typename enable_if< !is_convertible<const C*, const mutable_buffer*>::value && !is_convertible<const C*, const const_buffer*>::value >::type* = 0) BOOST_ASIO_NOEXCEPT -> decltype(c.end()) { return c.end(); } #else // defined(BOOST_ASIO_HAS_DECLTYPE) || defined(GENERATING_DOCUMENTATION) template <typename C> inline typename C::iterator buffer_sequence_end(C& c, typename enable_if< !is_convertible<const C*, const mutable_buffer*>::value && !is_convertible<const C*, const const_buffer*>::value >::type* = 0) BOOST_ASIO_NOEXCEPT { return c.end(); } template <typename C> inline typename C::const_iterator buffer_sequence_end(const C& c, typename enable_if< !is_convertible<const C*, const mutable_buffer*>::value && !is_convertible<const C*, const const_buffer*>::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 <typename BufferSequence> struct buffer_sequence_cardinality : conditional< is_same<BufferSequence, mutable_buffer>::value #if !defined(BOOST_ASIO_NO_DEPRECATED) || is_same<BufferSequence, mutable_buffers_1>::value || is_same<BufferSequence, const_buffers_1>::value #endif // !defined(BOOST_ASIO_NO_DEPRECATED) || is_same<BufferSequence, const_buffer>::value, one_buffer, multiple_buffers>::type {}; template <typename Iterator> inline std::size_t buffer_size(one_buffer, Iterator begin, Iterator) BOOST_ASIO_NOEXCEPT { return const_buffer(*begin).size(); } template <typename Iterator> 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 <typename BufferSequence> inline std::size_t buffer_size(const BufferSequence& b) BOOST_ASIO_NOEXCEPT { return detail::buffer_size( detail::buffer_sequence_cardinality<BufferSequence>(), 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<const unsigned char*>(b1); * @endcode * * To access the memory of a modifiable buffer, use: * @code boost::asio::mutable_buffer b2 = ...; * unsigned char* p2 = boost::asio::buffer_cast<unsigned char*>(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 <typename PointerToPodType> inline PointerToPodType buffer_cast(const mutable_buffer& b) BOOST_ASIO_NOEXCEPT { return static_cast<PointerToPodType>(b.data()); } /// Cast a non-modifiable buffer to a specified pointer to POD type. template <typename PointerToPodType> inline PointerToPodType buffer_cast(const const_buffer& b) BOOST_ASIO_NOEXCEPT { return static_cast<PointerToPodType>(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<char*>(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<const char*>(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 <typename Iterator> 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 <tt>{void*, * size_t}</tt> specifies a mutable (modifiable) region of memory. Similarly, a * tuple of the form <tt>{const void*, size_t}</tt> 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<char> d2(128); * bytes_transferred = sock.receive(boost::asio::buffer(d2)); * * std::array<char, 128> d3; * bytes_transferred = sock.receive(boost::asio::buffer(d3)); * * boost::array<char, 128> 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 <tt>size()</tt> * 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<unsigned char*>(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<const_buffer> buffers = ...; * * vector<unsigned char> 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<char, 6> 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, <tt>{ 'a', 'b', 'c', 'd', 'e' }</tt>. 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 <tt>{ 'a', 'b', 'c' }</tt>. 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 <tt>{ 'c', 'd', 'e' }</tt>. 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 <tt>{ 'b', 'c', 'd' }</tt>. * * @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<char> d2(128); * boost::array<char, 128> d3; * * boost::array<mutable_buffer, 3> bufs1 = { * boost::asio::buffer(d1), * boost::asio::buffer(d2), * boost::asio::buffer(d3) }; * bytes_transferred = sock.receive(bufs1); * * std::vector<const_buffer> 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 <tt>mutable_buffer(b)</tt>. */ 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 <tt>const_buffer(b)</tt>. */ 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 <tt>mutable_buffer(data, size_in_bytes)</tt>. */ 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 <tt>const_buffer(data, size_in_bytes)</tt>. */ 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<void*>(data), * N * sizeof(PodType)); @endcode */ template <typename PodType, std::size_t N> 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<void*>(data), * min(N * sizeof(PodType), max_size_in_bytes)); @endcode */ template <typename PodType, std::size_t N> 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<const void*>(data), * N * sizeof(PodType)); @endcode */ template <typename PodType, std::size_t N> 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<const void*>(data), * min(N * sizeof(PodType), max_size_in_bytes)); @endcode */ template <typename PodType, std::size_t N> 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<PodType, N>& array ...); // // and // // unspecified buffer(boost::array<const PodType, N>& 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 <bool IsConst> struct buffer_types_base; template <> struct buffer_types_base<false> { typedef mutable_buffer buffer_type; typedef BOOST_ASIO_MUTABLE_BUFFER container_type; }; template <> struct buffer_types_base<true> { typedef const_buffer buffer_type; typedef BOOST_ASIO_CONST_BUFFER container_type; }; template <typename PodType> struct buffer_types : public buffer_types_base<is_const<PodType>::value> { }; } // namespace detail template <typename PodType, std::size_t N> inline typename detail::buffer_types<PodType>::container_type buffer(boost::array<PodType, N>& data) BOOST_ASIO_NOEXCEPT { typedef typename boost::asio::detail::buffer_types<PodType>::buffer_type buffer_type; typedef typename boost::asio::detail::buffer_types<PodType>::container_type container_type; return container_type( buffer_type(data.c_array(), data.size() * sizeof(PodType))); } template <typename PodType, std::size_t N> inline typename detail::buffer_types<PodType>::container_type buffer(boost::array<PodType, N>& data, std::size_t max_size_in_bytes) BOOST_ASIO_NOEXCEPT { typedef typename boost::asio::detail::buffer_types<PodType>::buffer_type buffer_type; typedef typename boost::asio::detail::buffer_types<PodType>::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 <typename PodType, std::size_t N> inline BOOST_ASIO_MUTABLE_BUFFER buffer( boost::array<PodType, N>& 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 <typename PodType, std::size_t N> inline BOOST_ASIO_MUTABLE_BUFFER buffer(boost::array<PodType, N>& 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 <typename PodType, std::size_t N> inline BOOST_ASIO_CONST_BUFFER buffer( boost::array<const PodType, N>& 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 <typename PodType, std::size_t N> inline BOOST_ASIO_CONST_BUFFER buffer(boost::array<const PodType, N>& 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 <typename PodType, std::size_t N> inline BOOST_ASIO_CONST_BUFFER buffer( const boost::array<PodType, N>& 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 <typename PodType, std::size_t N> inline BOOST_ASIO_CONST_BUFFER buffer(const boost::array<PodType, N>& 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 <typename PodType, std::size_t N> inline BOOST_ASIO_MUTABLE_BUFFER buffer( std::array<PodType, N>& 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 <typename PodType, std::size_t N> inline BOOST_ASIO_MUTABLE_BUFFER buffer(std::array<PodType, N>& 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 <typename PodType, std::size_t N> inline BOOST_ASIO_CONST_BUFFER buffer( std::array<const PodType, N>& 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 <typename PodType, std::size_t N> inline BOOST_ASIO_CONST_BUFFER buffer(std::array<const PodType, N>& 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 <typename PodType, std::size_t N> inline BOOST_ASIO_CONST_BUFFER buffer( const std::array<PodType, N>& 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 <typename PodType, std::size_t N> inline BOOST_ASIO_CONST_BUFFER buffer(const std::array<PodType, N>& 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 <typename PodType, typename Allocator> inline BOOST_ASIO_MUTABLE_BUFFER buffer( std::vector<PodType, Allocator>& 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<PodType, Allocator>::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 <typename PodType, typename Allocator> inline BOOST_ASIO_MUTABLE_BUFFER buffer(std::vector<PodType, Allocator>& 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<PodType, Allocator>::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 <typename PodType, typename Allocator> inline BOOST_ASIO_CONST_BUFFER buffer( const std::vector<PodType, Allocator>& 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<PodType, Allocator>::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 <typename PodType, typename Allocator> inline BOOST_ASIO_CONST_BUFFER buffer( const std::vector<PodType, Allocator>& 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<PodType, Allocator>::const_iterator >(data.begin()) #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING ); } /// Create a new modifiable buffer that represents the given string. /** * @returns <tt>mutable_buffer(data.size() ? &data[0] : 0, * data.size() * sizeof(Elem))</tt>. * * @note The buffer is invalidated by any non-const operation called on the * given string object. */ template <typename Elem, typename Traits, typename Allocator> inline BOOST_ASIO_MUTABLE_BUFFER buffer( std::basic_string<Elem, Traits, Allocator>& 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<Elem, Traits, Allocator>::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 <typename Elem, typename Traits, typename Allocator> inline BOOST_ASIO_MUTABLE_BUFFER buffer( std::basic_string<Elem, Traits, Allocator>& 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<Elem, Traits, Allocator>::iterator >(data.begin()) #endif // BOOST_ASIO_ENABLE_BUFFER_DEBUGGING ); } /// Create a new non-modifiable buffer that represents the given string. /** * @returns <tt>const_buffer(data.data(), data.size() * sizeof(Elem))</tt>. * * @note The buffer is invalidated by any non-const operation called on the * given string object. */ template <typename Elem, typename Traits, typename Allocator> inline BOOST_ASIO_CONST_BUFFER buffer( const std::basic_string<Elem, Traits, Allocator>& 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<Elem, Traits, Allocator>::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 <typename Elem, typename Traits, typename Allocator> inline BOOST_ASIO_CONST_BUFFER buffer( const std::basic_string<Elem, Traits, Allocator>& 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<Elem, Traits, Allocator>::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 <tt>mutable_buffer(data.size() ? &data[0] : 0, * data.size() * sizeof(Elem))</tt>. */ template <typename Elem, typename Traits> inline BOOST_ASIO_CONST_BUFFER buffer( basic_string_view<Elem, Traits> 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<Elem, Traits>::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 <typename Elem, typename Traits> inline BOOST_ASIO_CONST_BUFFER buffer( basic_string_view<Elem, Traits> 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<Elem, Traits>::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 <tt>sizeof(Elem) == 1</tt>. */ template <typename Elem, typename Traits, typename Allocator> 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<Elem, Traits, Allocator>& s, std::size_t maximum_size = (std::numeric_limits<std::size_t>::max)()) BOOST_ASIO_NOEXCEPT : string_(s), #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) size_((std::numeric_limits<std::size_t>::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<std::size_t>::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 <tt>size() + n > max_size()</tt>. * * @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<std::size_t>::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 <tt>prepare(x)</tt> where <tt>x >= n</tt>, 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 <tt>size() + n > max_size()</tt>. */ 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<std::size_t>::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<Elem, Traits, Allocator>& 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 <tt>sizeof(Elem) == 1</tt>. */ template <typename Elem, typename Allocator> 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<Elem, Allocator>& v, std::size_t maximum_size = (std::numeric_limits<std::size_t>::max)()) BOOST_ASIO_NOEXCEPT : vector_(v), #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) size_((std::numeric_limits<std::size_t>::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<std::size_t>::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 <tt>size() + n > max_size()</tt>. * * @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<std::size_t>::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 <tt>prepare(x)</tt> where <tt>x >= n</tt>, 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 <tt>size() + n > max_size()</tt>. */ 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<std::size_t>::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<Elem, Allocator>& 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 <tt>dynamic_string_buffer<Elem, Traits, Allocator>(data)</tt>. */ template <typename Elem, typename Traits, typename Allocator> inline dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer( std::basic_string<Elem, Traits, Allocator>& data) BOOST_ASIO_NOEXCEPT { return dynamic_string_buffer<Elem, Traits, Allocator>(data); } /// Create a new dynamic buffer that represents the given string. /** * @returns <tt>dynamic_string_buffer<Elem, Traits, Allocator>(data, * max_size)</tt>. */ template <typename Elem, typename Traits, typename Allocator> inline dynamic_string_buffer<Elem, Traits, Allocator> dynamic_buffer( std::basic_string<Elem, Traits, Allocator>& data, std::size_t max_size) BOOST_ASIO_NOEXCEPT { return dynamic_string_buffer<Elem, Traits, Allocator>(data, max_size); } /// Create a new dynamic buffer that represents the given vector. /** * @returns <tt>dynamic_vector_buffer<Elem, Allocator>(data)</tt>. */ template <typename Elem, typename Allocator> inline dynamic_vector_buffer<Elem, Allocator> dynamic_buffer( std::vector<Elem, Allocator>& data) BOOST_ASIO_NOEXCEPT { return dynamic_vector_buffer<Elem, Allocator>(data); } /// Create a new dynamic buffer that represents the given vector. /** * @returns <tt>dynamic_vector_buffer<Elem, Allocator>(data, max_size)</tt>. */ template <typename Elem, typename Allocator> inline dynamic_vector_buffer<Elem, Allocator> dynamic_buffer( std::vector<Elem, Allocator>& data, std::size_t max_size) BOOST_ASIO_NOEXCEPT { return dynamic_vector_buffer<Elem, Allocator>(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 <typename TargetIterator, typename SourceIterator> 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 <typename TargetIterator, typename SourceIterator> 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 <typename TargetIterator, typename SourceIterator> 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<std::size_t>::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 <typename TargetIterator, typename SourceIterator> 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<std::size_t>::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 <typename TargetIterator, typename SourceIterator> 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 <typename TargetIterator, typename SourceIterator> 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 <typename MutableBufferSequence, typename ConstBufferSequence> inline std::size_t buffer_copy(const MutableBufferSequence& target, const ConstBufferSequence& source) BOOST_ASIO_NOEXCEPT { return detail::buffer_copy( detail::buffer_sequence_cardinality<MutableBufferSequence>(), detail::buffer_sequence_cardinality<ConstBufferSequence>(), 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 <typename MutableBufferSequence, typename ConstBufferSequence> 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<MutableBufferSequence>(), detail::buffer_sequence_cardinality<ConstBufferSequence>(), 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 <boost/asio/detail/pop_options.hpp> #include <boost/asio/detail/is_buffer_sequence.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { /// Trait to determine whether a type satisfies the MutableBufferSequence /// requirements. template <typename T> struct is_mutable_buffer_sequence #if defined(GENERATING_DOCUMENTATION) : integral_constant<bool, automatically_determined> #else // defined(GENERATING_DOCUMENTATION) : boost::asio::detail::is_buffer_sequence<T, mutable_buffer> #endif // defined(GENERATING_DOCUMENTATION) { }; /// Trait to determine whether a type satisfies the ConstBufferSequence /// requirements. template <typename T> struct is_const_buffer_sequence #if defined(GENERATING_DOCUMENTATION) : integral_constant<bool, automatically_determined> #else // defined(GENERATING_DOCUMENTATION) : boost::asio::detail::is_buffer_sequence<T, const_buffer> #endif // defined(GENERATING_DOCUMENTATION) { }; #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) /// Trait to determine whether a type satisfies the DynamicBuffer_v1 /// requirements. template <typename T> struct is_dynamic_buffer_v1 #if defined(GENERATING_DOCUMENTATION) : integral_constant<bool, automatically_determined> #else // defined(GENERATING_DOCUMENTATION) : boost::asio::detail::is_dynamic_buffer_v1<T> #endif // defined(GENERATING_DOCUMENTATION) { }; #endif // !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) /// Trait to determine whether a type satisfies the DynamicBuffer_v2 /// requirements. template <typename T> struct is_dynamic_buffer_v2 #if defined(GENERATING_DOCUMENTATION) : integral_constant<bool, automatically_determined> #else // defined(GENERATING_DOCUMENTATION) : boost::asio::detail::is_dynamic_buffer_v2<T> #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 <typename T> struct is_dynamic_buffer #if defined(GENERATING_DOCUMENTATION) : integral_constant<bool, automatically_determined> #elif defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) : boost::asio::is_dynamic_buffer_v2<T> #else // defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) : boost::asio::is_dynamic_buffer_v1<T> #endif // defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) { }; } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_BUFFER_HPP buffers_iterator.hpp 0000644 00000033341 15125530236 0010630 0 ustar 00 // // buffers_iterator.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <iterator> #include <boost/asio/buffer.hpp> #include <boost/asio/detail/assert.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <bool IsMutable> struct buffers_iterator_types_helper; template <> struct buffers_iterator_types_helper<false> { typedef const_buffer buffer_type; template <typename ByteType> struct byte_type { typedef typename add_const<ByteType>::type type; }; }; template <> struct buffers_iterator_types_helper<true> { typedef mutable_buffer buffer_type; template <typename ByteType> struct byte_type { typedef ByteType type; }; }; template <typename BufferSequence, typename ByteType> struct buffers_iterator_types { enum { is_mutable = is_convertible< typename BufferSequence::value_type, mutable_buffer>::value }; typedef buffers_iterator_types_helper<is_mutable> helper; typedef typename helper::buffer_type buffer_type; typedef typename helper::template byte_type<ByteType>::type byte_type; typedef typename BufferSequence::const_iterator const_iterator; }; template <typename ByteType> struct buffers_iterator_types<mutable_buffer, ByteType> { typedef mutable_buffer buffer_type; typedef ByteType byte_type; typedef const mutable_buffer* const_iterator; }; template <typename ByteType> struct buffers_iterator_types<const_buffer, ByteType> { typedef const_buffer buffer_type; typedef typename add_const<ByteType>::type byte_type; typedef const const_buffer* const_iterator; }; #if !defined(BOOST_ASIO_NO_DEPRECATED) template <typename ByteType> struct buffers_iterator_types<mutable_buffers_1, ByteType> { typedef mutable_buffer buffer_type; typedef ByteType byte_type; typedef const mutable_buffer* const_iterator; }; template <typename ByteType> struct buffers_iterator_types<const_buffers_1, ByteType> { typedef const_buffer buffer_type; typedef typename add_const<ByteType>::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 <typename BufferSequence, typename ByteType = char> class buffers_iterator { private: typedef typename detail::buffers_iterator_types< BufferSequence, ByteType>::buffer_type buffer_type; typedef typename detail::buffers_iterator_types<BufferSequence, ByteType>::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<pointer>( 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 <typename BufferSequence> inline buffers_iterator<BufferSequence> buffers_begin( const BufferSequence& buffers) { return buffers_iterator<BufferSequence>::begin(buffers); } /// Construct an iterator representing the end of the buffers' data. template <typename BufferSequence> inline buffers_iterator<BufferSequence> buffers_end( const BufferSequence& buffers) { return buffers_iterator<BufferSequence>::end(buffers); } } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_BUFFERS_ITERATOR_HPP associated_allocator.hpp 0000644 00000007317 15125530236 0011446 0 ustar 00 // // associated_allocator.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <memory> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename T, typename E, typename = void> struct associated_allocator_impl { typedef E type; static type get(const T&, const E& e) BOOST_ASIO_NOEXCEPT { return e; } }; template <typename T, typename E> struct associated_allocator_impl<T, E, typename void_type<typename T::allocator_type>::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 <typename T, typename Allocator = std::allocator<void> > struct associated_allocator { /// If @c T has a nested type @c allocator_type, <tt>T::allocator_type</tt>. /// Otherwise @c Allocator. #if defined(GENERATING_DOCUMENTATION) typedef see_below type; #else // defined(GENERATING_DOCUMENTATION) typedef typename detail::associated_allocator_impl<T, Allocator>::type type; #endif // defined(GENERATING_DOCUMENTATION) /// If @c T has a nested type @c allocator_type, returns /// <tt>t.get_allocator()</tt>. Otherwise returns @c a. static type get(const T& t, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return detail::associated_allocator_impl<T, Allocator>::get(t, a); } }; /// Helper function to obtain an object's associated allocator. /** * @returns <tt>associated_allocator<T>::get(t)</tt> */ template <typename T> inline typename associated_allocator<T>::type get_associated_allocator(const T& t) BOOST_ASIO_NOEXCEPT { return associated_allocator<T>::get(t); } /// Helper function to obtain an object's associated allocator. /** * @returns <tt>associated_allocator<T, Allocator>::get(t, a)</tt> */ template <typename T, typename Allocator> inline typename associated_allocator<T, Allocator>::type get_associated_allocator(const T& t, const Allocator& a) BOOST_ASIO_NOEXCEPT { return associated_allocator<T, Allocator>::get(t, a); } #if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) template <typename T, typename Allocator = std::allocator<void> > using associated_allocator_t = typename associated_allocator<T, Allocator>::type; #endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_ASSOCIATED_ALLOCATOR_HPP execution/allocator.hpp 0000644 00000017217 15125530236 0011252 0 ustar 00 // // execution/allocator.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_ALLOCATOR_HPP #define BOOST_ASIO_EXECUTION_ALLOCATOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/scheduler.hpp> #include <boost/asio/execution/sender.hpp> #include <boost/asio/is_applicable_property.hpp> #include <boost/asio/traits/query_static_constexpr_member.hpp> #include <boost/asio/traits/static_query.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if defined(GENERATING_DOCUMENTATION) namespace execution { /// A property to describe which allocator an executor will use to allocate the /// memory required to store a submitted function object. template <typename ProtoAllocator> struct allocator_t { /// The allocator_t property applies to executors, senders, and schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The allocator_t property can be required. static constexpr bool is_requirable = true; /// The allocator_t property can be preferred. static constexpr bool is_preferable = true; /// Default constructor. constexpr allocator_t(); /// Obtain the allocator stored in the allocator_t property object. /** * Present only if @c ProtoAllocator is non-void. */ constexpr ProtoAllocator value() const; /// Create an allocator_t object with a different allocator. /** * Present only if @c ProtoAllocator is void. */ template <typename OtherAllocator> allocator_t<OtherAllocator operator()(const OtherAllocator& a); }; /// A special value used for accessing the allocator_t property. constexpr allocator_t<void> allocator; } // namespace execution #else // defined(GENERATING_DOCUMENTATION) namespace execution { template <typename ProtoAllocator> struct allocator_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, allocator_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, allocator_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, allocator_t>::value(); } template <typename E, typename T = decltype(allocator_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = allocator_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) BOOST_ASIO_CONSTEXPR ProtoAllocator value() const { return a_; } private: friend struct allocator_t<void>; explicit BOOST_ASIO_CONSTEXPR allocator_t(const ProtoAllocator& a) : a_(a) { } ProtoAllocator a_; }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename ProtoAllocator> template <typename E, typename T> const T allocator_t<ProtoAllocator>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <> struct allocator_t<void> { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); BOOST_ASIO_CONSTEXPR allocator_t() { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, allocator_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, allocator_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, allocator_t>::value(); } template <typename E, typename T = decltype(allocator_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = allocator_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename OtherProtoAllocator> BOOST_ASIO_CONSTEXPR allocator_t<OtherProtoAllocator> operator()( const OtherProtoAllocator& a) const { return allocator_t<OtherProtoAllocator>(a); } }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename E, typename T> const T allocator_t<void>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) constexpr allocator_t<void> allocator; #else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) template <typename T> struct allocator_instance { static allocator_t<T> instance; }; template <typename T> allocator_t<T> allocator_instance<T>::instance; namespace { static const allocator_t<void>& allocator = allocator_instance<void>::instance; } // namespace #endif } // namespace execution #if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename ProtoAllocator> struct is_applicable_property<T, execution::allocator_t<ProtoAllocator> > : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; #endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T, typename ProtoAllocator> struct static_query<T, execution::allocator_t<ProtoAllocator>, typename enable_if< traits::query_static_constexpr_member<T, execution::allocator_t<ProtoAllocator> >::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::allocator_t<ProtoAllocator> >::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::allocator_t<ProtoAllocator> >::value(); } }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) } // namespace traits #endif // defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_ALLOCATOR_HPP execution/start.hpp 0000644 00000014112 15125530236 0010416 0 ustar 00 // // execution/start.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_START_HPP #define BOOST_ASIO_EXECUTION_START_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/traits/start_member.hpp> #include <boost/asio/traits/start_free.hpp> #include <boost/asio/detail/push_options.hpp> #if defined(GENERATING_DOCUMENTATION) namespace boost { namespace asio { namespace execution { /// A customisation point that notifies an operation state object to start /// its associated operation. /** * The name <tt>execution::start</tt> denotes a customisation point object. * The expression <tt>execution::start(R)</tt> for some subexpression * <tt>R</tt> is expression-equivalent to: * * @li <tt>R.start()</tt>, if that expression is valid. * * @li Otherwise, <tt>start(R)</tt>, if that expression is valid, with * overload resolution performed in a context that includes the declaration * <tt>void start();</tt> and that does not include a declaration of * <tt>execution::start</tt>. * * @li Otherwise, <tt>execution::start(R)</tt> is ill-formed. */ inline constexpr unspecified start = unspecified; /// A type trait that determines whether a @c start expression is /// well-formed. /** * Class template @c can_start is a trait that is derived from * @c true_type if the expression <tt>execution::start(std::declval<R>(), * std::declval<E>())</tt> is well formed; otherwise @c false_type. */ template <typename R> struct can_start : integral_constant<bool, automatically_determined> { }; } // namespace execution } // namespace asio } // namespace boost #else // defined(GENERATING_DOCUMENTATION) namespace asio_execution_start_fn { using boost::asio::decay; using boost::asio::declval; using boost::asio::enable_if; using boost::asio::traits::start_free; using boost::asio::traits::start_member; void start(); enum overload_type { call_member, call_free, ill_formed }; template <typename R, typename = void> struct call_traits { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; template <typename R> struct call_traits<R, typename enable_if< ( start_member<R>::is_valid ) >::type> : start_member<R> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); }; template <typename R> struct call_traits<R, typename enable_if< ( !start_member<R>::is_valid && start_free<R>::is_valid ) >::type> : start_free<R> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); }; struct impl { #if defined(BOOST_ASIO_HAS_MOVE) template <typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R>::overload == call_member, typename call_traits<R>::result_type >::type operator()(R&& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R>::is_noexcept)) { return BOOST_ASIO_MOVE_CAST(R)(r).start(); } template <typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R>::overload == call_free, typename call_traits<R>::result_type >::type operator()(R&& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R>::is_noexcept)) { return start(BOOST_ASIO_MOVE_CAST(R)(r)); } #else // defined(BOOST_ASIO_HAS_MOVE) template <typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R&>::overload == call_member, typename call_traits<R&>::result_type >::type operator()(R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R&>::is_noexcept)) { return r.start(); } template <typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const R&>::overload == call_member, typename call_traits<const R&>::result_type >::type operator()(const R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const R&>::is_noexcept)) { return r.start(); } template <typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R&>::overload == call_free, typename call_traits<R&>::result_type >::type operator()(R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R&>::is_noexcept)) { return start(r); } template <typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const R&>::overload == call_free, typename call_traits<const R&>::result_type >::type operator()(const R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const R&>::is_noexcept)) { return start(r); } #endif // defined(BOOST_ASIO_HAS_MOVE) }; template <typename T = impl> struct static_instance { static const T instance; }; template <typename T> const T static_instance<T>::instance = {}; } // namespace asio_execution_start_fn namespace boost { namespace asio { namespace execution { namespace { static BOOST_ASIO_CONSTEXPR const asio_execution_start_fn::impl& start = asio_execution_start_fn::static_instance<>::instance; } // namespace template <typename R> struct can_start : integral_constant<bool, asio_execution_start_fn::call_traits<R>::overload != asio_execution_start_fn::ill_formed> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename R> constexpr bool can_start_v = can_start<R>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename R> struct is_nothrow_start : integral_constant<bool, asio_execution_start_fn::call_traits<R>::is_noexcept> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename R> constexpr bool is_nothrow_start_v = is_nothrow_start<R>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) } // namespace execution } // namespace asio } // namespace boost #endif // defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_START_HPP execution/connect.hpp 0000644 00000034540 15125530236 0010721 0 ustar 00 // // execution/connect.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_CONNECT_HPP #define BOOST_ASIO_EXECUTION_CONNECT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/detail/as_invocable.hpp> #include <boost/asio/execution/detail/as_operation.hpp> #include <boost/asio/execution/detail/as_receiver.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/operation_state.hpp> #include <boost/asio/execution/receiver.hpp> #include <boost/asio/execution/sender.hpp> #include <boost/asio/traits/connect_member.hpp> #include <boost/asio/traits/connect_free.hpp> #include <boost/asio/detail/push_options.hpp> #if defined(GENERATING_DOCUMENTATION) namespace boost { namespace asio { namespace execution { /// A customisation point that connects a sender to a receiver. /** * The name <tt>execution::connect</tt> denotes a customisation point object. * For some subexpressions <tt>s</tt> and <tt>r</tt>, let <tt>S</tt> be a type * such that <tt>decltype((s))</tt> is <tt>S</tt> and let <tt>R</tt> be a type * such that <tt>decltype((r))</tt> is <tt>R</tt>. The expression * <tt>execution::connect(s, r)</tt> is expression-equivalent to: * * @li <tt>s.connect(r)</tt>, if that expression is valid, if its type * satisfies <tt>operation_state</tt>, and if <tt>S</tt> satisfies * <tt>sender</tt>. * * @li Otherwise, <tt>connect(s, r)</tt>, if that expression is valid, if its * type satisfies <tt>operation_state</tt>, and if <tt>S</tt> satisfies * <tt>sender</tt>, with overload resolution performed in a context that * includes the declaration <tt>void connect();</tt> and that does not include * a declaration of <tt>execution::connect</tt>. * * @li Otherwise, <tt>as_operation{s, r}</tt>, if <tt>r</tt> is not an instance * of <tt>as_receiver<F, S></tt> for some type <tt>F</tt>, and if * <tt>receiver_of<R> && executor_of<remove_cvref_t<S>, * as_invocable<remove_cvref_t<R>, S>></tt> is <tt>true</tt>, where * <tt>as_operation</tt> is an implementation-defined class equivalent to * @code template <class S, class R> * struct as_operation * { * remove_cvref_t<S> e_; * remove_cvref_t<R> r_; * void start() noexcept try { * execution::execute(std::move(e_), * as_invocable<remove_cvref_t<R>, S>{r_}); * } catch(...) { * execution::set_error(std::move(r_), current_exception()); * } * }; @endcode * and <tt>as_invocable</tt> is a class template equivalent to the following: * @code template<class R> * struct as_invocable * { * R* r_; * explicit as_invocable(R& r) noexcept * : r_(std::addressof(r)) {} * as_invocable(as_invocable && other) noexcept * : r_(std::exchange(other.r_, nullptr)) {} * ~as_invocable() { * if(r_) * execution::set_done(std::move(*r_)); * } * void operator()() & noexcept try { * execution::set_value(std::move(*r_)); * r_ = nullptr; * } catch(...) { * execution::set_error(std::move(*r_), current_exception()); * r_ = nullptr; * } * }; * @endcode * * @li Otherwise, <tt>execution::connect(s, r)</tt> is ill-formed. */ inline constexpr unspecified connect = unspecified; /// A type trait that determines whether a @c connect expression is /// well-formed. /** * Class template @c can_connect is a trait that is derived from * @c true_type if the expression <tt>execution::connect(std::declval<S>(), * std::declval<R>())</tt> is well formed; otherwise @c false_type. */ template <typename S, typename R> struct can_connect : integral_constant<bool, automatically_determined> { }; /// A type trait to determine the result of a @c connect expression. template <typename S, typename R> struct connect_result { /// The type of the connect expression. /** * The type of the expression <tt>execution::connect(std::declval<S>(), * std::declval<R>())</tt>. */ typedef automatically_determined type; }; /// A type alis to determine the result of a @c connect expression. template <typename S, typename R> using connect_result_t = typename connect_result<S, R>::type; } // namespace execution } // namespace asio } // namespace boost #else // defined(GENERATING_DOCUMENTATION) namespace asio_execution_connect_fn { using boost::asio::conditional; using boost::asio::declval; using boost::asio::enable_if; using boost::asio::execution::detail::as_invocable; using boost::asio::execution::detail::as_operation; using boost::asio::execution::detail::is_as_receiver; using boost::asio::execution::is_executor_of; using boost::asio::execution::is_operation_state; using boost::asio::execution::is_receiver; using boost::asio::execution::is_sender; using boost::asio::false_type; using boost::asio::remove_cvref; using boost::asio::traits::connect_free; using boost::asio::traits::connect_member; void connect(); enum overload_type { call_member, call_free, adapter, ill_formed }; template <typename S, typename R, typename = void> struct call_traits { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; template <typename S, typename R> struct call_traits<S, void(R), typename enable_if< ( connect_member<S, R>::is_valid && is_operation_state<typename connect_member<S, R>::result_type>::value && is_sender<typename remove_cvref<S>::type>::value ) >::type> : connect_member<S, R> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); }; template <typename S, typename R> struct call_traits<S, void(R), typename enable_if< ( !connect_member<S, R>::is_valid && connect_free<S, R>::is_valid && is_operation_state<typename connect_free<S, R>::result_type>::value && is_sender<typename remove_cvref<S>::type>::value ) >::type> : connect_free<S, R> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); }; template <typename S, typename R> struct call_traits<S, void(R), typename enable_if< ( !connect_member<S, R>::is_valid && !connect_free<S, R>::is_valid && is_receiver<R>::value && conditional< !is_as_receiver< typename remove_cvref<R>::type >::value, is_executor_of< typename remove_cvref<S>::type, as_invocable<typename remove_cvref<R>::type, S> >, false_type >::type::value ) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef as_operation<S, R> result_type; }; struct impl { #if defined(BOOST_ASIO_HAS_MOVE) template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S, void(R)>::overload == call_member, typename call_traits<S, void(R)>::result_type >::type operator()(S&& s, R&& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S, void(R)>::is_noexcept)) { return BOOST_ASIO_MOVE_CAST(S)(s).connect(BOOST_ASIO_MOVE_CAST(R)(r)); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S, void(R)>::overload == call_free, typename call_traits<S, void(R)>::result_type >::type operator()(S&& s, R&& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S, void(R)>::is_noexcept)) { return connect(BOOST_ASIO_MOVE_CAST(S)(s), BOOST_ASIO_MOVE_CAST(R)(r)); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S, void(R)>::overload == adapter, typename call_traits<S, void(R)>::result_type >::type operator()(S&& s, R&& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S, void(R)>::is_noexcept)) { return typename call_traits<S, void(R)>::result_type( BOOST_ASIO_MOVE_CAST(S)(s), BOOST_ASIO_MOVE_CAST(R)(r)); } #else // defined(BOOST_ASIO_HAS_MOVE) template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S&, void(R&)>::overload == call_member, typename call_traits<S&, void(R&)>::result_type >::type operator()(S& s, R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S&, void(R&)>::is_noexcept)) { return s.connect(r); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const S&, void(R&)>::overload == call_member, typename call_traits<const S&, void(R&)>::result_type >::type operator()(const S& s, R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const S&, void(R&)>::is_noexcept)) { return s.connect(r); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S&, void(R&)>::overload == call_free, typename call_traits<S&, void(R&)>::result_type >::type operator()(S& s, R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S&, void(R&)>::is_noexcept)) { return connect(s, r); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const S&, void(R&)>::overload == call_free, typename call_traits<const S&, void(R&)>::result_type >::type operator()(const S& s, R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const S&, void(R&)>::is_noexcept)) { return connect(s, r); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S&, void(R&)>::overload == adapter, typename call_traits<S&, void(R&)>::result_type >::type operator()(S& s, R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S&, void(R&)>::is_noexcept)) { return typename call_traits<S&, void(R&)>::result_type(s, r); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const S&, void(R&)>::overload == adapter, typename call_traits<const S&, void(R&)>::result_type >::type operator()(const S& s, R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const S&, void(R&)>::is_noexcept)) { return typename call_traits<const S&, void(R&)>::result_type(s, r); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S&, void(const R&)>::overload == call_member, typename call_traits<S&, void(const R&)>::result_type >::type operator()(S& s, const R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S&, void(const R&)>::is_noexcept)) { return s.connect(r); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const S&, void(const R&)>::overload == call_member, typename call_traits<const S&, void(const R&)>::result_type >::type operator()(const S& s, const R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const S&, void(const R&)>::is_noexcept)) { return s.connect(r); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S&, void(const R&)>::overload == call_free, typename call_traits<S&, void(const R&)>::result_type >::type operator()(S& s, const R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S&, void(const R&)>::is_noexcept)) { return connect(s, r); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const S&, void(const R&)>::overload == call_free, typename call_traits<const S&, void(const R&)>::result_type >::type operator()(const S& s, const R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const S&, void(const R&)>::is_noexcept)) { return connect(s, r); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S&, void(const R&)>::overload == adapter, typename call_traits<S&, void(const R&)>::result_type >::type operator()(S& s, const R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S&, void(const R&)>::is_noexcept)) { return typename call_traits<S&, void(const R&)>::result_type(s, r); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const S&, void(const R&)>::overload == adapter, typename call_traits<const S&, void(const R&)>::result_type >::type operator()(const S& s, const R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const S&, void(const R&)>::is_noexcept)) { return typename call_traits<const S&, void(const R&)>::result_type(s, r); } #endif // defined(BOOST_ASIO_HAS_MOVE) }; template <typename T = impl> struct static_instance { static const T instance; }; template <typename T> const T static_instance<T>::instance = {}; } // namespace asio_execution_connect_fn namespace boost { namespace asio { namespace execution { namespace { static BOOST_ASIO_CONSTEXPR const asio_execution_connect_fn::impl& connect = asio_execution_connect_fn::static_instance<>::instance; } // namespace template <typename S, typename R> struct can_connect : integral_constant<bool, asio_execution_connect_fn::call_traits<S, void(R)>::overload != asio_execution_connect_fn::ill_formed> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename S, typename R> constexpr bool can_connect_v = can_connect<S, R>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename S, typename R> struct is_nothrow_connect : integral_constant<bool, asio_execution_connect_fn::call_traits<S, void(R)>::is_noexcept> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename S, typename R> constexpr bool is_nothrow_connect_v = is_nothrow_connect<S, R>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename S, typename R> struct connect_result { typedef typename asio_execution_connect_fn::call_traits< S, void(R)>::result_type type; }; #if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) template <typename S, typename R> using connect_result_t = typename connect_result<S, R>::type; #endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) } // namespace execution } // namespace asio } // namespace boost #endif // defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_CONNECT_HPP execution/impl/bad_executor.ipp 0000644 00000002020 15125530236 0012662 0 ustar 00 // // exection/impl/bad_executor.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_IMPL_BAD_EXECUTOR_IPP #define BOOST_ASIO_EXECUTION_IMPL_BAD_EXECUTOR_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/execution/bad_executor.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace execution { bad_executor::bad_executor() BOOST_ASIO_NOEXCEPT { } const char* bad_executor::what() const BOOST_ASIO_NOEXCEPT_OR_NOTHROW { return "bad executor"; } } // namespace execution } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_IMPL_BAD_EXECUTOR_IPP execution/impl/receiver_invocation_error.ipp 0000644 00000002064 15125530236 0015474 0 ustar 00 // // exection/impl/receiver_invocation_error.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_IMPL_RECEIVER_INVOCATION_ERROR_IPP #define BOOST_ASIO_EXECUTION_IMPL_RECEIVER_INVOCATION_ERROR_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/execution/receiver_invocation_error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace execution { receiver_invocation_error::receiver_invocation_error() : std::runtime_error("receiver invocation error") { } } // namespace execution } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_IMPL_RECEIVER_INVOCATION_ERROR_IPP execution/occupancy.hpp 0000644 00000012575 15125530236 0011260 0 ustar 00 // // execution/occupancy.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_OCCUPANCY_HPP #define BOOST_ASIO_EXECUTION_OCCUPANCY_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/scheduler.hpp> #include <boost/asio/execution/sender.hpp> #include <boost/asio/is_applicable_property.hpp> #include <boost/asio/traits/query_static_constexpr_member.hpp> #include <boost/asio/traits/static_query.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if defined(GENERATING_DOCUMENTATION) namespace execution { /// A property that gives an estimate of the number of execution agents that /// should occupy the associated execution context. struct occupancy_t { /// The occupancy_t property applies to executors, senders, and schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The occupancy_t property cannot be required. static constexpr bool is_requirable = false; /// The occupancy_t property cannot be preferred. static constexpr bool is_preferable = false; /// The type returned by queries against an @c any_executor. typedef std::size_t polymorphic_query_result_type; }; /// A special value used for accessing the occupancy_t property. constexpr occupancy_t occupancy; } // namespace execution #else // defined(GENERATING_DOCUMENTATION) namespace execution { namespace detail { template <int I = 0> struct occupancy_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); typedef std::size_t polymorphic_query_result_type; BOOST_ASIO_CONSTEXPR occupancy_t() { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, occupancy_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, occupancy_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, occupancy_t>::value(); } template <typename E, typename T = decltype(occupancy_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = occupancy_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if !defined(BOOST_ASIO_HAS_CONSTEXPR) static const occupancy_t instance; #endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T occupancy_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if !defined(BOOST_ASIO_HAS_CONSTEXPR) template <int I> const occupancy_t<I> occupancy_t<I>::instance; #endif } // namespace detail typedef detail::occupancy_t<> occupancy_t; #if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) constexpr occupancy_t occupancy; #else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) namespace { static const occupancy_t& occupancy = occupancy_t::instance; } #endif } // namespace execution #if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> struct is_applicable_property<T, execution::occupancy_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; #endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> struct static_query<T, execution::occupancy_t, typename enable_if< traits::query_static_constexpr_member<T, execution::occupancy_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::occupancy_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::occupancy_t>::value(); } }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) } // namespace traits #endif // defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_OCCUPANCY_HPP execution/schedule.hpp 0000644 00000016571 15125530236 0011070 0 ustar 00 // // execution/schedule.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_SCHEDULE_HPP #define BOOST_ASIO_EXECUTION_SCHEDULE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/traits/schedule_member.hpp> #include <boost/asio/traits/schedule_free.hpp> #include <boost/asio/detail/push_options.hpp> #if defined(GENERATING_DOCUMENTATION) namespace boost { namespace asio { namespace execution { /// A customisation point that is used to obtain a sender from a scheduler. /** * The name <tt>execution::schedule</tt> denotes a customisation point object. * For some subexpression <tt>s</tt>, let <tt>S</tt> be a type such that * <tt>decltype((s))</tt> is <tt>S</tt>. The expression * <tt>execution::schedule(s)</tt> is expression-equivalent to: * * @li <tt>s.schedule()</tt>, if that expression is valid and its type models * <tt>sender</tt>. * * @li Otherwise, <tt>schedule(s)</tt>, if that expression is valid and its * type models <tt>sender</tt> with overload resolution performed in a context * that includes the declaration <tt>void schedule();</tt> and that does not * include a declaration of <tt>execution::schedule</tt>. * * @li Otherwise, <tt>S</tt> if <tt>S</tt> satisfies <tt>executor</tt>. * * @li Otherwise, <tt>execution::schedule(s)</tt> is ill-formed. */ inline constexpr unspecified schedule = unspecified; /// A type trait that determines whether a @c schedule expression is /// well-formed. /** * Class template @c can_schedule is a trait that is derived from @c true_type * if the expression <tt>execution::schedule(std::declval<S>())</tt> is well * formed; otherwise @c false_type. */ template <typename S> struct can_schedule : integral_constant<bool, automatically_determined> { }; } // namespace execution } // namespace asio } // namespace boost #else // defined(GENERATING_DOCUMENTATION) namespace asio_execution_schedule_fn { using boost::asio::decay; using boost::asio::declval; using boost::asio::enable_if; using boost::asio::execution::is_executor; using boost::asio::traits::schedule_free; using boost::asio::traits::schedule_member; void schedule(); enum overload_type { identity, call_member, call_free, ill_formed }; template <typename S, typename = void> struct call_traits { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; template <typename S> struct call_traits<S, typename enable_if< ( schedule_member<S>::is_valid ) >::type> : schedule_member<S> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); }; template <typename S> struct call_traits<S, typename enable_if< ( !schedule_member<S>::is_valid && schedule_free<S>::is_valid ) >::type> : schedule_free<S> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); }; template <typename S> struct call_traits<S, typename enable_if< ( !schedule_member<S>::is_valid && !schedule_free<S>::is_valid && is_executor<typename decay<S>::type>::value ) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = identity); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); #if defined(BOOST_ASIO_HAS_MOVE) typedef BOOST_ASIO_MOVE_ARG(S) result_type; #else // defined(BOOST_ASIO_HAS_MOVE) typedef BOOST_ASIO_MOVE_ARG(typename decay<S>::type) result_type; #endif // defined(BOOST_ASIO_HAS_MOVE) }; struct impl { template <typename S> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S>::overload == identity, typename call_traits<S>::result_type >::type operator()(BOOST_ASIO_MOVE_ARG(S) s) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S>::is_noexcept)) { return BOOST_ASIO_MOVE_CAST(S)(s); } #if defined(BOOST_ASIO_HAS_MOVE) template <typename S> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S>::overload == call_member, typename call_traits<S>::result_type >::type operator()(S&& s) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S>::is_noexcept)) { return BOOST_ASIO_MOVE_CAST(S)(s).schedule(); } template <typename S> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S>::overload == call_free, typename call_traits<S>::result_type >::type operator()(S&& s) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S>::is_noexcept)) { return schedule(BOOST_ASIO_MOVE_CAST(S)(s)); } #else // defined(BOOST_ASIO_HAS_MOVE) template <typename S> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S&>::overload == call_member, typename call_traits<S&>::result_type >::type operator()(S& s) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S&>::is_noexcept)) { return s.schedule(); } template <typename S> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const S&>::overload == call_member, typename call_traits<const S&>::result_type >::type operator()(const S& s) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const S&>::is_noexcept)) { return s.schedule(); } template <typename S> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S&>::overload == call_free, typename call_traits<S&>::result_type >::type operator()(S& s) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S&>::is_noexcept)) { return schedule(s); } template <typename S> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const S&>::overload == call_free, typename call_traits<const S&>::result_type >::type operator()(const S& s) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const S&>::is_noexcept)) { return schedule(s); } #endif // defined(BOOST_ASIO_HAS_MOVE) }; template <typename T = impl> struct static_instance { static const T instance; }; template <typename T> const T static_instance<T>::instance = {}; } // namespace asio_execution_schedule_fn namespace boost { namespace asio { namespace execution { namespace { static BOOST_ASIO_CONSTEXPR const asio_execution_schedule_fn::impl& schedule = asio_execution_schedule_fn::static_instance<>::instance; } // namespace template <typename S> struct can_schedule : integral_constant<bool, asio_execution_schedule_fn::call_traits<S>::overload != asio_execution_schedule_fn::ill_formed> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename S> constexpr bool can_schedule_v = can_schedule<S>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename S> struct is_nothrow_schedule : integral_constant<bool, asio_execution_schedule_fn::call_traits<S>::is_noexcept> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename S> constexpr bool is_nothrow_schedule_v = is_nothrow_schedule<S>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) } // namespace execution } // namespace asio } // namespace boost #endif // defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_SCHEDULE_HPP execution/prefer_only.hpp 0000644 00000022541 15125530236 0011612 0 ustar 00 // // execution/prefer_only.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_PREFER_ONLY_HPP #define BOOST_ASIO_EXECUTION_PREFER_ONLY_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/is_applicable_property.hpp> #include <boost/asio/prefer.hpp> #include <boost/asio/query.hpp> #include <boost/asio/traits/static_query.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if defined(GENERATING_DOCUMENTATION) namespace execution { /// A property adapter that is used with the polymorphic executor wrapper /// to mark properties as preferable, but not requirable. template <typename Property> struct prefer_only { /// The prefer_only adapter applies to the same types as the nested property. template <typename T> static constexpr bool is_applicable_property_v = is_applicable_property<T, Property>::value; /// The context_t property cannot be required. static constexpr bool is_requirable = false; /// The context_t property can be preferred, it the underlying property can /// be preferred. /** * @c true if @c Property::is_preferable is @c true, otherwise @c false. */ static constexpr bool is_preferable = automatically_determined; /// The type returned by queries against an @c any_executor. typedef typename Property::polymorphic_query_result_type polymorphic_query_result_type; }; } // namespace execution #else // defined(GENERATING_DOCUMENTATION) namespace execution { namespace detail { template <typename InnerProperty, typename = void> struct prefer_only_is_preferable { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); }; template <typename InnerProperty> struct prefer_only_is_preferable<InnerProperty, typename enable_if< InnerProperty::is_preferable >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); }; template <typename InnerProperty, typename = void> struct prefer_only_polymorphic_query_result_type { }; template <typename InnerProperty> struct prefer_only_polymorphic_query_result_type<InnerProperty, typename void_type< typename InnerProperty::polymorphic_query_result_type >::type> { typedef typename InnerProperty::polymorphic_query_result_type polymorphic_query_result_type; }; template <typename InnerProperty, typename = void> struct prefer_only_property { InnerProperty property; prefer_only_property(const InnerProperty& p) : property(p) { } }; #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) template <typename InnerProperty> struct prefer_only_property<InnerProperty, typename void_type< decltype(boost::asio::declval<const InnerProperty>().value()) >::type> { InnerProperty property; prefer_only_property(const InnerProperty& p) : property(p) { } BOOST_ASIO_CONSTEXPR auto value() const BOOST_ASIO_NOEXCEPT_IF(( noexcept(boost::asio::declval<const InnerProperty>().value()))) -> decltype(boost::asio::declval<const InnerProperty>().value()) { return property.value(); } }; #else // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) struct prefer_only_memfns_base { void value(); }; template <typename T> struct prefer_only_memfns_derived : T, prefer_only_memfns_base { }; template <typename T, T> struct prefer_only_memfns_check { }; template <typename> char (&prefer_only_value_memfn_helper(...))[2]; template <typename T> char prefer_only_value_memfn_helper( prefer_only_memfns_check< void (prefer_only_memfns_base::*)(), &prefer_only_memfns_derived<T>::value>*); template <typename InnerProperty> struct prefer_only_property<InnerProperty, typename enable_if< sizeof(prefer_only_value_memfn_helper<InnerProperty>(0)) != 1 && !is_same<typename InnerProperty::polymorphic_query_result_type, void>::value >::type> { InnerProperty property; prefer_only_property(const InnerProperty& p) : property(p) { } BOOST_ASIO_CONSTEXPR typename InnerProperty::polymorphic_query_result_type value() const { return property.value(); } }; #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) } // namespace detail template <typename InnerProperty> struct prefer_only : detail::prefer_only_is_preferable<InnerProperty>, detail::prefer_only_polymorphic_query_result_type<InnerProperty>, detail::prefer_only_property<InnerProperty> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); BOOST_ASIO_CONSTEXPR prefer_only(const InnerProperty& p) : detail::prefer_only_property<InnerProperty>(p) { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::static_query<T, InnerProperty>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::static_query<T, InnerProperty>::is_noexcept)) { return traits::static_query<T, InnerProperty>::value(); } template <typename E, typename T = decltype(prefer_only::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = prefer_only::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename Executor, typename Property> friend BOOST_ASIO_CONSTEXPR typename prefer_result<const Executor&, const InnerProperty&>::type prefer(const Executor& ex, const prefer_only<Property>& p, typename enable_if< is_same<Property, InnerProperty>::value && can_prefer<const Executor&, const InnerProperty&>::value >::type* = 0) #if !defined(BOOST_ASIO_MSVC) \ && !defined(__clang__) // Clang crashes if noexcept is used here. BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_prefer<const Executor&, const InnerProperty&>::value)) #endif // !defined(BOOST_ASIO_MSVC) // && !defined(__clang__) { return boost::asio::prefer(ex, p.property); } template <typename Executor, typename Property> friend BOOST_ASIO_CONSTEXPR typename query_result<const Executor&, const InnerProperty&>::type query(const Executor& ex, const prefer_only<Property>& p, typename enable_if< is_same<Property, InnerProperty>::value && can_query<const Executor&, const InnerProperty&>::value >::type* = 0) #if !defined(BOOST_ASIO_MSVC) \ && !defined(__clang__) // Clang crashes if noexcept is used here. BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, const InnerProperty&>::value)) #endif // !defined(BOOST_ASIO_MSVC) // && !defined(__clang__) { return boost::asio::query(ex, p.property); } }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename InnerProperty> template <typename E, typename T> const T prefer_only<InnerProperty>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) } // namespace execution template <typename T, typename InnerProperty> struct is_applicable_property<T, execution::prefer_only<InnerProperty> > : is_applicable_property<T, InnerProperty> { }; namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T, typename InnerProperty> struct static_query<T, execution::prefer_only<InnerProperty> > : static_query<T, const InnerProperty&> { }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) template <typename T, typename InnerProperty> struct prefer_free_default<T, execution::prefer_only<InnerProperty>, typename enable_if< can_prefer<const T&, const InnerProperty&>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_prefer<const T&, const InnerProperty&>::value)); typedef typename prefer_result<const T&, const InnerProperty&>::type result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) template <typename T, typename InnerProperty> struct query_free<T, execution::prefer_only<InnerProperty>, typename enable_if< can_query<const T&, const InnerProperty&>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<const T&, const InnerProperty&>::value)); typedef typename query_result<const T&, const InnerProperty&>::type result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) } // namespace traits #endif // defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_PREFER_ONLY_HPP execution/outstanding_work.hpp 0000644 00000055123 15125530236 0012671 0 ustar 00 // // execution/outstanding_work.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_OUTSTANDING_WORK_HPP #define BOOST_ASIO_EXECUTION_OUTSTANDING_WORK_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/scheduler.hpp> #include <boost/asio/execution/sender.hpp> #include <boost/asio/is_applicable_property.hpp> #include <boost/asio/query.hpp> #include <boost/asio/traits/query_free.hpp> #include <boost/asio/traits/query_member.hpp> #include <boost/asio/traits/query_static_constexpr_member.hpp> #include <boost/asio/traits/static_query.hpp> #include <boost/asio/traits/static_require.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if defined(GENERATING_DOCUMENTATION) namespace execution { /// A property to describe whether task submission is likely in the future. struct outstanding_work_t { /// The outstanding_work_t property applies to executors, senders, and /// schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The top-level outstanding_work_t property cannot be required. static constexpr bool is_requirable = false; /// The top-level outstanding_work_t property cannot be preferred. static constexpr bool is_preferable = false; /// The type returned by queries against an @c any_executor. typedef outstanding_work_t polymorphic_query_result_type; /// A sub-property that indicates that the executor does not represent likely /// future submission of a function object. struct untracked_t { /// The outstanding_work_t::untracked_t property applies to executors, /// senders, and schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The outstanding_work_t::untracked_t property can be required. static constexpr bool is_requirable = true; /// The outstanding_work_t::untracked_t property can be preferred. static constexpr bool is_preferable = true; /// The type returned by queries against an @c any_executor. typedef outstanding_work_t polymorphic_query_result_type; /// Default constructor. constexpr untracked_t(); /// Get the value associated with a property object. /** * @returns untracked_t(); */ static constexpr outstanding_work_t value(); }; /// A sub-property that indicates that the executor represents likely /// future submission of a function object. struct tracked_t { /// The outstanding_work_t::untracked_t property applies to executors, /// senders, and schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The outstanding_work_t::tracked_t property can be required. static constexpr bool is_requirable = true; /// The outstanding_work_t::tracked_t property can be preferred. static constexpr bool is_preferable = true; /// The type returned by queries against an @c any_executor. typedef outstanding_work_t polymorphic_query_result_type; /// Default constructor. constexpr tracked_t(); /// Get the value associated with a property object. /** * @returns tracked_t(); */ static constexpr outstanding_work_t value(); }; /// A special value used for accessing the outstanding_work_t::untracked_t /// property. static constexpr untracked_t untracked; /// A special value used for accessing the outstanding_work_t::tracked_t /// property. static constexpr tracked_t tracked; /// Default constructor. constexpr outstanding_work_t(); /// Construct from a sub-property value. constexpr outstanding_work_t(untracked_t); /// Construct from a sub-property value. constexpr outstanding_work_t(tracked_t); /// Compare property values for equality. friend constexpr bool operator==( const outstanding_work_t& a, const outstanding_work_t& b) noexcept; /// Compare property values for inequality. friend constexpr bool operator!=( const outstanding_work_t& a, const outstanding_work_t& b) noexcept; }; /// A special value used for accessing the outstanding_work_t property. constexpr outstanding_work_t outstanding_work; } // namespace execution #else // defined(GENERATING_DOCUMENTATION) namespace execution { namespace detail { namespace outstanding_work { template <int I> struct untracked_t; template <int I> struct tracked_t; } // namespace outstanding_work template <int I = 0> struct outstanding_work_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); typedef outstanding_work_t polymorphic_query_result_type; typedef detail::outstanding_work::untracked_t<I> untracked_t; typedef detail::outstanding_work::tracked_t<I> tracked_t; BOOST_ASIO_CONSTEXPR outstanding_work_t() : value_(-1) { } BOOST_ASIO_CONSTEXPR outstanding_work_t(untracked_t) : value_(0) { } BOOST_ASIO_CONSTEXPR outstanding_work_t(tracked_t) : value_(1) { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member< T, outstanding_work_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member< T, outstanding_work_t >::is_noexcept)) { return traits::query_static_constexpr_member< T, outstanding_work_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::static_query<T, untracked_t>::result_type static_query( typename enable_if< !traits::query_static_constexpr_member< T, outstanding_work_t>::is_valid && !traits::query_member<T, outstanding_work_t>::is_valid && traits::static_query<T, untracked_t>::is_valid >::type* = 0) BOOST_ASIO_NOEXCEPT { return traits::static_query<T, untracked_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::static_query<T, tracked_t>::result_type static_query( typename enable_if< !traits::query_static_constexpr_member< T, outstanding_work_t>::is_valid && !traits::query_member<T, outstanding_work_t>::is_valid && !traits::static_query<T, untracked_t>::is_valid && traits::static_query<T, tracked_t>::is_valid >::type* = 0) BOOST_ASIO_NOEXCEPT { return traits::static_query<T, tracked_t>::value(); } template <typename E, typename T = decltype(outstanding_work_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = outstanding_work_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) friend BOOST_ASIO_CONSTEXPR bool operator==( const outstanding_work_t& a, const outstanding_work_t& b) { return a.value_ == b.value_; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const outstanding_work_t& a, const outstanding_work_t& b) { return a.value_ != b.value_; } struct convertible_from_outstanding_work_t { BOOST_ASIO_CONSTEXPR convertible_from_outstanding_work_t(outstanding_work_t) { } }; template <typename Executor> friend BOOST_ASIO_CONSTEXPR outstanding_work_t query( const Executor& ex, convertible_from_outstanding_work_t, typename enable_if< can_query<const Executor&, untracked_t>::value >::type* = 0) #if !defined(__clang__) // Clang crashes if noexcept is used here. #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified. BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, outstanding_work_t<>::untracked_t>::value)) #else // defined(BOOST_ASIO_MSVC) BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, untracked_t>::value)) #endif // defined(BOOST_ASIO_MSVC) #endif // !defined(__clang__) { return boost::asio::query(ex, untracked_t()); } template <typename Executor> friend BOOST_ASIO_CONSTEXPR outstanding_work_t query( const Executor& ex, convertible_from_outstanding_work_t, typename enable_if< !can_query<const Executor&, untracked_t>::value && can_query<const Executor&, tracked_t>::value >::type* = 0) #if !defined(__clang__) // Clang crashes if noexcept is used here. #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified. BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, outstanding_work_t<>::tracked_t>::value)) #else // defined(BOOST_ASIO_MSVC) BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, tracked_t>::value)) #endif // defined(BOOST_ASIO_MSVC) #endif // !defined(__clang__) { return boost::asio::query(ex, tracked_t()); } BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(untracked_t, untracked); BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(tracked_t, tracked); #if !defined(BOOST_ASIO_HAS_CONSTEXPR) static const outstanding_work_t instance; #endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) private: int value_; }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T outstanding_work_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if !defined(BOOST_ASIO_HAS_CONSTEXPR) template <int I> const outstanding_work_t<I> outstanding_work_t<I>::instance; #endif template <int I> const typename outstanding_work_t<I>::untracked_t outstanding_work_t<I>::untracked; template <int I> const typename outstanding_work_t<I>::tracked_t outstanding_work_t<I>::tracked; namespace outstanding_work { template <int I = 0> struct untracked_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); typedef outstanding_work_t<I> polymorphic_query_result_type; BOOST_ASIO_CONSTEXPR untracked_t() { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, untracked_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, untracked_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, untracked_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR untracked_t static_query( typename enable_if< !traits::query_static_constexpr_member<T, untracked_t>::is_valid && !traits::query_member<T, untracked_t>::is_valid && !traits::query_free<T, untracked_t>::is_valid && !can_query<T, tracked_t<I> >::value >::type* = 0) BOOST_ASIO_NOEXCEPT { return untracked_t(); } template <typename E, typename T = decltype(untracked_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = untracked_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) static BOOST_ASIO_CONSTEXPR outstanding_work_t<I> value() { return untracked_t(); } friend BOOST_ASIO_CONSTEXPR bool operator==( const untracked_t&, const untracked_t&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const untracked_t&, const untracked_t&) { return false; } }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T untracked_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I = 0> struct tracked_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); typedef outstanding_work_t<I> polymorphic_query_result_type; BOOST_ASIO_CONSTEXPR tracked_t() { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, tracked_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, tracked_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, tracked_t>::value(); } template <typename E, typename T = decltype(tracked_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = tracked_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) static BOOST_ASIO_CONSTEXPR outstanding_work_t<I> value() { return tracked_t(); } friend BOOST_ASIO_CONSTEXPR bool operator==( const tracked_t&, const tracked_t&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const tracked_t&, const tracked_t&) { return false; } }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T tracked_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) } // namespace outstanding_work } // namespace detail typedef detail::outstanding_work_t<> outstanding_work_t; #if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) constexpr outstanding_work_t outstanding_work; #else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) namespace { static const outstanding_work_t& outstanding_work = outstanding_work_t::instance; } #endif } // namespace execution #if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> struct is_applicable_property<T, execution::outstanding_work_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; template <typename T> struct is_applicable_property<T, execution::outstanding_work_t::untracked_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; template <typename T> struct is_applicable_property<T, execution::outstanding_work_t::tracked_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; #endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) template <typename T> struct query_free_default<T, execution::outstanding_work_t, typename enable_if< can_query<T, execution::outstanding_work_t::untracked_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<T, execution::outstanding_work_t::untracked_t>::value)); typedef execution::outstanding_work_t result_type; }; template <typename T> struct query_free_default<T, execution::outstanding_work_t, typename enable_if< !can_query<T, execution::outstanding_work_t::untracked_t>::value && can_query<T, execution::outstanding_work_t::tracked_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<T, execution::outstanding_work_t::tracked_t>::value)); typedef execution::outstanding_work_t result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> struct static_query<T, execution::outstanding_work_t, typename enable_if< traits::query_static_constexpr_member<T, execution::outstanding_work_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::outstanding_work_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::outstanding_work_t>::value(); } }; template <typename T> struct static_query<T, execution::outstanding_work_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::outstanding_work_t>::is_valid && !traits::query_member<T, execution::outstanding_work_t>::is_valid && traits::static_query<T, execution::outstanding_work_t::untracked_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::static_query<T, execution::outstanding_work_t::untracked_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::static_query<T, execution::outstanding_work_t::untracked_t>::value(); } }; template <typename T> struct static_query<T, execution::outstanding_work_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::outstanding_work_t>::is_valid && !traits::query_member<T, execution::outstanding_work_t>::is_valid && !traits::static_query<T, execution::outstanding_work_t::untracked_t>::is_valid && traits::static_query<T, execution::outstanding_work_t::tracked_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::static_query<T, execution::outstanding_work_t::tracked_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::static_query<T, execution::outstanding_work_t::tracked_t>::value(); } }; template <typename T> struct static_query<T, execution::outstanding_work_t::untracked_t, typename enable_if< traits::query_static_constexpr_member<T, execution::outstanding_work_t::untracked_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::outstanding_work_t::untracked_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::outstanding_work_t::untracked_t>::value(); } }; template <typename T> struct static_query<T, execution::outstanding_work_t::untracked_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::outstanding_work_t::untracked_t>::is_valid && !traits::query_member<T, execution::outstanding_work_t::untracked_t>::is_valid && !traits::query_free<T, execution::outstanding_work_t::untracked_t>::is_valid && !can_query<T, execution::outstanding_work_t::tracked_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef execution::outstanding_work_t::untracked_t result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return result_type(); } }; template <typename T> struct static_query<T, execution::outstanding_work_t::tracked_t, typename enable_if< traits::query_static_constexpr_member<T, execution::outstanding_work_t::tracked_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::outstanding_work_t::tracked_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::outstanding_work_t::tracked_t>::value(); } }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) template <typename T> struct static_require<T, execution::outstanding_work_t::untracked_t, typename enable_if< static_query<T, execution::outstanding_work_t::untracked_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = (is_same<typename static_query<T, execution::outstanding_work_t::untracked_t>::result_type, execution::outstanding_work_t::untracked_t>::value)); }; template <typename T> struct static_require<T, execution::outstanding_work_t::tracked_t, typename enable_if< static_query<T, execution::outstanding_work_t::tracked_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = (is_same<typename static_query<T, execution::outstanding_work_t::tracked_t>::result_type, execution::outstanding_work_t::tracked_t>::value)); }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) } // namespace traits #endif // defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_OUTSTANDING_WORK_HPP execution/set_done.hpp 0000644 00000014760 15125530236 0011072 0 ustar 00 // // execution/set_done.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_SET_DONE_HPP #define BOOST_ASIO_EXECUTION_SET_DONE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/traits/set_done_member.hpp> #include <boost/asio/traits/set_done_free.hpp> #include <boost/asio/detail/push_options.hpp> #if defined(GENERATING_DOCUMENTATION) namespace boost { namespace asio { namespace execution { /// A customisation point that delivers a done notification to a receiver. /** * The name <tt>execution::set_done</tt> denotes a customisation point object. * The expression <tt>execution::set_done(R)</tt> for some subexpression * <tt>R</tt> is expression-equivalent to: * * @li <tt>R.set_done()</tt>, if that expression is valid. If the function * selected does not signal the receiver <tt>R</tt>'s done channel, the * program is ill-formed with no diagnostic required. * * @li Otherwise, <tt>set_done(R)</tt>, if that expression is valid, with * overload resolution performed in a context that includes the declaration * <tt>void set_done();</tt> and that does not include a declaration of * <tt>execution::set_done</tt>. If the function selected by overload * resolution does not signal the receiver <tt>R</tt>'s done channel, the * program is ill-formed with no diagnostic required. * * @li Otherwise, <tt>execution::set_done(R)</tt> is ill-formed. */ inline constexpr unspecified set_done = unspecified; /// A type trait that determines whether a @c set_done expression is /// well-formed. /** * Class template @c can_set_done is a trait that is derived from * @c true_type if the expression <tt>execution::set_done(std::declval<R>(), * std::declval<E>())</tt> is well formed; otherwise @c false_type. */ template <typename R> struct can_set_done : integral_constant<bool, automatically_determined> { }; } // namespace execution } // namespace asio } // namespace boost #else // defined(GENERATING_DOCUMENTATION) namespace asio_execution_set_done_fn { using boost::asio::decay; using boost::asio::declval; using boost::asio::enable_if; using boost::asio::traits::set_done_free; using boost::asio::traits::set_done_member; void set_done(); enum overload_type { call_member, call_free, ill_formed }; template <typename R, typename = void> struct call_traits { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; template <typename R> struct call_traits<R, typename enable_if< ( set_done_member<R>::is_valid ) >::type> : set_done_member<R> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); }; template <typename R> struct call_traits<R, typename enable_if< ( !set_done_member<R>::is_valid && set_done_free<R>::is_valid ) >::type> : set_done_free<R> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); }; struct impl { #if defined(BOOST_ASIO_HAS_MOVE) template <typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R>::overload == call_member, typename call_traits<R>::result_type >::type operator()(R&& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R>::is_noexcept)) { return BOOST_ASIO_MOVE_CAST(R)(r).set_done(); } template <typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R>::overload == call_free, typename call_traits<R>::result_type >::type operator()(R&& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R>::is_noexcept)) { return set_done(BOOST_ASIO_MOVE_CAST(R)(r)); } #else // defined(BOOST_ASIO_HAS_MOVE) template <typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R&>::overload == call_member, typename call_traits<R&>::result_type >::type operator()(R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R&>::is_noexcept)) { return r.set_done(); } template <typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const R&>::overload == call_member, typename call_traits<const R&>::result_type >::type operator()(const R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const R&>::is_noexcept)) { return r.set_done(); } template <typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R&>::overload == call_free, typename call_traits<R&>::result_type >::type operator()(R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R&>::is_noexcept)) { return set_done(r); } template <typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const R&>::overload == call_free, typename call_traits<const R&>::result_type >::type operator()(const R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const R&>::is_noexcept)) { return set_done(r); } #endif // defined(BOOST_ASIO_HAS_MOVE) }; template <typename T = impl> struct static_instance { static const T instance; }; template <typename T> const T static_instance<T>::instance = {}; } // namespace asio_execution_set_done_fn namespace boost { namespace asio { namespace execution { namespace { static BOOST_ASIO_CONSTEXPR const asio_execution_set_done_fn::impl& set_done = asio_execution_set_done_fn::static_instance<>::instance; } // namespace template <typename R> struct can_set_done : integral_constant<bool, asio_execution_set_done_fn::call_traits<R>::overload != asio_execution_set_done_fn::ill_formed> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename R> constexpr bool can_set_done_v = can_set_done<R>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename R> struct is_nothrow_set_done : integral_constant<bool, asio_execution_set_done_fn::call_traits<R>::is_noexcept> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename R> constexpr bool is_nothrow_set_done_v = is_nothrow_set_done<R>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) } // namespace execution } // namespace asio } // namespace boost #endif // defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_SET_DONE_HPP execution/submit.hpp 0000644 00000032246 15125530236 0010574 0 ustar 00 // // execution/submit.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_SUBMIT_HPP #define BOOST_ASIO_EXECUTION_SUBMIT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/detail/submit_receiver.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/receiver.hpp> #include <boost/asio/execution/sender.hpp> #include <boost/asio/execution/start.hpp> #include <boost/asio/traits/submit_member.hpp> #include <boost/asio/traits/submit_free.hpp> #include <boost/asio/detail/push_options.hpp> #if defined(GENERATING_DOCUMENTATION) namespace boost { namespace asio { namespace execution { /// A customisation point that submits a sender to a receiver. /** * The name <tt>execution::submit</tt> denotes a customisation point object. For * some subexpressions <tt>s</tt> and <tt>r</tt>, let <tt>S</tt> be a type such * that <tt>decltype((s))</tt> is <tt>S</tt> and let <tt>R</tt> be a type such * that <tt>decltype((r))</tt> is <tt>R</tt>. The expression * <tt>execution::submit(s, r)</tt> is ill-formed if <tt>sender_to<S, R></tt> is * not <tt>true</tt>. Otherwise, it is expression-equivalent to: * * @li <tt>s.submit(r)</tt>, if that expression is valid and <tt>S</tt> models * <tt>sender</tt>. If the function selected does not submit the receiver * object <tt>r</tt> via the sender <tt>s</tt>, the program is ill-formed with * no diagnostic required. * * @li Otherwise, <tt>submit(s, r)</tt>, if that expression is valid and * <tt>S</tt> models <tt>sender</tt>, with overload resolution performed in a * context that includes the declaration <tt>void submit();</tt> and that does * not include a declaration of <tt>execution::submit</tt>. If the function * selected by overload resolution does not submit the receiver object * <tt>r</tt> via the sender <tt>s</tt>, the program is ill-formed with no * diagnostic required. * * @li Otherwise, <tt>execution::start((new submit_receiver<S, * R>{s,r})->state_)</tt>, where <tt>submit_receiver</tt> is an * implementation-defined class template equivalent to: * @code template<class S, class R> * struct submit_receiver { * struct wrap { * submit_receiver * p_; * template<class...As> * requires receiver_of<R, As...> * void set_value(As&&... as) && * noexcept(is_nothrow_receiver_of_v<R, As...>) { * execution::set_value(std::move(p_->r_), (As&&) as...); * delete p_; * } * template<class E> * requires receiver<R, E> * void set_error(E&& e) && noexcept { * execution::set_error(std::move(p_->r_), (E&&) e); * delete p_; * } * void set_done() && noexcept { * execution::set_done(std::move(p_->r_)); * delete p_; * } * }; * remove_cvref_t<R> r_; * connect_result_t<S, wrap> state_; * submit_receiver(S&& s, R&& r) * : r_((R&&) r) * , state_(execution::connect((S&&) s, wrap{this})) {} * }; * @endcode */ inline constexpr unspecified submit = unspecified; /// A type trait that determines whether a @c submit expression is /// well-formed. /** * Class template @c can_submit is a trait that is derived from * @c true_type if the expression <tt>execution::submit(std::declval<R>(), * std::declval<E>())</tt> is well formed; otherwise @c false_type. */ template <typename S, typename R> struct can_submit : integral_constant<bool, automatically_determined> { }; } // namespace execution } // namespace asio } // namespace boost #else // defined(GENERATING_DOCUMENTATION) namespace asio_execution_submit_fn { using boost::asio::declval; using boost::asio::enable_if; using boost::asio::execution::is_sender_to; using boost::asio::traits::submit_free; using boost::asio::traits::submit_member; void submit(); enum overload_type { call_member, call_free, adapter, ill_formed }; template <typename S, typename R, typename = void> struct call_traits { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; template <typename S, typename R> struct call_traits<S, void(R), typename enable_if< ( submit_member<S, R>::is_valid && is_sender_to<S, R>::value ) >::type> : submit_member<S, R> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); }; template <typename S, typename R> struct call_traits<S, void(R), typename enable_if< ( !submit_member<S, R>::is_valid && submit_free<S, R>::is_valid && is_sender_to<S, R>::value ) >::type> : submit_free<S, R> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); }; template <typename S, typename R> struct call_traits<S, void(R), typename enable_if< ( !submit_member<S, R>::is_valid && !submit_free<S, R>::is_valid && is_sender_to<S, R>::value ) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; struct impl { #if defined(BOOST_ASIO_HAS_MOVE) template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S, void(R)>::overload == call_member, typename call_traits<S, void(R)>::result_type >::type operator()(S&& s, R&& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S, void(R)>::is_noexcept)) { return BOOST_ASIO_MOVE_CAST(S)(s).submit(BOOST_ASIO_MOVE_CAST(R)(r)); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S, void(R)>::overload == call_free, typename call_traits<S, void(R)>::result_type >::type operator()(S&& s, R&& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S, void(R)>::is_noexcept)) { return submit(BOOST_ASIO_MOVE_CAST(S)(s), BOOST_ASIO_MOVE_CAST(R)(r)); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S, void(R)>::overload == adapter, typename call_traits<S, void(R)>::result_type >::type operator()(S&& s, R&& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S, void(R)>::is_noexcept)) { return boost::asio::execution::start( (new boost::asio::execution::detail::submit_receiver<S, R>( BOOST_ASIO_MOVE_CAST(S)(s), BOOST_ASIO_MOVE_CAST(R)(r)))->state_); } #else // defined(BOOST_ASIO_HAS_MOVE) template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S&, void(R&)>::overload == call_member, typename call_traits<S&, void(R&)>::result_type >::type operator()(S& s, R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S&, void(R&)>::is_noexcept)) { return s.submit(r); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const S&, void(R&)>::overload == call_member, typename call_traits<const S&, void(R&)>::result_type >::type operator()(const S& s, R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const S&, void(R&)>::is_noexcept)) { return s.submit(r); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S&, void(R&)>::overload == call_free, typename call_traits<S&, void(R&)>::result_type >::type operator()(S& s, R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S&, void(R&)>::is_noexcept)) { return submit(s, r); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const S&, void(R&)>::overload == call_free, typename call_traits<const S&, void(R&)>::result_type >::type operator()(const S& s, R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const S&, void(R&)>::is_noexcept)) { return submit(s, r); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S&, void(R&)>::overload == adapter, typename call_traits<S&, void(R&)>::result_type >::type operator()(S& s, R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S&, void(R&)>::is_noexcept)) { return boost::asio::execution::start( (new boost::asio::execution::detail::submit_receiver< S&, R&>(s, r))->state_); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const S&, void(R&)>::overload == adapter, typename call_traits<const S&, void(R&)>::result_type >::type operator()(const S& s, R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const S&, void(R&)>::is_noexcept)) { boost::asio::execution::start( (new boost::asio::execution::detail::submit_receiver< const S&, R&>(s, r))->state_); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S&, void(const R&)>::overload == call_member, typename call_traits<S&, void(const R&)>::result_type >::type operator()(S& s, const R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S&, void(const R&)>::is_noexcept)) { return s.submit(r); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const S&, void(const R&)>::overload == call_member, typename call_traits<const S&, void(const R&)>::result_type >::type operator()(const S& s, const R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const S&, void(const R&)>::is_noexcept)) { return s.submit(r); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S&, void(const R&)>::overload == call_free, typename call_traits<S&, void(const R&)>::result_type >::type operator()(S& s, const R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S&, void(const R&)>::is_noexcept)) { return submit(s, r); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const S&, void(const R&)>::overload == call_free, typename call_traits<const S&, void(const R&)>::result_type >::type operator()(const S& s, const R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const S&, void(const R&)>::is_noexcept)) { return submit(s, r); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S&, void(const R&)>::overload == adapter, typename call_traits<S&, void(const R&)>::result_type >::type operator()(S& s, const R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S&, void(const R&)>::is_noexcept)) { boost::asio::execution::start( (new boost::asio::execution::detail::submit_receiver< S&, const R&>(s, r))->state_); } template <typename S, typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const S&, void(const R&)>::overload == adapter, typename call_traits<const S&, void(const R&)>::result_type >::type operator()(const S& s, const R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const S&, void(const R&)>::is_noexcept)) { boost::asio::execution::start( (new boost::asio::execution::detail::submit_receiver< const S&, const R&>(s, r))->state_); } #endif // defined(BOOST_ASIO_HAS_MOVE) }; template <typename T = impl> struct static_instance { static const T instance; }; template <typename T> const T static_instance<T>::instance = {}; } // namespace asio_execution_submit_fn namespace boost { namespace asio { namespace execution { namespace { static BOOST_ASIO_CONSTEXPR const asio_execution_submit_fn::impl& submit = asio_execution_submit_fn::static_instance<>::instance; } // namespace template <typename S, typename R> struct can_submit : integral_constant<bool, asio_execution_submit_fn::call_traits<S, void(R)>::overload != asio_execution_submit_fn::ill_formed> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename S, typename R> constexpr bool can_submit_v = can_submit<S, R>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename S, typename R> struct is_nothrow_submit : integral_constant<bool, asio_execution_submit_fn::call_traits<S, void(R)>::is_noexcept> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename S, typename R> constexpr bool is_nothrow_submit_v = is_nothrow_submit<S, R>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename S, typename R> struct submit_result { typedef typename asio_execution_submit_fn::call_traits< S, void(R)>::result_type type; }; namespace detail { template <typename S, typename R> void submit_helper(BOOST_ASIO_MOVE_ARG(S) s, BOOST_ASIO_MOVE_ARG(R) r) { execution::submit(BOOST_ASIO_MOVE_CAST(S)(s), BOOST_ASIO_MOVE_CAST(R)(r)); } } // namespace detail } // namespace execution } // namespace asio } // namespace boost #endif // defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_SUBMIT_HPP execution/mapping.hpp 0000644 00000070475 15125530236 0010732 0 ustar 00 // // execution/mapping.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_MAPPING_HPP #define BOOST_ASIO_EXECUTION_MAPPING_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/scheduler.hpp> #include <boost/asio/execution/sender.hpp> #include <boost/asio/is_applicable_property.hpp> #include <boost/asio/query.hpp> #include <boost/asio/traits/query_free.hpp> #include <boost/asio/traits/query_member.hpp> #include <boost/asio/traits/query_static_constexpr_member.hpp> #include <boost/asio/traits/static_query.hpp> #include <boost/asio/traits/static_require.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if defined(GENERATING_DOCUMENTATION) namespace execution { /// A property to describe what guarantees an executor makes about the mapping /// of execution agents on to threads of execution. struct mapping_t { /// The mapping_t property applies to executors, senders, and schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The top-level mapping_t property cannot be required. static constexpr bool is_requirable = false; /// The top-level mapping_t property cannot be preferred. static constexpr bool is_preferable = false; /// The type returned by queries against an @c any_executor. typedef mapping_t polymorphic_query_result_type; /// A sub-property that indicates that execution agents are mapped on to /// threads of execution. struct thread_t { /// The mapping_t::thread_t property applies to executors, senders, and /// schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The mapping_t::thread_t property can be required. static constexpr bool is_requirable = true; /// The mapping_t::thread_t property can be preferred. static constexpr bool is_preferable = true; /// The type returned by queries against an @c any_executor. typedef mapping_t polymorphic_query_result_type; /// Default constructor. constexpr thread_t(); /// Get the value associated with a property object. /** * @returns thread_t(); */ static constexpr mapping_t value(); }; /// A sub-property that indicates that execution agents are mapped on to /// new threads of execution. struct new_thread_t { /// The mapping_t::new_thread_t property applies to executors, senders, and /// schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The mapping_t::new_thread_t property can be required. static constexpr bool is_requirable = true; /// The mapping_t::new_thread_t property can be preferred. static constexpr bool is_preferable = true; /// The type returned by queries against an @c any_executor. typedef mapping_t polymorphic_query_result_type; /// Default constructor. constexpr new_thread_t(); /// Get the value associated with a property object. /** * @returns new_thread_t(); */ static constexpr mapping_t value(); }; /// A sub-property that indicates that the mapping of execution agents is /// implementation-defined. struct other_t { /// The mapping_t::other_t property applies to executors, senders, and /// schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The mapping_t::other_t property can be required. static constexpr bool is_requirable = true; /// The mapping_t::other_t property can be preferred. static constexpr bool is_preferable = true; /// The type returned by queries against an @c any_executor. typedef mapping_t polymorphic_query_result_type; /// Default constructor. constexpr other_t(); /// Get the value associated with a property object. /** * @returns other_t(); */ static constexpr mapping_t value(); }; /// A special value used for accessing the mapping_t::thread_t property. static constexpr thread_t thread; /// A special value used for accessing the mapping_t::new_thread_t property. static constexpr new_thread_t new_thread; /// A special value used for accessing the mapping_t::other_t property. static constexpr other_t other; /// Default constructor. constexpr mapping_t(); /// Construct from a sub-property value. constexpr mapping_t(thread_t); /// Construct from a sub-property value. constexpr mapping_t(new_thread_t); /// Construct from a sub-property value. constexpr mapping_t(other_t); /// Compare property values for equality. friend constexpr bool operator==( const mapping_t& a, const mapping_t& b) noexcept; /// Compare property values for inequality. friend constexpr bool operator!=( const mapping_t& a, const mapping_t& b) noexcept; }; /// A special value used for accessing the mapping_t property. constexpr mapping_t mapping; } // namespace execution #else // defined(GENERATING_DOCUMENTATION) namespace execution { namespace detail { namespace mapping { template <int I> struct thread_t; template <int I> struct new_thread_t; template <int I> struct other_t; } // namespace mapping template <int I = 0> struct mapping_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); typedef mapping_t polymorphic_query_result_type; typedef detail::mapping::thread_t<I> thread_t; typedef detail::mapping::new_thread_t<I> new_thread_t; typedef detail::mapping::other_t<I> other_t; BOOST_ASIO_CONSTEXPR mapping_t() : value_(-1) { } BOOST_ASIO_CONSTEXPR mapping_t(thread_t) : value_(0) { } BOOST_ASIO_CONSTEXPR mapping_t(new_thread_t) : value_(1) { } BOOST_ASIO_CONSTEXPR mapping_t(other_t) : value_(2) { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, mapping_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, mapping_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, mapping_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::static_query<T, thread_t>::result_type static_query( typename enable_if< !traits::query_static_constexpr_member<T, mapping_t>::is_valid && !traits::query_member<T, mapping_t>::is_valid && traits::static_query<T, thread_t>::is_valid >::type* = 0) BOOST_ASIO_NOEXCEPT { return traits::static_query<T, thread_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::static_query<T, new_thread_t>::result_type static_query( typename enable_if< !traits::query_static_constexpr_member<T, mapping_t>::is_valid && !traits::query_member<T, mapping_t>::is_valid && !traits::static_query<T, thread_t>::is_valid && traits::static_query<T, new_thread_t>::is_valid >::type* = 0) BOOST_ASIO_NOEXCEPT { return traits::static_query<T, new_thread_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::static_query<T, other_t>::result_type static_query( typename enable_if< !traits::query_static_constexpr_member<T, mapping_t>::is_valid && !traits::query_member<T, mapping_t>::is_valid && !traits::static_query<T, thread_t>::is_valid && !traits::static_query<T, new_thread_t>::is_valid && traits::static_query<T, other_t>::is_valid >::type* = 0) BOOST_ASIO_NOEXCEPT { return traits::static_query<T, other_t>::value(); } template <typename E, typename T = decltype(mapping_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = mapping_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) friend BOOST_ASIO_CONSTEXPR bool operator==( const mapping_t& a, const mapping_t& b) { return a.value_ == b.value_; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const mapping_t& a, const mapping_t& b) { return a.value_ != b.value_; } struct convertible_from_mapping_t { BOOST_ASIO_CONSTEXPR convertible_from_mapping_t(mapping_t) {} }; template <typename Executor> friend BOOST_ASIO_CONSTEXPR mapping_t query( const Executor& ex, convertible_from_mapping_t, typename enable_if< can_query<const Executor&, thread_t>::value >::type* = 0) #if !defined(__clang__) // Clang crashes if noexcept is used here. #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified. BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, mapping_t<>::thread_t>::value)) #else // defined(BOOST_ASIO_MSVC) BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, thread_t>::value)) #endif // defined(BOOST_ASIO_MSVC) #endif // !defined(__clang__) { return boost::asio::query(ex, thread_t()); } template <typename Executor> friend BOOST_ASIO_CONSTEXPR mapping_t query( const Executor& ex, convertible_from_mapping_t, typename enable_if< !can_query<const Executor&, thread_t>::value && can_query<const Executor&, new_thread_t>::value >::type* = 0) #if !defined(__clang__) // Clang crashes if noexcept is used here. #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified. BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, mapping_t<>::new_thread_t>::value)) #else // defined(BOOST_ASIO_MSVC) BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, new_thread_t>::value)) #endif // defined(BOOST_ASIO_MSVC) #endif // !defined(__clang__) { return boost::asio::query(ex, new_thread_t()); } template <typename Executor> friend BOOST_ASIO_CONSTEXPR mapping_t query( const Executor& ex, convertible_from_mapping_t, typename enable_if< !can_query<const Executor&, thread_t>::value && !can_query<const Executor&, new_thread_t>::value && can_query<const Executor&, other_t>::value >::type* = 0) #if !defined(__clang__) // Clang crashes if noexcept is used here. #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified. BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, mapping_t<>::other_t>::value)) #else // defined(BOOST_ASIO_MSVC) BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, other_t>::value)) #endif // defined(BOOST_ASIO_MSVC) #endif // !defined(__clang__) { return boost::asio::query(ex, other_t()); } BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(thread_t, thread); BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(new_thread_t, new_thread); BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(other_t, other); #if !defined(BOOST_ASIO_HAS_CONSTEXPR) static const mapping_t instance; #endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) private: int value_; }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T mapping_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if !defined(BOOST_ASIO_HAS_CONSTEXPR) template <int I> const mapping_t<I> mapping_t<I>::instance; #endif template <int I> const typename mapping_t<I>::thread_t mapping_t<I>::thread; template <int I> const typename mapping_t<I>::new_thread_t mapping_t<I>::new_thread; template <int I> const typename mapping_t<I>::other_t mapping_t<I>::other; namespace mapping { template <int I = 0> struct thread_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); typedef mapping_t<I> polymorphic_query_result_type; BOOST_ASIO_CONSTEXPR thread_t() { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, thread_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, thread_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, thread_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR thread_t static_query( typename enable_if< !traits::query_static_constexpr_member<T, thread_t>::is_valid && !traits::query_member<T, thread_t>::is_valid && !traits::query_free<T, thread_t>::is_valid && !can_query<T, new_thread_t<I> >::value && !can_query<T, other_t<I> >::value >::type* = 0) BOOST_ASIO_NOEXCEPT { return thread_t(); } template <typename E, typename T = decltype(thread_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = thread_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) static BOOST_ASIO_CONSTEXPR mapping_t<I> value() { return thread_t(); } friend BOOST_ASIO_CONSTEXPR bool operator==( const thread_t&, const thread_t&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const thread_t&, const thread_t&) { return false; } }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T thread_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I = 0> struct new_thread_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); typedef mapping_t<I> polymorphic_query_result_type; BOOST_ASIO_CONSTEXPR new_thread_t() { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, new_thread_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, new_thread_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, new_thread_t>::value(); } template <typename E, typename T = decltype(new_thread_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = new_thread_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) static BOOST_ASIO_CONSTEXPR mapping_t<I> value() { return new_thread_t(); } friend BOOST_ASIO_CONSTEXPR bool operator==( const new_thread_t&, const new_thread_t&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const new_thread_t&, const new_thread_t&) { return false; } }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T new_thread_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> struct other_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); typedef mapping_t<I> polymorphic_query_result_type; BOOST_ASIO_CONSTEXPR other_t() { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, other_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, other_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, other_t>::value(); } template <typename E, typename T = decltype(other_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = other_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) static BOOST_ASIO_CONSTEXPR mapping_t<I> value() { return other_t(); } friend BOOST_ASIO_CONSTEXPR bool operator==( const other_t&, const other_t&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const other_t&, const other_t&) { return false; } }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T other_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) } // namespace mapping } // namespace detail typedef detail::mapping_t<> mapping_t; #if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) constexpr mapping_t mapping; #else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) namespace { static const mapping_t& mapping = mapping_t::instance; } #endif } // namespace execution #if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> struct is_applicable_property<T, execution::mapping_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; template <typename T> struct is_applicable_property<T, execution::mapping_t::thread_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; template <typename T> struct is_applicable_property<T, execution::mapping_t::new_thread_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; template <typename T> struct is_applicable_property<T, execution::mapping_t::other_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; #endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) template <typename T> struct query_free_default<T, execution::mapping_t, typename enable_if< can_query<T, execution::mapping_t::thread_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<T, execution::mapping_t::thread_t>::value)); typedef execution::mapping_t result_type; }; template <typename T> struct query_free_default<T, execution::mapping_t, typename enable_if< !can_query<T, execution::mapping_t::thread_t>::value && can_query<T, execution::mapping_t::new_thread_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<T, execution::mapping_t::new_thread_t>::value)); typedef execution::mapping_t result_type; }; template <typename T> struct query_free_default<T, execution::mapping_t, typename enable_if< !can_query<T, execution::mapping_t::thread_t>::value && !can_query<T, execution::mapping_t::new_thread_t>::value && can_query<T, execution::mapping_t::other_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<T, execution::mapping_t::other_t>::value)); typedef execution::mapping_t result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> struct static_query<T, execution::mapping_t, typename enable_if< traits::query_static_constexpr_member<T, execution::mapping_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::mapping_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::mapping_t>::value(); } }; template <typename T> struct static_query<T, execution::mapping_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::mapping_t>::is_valid && !traits::query_member<T, execution::mapping_t>::is_valid && traits::static_query<T, execution::mapping_t::thread_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::static_query<T, execution::mapping_t::thread_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::static_query<T, execution::mapping_t::thread_t>::value(); } }; template <typename T> struct static_query<T, execution::mapping_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::mapping_t>::is_valid && !traits::query_member<T, execution::mapping_t>::is_valid && !traits::static_query<T, execution::mapping_t::thread_t>::is_valid && traits::static_query<T, execution::mapping_t::new_thread_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::static_query<T, execution::mapping_t::new_thread_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::static_query<T, execution::mapping_t::new_thread_t>::value(); } }; template <typename T> struct static_query<T, execution::mapping_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::mapping_t>::is_valid && !traits::query_member<T, execution::mapping_t>::is_valid && !traits::static_query<T, execution::mapping_t::thread_t>::is_valid && !traits::static_query<T, execution::mapping_t::new_thread_t>::is_valid && traits::static_query<T, execution::mapping_t::other_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::static_query<T, execution::mapping_t::other_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::static_query<T, execution::mapping_t::other_t>::value(); } }; template <typename T> struct static_query<T, execution::mapping_t::thread_t, typename enable_if< traits::query_static_constexpr_member<T, execution::mapping_t::thread_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::mapping_t::thread_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::mapping_t::thread_t>::value(); } }; template <typename T> struct static_query<T, execution::mapping_t::thread_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::mapping_t::thread_t>::is_valid && !traits::query_member<T, execution::mapping_t::thread_t>::is_valid && !traits::query_free<T, execution::mapping_t::thread_t>::is_valid && !can_query<T, execution::mapping_t::new_thread_t>::value && !can_query<T, execution::mapping_t::other_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef execution::mapping_t::thread_t result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return result_type(); } }; template <typename T> struct static_query<T, execution::mapping_t::new_thread_t, typename enable_if< traits::query_static_constexpr_member<T, execution::mapping_t::new_thread_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::mapping_t::new_thread_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::mapping_t::new_thread_t>::value(); } }; template <typename T> struct static_query<T, execution::mapping_t::other_t, typename enable_if< traits::query_static_constexpr_member<T, execution::mapping_t::other_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::mapping_t::other_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::mapping_t::other_t>::value(); } }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) template <typename T> struct static_require<T, execution::mapping_t::thread_t, typename enable_if< static_query<T, execution::mapping_t::thread_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = (is_same<typename static_query<T, execution::mapping_t::thread_t>::result_type, execution::mapping_t::thread_t>::value)); }; template <typename T> struct static_require<T, execution::mapping_t::new_thread_t, typename enable_if< static_query<T, execution::mapping_t::new_thread_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = (is_same<typename static_query<T, execution::mapping_t::new_thread_t>::result_type, execution::mapping_t::new_thread_t>::value)); }; template <typename T> struct static_require<T, execution::mapping_t::other_t, typename enable_if< static_query<T, execution::mapping_t::other_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = (is_same<typename static_query<T, execution::mapping_t::other_t>::result_type, execution::mapping_t::other_t>::value)); }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) } // namespace traits #endif // defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_MAPPING_HPP execution/bad_executor.hpp 0000644 00000002436 15125530236 0011733 0 ustar 00 // // execution/bad_executor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_BAD_EXECUTOR_HPP #define BOOST_ASIO_EXECUTION_BAD_EXECUTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <exception> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace execution { /// 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; }; } // namespace execution } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/execution/impl/bad_executor.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_EXECUTION_BAD_EXECUTOR_HPP execution/set_value.hpp 0000644 00000035665 15125530236 0011270 0 ustar 00 // // execution/set_value.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_SET_VALUE_HPP #define BOOST_ASIO_EXECUTION_SET_VALUE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/variadic_templates.hpp> #include <boost/asio/traits/set_value_member.hpp> #include <boost/asio/traits/set_value_free.hpp> #include <boost/asio/detail/push_options.hpp> #if defined(GENERATING_DOCUMENTATION) namespace boost { namespace asio { namespace execution { /// A customisation point that delivers a value to a receiver. /** * The name <tt>execution::set_value</tt> denotes a customisation point object. * The expression <tt>execution::set_value(R, Vs...)</tt> for some * subexpressions <tt>R</tt> and <tt>Vs...</tt> is expression-equivalent to: * * @li <tt>R.set_value(Vs...)</tt>, if that expression is valid. If the * function selected does not send the value(s) <tt>Vs...</tt> to the receiver * <tt>R</tt>'s value channel, the program is ill-formed with no diagnostic * required. * * @li Otherwise, <tt>set_value(R, Vs...)</tt>, if that expression is valid, * with overload resolution performed in a context that includes the * declaration <tt>void set_value();</tt> and that does not include a * declaration of <tt>execution::set_value</tt>. If the function selected by * overload resolution does not send the value(s) <tt>Vs...</tt> to the * receiver <tt>R</tt>'s value channel, the program is ill-formed with no * diagnostic required. * * @li Otherwise, <tt>execution::set_value(R, Vs...)</tt> is ill-formed. */ inline constexpr unspecified set_value = unspecified; /// A type trait that determines whether a @c set_value expression is /// well-formed. /** * Class template @c can_set_value is a trait that is derived from * @c true_type if the expression <tt>execution::set_value(std::declval<R>(), * std::declval<Vs>()...)</tt> is well formed; otherwise @c false_type. */ template <typename R, typename... Vs> struct can_set_value : integral_constant<bool, automatically_determined> { }; } // namespace execution } // namespace asio } // namespace boost #else // defined(GENERATING_DOCUMENTATION) namespace asio_execution_set_value_fn { using boost::asio::decay; using boost::asio::declval; using boost::asio::enable_if; using boost::asio::traits::set_value_free; using boost::asio::traits::set_value_member; void set_value(); enum overload_type { call_member, call_free, ill_formed }; template <typename R, typename Vs, typename = void> struct call_traits { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; template <typename R, typename Vs> struct call_traits<R, Vs, typename enable_if< ( set_value_member<R, Vs>::is_valid ) >::type> : set_value_member<R, Vs> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); }; template <typename R, typename Vs> struct call_traits<R, Vs, typename enable_if< ( !set_value_member<R, Vs>::is_valid && set_value_free<R, Vs>::is_valid ) >::type> : set_value_free<R, Vs> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); }; struct impl { #if defined(BOOST_ASIO_HAS_MOVE) #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename R, typename... Vs> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R, void(Vs...)>::overload == call_member, typename call_traits<R, void(Vs...)>::result_type >::type operator()(R&& r, Vs&&... v) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R, void(Vs...)>::is_noexcept)) { return BOOST_ASIO_MOVE_CAST(R)(r).set_value(BOOST_ASIO_MOVE_CAST(Vs)(v)...); } template <typename R, typename... Vs> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R, void(Vs...)>::overload == call_free, typename call_traits<R, void(Vs...)>::result_type >::type operator()(R&& r, Vs&&... v) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R, void(Vs...)>::is_noexcept)) { return set_value(BOOST_ASIO_MOVE_CAST(R)(r), BOOST_ASIO_MOVE_CAST(Vs)(v)...); } #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R, void()>::overload == call_member, typename call_traits<R, void()>::result_type >::type operator()(R&& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R, void()>::is_noexcept)) { return BOOST_ASIO_MOVE_CAST(R)(r).set_value(); } template <typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R, void()>::overload == call_free, typename call_traits<R, void()>::result_type >::type operator()(R&& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R, void()>::is_noexcept)) { return set_value(BOOST_ASIO_MOVE_CAST(R)(r)); } #define BOOST_ASIO_PRIVATE_SET_VALUE_CALL_DEF(n) \ template <typename R, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ BOOST_ASIO_CONSTEXPR typename enable_if< \ call_traits<R, \ void(BOOST_ASIO_VARIADIC_TARGS(n))>::overload == call_member, \ typename call_traits<R, void(BOOST_ASIO_VARIADIC_TARGS(n))>::result_type \ >::type \ operator()(R&& r, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) const \ BOOST_ASIO_NOEXCEPT_IF(( \ call_traits<R, void(BOOST_ASIO_VARIADIC_TARGS(n))>::is_noexcept)) \ { \ return BOOST_ASIO_MOVE_CAST(R)(r).set_value( \ BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ } \ \ template <typename R, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ BOOST_ASIO_CONSTEXPR typename enable_if< \ call_traits<R, void(BOOST_ASIO_VARIADIC_TARGS(n))>::overload == call_free, \ typename call_traits<R, void(BOOST_ASIO_VARIADIC_TARGS(n))>::result_type \ >::type \ operator()(R&& r, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) const \ BOOST_ASIO_NOEXCEPT_IF(( \ call_traits<R, void(BOOST_ASIO_VARIADIC_TARGS(n))>::is_noexcept)) \ { \ return set_value(BOOST_ASIO_MOVE_CAST(R)(r), \ BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ } \ /**/ BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_SET_VALUE_CALL_DEF) #undef BOOST_ASIO_PRIVATE_SET_VALUE_CALL_DEF #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #else // defined(BOOST_ASIO_HAS_MOVE) #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename R, typename... Vs> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R&, void(const Vs&...)>::overload == call_member, typename call_traits<R&, void(const Vs&...)>::result_type >::type operator()(R& r, const Vs&... v) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R&, void(const Vs&...)>::is_noexcept)) { return r.set_value(v...); } template <typename R, typename... Vs> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const R&, void(const Vs&...)>::overload == call_member, typename call_traits<const R&, void(const Vs&...)>::result_type >::type operator()(const R& r, const Vs&... v) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const R&, void(const Vs&...)>::is_noexcept)) { return r.set_value(v...); } template <typename R, typename... Vs> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R&, void(const Vs&...)>::overload == call_free, typename call_traits<R&, void(const Vs&...)>::result_type >::type operator()(R& r, const Vs&... v) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R&, void(const Vs&...)>::is_noexcept)) { return set_value(r, v...); } template <typename R, typename... Vs> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const R&, void(const Vs&...)>::overload == call_free, typename call_traits<const R&, void(const Vs&...)>::result_type >::type operator()(const R& r, const Vs&... v) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const R&, void(const Vs&...)>::is_noexcept)) { return set_value(r, v...); } #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R&, void()>::overload == call_member, typename call_traits<R&, void()>::result_type >::type operator()(R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R&, void()>::is_noexcept)) { return r.set_value(); } template <typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const R&, void()>::overload == call_member, typename call_traits<const R&, void()>::result_type >::type operator()(const R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const R&, void()>::is_noexcept)) { return r.set_value(); } template <typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R&, void()>::overload == call_free, typename call_traits<R&, void()>::result_type >::type operator()(R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R&, void()>::is_noexcept)) { return set_value(r); } template <typename R> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const R&, void()>::overload == call_free, typename call_traits<const R&, void()>::result_type >::type operator()(const R& r) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const R&, void()>::is_noexcept)) { return set_value(r); } #define BOOST_ASIO_PRIVATE_SET_VALUE_CALL_DEF(n) \ template <typename R, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ BOOST_ASIO_CONSTEXPR typename enable_if< \ call_traits<R&, \ void(BOOST_ASIO_VARIADIC_TARGS(n))>::overload == call_member, \ typename call_traits<R&, void(BOOST_ASIO_VARIADIC_TARGS(n))>::result_type \ >::type \ operator()(R& r, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) const \ BOOST_ASIO_NOEXCEPT_IF(( \ call_traits<R&, void(BOOST_ASIO_VARIADIC_TARGS(n))>::is_noexcept)) \ { \ return r.set_value(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ } \ \ template <typename R, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ BOOST_ASIO_CONSTEXPR typename enable_if< \ call_traits<const R&, \ void(BOOST_ASIO_VARIADIC_TARGS(n))>::overload == call_member, \ typename call_traits<const R&, \ void(BOOST_ASIO_VARIADIC_TARGS(n))>::result_type \ >::type \ operator()(const R& r, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) const \ BOOST_ASIO_NOEXCEPT_IF(( \ call_traits<const R&, void(BOOST_ASIO_VARIADIC_TARGS(n))>::is_noexcept)) \ { \ return r.set_value(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ } \ \ template <typename R, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ BOOST_ASIO_CONSTEXPR typename enable_if< \ call_traits<R&, \ void(BOOST_ASIO_VARIADIC_TARGS(n))>::overload == call_free, \ typename call_traits<R&, void(BOOST_ASIO_VARIADIC_TARGS(n))>::result_type \ >::type \ operator()(R& r, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) const \ BOOST_ASIO_NOEXCEPT_IF(( \ call_traits<R&, void(BOOST_ASIO_VARIADIC_TARGS(n))>::is_noexcept)) \ { \ return set_value(r, BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ } \ \ template <typename R, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ BOOST_ASIO_CONSTEXPR typename enable_if< \ call_traits<const R&, \ void(BOOST_ASIO_VARIADIC_TARGS(n))>::overload == call_free, \ typename call_traits<const R&, \ void(BOOST_ASIO_VARIADIC_TARGS(n))>::result_type \ >::type \ operator()(const R& r, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) const \ BOOST_ASIO_NOEXCEPT_IF(( \ call_traits<const R&, void(BOOST_ASIO_VARIADIC_TARGS(n))>::is_noexcept)) \ { \ return set_value(r, BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ } \ /**/ BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_SET_VALUE_CALL_DEF) #undef BOOST_ASIO_PRIVATE_SET_VALUE_CALL_DEF #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #endif // defined(BOOST_ASIO_HAS_MOVE) }; template <typename T = impl> struct static_instance { static const T instance; }; template <typename T> const T static_instance<T>::instance = {}; } // namespace asio_execution_set_value_fn namespace boost { namespace asio { namespace execution { namespace { static BOOST_ASIO_CONSTEXPR const asio_execution_set_value_fn::impl& set_value = asio_execution_set_value_fn::static_instance<>::instance; } // namespace #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename R, typename... Vs> struct can_set_value : integral_constant<bool, asio_execution_set_value_fn::call_traits<R, void(Vs...)>::overload != asio_execution_set_value_fn::ill_formed> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename R, typename... Vs> constexpr bool can_set_value_v = can_set_value<R, Vs...>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename R, typename... Vs> struct is_nothrow_set_value : integral_constant<bool, asio_execution_set_value_fn::call_traits<R, void(Vs...)>::is_noexcept> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename R, typename... Vs> constexpr bool is_nothrow_set_value_v = is_nothrow_set_value<R, Vs...>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename R, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void> struct can_set_value; template <typename R, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void> struct is_nothrow_set_value; template <typename R> struct can_set_value<R> : integral_constant<bool, asio_execution_set_value_fn::call_traits<R, void()>::overload != asio_execution_set_value_fn::ill_formed> { }; template <typename R> struct is_nothrow_set_value<R> : integral_constant<bool, asio_execution_set_value_fn::call_traits<R, void()>::is_noexcept> { }; #define BOOST_ASIO_PRIVATE_SET_VALUE_TRAITS_DEF(n) \ template <typename R, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ struct can_set_value<R, BOOST_ASIO_VARIADIC_TARGS(n)> : \ integral_constant<bool, \ asio_execution_set_value_fn::call_traits<R, \ void(BOOST_ASIO_VARIADIC_TARGS(n))>::overload != \ asio_execution_set_value_fn::ill_formed> \ { \ }; \ \ template <typename R, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ struct is_nothrow_set_value<R, BOOST_ASIO_VARIADIC_TARGS(n)> : \ integral_constant<bool, \ asio_execution_set_value_fn::call_traits<R, \ void(BOOST_ASIO_VARIADIC_TARGS(n))>::is_noexcept> \ { \ }; \ /**/ BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_SET_VALUE_TRAITS_DEF) #undef BOOST_ASIO_PRIVATE_SET_VALUE_TRAITS_DEF #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) } // namespace execution } // namespace asio } // namespace boost #endif // defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_SET_VALUE_HPP execution/blocking_adaptation.hpp 0000644 00000101362 15125530236 0013261 0 ustar 00 // // execution/blocking_adaptation.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_BLOCKING_ADAPTATION_HPP #define BOOST_ASIO_EXECUTION_BLOCKING_ADAPTATION_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/event.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/execute.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/scheduler.hpp> #include <boost/asio/execution/sender.hpp> #include <boost/asio/is_applicable_property.hpp> #include <boost/asio/prefer.hpp> #include <boost/asio/query.hpp> #include <boost/asio/require.hpp> #include <boost/asio/traits/prefer_member.hpp> #include <boost/asio/traits/query_free.hpp> #include <boost/asio/traits/query_member.hpp> #include <boost/asio/traits/query_static_constexpr_member.hpp> #include <boost/asio/traits/require_member.hpp> #include <boost/asio/traits/static_query.hpp> #include <boost/asio/traits/static_require.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if defined(GENERATING_DOCUMENTATION) namespace execution { /// A property to describe whether automatic adaptation of an executor is /// allowed in order to apply the blocking_adaptation_t::allowed_t property. struct blocking_adaptation_t { /// The blocking_adaptation_t property applies to executors, senders, and /// schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The top-level blocking_adaptation_t property cannot be required. static constexpr bool is_requirable = false; /// The top-level blocking_adaptation_t property cannot be preferred. static constexpr bool is_preferable = false; /// The type returned by queries against an @c any_executor. typedef blocking_adaptation_t polymorphic_query_result_type; /// A sub-property that indicates that automatic adaptation is not allowed. struct disallowed_t { /// The blocking_adaptation_t::disallowed_t property applies to executors, /// senders, and schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The blocking_adaptation_t::disallowed_t property can be required. static constexpr bool is_requirable = true; /// The blocking_adaptation_t::disallowed_t property can be preferred. static constexpr bool is_preferable = true; /// The type returned by queries against an @c any_executor. typedef blocking_adaptation_t polymorphic_query_result_type; /// Default constructor. constexpr disallowed_t(); /// Get the value associated with a property object. /** * @returns disallowed_t(); */ static constexpr blocking_adaptation_t value(); }; /// A sub-property that indicates that automatic adaptation is allowed. struct allowed_t { /// The blocking_adaptation_t::allowed_t property applies to executors, /// senders, and schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The blocking_adaptation_t::allowed_t property can be required. static constexpr bool is_requirable = true; /// The blocking_adaptation_t::allowed_t property can be preferred. static constexpr bool is_preferable = false; /// The type returned by queries against an @c any_executor. typedef blocking_adaptation_t polymorphic_query_result_type; /// Default constructor. constexpr allowed_t(); /// Get the value associated with a property object. /** * @returns allowed_t(); */ static constexpr blocking_adaptation_t value(); }; /// A special value used for accessing the blocking_adaptation_t::disallowed_t /// property. static constexpr disallowed_t disallowed; /// A special value used for accessing the blocking_adaptation_t::allowed_t /// property. static constexpr allowed_t allowed; /// Default constructor. constexpr blocking_adaptation_t(); /// Construct from a sub-property value. constexpr blocking_adaptation_t(disallowed_t); /// Construct from a sub-property value. constexpr blocking_adaptation_t(allowed_t); /// Compare property values for equality. friend constexpr bool operator==( const blocking_adaptation_t& a, const blocking_adaptation_t& b) noexcept; /// Compare property values for inequality. friend constexpr bool operator!=( const blocking_adaptation_t& a, const blocking_adaptation_t& b) noexcept; }; /// A special value used for accessing the blocking_adaptation_t property. constexpr blocking_adaptation_t blocking_adaptation; } // namespace execution #else // defined(GENERATING_DOCUMENTATION) namespace execution { namespace detail { namespace blocking_adaptation { template <int I> struct disallowed_t; template <int I> struct allowed_t; } // namespace blocking_adaptation template <int I = 0> struct blocking_adaptation_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); typedef blocking_adaptation_t polymorphic_query_result_type; typedef detail::blocking_adaptation::disallowed_t<I> disallowed_t; typedef detail::blocking_adaptation::allowed_t<I> allowed_t; BOOST_ASIO_CONSTEXPR blocking_adaptation_t() : value_(-1) { } BOOST_ASIO_CONSTEXPR blocking_adaptation_t(disallowed_t) : value_(0) { } BOOST_ASIO_CONSTEXPR blocking_adaptation_t(allowed_t) : value_(1) { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member< T, blocking_adaptation_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member< T, blocking_adaptation_t >::is_noexcept)) { return traits::query_static_constexpr_member< T, blocking_adaptation_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::static_query<T, disallowed_t>::result_type static_query( typename enable_if< !traits::query_static_constexpr_member< T, blocking_adaptation_t>::is_valid && !traits::query_member<T, blocking_adaptation_t>::is_valid && traits::static_query<T, disallowed_t>::is_valid >::type* = 0) BOOST_ASIO_NOEXCEPT { return traits::static_query<T, disallowed_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::static_query<T, allowed_t>::result_type static_query( typename enable_if< !traits::query_static_constexpr_member< T, blocking_adaptation_t>::is_valid && !traits::query_member<T, blocking_adaptation_t>::is_valid && !traits::static_query<T, disallowed_t>::is_valid && traits::static_query<T, allowed_t>::is_valid >::type* = 0) BOOST_ASIO_NOEXCEPT { return traits::static_query<T, allowed_t>::value(); } template <typename E, typename T = decltype(blocking_adaptation_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = blocking_adaptation_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) friend BOOST_ASIO_CONSTEXPR bool operator==( const blocking_adaptation_t& a, const blocking_adaptation_t& b) { return a.value_ == b.value_; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const blocking_adaptation_t& a, const blocking_adaptation_t& b) { return a.value_ != b.value_; } struct convertible_from_blocking_adaptation_t { BOOST_ASIO_CONSTEXPR convertible_from_blocking_adaptation_t( blocking_adaptation_t) { } }; template <typename Executor> friend BOOST_ASIO_CONSTEXPR blocking_adaptation_t query( const Executor& ex, convertible_from_blocking_adaptation_t, typename enable_if< can_query<const Executor&, disallowed_t>::value >::type* = 0) #if !defined(__clang__) // Clang crashes if noexcept is used here. #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified. BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, blocking_adaptation_t<>::disallowed_t>::value)) #else // defined(BOOST_ASIO_MSVC) BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, disallowed_t>::value)) #endif // defined(BOOST_ASIO_MSVC) #endif // !defined(__clang__) { return boost::asio::query(ex, disallowed_t()); } template <typename Executor> friend BOOST_ASIO_CONSTEXPR blocking_adaptation_t query( const Executor& ex, convertible_from_blocking_adaptation_t, typename enable_if< !can_query<const Executor&, disallowed_t>::value && can_query<const Executor&, allowed_t>::value >::type* = 0) #if !defined(__clang__) // Clang crashes if noexcept is used here. #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified. BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, blocking_adaptation_t<>::allowed_t>::value)) #else // defined(BOOST_ASIO_MSVC) BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, allowed_t>::value)) #endif // defined(BOOST_ASIO_MSVC) #endif // !defined(__clang__) { return boost::asio::query(ex, allowed_t()); } BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(disallowed_t, disallowed); BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(allowed_t, allowed); #if !defined(BOOST_ASIO_HAS_CONSTEXPR) static const blocking_adaptation_t instance; #endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) private: int value_; }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T blocking_adaptation_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if !defined(BOOST_ASIO_HAS_CONSTEXPR) template <int I> const blocking_adaptation_t<I> blocking_adaptation_t<I>::instance; #endif template <int I> const typename blocking_adaptation_t<I>::disallowed_t blocking_adaptation_t<I>::disallowed; template <int I> const typename blocking_adaptation_t<I>::allowed_t blocking_adaptation_t<I>::allowed; namespace blocking_adaptation { template <int I = 0> struct disallowed_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); typedef blocking_adaptation_t<I> polymorphic_query_result_type; BOOST_ASIO_CONSTEXPR disallowed_t() { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, disallowed_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, disallowed_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, disallowed_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR disallowed_t static_query( typename enable_if< !traits::query_static_constexpr_member<T, disallowed_t>::is_valid && !traits::query_member<T, disallowed_t>::is_valid && !traits::query_free<T, disallowed_t>::is_valid && !can_query<T, allowed_t<I> >::value >::type* = 0) BOOST_ASIO_NOEXCEPT { return disallowed_t(); } template <typename E, typename T = decltype(disallowed_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = disallowed_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) static BOOST_ASIO_CONSTEXPR blocking_adaptation_t<I> value() { return disallowed_t(); } friend BOOST_ASIO_CONSTEXPR bool operator==( const disallowed_t&, const disallowed_t&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const disallowed_t&, const disallowed_t&) { return false; } }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T disallowed_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename Executor> class adapter { public: adapter(int, const Executor& e) BOOST_ASIO_NOEXCEPT : executor_(e) { } adapter(const adapter& other) BOOST_ASIO_NOEXCEPT : executor_(other.executor_) { } #if defined(BOOST_ASIO_HAS_MOVE) adapter(adapter&& other) BOOST_ASIO_NOEXCEPT : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)) { } #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) template <int I> static BOOST_ASIO_CONSTEXPR allowed_t<I> query( blocking_adaptation_t<I>) BOOST_ASIO_NOEXCEPT { return allowed_t<I>(); } template <int I> static BOOST_ASIO_CONSTEXPR allowed_t<I> query( allowed_t<I>) BOOST_ASIO_NOEXCEPT { return allowed_t<I>(); } template <int I> static BOOST_ASIO_CONSTEXPR allowed_t<I> query( disallowed_t<I>) BOOST_ASIO_NOEXCEPT { return allowed_t<I>(); } template <typename Property> typename enable_if< can_query<const Executor&, Property>::value, typename query_result<const Executor&, Property>::type >::type query(const Property& p) const BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, Property>::value)) { return boost::asio::query(executor_, p); } template <int I> Executor require(disallowed_t<I>) const BOOST_ASIO_NOEXCEPT { return executor_; } template <typename Property> typename enable_if< can_require<const Executor&, Property>::value, adapter<typename decay< typename require_result<const Executor&, Property>::type >::type> >::type require(const Property& p) const BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_require<const Executor&, Property>::value)) { return adapter<typename decay< typename require_result<const Executor&, Property>::type >::type>(0, boost::asio::require(executor_, p)); } template <typename Property> typename enable_if< can_prefer<const Executor&, Property>::value, adapter<typename decay< typename prefer_result<const Executor&, Property>::type >::type> >::type prefer(const Property& p) const BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_prefer<const Executor&, Property>::value)) { return adapter<typename decay< typename prefer_result<const Executor&, Property>::type >::type>(0, boost::asio::prefer(executor_, p)); } template <typename Function> typename enable_if< execution::can_execute<const Executor&, Function>::value >::type execute(BOOST_ASIO_MOVE_ARG(Function) f) const { execution::execute(executor_, BOOST_ASIO_MOVE_CAST(Function)(f)); } friend bool operator==(const adapter& a, const adapter& b) BOOST_ASIO_NOEXCEPT { return a.executor_ == b.executor_; } friend bool operator!=(const adapter& a, const adapter& b) BOOST_ASIO_NOEXCEPT { return a.executor_ != b.executor_; } private: Executor executor_; }; template <int I = 0> struct allowed_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); typedef blocking_adaptation_t<I> polymorphic_query_result_type; BOOST_ASIO_CONSTEXPR allowed_t() { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, allowed_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, allowed_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, allowed_t>::value(); } template <typename E, typename T = decltype(allowed_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = allowed_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) static BOOST_ASIO_CONSTEXPR blocking_adaptation_t<I> value() { return allowed_t(); } friend BOOST_ASIO_CONSTEXPR bool operator==( const allowed_t&, const allowed_t&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const allowed_t&, const allowed_t&) { return false; } template <typename Executor> friend adapter<Executor> require( const Executor& e, const allowed_t&, typename enable_if< is_executor<Executor>::value >::type* = 0) { return adapter<Executor>(0, e); } }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T allowed_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename Function> class blocking_execute_state { public: template <typename F> blocking_execute_state(BOOST_ASIO_MOVE_ARG(F) f) : func_(BOOST_ASIO_MOVE_CAST(F)(f)), is_complete_(false) { } template <typename Executor> void execute_and_wait(BOOST_ASIO_MOVE_ARG(Executor) ex) { handler h = { this }; execution::execute(BOOST_ASIO_MOVE_CAST(Executor)(ex), h); boost::asio::detail::mutex::scoped_lock lock(mutex_); while (!is_complete_) event_.wait(lock); } struct cleanup { ~cleanup() { boost::asio::detail::mutex::scoped_lock lock(state_->mutex_); state_->is_complete_ = true; state_->event_.unlock_and_signal_one_for_destruction(lock); } blocking_execute_state* state_; }; struct handler { void operator()() { cleanup c = { state_ }; state_->func_(); } blocking_execute_state* state_; }; Function func_; boost::asio::detail::mutex mutex_; boost::asio::detail::event event_; bool is_complete_; }; template <typename Executor, typename Function> void blocking_execute( BOOST_ASIO_MOVE_ARG(Executor) ex, BOOST_ASIO_MOVE_ARG(Function) func) { typedef typename decay<Function>::type func_t; blocking_execute_state<func_t> state(BOOST_ASIO_MOVE_CAST(Function)(func)); state.execute_and_wait(ex); } } // namespace blocking_adaptation } // namespace detail typedef detail::blocking_adaptation_t<> blocking_adaptation_t; #if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) constexpr blocking_adaptation_t blocking_adaptation; #else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) namespace { static const blocking_adaptation_t& blocking_adaptation = blocking_adaptation_t::instance; } #endif } // namespace execution #if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> struct is_applicable_property<T, execution::blocking_adaptation_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; template <typename T> struct is_applicable_property<T, execution::blocking_adaptation_t::disallowed_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; template <typename T> struct is_applicable_property<T, execution::blocking_adaptation_t::allowed_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; #endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) template <typename T> struct query_free_default<T, execution::blocking_adaptation_t, typename enable_if< can_query<T, execution::blocking_adaptation_t::disallowed_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<T, execution::blocking_adaptation_t::disallowed_t>::value)); typedef execution::blocking_adaptation_t result_type; }; template <typename T> struct query_free_default<T, execution::blocking_adaptation_t, typename enable_if< !can_query<T, execution::blocking_adaptation_t::disallowed_t>::value && can_query<T, execution::blocking_adaptation_t::allowed_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<T, execution::blocking_adaptation_t::allowed_t>::value)); typedef execution::blocking_adaptation_t result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> struct static_query<T, execution::blocking_adaptation_t, typename enable_if< traits::query_static_constexpr_member<T, execution::blocking_adaptation_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::blocking_adaptation_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::blocking_adaptation_t>::value(); } }; template <typename T> struct static_query<T, execution::blocking_adaptation_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::blocking_adaptation_t>::is_valid && !traits::query_member<T, execution::blocking_adaptation_t>::is_valid && traits::static_query<T, execution::blocking_adaptation_t::disallowed_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::static_query<T, execution::blocking_adaptation_t::disallowed_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::static_query<T, execution::blocking_adaptation_t::disallowed_t>::value(); } }; template <typename T> struct static_query<T, execution::blocking_adaptation_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::blocking_adaptation_t>::is_valid && !traits::query_member<T, execution::blocking_adaptation_t>::is_valid && !traits::static_query<T, execution::blocking_adaptation_t::disallowed_t>::is_valid && traits::static_query<T, execution::blocking_adaptation_t::allowed_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::static_query<T, execution::blocking_adaptation_t::allowed_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::static_query<T, execution::blocking_adaptation_t::allowed_t>::value(); } }; template <typename T> struct static_query<T, execution::blocking_adaptation_t::disallowed_t, typename enable_if< traits::query_static_constexpr_member<T, execution::blocking_adaptation_t::disallowed_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::blocking_adaptation_t::disallowed_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::blocking_adaptation_t::disallowed_t>::value(); } }; template <typename T> struct static_query<T, execution::blocking_adaptation_t::disallowed_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::blocking_adaptation_t::disallowed_t>::is_valid && !traits::query_member<T, execution::blocking_adaptation_t::disallowed_t>::is_valid && !traits::query_free<T, execution::blocking_adaptation_t::disallowed_t>::is_valid && !can_query<T, execution::blocking_adaptation_t::allowed_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef execution::blocking_adaptation_t::disallowed_t result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return result_type(); } }; template <typename T> struct static_query<T, execution::blocking_adaptation_t::allowed_t, typename enable_if< traits::query_static_constexpr_member<T, execution::blocking_adaptation_t::allowed_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::blocking_adaptation_t::allowed_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::blocking_adaptation_t::allowed_t>::value(); } }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) template <typename T> struct static_require<T, execution::blocking_adaptation_t::disallowed_t, typename enable_if< static_query<T, execution::blocking_adaptation_t::disallowed_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = (is_same<typename static_query<T, execution::blocking_adaptation_t::disallowed_t>::result_type, execution::blocking_adaptation_t::disallowed_t>::value)); }; template <typename T> struct static_require<T, execution::blocking_adaptation_t::allowed_t, typename enable_if< static_query<T, execution::blocking_adaptation_t::allowed_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = (is_same<typename static_query<T, execution::blocking_adaptation_t::allowed_t>::result_type, execution::blocking_adaptation_t::allowed_t>::value)); }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) template <typename T> struct require_free_default<T, execution::blocking_adaptation_t::allowed_t, typename enable_if< is_same<T, typename decay<T>::type>::value && execution::is_executor<T>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef execution::detail::blocking_adaptation::adapter<T> result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) template <typename Executor> struct equality_comparable< execution::detail::blocking_adaptation::adapter<Executor> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) template <typename Executor, typename Function> struct execute_member< execution::detail::blocking_adaptation::adapter<Executor>, Function> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) template <typename Executor, int I> struct query_static_constexpr_member< execution::detail::blocking_adaptation::adapter<Executor>, execution::detail::blocking_adaptation_t<I> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef execution::blocking_adaptation_t::allowed_t result_type; static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT { return result_type(); } }; template <typename Executor, int I> struct query_static_constexpr_member< execution::detail::blocking_adaptation::adapter<Executor>, execution::detail::blocking_adaptation::allowed_t<I> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef execution::blocking_adaptation_t::allowed_t result_type; static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT { return result_type(); } }; template <typename Executor, int I> struct query_static_constexpr_member< execution::detail::blocking_adaptation::adapter<Executor>, execution::detail::blocking_adaptation::disallowed_t<I> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef execution::blocking_adaptation_t::allowed_t result_type; static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT { return result_type(); } }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) template <typename Executor, typename Property> struct query_member< execution::detail::blocking_adaptation::adapter<Executor>, Property, typename enable_if< can_query<const Executor&, Property>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<Executor, Property>::value)); typedef typename query_result<Executor, Property>::type result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) template <typename Executor, int I> struct require_member< execution::detail::blocking_adaptation::adapter<Executor>, execution::detail::blocking_adaptation::disallowed_t<I> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef Executor result_type; }; template <typename Executor, typename Property> struct require_member< execution::detail::blocking_adaptation::adapter<Executor>, Property, typename enable_if< can_require<const Executor&, Property>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_require<Executor, Property>::value)); typedef execution::detail::blocking_adaptation::adapter<typename decay< typename require_result<Executor, Property>::type >::type> result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) template <typename Executor, typename Property> struct prefer_member< execution::detail::blocking_adaptation::adapter<Executor>, Property, typename enable_if< can_prefer<const Executor&, Property>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_prefer<Executor, Property>::value)); typedef execution::detail::blocking_adaptation::adapter<typename decay< typename prefer_result<Executor, Property>::type >::type> result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) } // namespace traits #endif // defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_BLOCKING_ADAPTATION_HPP execution/set_error.hpp 0000644 00000016307 15125530236 0011275 0 ustar 00 // // execution/set_error.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_SET_ERROR_HPP #define BOOST_ASIO_EXECUTION_SET_ERROR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/traits/set_error_member.hpp> #include <boost/asio/traits/set_error_free.hpp> #include <boost/asio/detail/push_options.hpp> #if defined(GENERATING_DOCUMENTATION) namespace boost { namespace asio { namespace execution { /// A customisation point that delivers an error notification to a receiver. /** * The name <tt>execution::set_error</tt> denotes a customisation point object. * The expression <tt>execution::set_error(R, E)</tt> for some subexpressions * <tt>R</tt> and <tt>E</tt> are expression-equivalent to: * * @li <tt>R.set_error(E)</tt>, if that expression is valid. If the function * selected does not send the error <tt>E</tt> to the receiver <tt>R</tt>'s * error channel, the program is ill-formed with no diagnostic required. * * @li Otherwise, <tt>set_error(R, E)</tt>, if that expression is valid, with * overload resolution performed in a context that includes the declaration * <tt>void set_error();</tt> and that does not include a declaration of * <tt>execution::set_error</tt>. If the function selected by overload * resolution does not send the error <tt>E</tt> to the receiver <tt>R</tt>'s * error channel, the program is ill-formed with no diagnostic required. * * @li Otherwise, <tt>execution::set_error(R, E)</tt> is ill-formed. */ inline constexpr unspecified set_error = unspecified; /// A type trait that determines whether a @c set_error expression is /// well-formed. /** * Class template @c can_set_error is a trait that is derived from * @c true_type if the expression <tt>execution::set_error(std::declval<R>(), * std::declval<E>())</tt> is well formed; otherwise @c false_type. */ template <typename R, typename E> struct can_set_error : integral_constant<bool, automatically_determined> { }; } // namespace execution } // namespace asio } // namespace boost #else // defined(GENERATING_DOCUMENTATION) namespace asio_execution_set_error_fn { using boost::asio::decay; using boost::asio::declval; using boost::asio::enable_if; using boost::asio::traits::set_error_free; using boost::asio::traits::set_error_member; void set_error(); enum overload_type { call_member, call_free, ill_formed }; template <typename R, typename E, typename = void> struct call_traits { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; template <typename R, typename E> struct call_traits<R, void(E), typename enable_if< ( set_error_member<R, E>::is_valid ) >::type> : set_error_member<R, E> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); }; template <typename R, typename E> struct call_traits<R, void(E), typename enable_if< ( !set_error_member<R, E>::is_valid && set_error_free<R, E>::is_valid ) >::type> : set_error_free<R, E> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); }; struct impl { #if defined(BOOST_ASIO_HAS_MOVE) template <typename R, typename E> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R, void(E)>::overload == call_member, typename call_traits<R, void(E)>::result_type >::type operator()(R&& r, E&& e) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R, void(E)>::is_noexcept)) { return BOOST_ASIO_MOVE_CAST(R)(r).set_error(BOOST_ASIO_MOVE_CAST(E)(e)); } template <typename R, typename E> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R, void(E)>::overload == call_free, typename call_traits<R, void(E)>::result_type >::type operator()(R&& r, E&& e) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R, void(E)>::is_noexcept)) { return set_error(BOOST_ASIO_MOVE_CAST(R)(r), BOOST_ASIO_MOVE_CAST(E)(e)); } #else // defined(BOOST_ASIO_HAS_MOVE) template <typename R, typename E> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R&, void(const E&)>::overload == call_member, typename call_traits<R&, void(const E&)>::result_type >::type operator()(R& r, const E& e) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R&, void(const E&)>::is_noexcept)) { return r.set_error(e); } template <typename R, typename E> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const R&, void(const E&)>::overload == call_member, typename call_traits<const R&, void(const E&)>::result_type >::type operator()(const R& r, const E& e) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const R&, void(const E&)>::is_noexcept)) { return r.set_error(e); } template <typename R, typename E> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<R&, void(const E&)>::overload == call_free, typename call_traits<R&, void(const E&)>::result_type >::type operator()(R& r, const E& e) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<R&, void(const E&)>::is_noexcept)) { return set_error(r, e); } template <typename R, typename E> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<const R&, void(const E&)>::overload == call_free, typename call_traits<const R&, void(const E&)>::result_type >::type operator()(const R& r, const E& e) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<const R&, void(const E&)>::is_noexcept)) { return set_error(r, e); } #endif // defined(BOOST_ASIO_HAS_MOVE) }; template <typename T = impl> struct static_instance { static const T instance; }; template <typename T> const T static_instance<T>::instance = {}; } // namespace asio_execution_set_error_fn namespace boost { namespace asio { namespace execution { namespace { static BOOST_ASIO_CONSTEXPR const asio_execution_set_error_fn::impl& set_error = asio_execution_set_error_fn::static_instance<>::instance; } // namespace template <typename R, typename E> struct can_set_error : integral_constant<bool, asio_execution_set_error_fn::call_traits<R, void(E)>::overload != asio_execution_set_error_fn::ill_formed> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename R, typename E> constexpr bool can_set_error_v = can_set_error<R, E>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename R, typename E> struct is_nothrow_set_error : integral_constant<bool, asio_execution_set_error_fn::call_traits<R, void(E)>::is_noexcept> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename R, typename E> constexpr bool is_nothrow_set_error_v = is_nothrow_set_error<R, E>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) } // namespace execution } // namespace asio } // namespace boost #endif // defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_SET_ERROR_HPP execution/context.hpp 0000644 00000012706 15125530236 0010754 0 ustar 00 // // execution/context.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_CONTEXT2_HPP #define BOOST_ASIO_EXECUTION_CONTEXT2_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/scheduler.hpp> #include <boost/asio/execution/sender.hpp> #include <boost/asio/is_applicable_property.hpp> #include <boost/asio/traits/query_static_constexpr_member.hpp> #include <boost/asio/traits/static_query.hpp> #if defined(BOOST_ASIO_HAS_STD_ANY) # include <any> #endif // defined(BOOST_ASIO_HAS_STD_ANY) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if defined(GENERATING_DOCUMENTATION) namespace execution { /// A property that is used to obtain the execution context that is associated /// with an executor. struct context_t { /// The context_t property applies to executors, senders, and schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The context_t property cannot be required. static constexpr bool is_requirable = false; /// The context_t property cannot be preferred. static constexpr bool is_preferable = false; /// The type returned by queries against an @c any_executor. typedef std::any polymorphic_query_result_type; }; /// A special value used for accessing the context_t property. constexpr context_t context; } // namespace execution #else // defined(GENERATING_DOCUMENTATION) namespace execution { namespace detail { template <int I = 0> struct context_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); #if defined(BOOST_ASIO_HAS_STD_ANY) typedef std::any polymorphic_query_result_type; #endif // defined(BOOST_ASIO_HAS_STD_ANY) BOOST_ASIO_CONSTEXPR context_t() { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, context_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, context_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, context_t>::value(); } template <typename E, typename T = decltype(context_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = context_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if !defined(BOOST_ASIO_HAS_CONSTEXPR) static const context_t instance; #endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T context_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if !defined(BOOST_ASIO_HAS_CONSTEXPR) template <int I> const context_t<I> context_t<I>::instance; #endif } // namespace detail typedef detail::context_t<> context_t; #if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) constexpr context_t context; #else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) namespace { static const context_t& context = context_t::instance; } #endif } // namespace execution #if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> struct is_applicable_property<T, execution::context_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; #endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> struct static_query<T, execution::context_t, typename enable_if< traits::query_static_constexpr_member<T, execution::context_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::context_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::context_t>::value(); } }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) } // namespace traits #endif // defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_CONTEXT2_HPP execution/bulk_execute.hpp 0000644 00000031254 15125530236 0011746 0 ustar 00 // // execution/bulk_execute.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_BULK_EXECUTE_HPP #define BOOST_ASIO_EXECUTION_BULK_EXECUTE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/bulk_guarantee.hpp> #include <boost/asio/execution/detail/bulk_sender.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/sender.hpp> #include <boost/asio/traits/bulk_execute_member.hpp> #include <boost/asio/traits/bulk_execute_free.hpp> #include <boost/asio/detail/push_options.hpp> #if defined(GENERATING_DOCUMENTATION) namespace boost { namespace asio { namespace execution { /// A customisation point that creates a bulk sender. /** * The name <tt>execution::bulk_execute</tt> denotes a customisation point * object. If <tt>is_convertible_v<N, size_t></tt> is true, then the expression * <tt>execution::bulk_execute(S, F, N)</tt> for some subexpressions * <tt>S</tt>, <tt>F</tt>, and <tt>N</tt> is expression-equivalent to: * * @li <tt>S.bulk_execute(F, N)</tt>, if that expression is valid. If the * function selected does not execute <tt>N</tt> invocations of the function * object <tt>F</tt> on the executor <tt>S</tt> in bulk with forward progress * guarantee <tt>boost::asio::query(S, execution::bulk_guarantee)</tt>, and * the result of that function does not model <tt>sender<void></tt>, the * program is ill-formed with no diagnostic required. * * @li Otherwise, <tt>bulk_execute(S, F, N)</tt>, if that expression is valid, * with overload resolution performed in a context that includes the * declaration <tt>void bulk_execute();</tt> and that does not include a * declaration of <tt>execution::bulk_execute</tt>. If the function selected * by overload resolution does not execute <tt>N</tt> invocations of the * function object <tt>F</tt> on the executor <tt>S</tt> in bulk with forward * progress guarantee <tt>boost::asio::query(E, * execution::bulk_guarantee)</tt>, and the result of that function does not * model <tt>sender<void></tt>, the program is ill-formed with no diagnostic * required. * * @li Otherwise, if the types <tt>F</tt> and * <tt>executor_index_t<remove_cvref_t<S>></tt> model <tt>invocable</tt> and * if <tt>boost::asio::query(S, execution::bulk_guarantee)</tt> equals * <tt>execution::bulk_guarantee.unsequenced</tt>, then * * - Evaluates <tt>DECAY_COPY(std::forward<decltype(F)>(F))</tt> on the * calling thread to create a function object <tt>cf</tt>. [Note: * Additional copies of <tt>cf</tt> may subsequently be created. --end * note.] * * - For each value of <tt>i</tt> in <tt>N</tt>, <tt>cf(i)</tt> (or copy of * <tt>cf</tt>)) will be invoked at most once by an execution agent that is * unique for each value of <tt>i</tt>. * * - May block pending completion of one or more invocations of <tt>cf</tt>. * * - Synchronizes with (C++Std [intro.multithread]) the invocations of * <tt>cf</tt>. * * @li Otherwise, <tt>execution::bulk_execute(S, F, N)</tt> is ill-formed. */ inline constexpr unspecified bulk_execute = unspecified; /// A type trait that determines whether a @c bulk_execute expression is /// well-formed. /** * Class template @c can_bulk_execute is a trait that is derived from @c * true_type if the expression <tt>execution::bulk_execute(std::declval<S>(), * std::declval<F>(), std::declval<N>)</tt> is well formed; otherwise @c * false_type. */ template <typename S, typename F, typename N> struct can_bulk_execute : integral_constant<bool, automatically_determined> { }; } // namespace execution } // namespace asio } // namespace boost #else // defined(GENERATING_DOCUMENTATION) namespace asio_execution_bulk_execute_fn { using boost::asio::declval; using boost::asio::enable_if; using boost::asio::execution::bulk_guarantee_t; using boost::asio::execution::detail::bulk_sender; using boost::asio::execution::executor_index; using boost::asio::execution::is_sender; using boost::asio::is_convertible; using boost::asio::is_same; using boost::asio::remove_cvref; using boost::asio::result_of; using boost::asio::traits::bulk_execute_free; using boost::asio::traits::bulk_execute_member; using boost::asio::traits::static_require; void bulk_execute(); enum overload_type { call_member, call_free, adapter, ill_formed }; template <typename S, typename Args, typename = void> struct call_traits { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; template <typename S, typename F, typename N> struct call_traits<S, void(F, N), typename enable_if< ( is_convertible<N, std::size_t>::value && bulk_execute_member<S, F, N>::is_valid && is_sender< typename bulk_execute_member<S, F, N>::result_type >::value ) >::type> : bulk_execute_member<S, F, N> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); }; template <typename S, typename F, typename N> struct call_traits<S, void(F, N), typename enable_if< ( is_convertible<N, std::size_t>::value && !bulk_execute_member<S, F, N>::is_valid && bulk_execute_free<S, F, N>::is_valid && is_sender< typename bulk_execute_free<S, F, N>::result_type >::value ) >::type> : bulk_execute_free<S, F, N> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); }; template <typename S, typename F, typename N> struct call_traits<S, void(F, N), typename enable_if< ( is_convertible<N, std::size_t>::value && !bulk_execute_member<S, F, N>::is_valid && !bulk_execute_free<S, F, N>::is_valid && is_sender<S>::value && is_same< typename result_of< F(typename executor_index<typename remove_cvref<S>::type>::type) >::type, typename result_of< F(typename executor_index<typename remove_cvref<S>::type>::type) >::type >::value && static_require<S, bulk_guarantee_t::unsequenced_t>::is_valid ) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef bulk_sender<S, F, N> result_type; }; struct impl { #if defined(BOOST_ASIO_HAS_MOVE) template <typename S, typename F, typename N> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S, void(F, N)>::overload == call_member, typename call_traits<S, void(F, N)>::result_type >::type operator()(S&& s, F&& f, N&& n) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S, void(F, N)>::is_noexcept)) { return BOOST_ASIO_MOVE_CAST(S)(s).bulk_execute( BOOST_ASIO_MOVE_CAST(F)(f), BOOST_ASIO_MOVE_CAST(N)(n)); } template <typename S, typename F, typename N> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S, void(F, N)>::overload == call_free, typename call_traits<S, void(F, N)>::result_type >::type operator()(S&& s, F&& f, N&& n) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S, void(F, N)>::is_noexcept)) { return bulk_execute(BOOST_ASIO_MOVE_CAST(S)(s), BOOST_ASIO_MOVE_CAST(F)(f), BOOST_ASIO_MOVE_CAST(N)(n)); } template <typename S, typename F, typename N> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S, void(F, N)>::overload == adapter, typename call_traits<S, void(F, N)>::result_type >::type operator()(S&& s, F&& f, N&& n) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S, void(F, N)>::is_noexcept)) { return typename call_traits<S, void(F, N)>::result_type( BOOST_ASIO_MOVE_CAST(S)(s), BOOST_ASIO_MOVE_CAST(F)(f), BOOST_ASIO_MOVE_CAST(N)(n)); } #else // defined(BOOST_ASIO_HAS_MOVE) template <typename S, typename F, typename N> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S, void(const F&, const N&)>::overload == call_member, typename call_traits<S, void(const F&, const N&)>::result_type >::type operator()(S& s, const F& f, const N& n) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S, void(const F&, const N&)>::is_noexcept)) { return s.bulk_execute(BOOST_ASIO_MOVE_CAST(F)(f), BOOST_ASIO_MOVE_CAST(N)(n)); } template <typename S, typename F, typename N> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S, void(const F&, const N&)>::overload == call_member, typename call_traits<S, void(const F&, const N&)>::result_type >::type operator()(const S& s, const F& f, const N& n) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S, void(const F&, const N&)>::is_noexcept)) { return s.bulk_execute(BOOST_ASIO_MOVE_CAST(F)(f), BOOST_ASIO_MOVE_CAST(N)(n)); } template <typename S, typename F, typename N> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S, void(const F&, const N&)>::overload == call_free, typename call_traits<S, void(const F&, const N&)>::result_type >::type operator()(S& s, const F& f, const N& n) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S, void(const F&, const N&)>::is_noexcept)) { return bulk_execute(s, BOOST_ASIO_MOVE_CAST(F)(f), BOOST_ASIO_MOVE_CAST(N)(n)); } template <typename S, typename F, typename N> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S, void(const F&, const N&)>::overload == call_free, typename call_traits<S, void(const F&, const N&)>::result_type >::type operator()(const S& s, const F& f, const N& n) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S, void(const F&, const N&)>::is_noexcept)) { return bulk_execute(s, BOOST_ASIO_MOVE_CAST(F)(f), BOOST_ASIO_MOVE_CAST(N)(n)); } template <typename S, typename F, typename N> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S, void(const F&, const N&)>::overload == adapter, typename call_traits<S, void(const F&, const N&)>::result_type >::type operator()(S& s, const F& f, const N& n) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S, void(const F&, const N&)>::is_noexcept)) { return typename call_traits<S, void(const F&, const N&)>::result_type( s, BOOST_ASIO_MOVE_CAST(F)(f), BOOST_ASIO_MOVE_CAST(N)(n)); } template <typename S, typename F, typename N> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<S, void(const F&, const N&)>::overload == adapter, typename call_traits<S, void(const F&, const N&)>::result_type >::type operator()(const S& s, const F& f, const N& n) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<S, void(const F&, const N&)>::is_noexcept)) { return typename call_traits<S, void(const F&, const N&)>::result_type( s, BOOST_ASIO_MOVE_CAST(F)(f), BOOST_ASIO_MOVE_CAST(N)(n)); } #endif // defined(BOOST_ASIO_HAS_MOVE) }; template <typename T = impl> struct static_instance { static const T instance; }; template <typename T> const T static_instance<T>::instance = {}; } // namespace asio_execution_bulk_execute_fn namespace boost { namespace asio { namespace execution { namespace { static BOOST_ASIO_CONSTEXPR const asio_execution_bulk_execute_fn::impl& bulk_execute = asio_execution_bulk_execute_fn::static_instance<>::instance; } // namespace template <typename S, typename F, typename N> struct can_bulk_execute : integral_constant<bool, asio_execution_bulk_execute_fn::call_traits<S, void(F, N)>::overload != asio_execution_bulk_execute_fn::ill_formed> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename S, typename F, typename N> constexpr bool can_bulk_execute_v = can_bulk_execute<S, F, N>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename S, typename F, typename N> struct is_nothrow_bulk_execute : integral_constant<bool, asio_execution_bulk_execute_fn::call_traits<S, void(F, N)>::is_noexcept> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename S, typename F, typename N> constexpr bool is_nothrow_bulk_execute_v = is_nothrow_bulk_execute<S, F, N>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename S, typename F, typename N> struct bulk_execute_result { typedef typename asio_execution_bulk_execute_fn::call_traits< S, void(F, N)>::result_type type; }; } // namespace execution } // namespace asio } // namespace boost #endif // defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_BULK_EXECUTE_HPP execution/detail/void_receiver.hpp 0000644 00000004523 15125530236 0013355 0 ustar 00 // // execution/detail/void_receiver.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_DETAIL_VOID_RECEIVER_HPP #define BOOST_ASIO_EXECUTION_DETAIL_VOID_RECEIVER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/traits/set_done_member.hpp> #include <boost/asio/traits/set_error_member.hpp> #include <boost/asio/traits/set_value_member.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace execution { namespace detail { struct void_receiver { void set_value() BOOST_ASIO_NOEXCEPT { } template <typename E> void set_error(BOOST_ASIO_MOVE_ARG(E)) BOOST_ASIO_NOEXCEPT { } void set_done() BOOST_ASIO_NOEXCEPT { } }; } // namespace detail } // namespace execution namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) template <> struct set_value_member<boost::asio::execution::detail::void_receiver, void()> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) template <typename E> struct set_error_member<boost::asio::execution::detail::void_receiver, E> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) template <> struct set_done_member<boost::asio::execution::detail::void_receiver> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_DETAIL_VOID_RECEIVER_HPP execution/detail/submit_receiver.hpp 0000644 00000016454 15125530236 0013725 0 ustar 00 // // execution/detail/submit_receiver.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_DETAIL_SUBMIT_RECEIVER_HPP #define BOOST_ASIO_EXECUTION_DETAIL_SUBMIT_RECEIVER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/variadic_templates.hpp> #include <boost/asio/execution/connect.hpp> #include <boost/asio/execution/receiver.hpp> #include <boost/asio/execution/set_done.hpp> #include <boost/asio/execution/set_error.hpp> #include <boost/asio/execution/set_value.hpp> #include <boost/asio/traits/set_done_member.hpp> #include <boost/asio/traits/set_error_member.hpp> #include <boost/asio/traits/set_value_member.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace execution { namespace detail { template <typename Sender, typename Receiver> struct submit_receiver; template <typename Sender, typename Receiver> struct submit_receiver_wrapper { submit_receiver<Sender, Receiver>* p_; explicit submit_receiver_wrapper(submit_receiver<Sender, Receiver>* p) : p_(p) { } #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename... Args> typename enable_if<is_receiver_of<Receiver, Args...>::value>::type set_value(BOOST_ASIO_MOVE_ARG(Args)... args) BOOST_ASIO_RVALUE_REF_QUAL BOOST_ASIO_NOEXCEPT_IF((is_nothrow_receiver_of<Receiver, Args...>::value)) { execution::set_value( BOOST_ASIO_MOVE_OR_LVALUE( typename remove_cvref<Receiver>::type)(p_->r_), BOOST_ASIO_MOVE_CAST(Args)(args)...); delete p_; } #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) void set_value() BOOST_ASIO_RVALUE_REF_QUAL BOOST_ASIO_NOEXCEPT_IF((is_nothrow_receiver_of<Receiver>::value)) { execution::set_value( BOOST_ASIO_MOVE_OR_LVALUE( typename remove_cvref<Receiver>::type)(p_->r_)); delete p_; } #define BOOST_ASIO_PRIVATE_SUBMIT_RECEIVER_SET_VALUE_DEF(n) \ template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ typename enable_if<is_receiver_of<Receiver, \ BOOST_ASIO_VARIADIC_TARGS(n)>::value>::type \ set_value(BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) BOOST_ASIO_RVALUE_REF_QUAL \ BOOST_ASIO_NOEXCEPT_IF((is_nothrow_receiver_of< \ Receiver, BOOST_ASIO_VARIADIC_TARGS(n)>::value)) \ { \ execution::set_value( \ BOOST_ASIO_MOVE_OR_LVALUE( \ typename remove_cvref<Receiver>::type)(p_->r_), \ BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ delete p_; \ } \ /**/ BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_SUBMIT_RECEIVER_SET_VALUE_DEF) #undef BOOST_ASIO_PRIVATE_SUBMIT_RECEIVER_SET_VALUE_DEF #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename E> void set_error(BOOST_ASIO_MOVE_ARG(E) e) BOOST_ASIO_RVALUE_REF_QUAL BOOST_ASIO_NOEXCEPT { execution::set_error( BOOST_ASIO_MOVE_OR_LVALUE( typename remove_cvref<Receiver>::type)(p_->r_), BOOST_ASIO_MOVE_CAST(E)(e)); delete p_; } void set_done() BOOST_ASIO_RVALUE_REF_QUAL BOOST_ASIO_NOEXCEPT { execution::set_done( BOOST_ASIO_MOVE_OR_LVALUE( typename remove_cvref<Receiver>::type)(p_->r_)); delete p_; } }; template <typename Sender, typename Receiver> struct submit_receiver { typename remove_cvref<Receiver>::type r_; #if defined(BOOST_ASIO_HAS_MOVE) typename connect_result<Sender, submit_receiver_wrapper<Sender, Receiver> >::type state_; #else // defined(BOOST_ASIO_HAS_MOVE) typename connect_result<Sender, const submit_receiver_wrapper<Sender, Receiver>& >::type state_; #endif // defined(BOOST_ASIO_HAS_MOVE) #if defined(BOOST_ASIO_HAS_MOVE) template <typename S, typename R> explicit submit_receiver(BOOST_ASIO_MOVE_ARG(S) s, BOOST_ASIO_MOVE_ARG(R) r) : r_(BOOST_ASIO_MOVE_CAST(R)(r)), state_(execution::connect(BOOST_ASIO_MOVE_CAST(S)(s), submit_receiver_wrapper<Sender, Receiver>(this))) { } #else // defined(BOOST_ASIO_HAS_MOVE) explicit submit_receiver(Sender s, Receiver r) : r_(r), state_(execution::connect(s, submit_receiver_wrapper<Sender, Receiver>(this))) { } #endif // defined(BOOST_ASIO_HAS_MOVE) }; } // namespace detail } // namespace execution namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename Sender, typename Receiver, typename... Args> struct set_value_member< boost::asio::execution::detail::submit_receiver_wrapper< Sender, Receiver>, void(Args...)> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (boost::asio::execution::is_nothrow_receiver_of<Receiver, Args...>::value)); typedef void result_type; }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename Sender, typename Receiver> struct set_value_member< boost::asio::execution::detail::submit_receiver_wrapper< Sender, Receiver>, void()> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = boost::asio::execution::is_nothrow_receiver_of<Receiver>::value); typedef void result_type; }; #define BOOST_ASIO_PRIVATE_SUBMIT_RECEIVER_TRAIT_DEF(n) \ template <typename Sender, typename Receiver, \ BOOST_ASIO_VARIADIC_TPARAMS(n)> \ struct set_value_member< \ boost::asio::execution::detail::submit_receiver_wrapper< \ Sender, Receiver>, \ void(BOOST_ASIO_VARIADIC_TARGS(n))> \ { \ BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); \ BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = \ (boost::asio::execution::is_nothrow_receiver_of<Receiver, \ BOOST_ASIO_VARIADIC_TARGS(n)>::value)); \ typedef void result_type; \ }; \ /**/ BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_SUBMIT_RECEIVER_TRAIT_DEF) #undef BOOST_ASIO_PRIVATE_SUBMIT_RECEIVER_TRAIT_DEF #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #endif // !defined(BOOST_ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) template <typename Sender, typename Receiver, typename E> struct set_error_member< boost::asio::execution::detail::submit_receiver_wrapper< Sender, Receiver>, E> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) template <typename Sender, typename Receiver> struct set_done_member< boost::asio::execution::detail::submit_receiver_wrapper< Sender, Receiver> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_DETAIL_SUBMIT_RECEIVER_HPP execution/detail/as_receiver.hpp 0000644 00000006504 15125530236 0013020 0 ustar 00 // // execution/detail/as_receiver.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_DETAIL_AS_RECEIVER_HPP #define BOOST_ASIO_EXECUTION_DETAIL_AS_RECEIVER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/traits/set_done_member.hpp> #include <boost/asio/traits/set_error_member.hpp> #include <boost/asio/traits/set_value_member.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace execution { namespace detail { template <typename Function, typename> struct as_receiver { Function f_; template <typename F> explicit as_receiver(BOOST_ASIO_MOVE_ARG(F) f, int) : f_(BOOST_ASIO_MOVE_CAST(F)(f)) { } #if defined(BOOST_ASIO_MSVC) && defined(BOOST_ASIO_HAS_MOVE) as_receiver(as_receiver&& other) : f_(BOOST_ASIO_MOVE_CAST(Function)(other.f_)) { } #endif // defined(BOOST_ASIO_MSVC) && defined(BOOST_ASIO_HAS_MOVE) void set_value() BOOST_ASIO_NOEXCEPT_IF(noexcept(declval<Function&>()())) { f_(); } template <typename E> void set_error(E) BOOST_ASIO_NOEXCEPT { std::terminate(); } void set_done() BOOST_ASIO_NOEXCEPT { } }; template <typename T> struct is_as_receiver : false_type { }; template <typename Function, typename T> struct is_as_receiver<as_receiver<Function, T> > : true_type { }; } // namespace detail } // namespace execution namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) template <typename Function, typename T> struct set_value_member< boost::asio::execution::detail::as_receiver<Function, T>, void()> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); #if defined(BOOST_ASIO_HAS_NOEXCEPT) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(declval<Function&>()())); #else // defined(BOOST_ASIO_HAS_NOEXCEPT) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); #endif // defined(BOOST_ASIO_HAS_NOEXCEPT) typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) template <typename Function, typename T, typename E> struct set_error_member< boost::asio::execution::detail::as_receiver<Function, T>, E> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) template <typename Function, typename T> struct set_done_member< boost::asio::execution::detail::as_receiver<Function, T> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_DETAIL_AS_RECEIVER_HPP execution/detail/as_invocable.hpp 0000644 00000007620 15125530236 0013156 0 ustar 00 // // execution/detail/as_invocable.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_DETAIL_AS_INVOCABLE_HPP #define BOOST_ASIO_EXECUTION_DETAIL_AS_INVOCABLE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/atomic_count.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/receiver_invocation_error.hpp> #include <boost/asio/execution/set_done.hpp> #include <boost/asio/execution/set_error.hpp> #include <boost/asio/execution/set_value.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace execution { namespace detail { #if defined(BOOST_ASIO_HAS_MOVE) template <typename Receiver, typename> struct as_invocable { Receiver* receiver_; explicit as_invocable(Receiver& r) BOOST_ASIO_NOEXCEPT : receiver_(boost::asio::detail::addressof(r)) { } as_invocable(as_invocable&& other) BOOST_ASIO_NOEXCEPT : receiver_(other.receiver_) { other.receiver_ = 0; } ~as_invocable() { if (receiver_) execution::set_done(BOOST_ASIO_MOVE_OR_LVALUE(Receiver)(*receiver_)); } void operator()() BOOST_ASIO_LVALUE_REF_QUAL BOOST_ASIO_NOEXCEPT { #if !defined(BOOST_ASIO_NO_EXCEPTIONS) try { #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) execution::set_value(BOOST_ASIO_MOVE_CAST(Receiver)(*receiver_)); receiver_ = 0; #if !defined(BOOST_ASIO_NO_EXCEPTIONS) } catch (...) { #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) execution::set_error(BOOST_ASIO_MOVE_CAST(Receiver)(*receiver_), std::make_exception_ptr(receiver_invocation_error())); receiver_ = 0; #else // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) std::terminate(); #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) } #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) } }; #else // defined(BOOST_ASIO_HAS_MOVE) template <typename Receiver, typename> struct as_invocable { Receiver* receiver_; boost::asio::detail::shared_ptr<boost::asio::detail::atomic_count> ref_count_; explicit as_invocable(Receiver& r, const boost::asio::detail::shared_ptr< boost::asio::detail::atomic_count>& c) BOOST_ASIO_NOEXCEPT : receiver_(boost::asio::detail::addressof(r)), ref_count_(c) { } as_invocable(const as_invocable& other) BOOST_ASIO_NOEXCEPT : receiver_(other.receiver_), ref_count_(other.ref_count_) { ++(*ref_count_); } ~as_invocable() { if (--(*ref_count_) == 0) execution::set_done(*receiver_); } void operator()() BOOST_ASIO_LVALUE_REF_QUAL BOOST_ASIO_NOEXCEPT { #if !defined(BOOST_ASIO_NO_EXCEPTIONS) try { #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) execution::set_value(*receiver_); ++(*ref_count_); } #if !defined(BOOST_ASIO_NO_EXCEPTIONS) catch (...) { #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) execution::set_error(*receiver_, std::make_exception_ptr(receiver_invocation_error())); ++(*ref_count_); #else // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) std::terminate(); #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) } #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) } }; #endif // defined(BOOST_ASIO_HAS_MOVE) template <typename T> struct is_as_invocable : false_type { }; template <typename Function, typename T> struct is_as_invocable<as_invocable<Function, T> > : true_type { }; } // namespace detail } // namespace execution } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_DETAIL_AS_INVOCABLE_HPP execution/detail/bulk_sender.hpp 0000644 00000020213 15125530236 0013017 0 ustar 00 // // execution/detail/bulk_sender.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_DETAIL_BULK_SENDER_HPP #define BOOST_ASIO_EXECUTION_DETAIL_BULK_SENDER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/connect.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/set_done.hpp> #include <boost/asio/execution/set_error.hpp> #include <boost/asio/traits/connect_member.hpp> #include <boost/asio/traits/set_done_member.hpp> #include <boost/asio/traits/set_error_member.hpp> #include <boost/asio/traits/set_value_member.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace execution { namespace detail { template <typename Receiver, typename Function, typename Number, typename Index> struct bulk_receiver { typename remove_cvref<Receiver>::type receiver_; typename decay<Function>::type f_; typename decay<Number>::type n_; template <typename R, typename F, typename N> explicit bulk_receiver(BOOST_ASIO_MOVE_ARG(R) r, BOOST_ASIO_MOVE_ARG(F) f, BOOST_ASIO_MOVE_ARG(N) n) : receiver_(BOOST_ASIO_MOVE_CAST(R)(r)), f_(BOOST_ASIO_MOVE_CAST(F)(f)), n_(BOOST_ASIO_MOVE_CAST(N)(n)) { } void set_value() { for (Index i = 0; i < n_; ++i) f_(i); execution::set_value( BOOST_ASIO_MOVE_OR_LVALUE( typename remove_cvref<Receiver>::type)(receiver_)); } template <typename Error> void set_error(BOOST_ASIO_MOVE_ARG(Error) e) BOOST_ASIO_NOEXCEPT { execution::set_error( BOOST_ASIO_MOVE_OR_LVALUE( typename remove_cvref<Receiver>::type)(receiver_), BOOST_ASIO_MOVE_CAST(Error)(e)); } void set_done() BOOST_ASIO_NOEXCEPT { execution::set_done( BOOST_ASIO_MOVE_OR_LVALUE( typename remove_cvref<Receiver>::type)(receiver_)); } }; template <typename Sender, typename Receiver, typename Function, typename Number> struct bulk_receiver_traits { typedef bulk_receiver< Receiver, Function, Number, typename execution::executor_index< typename remove_cvref<Sender>::type >::type > type; #if defined(BOOST_ASIO_HAS_MOVE) typedef type arg_type; #else // defined(BOOST_ASIO_HAS_MOVE) typedef const type& arg_type; #endif // defined(BOOST_ASIO_HAS_MOVE) }; template <typename Sender, typename Function, typename Number> struct bulk_sender : sender_base { typename remove_cvref<Sender>::type sender_; typename decay<Function>::type f_; typename decay<Number>::type n_; template <typename S, typename F, typename N> explicit bulk_sender(BOOST_ASIO_MOVE_ARG(S) s, BOOST_ASIO_MOVE_ARG(F) f, BOOST_ASIO_MOVE_ARG(N) n) : sender_(BOOST_ASIO_MOVE_CAST(S)(s)), f_(BOOST_ASIO_MOVE_CAST(F)(f)), n_(BOOST_ASIO_MOVE_CAST(N)(n)) { } template <typename Receiver> typename connect_result< BOOST_ASIO_MOVE_OR_LVALUE_TYPE(typename remove_cvref<Sender>::type), typename bulk_receiver_traits< Sender, Receiver, Function, Number >::arg_type >::type connect(BOOST_ASIO_MOVE_ARG(Receiver) r, typename enable_if< can_connect< typename remove_cvref<Sender>::type, typename bulk_receiver_traits< Sender, Receiver, Function, Number >::arg_type >::value >::type* = 0) BOOST_ASIO_RVALUE_REF_QUAL BOOST_ASIO_NOEXCEPT { return execution::connect( BOOST_ASIO_MOVE_OR_LVALUE(typename remove_cvref<Sender>::type)(sender_), typename bulk_receiver_traits<Sender, Receiver, Function, Number>::type( BOOST_ASIO_MOVE_CAST(Receiver)(r), BOOST_ASIO_MOVE_CAST(typename decay<Function>::type)(f_), BOOST_ASIO_MOVE_CAST(typename decay<Number>::type)(n_))); } template <typename Receiver> typename connect_result< const typename remove_cvref<Sender>::type&, typename bulk_receiver_traits< Sender, Receiver, Function, Number >::arg_type >::type connect(BOOST_ASIO_MOVE_ARG(Receiver) r, typename enable_if< can_connect< const typename remove_cvref<Sender>::type&, typename bulk_receiver_traits< Sender, Receiver, Function, Number >::arg_type >::value >::type* = 0) const BOOST_ASIO_LVALUE_REF_QUAL BOOST_ASIO_NOEXCEPT { return execution::connect(sender_, typename bulk_receiver_traits<Sender, Receiver, Function, Number>::type( BOOST_ASIO_MOVE_CAST(Receiver)(r), f_, n_)); } }; } // namespace detail } // namespace execution namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) template <typename Receiver, typename Function, typename Number, typename Index> struct set_value_member< execution::detail::bulk_receiver<Receiver, Function, Number, Index>, void()> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) template <typename Receiver, typename Function, typename Number, typename Index, typename Error> struct set_error_member< execution::detail::bulk_receiver<Receiver, Function, Number, Index>, Error> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) template <typename Receiver, typename Function, typename Number, typename Index> struct set_done_member< execution::detail::bulk_receiver<Receiver, Function, Number, Index> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT) template <typename Sender, typename Function, typename Number, typename Receiver> struct connect_member< execution::detail::bulk_sender<Sender, Function, Number>, Receiver, typename enable_if< execution::can_connect< BOOST_ASIO_MOVE_OR_LVALUE_TYPE(typename remove_cvref<Sender>::type), typename execution::detail::bulk_receiver_traits< Sender, Receiver, Function, Number >::arg_type >::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef typename execution::connect_result< BOOST_ASIO_MOVE_OR_LVALUE_TYPE(typename remove_cvref<Sender>::type), typename execution::detail::bulk_receiver_traits< Sender, Receiver, Function, Number >::arg_type >::type result_type; }; template <typename Sender, typename Function, typename Number, typename Receiver> struct connect_member< const execution::detail::bulk_sender<Sender, Function, Number>, Receiver, typename enable_if< execution::can_connect< const typename remove_cvref<Sender>::type&, typename execution::detail::bulk_receiver_traits< Sender, Receiver, Function, Number >::arg_type >::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef typename execution::connect_result< const typename remove_cvref<Sender>::type&, typename execution::detail::bulk_receiver_traits< Sender, Receiver, Function, Number >::arg_type >::type result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT) } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_DETAIL_BULK_SENDER_HPP execution/detail/as_operation.hpp 0000644 00000006212 15125530236 0013210 0 ustar 00 // // execution/detail/as_operation.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_DETAIL_AS_OPERATION_HPP #define BOOST_ASIO_EXECUTION_DETAIL_AS_OPERATION_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/detail/as_invocable.hpp> #include <boost/asio/execution/execute.hpp> #include <boost/asio/execution/set_error.hpp> #include <boost/asio/traits/start_member.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace execution { namespace detail { template <typename Executor, typename Receiver> struct as_operation { typename remove_cvref<Executor>::type ex_; typename remove_cvref<Receiver>::type receiver_; #if !defined(BOOST_ASIO_HAS_MOVE) boost::asio::detail::shared_ptr<boost::asio::detail::atomic_count> ref_count_; #endif // !defined(BOOST_ASIO_HAS_MOVE) template <typename E, typename R> explicit as_operation(BOOST_ASIO_MOVE_ARG(E) e, BOOST_ASIO_MOVE_ARG(R) r) : ex_(BOOST_ASIO_MOVE_CAST(E)(e)), receiver_(BOOST_ASIO_MOVE_CAST(R)(r)) #if !defined(BOOST_ASIO_HAS_MOVE) , ref_count_(new boost::asio::detail::atomic_count(1)) #endif // !defined(BOOST_ASIO_HAS_MOVE) { } void start() BOOST_ASIO_NOEXCEPT { #if !defined(BOOST_ASIO_NO_EXCEPTIONS) try { #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) execution::execute( BOOST_ASIO_MOVE_CAST(typename remove_cvref<Executor>::type)(ex_), as_invocable<typename remove_cvref<Receiver>::type, Executor>(receiver_ #if !defined(BOOST_ASIO_HAS_MOVE) , ref_count_ #endif // !defined(BOOST_ASIO_HAS_MOVE) )); #if !defined(BOOST_ASIO_NO_EXCEPTIONS) } catch (...) { #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) execution::set_error( BOOST_ASIO_MOVE_OR_LVALUE( typename remove_cvref<Receiver>::type)( receiver_), std::current_exception()); #else // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) std::terminate(); #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) } #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) } }; } // namespace detail } // namespace execution namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_START_MEMBER_TRAIT) template <typename Executor, typename Receiver> struct start_member< boost::asio::execution::detail::as_operation<Executor, Receiver> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_START_MEMBER_TRAIT) } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_DETAIL_AS_OPERATION_HPP execution/any_executor.hpp 0000644 00000215773 15125530236 0012006 0 ustar 00 // // execution/any_executor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_ANY_EXECUTOR_HPP #define BOOST_ASIO_EXECUTION_ANY_EXECUTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <new> #include <typeinfo> #include <boost/asio/detail/assert.hpp> #include <boost/asio/detail/cstddef.hpp> #include <boost/asio/detail/executor_function.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/scoped_ptr.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/detail/variadic_templates.hpp> #include <boost/asio/execution/bad_executor.hpp> #include <boost/asio/execution/blocking.hpp> #include <boost/asio/execution/execute.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/prefer.hpp> #include <boost/asio/query.hpp> #include <boost/asio/require.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if defined(GENERATING_DOCUMENTATION) namespace execution { /// Polymorphic executor wrapper. template <typename... SupportableProperties> class any_executor { public: /// Default constructor. any_executor() noexcept; /// Construct in an empty state. Equivalent effects to default constructor. any_executor(nullptr_t) noexcept; /// Copy constructor. any_executor(const any_executor& e) noexcept; /// Move constructor. any_executor(any_executor&& e) noexcept; /// Construct to point to the same target as another any_executor. template <class... OtherSupportableProperties> any_executor(any_executor<OtherSupportableProperties...> e); /// Construct a polymorphic wrapper for the specified executor. template <typename Executor> any_executor(Executor e); /// Assignment operator. any_executor& operator=(const any_executor& e) noexcept; /// Move assignment operator. any_executor& operator=(any_executor&& e) noexcept; /// Assignment operator that sets the polymorphic wrapper to the empty state. any_executor& operator=(nullptr_t); /// Assignment operator to create a polymorphic wrapper for the specified /// executor. template <typename Executor> any_executor& operator=(Executor e); /// Destructor. ~any_executor(); /// Swap targets with another polymorphic wrapper. void swap(any_executor& other) noexcept; /// Obtain a polymorphic wrapper with the specified property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require and boost::asio::prefer customisation points. * * For example: * @code execution::any_executor<execution::blocking_t::possibly_t> ex = ...; * auto ex2 = boost::asio::requre(ex, execution::blocking.possibly); @endcode */ template <typename Property> any_executor require(Property) const; /// Obtain a polymorphic wrapper with the specified property. /** * Do not call this function directly. It is intended for use with the * boost::asio::prefer customisation point. * * For example: * @code execution::any_executor<execution::blocking_t::possibly_t> ex = ...; * auto ex2 = boost::asio::prefer(ex, execution::blocking.possibly); @endcode */ template <typename Property> any_executor prefer(Property) const; /// Obtain the value associated with the specified property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code execution::any_executor<execution::occupancy_t> ex = ...; * size_t n = boost::asio::query(ex, execution::occupancy); @endcode */ template <typename Property> typename Property::polymorphic_query_result_type query(Property) const; /// Execute the function on the target executor. /** * Do not call this function directly. It is intended for use with the * execution::execute customisation point. * * For example: * @code execution::any_executor<> ex = ...; * execution::execute(ex, my_function_object); @endcode * * Throws boost::asio::bad_executor if the polymorphic wrapper has no target. */ template <typename Function> void execute(Function&& f) const; /// Obtain the underlying execution context. /** * This function is provided for backward compatibility. It is automatically * defined when the @c SupportableProperties... list includes a property of * type <tt>execution::context_as<U></tt>, for some type <tt>U</tt>. */ automatically_determined context() const; /// Determine whether the wrapper has a target executor. /** * @returns @c true if the polymorphic wrapper has a target executor, * otherwise false. */ explicit operator bool() const noexcept; /// Get the type of the target executor. const type_info& target_type() const noexcept; /// Get a pointer to the target executor. template <typename Executor> Executor* target() noexcept; /// Get a pointer to the target executor. template <typename Executor> const Executor* target() const noexcept; }; /// Equality operator. /** * @relates any_executor */ template <typename... SupportableProperties> bool operator==(const any_executor<SupportableProperties...>& a, const any_executor<SupportableProperties...>& b) noexcept; /// Equality operator. /** * @relates any_executor */ template <typename... SupportableProperties> bool operator==(const any_executor<SupportableProperties...>& a, nullptr_t) noexcept; /// Equality operator. /** * @relates any_executor */ template <typename... SupportableProperties> bool operator==(nullptr_t, const any_executor<SupportableProperties...>& b) noexcept; /// Inequality operator. /** * @relates any_executor */ template <typename... SupportableProperties> bool operator!=(const any_executor<SupportableProperties...>& a, const any_executor<SupportableProperties...>& b) noexcept; /// Inequality operator. /** * @relates any_executor */ template <typename... SupportableProperties> bool operator!=(const any_executor<SupportableProperties...>& a, nullptr_t) noexcept; /// Inequality operator. /** * @relates any_executor */ template <typename... SupportableProperties> bool operator!=(nullptr_t, const any_executor<SupportableProperties...>& b) noexcept; } // namespace execution #else // defined(GENERATING_DOCUMENTATION) namespace execution { #if !defined(BOOST_ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL) #define BOOST_ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename... SupportableProperties> class any_executor; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename = void, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void> class any_executor; #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #endif // !defined(BOOST_ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL) template <typename U> struct context_as_t; namespace detail { // Traits used to detect whether a property is requirable or preferable, taking // into account that T::is_requirable or T::is_preferable may not not be well // formed. template <typename T, typename = void> struct is_requirable : false_type {}; template <typename T> struct is_requirable<T, typename enable_if<T::is_requirable>::type> : true_type {}; template <typename T, typename = void> struct is_preferable : false_type {}; template <typename T> struct is_preferable<T, typename enable_if<T::is_preferable>::type> : true_type {}; // Trait used to detect context_as property, for backward compatibility. template <typename T> struct is_context_as : false_type {}; template <typename U> struct is_context_as<context_as_t<U> > : true_type {}; // Helper template to: // - Check if a target can supply the supportable properties. // - Find the first convertible-from-T property in the list. template <std::size_t I, typename Props> struct supportable_properties; template <std::size_t I, typename Prop> struct supportable_properties<I, void(Prop)> { template <typename T> struct is_valid_target : integral_constant<bool, ( is_requirable<Prop>::value ? can_require<T, Prop>::value : true ) && ( is_preferable<Prop>::value ? can_prefer<T, Prop>::value : true ) && ( !is_requirable<Prop>::value && !is_preferable<Prop>::value ? can_query<T, Prop>::value : true ) > { }; struct found { BOOST_ASIO_STATIC_CONSTEXPR(bool, value = true); typedef Prop type; typedef typename Prop::polymorphic_query_result_type query_result_type; BOOST_ASIO_STATIC_CONSTEXPR(std::size_t, index = I); }; struct not_found { BOOST_ASIO_STATIC_CONSTEXPR(bool, value = false); }; template <typename T> struct find_convertible_property : conditional< is_same<T, Prop>::value || is_convertible<T, Prop>::value, found, not_found >::type {}; template <typename T> struct find_convertible_requirable_property : conditional< is_requirable<Prop>::value && (is_same<T, Prop>::value || is_convertible<T, Prop>::value), found, not_found >::type {}; template <typename T> struct find_convertible_preferable_property : conditional< is_preferable<Prop>::value && (is_same<T, Prop>::value || is_convertible<T, Prop>::value), found, not_found >::type {}; struct find_context_as_property : conditional< is_context_as<Prop>::value, found, not_found >::type {}; }; #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <std::size_t I, typename Head, typename... Tail> struct supportable_properties<I, void(Head, Tail...)> { template <typename T> struct is_valid_target : integral_constant<bool, ( supportable_properties<I, void(Head)>::template is_valid_target<T>::value && supportable_properties<I + 1, void(Tail...)>::template is_valid_target<T>::value ) > { }; template <typename T> struct find_convertible_property : conditional< is_convertible<T, Head>::value, typename supportable_properties<I, void(Head)>::found, typename supportable_properties<I + 1, void(Tail...)>::template find_convertible_property<T> >::type {}; template <typename T> struct find_convertible_requirable_property : conditional< is_requirable<Head>::value && is_convertible<T, Head>::value, typename supportable_properties<I, void(Head)>::found, typename supportable_properties<I + 1, void(Tail...)>::template find_convertible_requirable_property<T> >::type {}; template <typename T> struct find_convertible_preferable_property : conditional< is_preferable<Head>::value && is_convertible<T, Head>::value, typename supportable_properties<I, void(Head)>::found, typename supportable_properties<I + 1, void(Tail...)>::template find_convertible_preferable_property<T> >::type {}; struct find_context_as_property : conditional< is_context_as<Head>::value, typename supportable_properties<I, void(Head)>::found, typename supportable_properties<I + 1, void(Tail...)>::find_context_as_property >::type {}; }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROPS_BASE_DEF(n) \ template <std::size_t I, \ typename Head, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ struct supportable_properties<I, \ void(Head, BOOST_ASIO_VARIADIC_TARGS(n))> \ { \ template <typename T> \ struct is_valid_target : integral_constant<bool, \ ( \ supportable_properties<I, \ void(Head)>::template is_valid_target<T>::value \ && \ supportable_properties<I + 1, \ void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ is_valid_target<T>::value \ ) \ > \ { \ }; \ \ template <typename T> \ struct find_convertible_property : \ conditional< \ is_convertible<T, Head>::value, \ typename supportable_properties<I, void(Head)>::found, \ typename supportable_properties<I + 1, \ void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ find_convertible_property<T> \ >::type {}; \ \ template <typename T> \ struct find_convertible_requirable_property : \ conditional< \ is_requirable<Head>::value \ && is_convertible<T, Head>::value, \ typename supportable_properties<I, void(Head)>::found, \ typename supportable_properties<I + 1, \ void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ find_convertible_requirable_property<T> \ >::type {}; \ \ template <typename T> \ struct find_convertible_preferable_property : \ conditional< \ is_preferable<Head>::value \ && is_convertible<T, Head>::value, \ typename supportable_properties<I, void(Head)>::found, \ typename supportable_properties<I + 1, \ void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ find_convertible_preferable_property<T> \ >::type {}; \ \ struct find_context_as_property : \ conditional< \ is_context_as<Head>::value, \ typename supportable_properties<I, void(Head)>::found, \ typename supportable_properties<I + 1, void( \ BOOST_ASIO_VARIADIC_TARGS(n))>::find_context_as_property \ >::type {}; \ }; \ /**/ BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROPS_BASE_DEF) #undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROPS_BASE_DEF #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T, typename Props> struct is_valid_target_executor : conditional< is_executor<T>::value, typename supportable_properties<0, Props>::template is_valid_target<T>, false_type >::type { }; class any_executor_base { public: any_executor_base() BOOST_ASIO_NOEXCEPT : object_fns_(object_fns_table<void>()), target_(0), target_fns_(target_fns_table<void>()) { } template <BOOST_ASIO_EXECUTION_EXECUTOR Executor> any_executor_base(Executor ex, false_type) : target_fns_(target_fns_table<Executor>( any_executor_base::query_blocking(ex, can_query<const Executor&, const execution::blocking_t&>()) == execution::blocking.always)) { any_executor_base::construct_object(ex, integral_constant<bool, sizeof(Executor) <= sizeof(object_type) && alignment_of<Executor>::value <= alignment_of<object_type>::value >()); } template <BOOST_ASIO_EXECUTION_EXECUTOR Executor> any_executor_base(Executor other, true_type) : object_fns_(object_fns_table<boost::asio::detail::shared_ptr<void> >()), target_fns_(other.target_fns_) { boost::asio::detail::shared_ptr<Executor> p = boost::asio::detail::make_shared<Executor>( BOOST_ASIO_MOVE_CAST(Executor)(other)); target_ = p->template target<void>(); new (&object_) boost::asio::detail::shared_ptr<void>( BOOST_ASIO_MOVE_CAST(boost::asio::detail::shared_ptr<Executor>)(p)); } any_executor_base(const any_executor_base& other) BOOST_ASIO_NOEXCEPT : object_fns_(other.object_fns_), target_fns_(other.target_fns_) { object_fns_->copy(*this, other); } ~any_executor_base() BOOST_ASIO_NOEXCEPT { object_fns_->destroy(*this); } any_executor_base& operator=( const any_executor_base& other) BOOST_ASIO_NOEXCEPT { if (this != &other) { object_fns_->destroy(*this); object_fns_ = other.object_fns_; target_fns_ = other.target_fns_; object_fns_->copy(*this, other); } return *this; } any_executor_base& operator=(nullptr_t) BOOST_ASIO_NOEXCEPT { object_fns_->destroy(*this); target_ = 0; object_fns_ = object_fns_table<void>(); target_fns_ = target_fns_table<void>(); return *this; } #if defined(BOOST_ASIO_HAS_MOVE) any_executor_base(any_executor_base&& other) BOOST_ASIO_NOEXCEPT : object_fns_(other.object_fns_), target_fns_(other.target_fns_) { other.object_fns_ = object_fns_table<void>(); other.target_fns_ = target_fns_table<void>(); object_fns_->move(*this, other); other.target_ = 0; } any_executor_base& operator=( any_executor_base&& other) BOOST_ASIO_NOEXCEPT { if (this != &other) { object_fns_->destroy(*this); object_fns_ = other.object_fns_; other.object_fns_ = object_fns_table<void>(); target_fns_ = other.target_fns_; other.target_fns_ = target_fns_table<void>(); object_fns_->move(*this, other); other.target_ = 0; } return *this; } #endif // defined(BOOST_ASIO_HAS_MOVE) void swap(any_executor_base& other) BOOST_ASIO_NOEXCEPT { if (this != &other) { any_executor_base tmp(BOOST_ASIO_MOVE_CAST(any_executor_base)(other)); other = BOOST_ASIO_MOVE_CAST(any_executor_base)(*this); *this = BOOST_ASIO_MOVE_CAST(any_executor_base)(tmp); } } template <typename F> void execute(BOOST_ASIO_MOVE_ARG(F) f) const { if (target_fns_->blocking_execute != 0) { boost::asio::detail::non_const_lvalue<F> f2(f); target_fns_->blocking_execute(*this, function_view(f2.value)); } else { target_fns_->execute(*this, function(BOOST_ASIO_MOVE_CAST(F)(f), std::allocator<void>())); } } template <typename Executor> Executor* target() { return static_cast<Executor*>(target_); } template <typename Executor> const Executor* target() const { return static_cast<Executor*>(target_); } #if !defined(BOOST_ASIO_NO_TYPEID) const std::type_info& target_type() const #else // !defined(BOOST_ASIO_NO_TYPEID) const void* target_type() const #endif // !defined(BOOST_ASIO_NO_TYPEID) { return target_fns_->target_type(); } struct unspecified_bool_type_t {}; typedef void (*unspecified_bool_type)(unspecified_bool_type_t); static void unspecified_bool_true(unspecified_bool_type_t) {} operator unspecified_bool_type() const BOOST_ASIO_NOEXCEPT { return target_ ? &any_executor_base::unspecified_bool_true : 0; } bool operator!() const BOOST_ASIO_NOEXCEPT { return target_ == 0; } protected: bool equality_helper(const any_executor_base& other) const BOOST_ASIO_NOEXCEPT { if (target_ == other.target_) return true; if (target_ && !other.target_) return false; if (!target_ && other.target_) return false; if (target_fns_ != other.target_fns_) return false; return target_fns_->equal(*this, other); } template <typename Ex> Ex& object() { return *static_cast<Ex*>(static_cast<void*>(&object_)); } template <typename Ex> const Ex& object() const { return *static_cast<const Ex*>(static_cast<const void*>(&object_)); } struct object_fns { void (*destroy)(any_executor_base&); void (*copy)(any_executor_base&, const any_executor_base&); void (*move)(any_executor_base&, any_executor_base&); const void* (*target)(const any_executor_base&); }; static void destroy_void(any_executor_base&) { } static void copy_void(any_executor_base& ex1, const any_executor_base&) { ex1.target_ = 0; } static void move_void(any_executor_base& ex1, any_executor_base&) { ex1.target_ = 0; } static const void* target_void(const any_executor_base&) { return 0; } template <typename Obj> static const object_fns* object_fns_table( typename enable_if< is_same<Obj, void>::value >::type* = 0) { static const object_fns fns = { &any_executor_base::destroy_void, &any_executor_base::copy_void, &any_executor_base::move_void, &any_executor_base::target_void }; return &fns; } static void destroy_shared(any_executor_base& ex) { typedef boost::asio::detail::shared_ptr<void> type; ex.object<type>().~type(); } static void copy_shared(any_executor_base& ex1, const any_executor_base& ex2) { typedef boost::asio::detail::shared_ptr<void> type; new (&ex1.object_) type(ex2.object<type>()); ex1.target_ = ex2.target_; } static void move_shared(any_executor_base& ex1, any_executor_base& ex2) { typedef boost::asio::detail::shared_ptr<void> type; new (&ex1.object_) type(BOOST_ASIO_MOVE_CAST(type)(ex2.object<type>())); ex1.target_ = ex2.target_; ex2.object<type>().~type(); } static const void* target_shared(const any_executor_base& ex) { typedef boost::asio::detail::shared_ptr<void> type; return ex.object<type>().get(); } template <typename Obj> static const object_fns* object_fns_table( typename enable_if< is_same<Obj, boost::asio::detail::shared_ptr<void> >::value >::type* = 0) { static const object_fns fns = { &any_executor_base::destroy_shared, &any_executor_base::copy_shared, &any_executor_base::move_shared, &any_executor_base::target_shared }; return &fns; } template <typename Obj> static void destroy_object(any_executor_base& ex) { ex.object<Obj>().~Obj(); } template <typename Obj> static void copy_object(any_executor_base& ex1, const any_executor_base& ex2) { new (&ex1.object_) Obj(ex2.object<Obj>()); ex1.target_ = &ex1.object<Obj>(); } template <typename Obj> static void move_object(any_executor_base& ex1, any_executor_base& ex2) { new (&ex1.object_) Obj(BOOST_ASIO_MOVE_CAST(Obj)(ex2.object<Obj>())); ex1.target_ = &ex1.object<Obj>(); ex2.object<Obj>().~Obj(); } template <typename Obj> static const void* target_object(const any_executor_base& ex) { return &ex.object<Obj>(); } template <typename Obj> static const object_fns* object_fns_table( typename enable_if< !is_same<Obj, void>::value && !is_same<Obj, boost::asio::detail::shared_ptr<void> >::value >::type* = 0) { static const object_fns fns = { &any_executor_base::destroy_object<Obj>, &any_executor_base::copy_object<Obj>, &any_executor_base::move_object<Obj>, &any_executor_base::target_object<Obj> }; return &fns; } typedef boost::asio::detail::executor_function function; typedef boost::asio::detail::executor_function_view function_view; struct target_fns { #if !defined(BOOST_ASIO_NO_TYPEID) const std::type_info& (*target_type)(); #else // !defined(BOOST_ASIO_NO_TYPEID) const void* (*target_type)(); #endif // !defined(BOOST_ASIO_NO_TYPEID) bool (*equal)(const any_executor_base&, const any_executor_base&); void (*execute)(const any_executor_base&, BOOST_ASIO_MOVE_ARG(function)); void (*blocking_execute)(const any_executor_base&, function_view); }; #if !defined(BOOST_ASIO_NO_TYPEID) static const std::type_info& target_type_void() { return typeid(void); } #else // !defined(BOOST_ASIO_NO_TYPEID) static const void* target_type_void() { return 0; } #endif // !defined(BOOST_ASIO_NO_TYPEID) static bool equal_void(const any_executor_base&, const any_executor_base&) { return true; } static void execute_void(const any_executor_base&, BOOST_ASIO_MOVE_ARG(function)) { bad_executor ex; boost::asio::detail::throw_exception(ex); } static void blocking_execute_void(const any_executor_base&, function_view) { bad_executor ex; boost::asio::detail::throw_exception(ex); } template <typename Ex> static const target_fns* target_fns_table( typename enable_if< is_same<Ex, void>::value >::type* = 0) { static const target_fns fns = { &any_executor_base::target_type_void, &any_executor_base::equal_void, &any_executor_base::execute_void, &any_executor_base::blocking_execute_void }; return &fns; } #if !defined(BOOST_ASIO_NO_TYPEID) template <typename Ex> static const std::type_info& target_type_ex() { return typeid(Ex); } #else // !defined(BOOST_ASIO_NO_TYPEID) template <typename Ex> static const void* target_type_ex() { static int unique_id; return &unique_id; } #endif // !defined(BOOST_ASIO_NO_TYPEID) template <typename Ex> static bool equal_ex(const any_executor_base& ex1, const any_executor_base& ex2) { return *ex1.target<Ex>() == *ex2.target<Ex>(); } template <typename Ex> static void execute_ex(const any_executor_base& ex, BOOST_ASIO_MOVE_ARG(function) f) { execution::execute(*ex.target<Ex>(), BOOST_ASIO_MOVE_CAST(function)(f)); } template <typename Ex> static void blocking_execute_ex(const any_executor_base& ex, function_view f) { execution::execute(*ex.target<Ex>(), f); } template <typename Ex> static const target_fns* target_fns_table(bool is_always_blocking, typename enable_if< !is_same<Ex, void>::value >::type* = 0) { static const target_fns fns_with_execute = { &any_executor_base::target_type_ex<Ex>, &any_executor_base::equal_ex<Ex>, &any_executor_base::execute_ex<Ex>, 0 }; static const target_fns fns_with_blocking_execute = { &any_executor_base::target_type_ex<Ex>, &any_executor_base::equal_ex<Ex>, 0, &any_executor_base::blocking_execute_ex<Ex> }; return is_always_blocking ? &fns_with_blocking_execute : &fns_with_execute; } #if defined(BOOST_ASIO_MSVC) # pragma warning (push) # pragma warning (disable:4702) #endif // defined(BOOST_ASIO_MSVC) static void query_fn_void(void*, const void*, const void*) { bad_executor ex; boost::asio::detail::throw_exception(ex); } template <typename Ex, class Prop> static void query_fn_non_void(void*, const void* ex, const void* prop, typename enable_if< boost::asio::can_query<const Ex&, const Prop&>::value && is_same<typename Prop::polymorphic_query_result_type, void>::value >::type*) { boost::asio::query(*static_cast<const Ex*>(ex), *static_cast<const Prop*>(prop)); } template <typename Ex, class Prop> static void query_fn_non_void(void*, const void*, const void*, typename enable_if< !boost::asio::can_query<const Ex&, const Prop&>::value && is_same<typename Prop::polymorphic_query_result_type, void>::value >::type*) { } template <typename Ex, class Prop> static void query_fn_non_void(void* result, const void* ex, const void* prop, typename enable_if< boost::asio::can_query<const Ex&, const Prop&>::value && !is_same<typename Prop::polymorphic_query_result_type, void>::value && is_reference<typename Prop::polymorphic_query_result_type>::value >::type*) { *static_cast<typename remove_reference< typename Prop::polymorphic_query_result_type>::type**>(result) = &static_cast<typename Prop::polymorphic_query_result_type>( boost::asio::query(*static_cast<const Ex*>(ex), *static_cast<const Prop*>(prop))); } template <typename Ex, class Prop> static void query_fn_non_void(void*, const void*, const void*, typename enable_if< !boost::asio::can_query<const Ex&, const Prop&>::value && !is_same<typename Prop::polymorphic_query_result_type, void>::value && is_reference<typename Prop::polymorphic_query_result_type>::value >::type*) { std::terminate(); // Combination should not be possible. } template <typename Ex, class Prop> static void query_fn_non_void(void* result, const void* ex, const void* prop, typename enable_if< boost::asio::can_query<const Ex&, const Prop&>::value && !is_same<typename Prop::polymorphic_query_result_type, void>::value && is_scalar<typename Prop::polymorphic_query_result_type>::value >::type*) { *static_cast<typename Prop::polymorphic_query_result_type*>(result) = static_cast<typename Prop::polymorphic_query_result_type>( boost::asio::query(*static_cast<const Ex*>(ex), *static_cast<const Prop*>(prop))); } template <typename Ex, class Prop> static void query_fn_non_void(void* result, const void*, const void*, typename enable_if< !boost::asio::can_query<const Ex&, const Prop&>::value && !is_same<typename Prop::polymorphic_query_result_type, void>::value && is_scalar<typename Prop::polymorphic_query_result_type>::value >::type*) { *static_cast<typename Prop::polymorphic_query_result_type*>(result) = typename Prop::polymorphic_query_result_type(); } template <typename Ex, class Prop> static void query_fn_non_void(void* result, const void* ex, const void* prop, typename enable_if< boost::asio::can_query<const Ex&, const Prop&>::value && !is_same<typename Prop::polymorphic_query_result_type, void>::value && !is_reference<typename Prop::polymorphic_query_result_type>::value && !is_scalar<typename Prop::polymorphic_query_result_type>::value >::type*) { *static_cast<typename Prop::polymorphic_query_result_type**>(result) = new typename Prop::polymorphic_query_result_type( boost::asio::query(*static_cast<const Ex*>(ex), *static_cast<const Prop*>(prop))); } template <typename Ex, class Prop> static void query_fn_non_void(void* result, const void*, const void*, ...) { *static_cast<typename Prop::polymorphic_query_result_type**>(result) = new typename Prop::polymorphic_query_result_type(); } template <typename Ex, class Prop> static void query_fn_impl(void* result, const void* ex, const void* prop, typename enable_if< is_same<Ex, void>::value >::type*) { query_fn_void(result, ex, prop); } template <typename Ex, class Prop> static void query_fn_impl(void* result, const void* ex, const void* prop, typename enable_if< !is_same<Ex, void>::value >::type*) { query_fn_non_void<Ex, Prop>(result, ex, prop, 0); } template <typename Ex, class Prop> static void query_fn(void* result, const void* ex, const void* prop) { query_fn_impl<Ex, Prop>(result, ex, prop, 0); } template <typename Poly, typename Ex, class Prop> static Poly require_fn_impl(const void*, const void*, typename enable_if< is_same<Ex, void>::value >::type*) { bad_executor ex; boost::asio::detail::throw_exception(ex); return Poly(); } template <typename Poly, typename Ex, class Prop> static Poly require_fn_impl(const void* ex, const void* prop, typename enable_if< !is_same<Ex, void>::value && Prop::is_requirable >::type*) { return boost::asio::require(*static_cast<const Ex*>(ex), *static_cast<const Prop*>(prop)); } template <typename Poly, typename Ex, class Prop> static Poly require_fn_impl(const void*, const void*, ...) { return Poly(); } template <typename Poly, typename Ex, class Prop> static Poly require_fn(const void* ex, const void* prop) { return require_fn_impl<Poly, Ex, Prop>(ex, prop, 0); } template <typename Poly, typename Ex, class Prop> static Poly prefer_fn_impl(const void*, const void*, typename enable_if< is_same<Ex, void>::value >::type*) { bad_executor ex; boost::asio::detail::throw_exception(ex); return Poly(); } template <typename Poly, typename Ex, class Prop> static Poly prefer_fn_impl(const void* ex, const void* prop, typename enable_if< !is_same<Ex, void>::value && Prop::is_preferable >::type*) { return boost::asio::prefer(*static_cast<const Ex*>(ex), *static_cast<const Prop*>(prop)); } template <typename Poly, typename Ex, class Prop> static Poly prefer_fn_impl(const void*, const void*, ...) { return Poly(); } template <typename Poly, typename Ex, class Prop> static Poly prefer_fn(const void* ex, const void* prop) { return prefer_fn_impl<Poly, Ex, Prop>(ex, prop, 0); } template <typename Poly> struct prop_fns { void (*query)(void*, const void*, const void*); Poly (*require)(const void*, const void*); Poly (*prefer)(const void*, const void*); }; #if defined(BOOST_ASIO_MSVC) # pragma warning (pop) #endif // defined(BOOST_ASIO_MSVC) private: template <typename Executor> static execution::blocking_t query_blocking(const Executor& ex, true_type) { return boost::asio::query(ex, execution::blocking); } template <typename Executor> static execution::blocking_t query_blocking(const Executor&, false_type) { return execution::blocking_t(); } template <typename Executor> void construct_object(Executor& ex, true_type) { object_fns_ = object_fns_table<Executor>(); target_ = new (&object_) Executor(BOOST_ASIO_MOVE_CAST(Executor)(ex)); } template <typename Executor> void construct_object(Executor& ex, false_type) { object_fns_ = object_fns_table<boost::asio::detail::shared_ptr<void> >(); boost::asio::detail::shared_ptr<Executor> p = boost::asio::detail::make_shared<Executor>( BOOST_ASIO_MOVE_CAST(Executor)(ex)); target_ = p.get(); new (&object_) boost::asio::detail::shared_ptr<void>( BOOST_ASIO_MOVE_CAST(boost::asio::detail::shared_ptr<Executor>)(p)); } /*private:*/public: // template <typename...> friend class any_executor; typedef aligned_storage< sizeof(boost::asio::detail::shared_ptr<void>), alignment_of<boost::asio::detail::shared_ptr<void> >::value >::type object_type; object_type object_; const object_fns* object_fns_; void* target_; const target_fns* target_fns_; }; template <typename Derived, typename Property, typename = void> struct any_executor_context { }; #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) template <typename Derived, typename Property> struct any_executor_context<Derived, Property, typename enable_if<Property::value>::type> { typename Property::query_result_type context() const { return static_cast<const Derived*>(this)->query(typename Property::type()); } }; #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) } // namespace detail template <> class any_executor<> : public detail::any_executor_base { public: any_executor() BOOST_ASIO_NOEXCEPT : detail::any_executor_base() { } any_executor(nullptr_t) BOOST_ASIO_NOEXCEPT : detail::any_executor_base() { } template <typename Executor> any_executor(Executor ex, typename enable_if< conditional< !is_same<Executor, any_executor>::value && !is_base_of<detail::any_executor_base, Executor>::value, is_executor<Executor>, false_type >::type::value >::type* = 0) : detail::any_executor_base( BOOST_ASIO_MOVE_CAST(Executor)(ex), false_type()) { } #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename... OtherSupportableProperties> any_executor(any_executor<OtherSupportableProperties...> other) : detail::any_executor_base( static_cast<const detail::any_executor_base&>(other)) { } #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename U0, typename U1, typename U2, typename U3, typename U4, typename U5, typename U6, typename U7> any_executor(any_executor<U0, U1, U2, U3, U4, U5, U6, U7> other) : detail::any_executor_base( static_cast<const detail::any_executor_base&>(other)) { } #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) any_executor(const any_executor& other) BOOST_ASIO_NOEXCEPT : detail::any_executor_base( static_cast<const detail::any_executor_base&>(other)) { } any_executor& operator=(const any_executor& other) BOOST_ASIO_NOEXCEPT { if (this != &other) { detail::any_executor_base::operator=( static_cast<const detail::any_executor_base&>(other)); } return *this; } any_executor& operator=(nullptr_t p) BOOST_ASIO_NOEXCEPT { detail::any_executor_base::operator=(p); return *this; } #if defined(BOOST_ASIO_HAS_MOVE) any_executor(any_executor&& other) BOOST_ASIO_NOEXCEPT : detail::any_executor_base( static_cast<any_executor_base&&>( static_cast<any_executor_base&>(other))) { } any_executor& operator=(any_executor&& other) BOOST_ASIO_NOEXCEPT { if (this != &other) { detail::any_executor_base::operator=( static_cast<detail::any_executor_base&&>( static_cast<detail::any_executor_base&>(other))); } return *this; } #endif // defined(BOOST_ASIO_HAS_MOVE) void swap(any_executor& other) BOOST_ASIO_NOEXCEPT { detail::any_executor_base::swap( static_cast<detail::any_executor_base&>(other)); } using detail::any_executor_base::execute; using detail::any_executor_base::target; using detail::any_executor_base::target_type; using detail::any_executor_base::operator unspecified_bool_type; using detail::any_executor_base::operator!; bool equality_helper(const any_executor& other) const BOOST_ASIO_NOEXCEPT { return any_executor_base::equality_helper(other); } template <typename AnyExecutor1, typename AnyExecutor2> friend typename enable_if< is_same<AnyExecutor1, any_executor>::value || is_same<AnyExecutor2, any_executor>::value, bool >::type operator==(const AnyExecutor1& a, const AnyExecutor2& b) BOOST_ASIO_NOEXCEPT { return static_cast<const any_executor&>(a).equality_helper(b); } template <typename AnyExecutor> friend typename enable_if< is_same<AnyExecutor, any_executor>::value, bool >::type operator==(const AnyExecutor& a, nullptr_t) BOOST_ASIO_NOEXCEPT { return !a; } template <typename AnyExecutor> friend typename enable_if< is_same<AnyExecutor, any_executor>::value, bool >::type operator==(nullptr_t, const AnyExecutor& b) BOOST_ASIO_NOEXCEPT { return !b; } template <typename AnyExecutor1, typename AnyExecutor2> friend typename enable_if< is_same<AnyExecutor1, any_executor>::value || is_same<AnyExecutor2, any_executor>::value, bool >::type operator!=(const AnyExecutor1& a, const AnyExecutor2& b) BOOST_ASIO_NOEXCEPT { return !static_cast<const any_executor&>(a).equality_helper(b); } template <typename AnyExecutor> friend typename enable_if< is_same<AnyExecutor, any_executor>::value, bool >::type operator!=(const AnyExecutor& a, nullptr_t) BOOST_ASIO_NOEXCEPT { return !!a; } template <typename AnyExecutor> friend typename enable_if< is_same<AnyExecutor, any_executor>::value, bool >::type operator!=(nullptr_t, const AnyExecutor& b) BOOST_ASIO_NOEXCEPT { return !!b; } }; inline void swap(any_executor<>& a, any_executor<>& b) BOOST_ASIO_NOEXCEPT { return a.swap(b); } #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename... SupportableProperties> class any_executor : public detail::any_executor_base, public detail::any_executor_context< any_executor<SupportableProperties...>, typename detail::supportable_properties< 0, void(SupportableProperties...)>::find_context_as_property> { public: any_executor() BOOST_ASIO_NOEXCEPT : detail::any_executor_base(), prop_fns_(prop_fns_table<void>()) { } any_executor(nullptr_t) BOOST_ASIO_NOEXCEPT : detail::any_executor_base(), prop_fns_(prop_fns_table<void>()) { } template <typename Executor> any_executor(Executor ex, typename enable_if< conditional< !is_same<Executor, any_executor>::value && !is_base_of<detail::any_executor_base, Executor>::value, detail::is_valid_target_executor< Executor, void(SupportableProperties...)>, false_type >::type::value >::type* = 0) : detail::any_executor_base( BOOST_ASIO_MOVE_CAST(Executor)(ex), false_type()), prop_fns_(prop_fns_table<Executor>()) { } template <typename... OtherSupportableProperties> any_executor(any_executor<OtherSupportableProperties...> other, typename enable_if< conditional< !is_same< any_executor<OtherSupportableProperties...>, any_executor >::value, typename detail::supportable_properties< 0, void(SupportableProperties...)>::template is_valid_target< any_executor<OtherSupportableProperties...> >, false_type >::type::value >::type* = 0) : detail::any_executor_base(BOOST_ASIO_MOVE_CAST( any_executor<OtherSupportableProperties...>)(other), true_type()), prop_fns_(prop_fns_table<any_executor<OtherSupportableProperties...> >()) { } any_executor(const any_executor& other) BOOST_ASIO_NOEXCEPT : detail::any_executor_base( static_cast<const detail::any_executor_base&>(other)), prop_fns_(other.prop_fns_) { } any_executor& operator=(const any_executor& other) BOOST_ASIO_NOEXCEPT { if (this != &other) { prop_fns_ = other.prop_fns_; detail::any_executor_base::operator=( static_cast<const detail::any_executor_base&>(other)); } return *this; } any_executor& operator=(nullptr_t p) BOOST_ASIO_NOEXCEPT { prop_fns_ = prop_fns_table<void>(); detail::any_executor_base::operator=(p); return *this; } #if defined(BOOST_ASIO_HAS_MOVE) any_executor(any_executor&& other) BOOST_ASIO_NOEXCEPT : detail::any_executor_base( static_cast<any_executor_base&&>( static_cast<any_executor_base&>(other))), prop_fns_(other.prop_fns_) { other.prop_fns_ = prop_fns_table<void>(); } any_executor& operator=(any_executor&& other) BOOST_ASIO_NOEXCEPT { if (this != &other) { prop_fns_ = other.prop_fns_; detail::any_executor_base::operator=( static_cast<detail::any_executor_base&&>( static_cast<detail::any_executor_base&>(other))); } return *this; } #endif // defined(BOOST_ASIO_HAS_MOVE) void swap(any_executor& other) BOOST_ASIO_NOEXCEPT { if (this != &other) { detail::any_executor_base::swap( static_cast<detail::any_executor_base&>(other)); const prop_fns<any_executor>* tmp_prop_fns = other.prop_fns_; other.prop_fns_ = prop_fns_; prop_fns_ = tmp_prop_fns; } } using detail::any_executor_base::execute; using detail::any_executor_base::target; using detail::any_executor_base::target_type; using detail::any_executor_base::operator unspecified_bool_type; using detail::any_executor_base::operator!; bool equality_helper(const any_executor& other) const BOOST_ASIO_NOEXCEPT { return any_executor_base::equality_helper(other); } template <typename AnyExecutor1, typename AnyExecutor2> friend typename enable_if< is_same<AnyExecutor1, any_executor>::value || is_same<AnyExecutor2, any_executor>::value, bool >::type operator==(const AnyExecutor1& a, const AnyExecutor2& b) BOOST_ASIO_NOEXCEPT { return static_cast<const any_executor&>(a).equality_helper(b); } template <typename AnyExecutor> friend typename enable_if< is_same<AnyExecutor, any_executor>::value, bool >::type operator==(const AnyExecutor& a, nullptr_t) BOOST_ASIO_NOEXCEPT { return !a; } template <typename AnyExecutor> friend typename enable_if< is_same<AnyExecutor, any_executor>::value, bool >::type operator==(nullptr_t, const AnyExecutor& b) BOOST_ASIO_NOEXCEPT { return !b; } template <typename AnyExecutor1, typename AnyExecutor2> friend typename enable_if< is_same<AnyExecutor1, any_executor>::value || is_same<AnyExecutor2, any_executor>::value, bool >::type operator!=(const AnyExecutor1& a, const AnyExecutor2& b) BOOST_ASIO_NOEXCEPT { return !static_cast<const any_executor&>(a).equality_helper(b); } template <typename AnyExecutor> friend typename enable_if< is_same<AnyExecutor, any_executor>::value, bool >::type operator!=(const AnyExecutor& a, nullptr_t) BOOST_ASIO_NOEXCEPT { return !!a; } template <typename AnyExecutor> friend typename enable_if< is_same<AnyExecutor, any_executor>::value, bool >::type operator!=(nullptr_t, const AnyExecutor& b) BOOST_ASIO_NOEXCEPT { return !!b; } template <typename T> struct find_convertible_property : detail::supportable_properties< 0, void(SupportableProperties...)>::template find_convertible_property<T> {}; template <typename Property> void query(const Property& p, typename enable_if< is_same< typename find_convertible_property<Property>::query_result_type, void >::value >::type* = 0) const { typedef find_convertible_property<Property> found; prop_fns_[found::index].query(0, object_fns_->target(*this), &static_cast<const typename found::type&>(p)); } template <typename Property> typename find_convertible_property<Property>::query_result_type query(const Property& p, typename enable_if< !is_same< typename find_convertible_property<Property>::query_result_type, void >::value && is_reference< typename find_convertible_property<Property>::query_result_type >::value >::type* = 0) const { typedef find_convertible_property<Property> found; typename remove_reference< typename found::query_result_type>::type* result = 0; prop_fns_[found::index].query(&result, object_fns_->target(*this), &static_cast<const typename found::type&>(p)); return *result; } template <typename Property> typename find_convertible_property<Property>::query_result_type query(const Property& p, typename enable_if< !is_same< typename find_convertible_property<Property>::query_result_type, void >::value && is_scalar< typename find_convertible_property<Property>::query_result_type >::value >::type* = 0) const { typedef find_convertible_property<Property> found; typename found::query_result_type result; prop_fns_[found::index].query(&result, object_fns_->target(*this), &static_cast<const typename found::type&>(p)); return result; } template <typename Property> typename find_convertible_property<Property>::query_result_type query(const Property& p, typename enable_if< !is_same< typename find_convertible_property<Property>::query_result_type, void >::value && !is_reference< typename find_convertible_property<Property>::query_result_type >::value && !is_scalar< typename find_convertible_property<Property>::query_result_type >::value >::type* = 0) const { typedef find_convertible_property<Property> found; typename found::query_result_type* result; prop_fns_[found::index].query(&result, object_fns_->target(*this), &static_cast<const typename found::type&>(p)); return *boost::asio::detail::scoped_ptr< typename found::query_result_type>(result); } template <typename T> struct find_convertible_requirable_property : detail::supportable_properties< 0, void(SupportableProperties...)>::template find_convertible_requirable_property<T> {}; template <typename Property> any_executor require(const Property& p, typename enable_if< find_convertible_requirable_property<Property>::value >::type* = 0) const { typedef find_convertible_requirable_property<Property> found; return prop_fns_[found::index].require(object_fns_->target(*this), &static_cast<const typename found::type&>(p)); } template <typename T> struct find_convertible_preferable_property : detail::supportable_properties< 0, void(SupportableProperties...)>::template find_convertible_preferable_property<T> {}; template <typename Property> any_executor prefer(const Property& p, typename enable_if< find_convertible_preferable_property<Property>::value >::type* = 0) const { typedef find_convertible_preferable_property<Property> found; return prop_fns_[found::index].prefer(object_fns_->target(*this), &static_cast<const typename found::type&>(p)); } //private: template <typename Ex> static const prop_fns<any_executor>* prop_fns_table() { static const prop_fns<any_executor> fns[] = { { &detail::any_executor_base::query_fn< Ex, SupportableProperties>, &detail::any_executor_base::require_fn< any_executor, Ex, SupportableProperties>, &detail::any_executor_base::prefer_fn< any_executor, Ex, SupportableProperties> }... }; return fns; } const prop_fns<any_executor>* prop_fns_; }; template <typename... SupportableProperties> inline void swap(any_executor<SupportableProperties...>& a, any_executor<SupportableProperties...>& b) BOOST_ASIO_NOEXCEPT { return a.swap(b); } #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS(n) \ BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_##n #define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_1 \ { \ &detail::any_executor_base::query_fn<Ex, T1>, \ &detail::any_executor_base::require_fn<any_executor, Ex, T1>, \ &detail::any_executor_base::prefer_fn<any_executor, Ex, T1> \ } #define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_2 \ BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_1, \ { \ &detail::any_executor_base::query_fn<Ex, T2>, \ &detail::any_executor_base::require_fn<any_executor, Ex, T2>, \ &detail::any_executor_base::prefer_fn<any_executor, Ex, T2> \ } #define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_3 \ BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_2, \ { \ &detail::any_executor_base::query_fn<Ex, T3>, \ &detail::any_executor_base::require_fn<any_executor, Ex, T3>, \ &detail::any_executor_base::prefer_fn<any_executor, Ex, T3> \ } #define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_4 \ BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_3, \ { \ &detail::any_executor_base::query_fn<Ex, T4>, \ &detail::any_executor_base::require_fn<any_executor, Ex, T4>, \ &detail::any_executor_base::prefer_fn<any_executor, Ex, T4> \ } #define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_5 \ BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_4, \ { \ &detail::any_executor_base::query_fn<Ex, T5>, \ &detail::any_executor_base::require_fn<any_executor, Ex, T5>, \ &detail::any_executor_base::prefer_fn<any_executor, Ex, T5> \ } #define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_6 \ BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_5, \ { \ &detail::any_executor_base::query_fn<Ex, T6>, \ &detail::any_executor_base::require_fn<any_executor, Ex, T6>, \ &detail::any_executor_base::prefer_fn<any_executor, Ex, T6> \ } #define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_7 \ BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_6, \ { \ &detail::any_executor_base::query_fn<Ex, T7>, \ &detail::any_executor_base::require_fn<any_executor, Ex, T7>, \ &detail::any_executor_base::prefer_fn<any_executor, Ex, T7> \ } #define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_8 \ BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_7, \ { \ &detail::any_executor_base::query_fn<Ex, T8>, \ &detail::any_executor_base::require_fn<any_executor, Ex, T8>, \ &detail::any_executor_base::prefer_fn<any_executor, Ex, T8> \ } #if defined(BOOST_ASIO_HAS_MOVE) # define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS \ any_executor(any_executor&& other) BOOST_ASIO_NOEXCEPT \ : detail::any_executor_base( \ static_cast<any_executor_base&&>( \ static_cast<any_executor_base&>(other))), \ prop_fns_(other.prop_fns_) \ { \ other.prop_fns_ = prop_fns_table<void>(); \ } \ \ any_executor& operator=(any_executor&& other) BOOST_ASIO_NOEXCEPT \ { \ if (this != &other) \ { \ prop_fns_ = other.prop_fns_; \ detail::any_executor_base::operator=( \ static_cast<detail::any_executor_base&&>( \ static_cast<detail::any_executor_base&>(other))); \ } \ return *this; \ } \ /**/ #else // defined(BOOST_ASIO_HAS_MOVE) # define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS #endif // defined(BOOST_ASIO_HAS_MOVE) #define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_DEF(n) \ template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ class any_executor<BOOST_ASIO_VARIADIC_TARGS(n)> : \ public detail::any_executor_base, \ public detail::any_executor_context< \ any_executor<BOOST_ASIO_VARIADIC_TARGS(n)>, \ typename detail::supportable_properties< \ 0, void(BOOST_ASIO_VARIADIC_TARGS(n))>::find_context_as_property> \ { \ public: \ any_executor() BOOST_ASIO_NOEXCEPT \ : detail::any_executor_base(), \ prop_fns_(prop_fns_table<void>()) \ { \ } \ \ any_executor(nullptr_t) BOOST_ASIO_NOEXCEPT \ : detail::any_executor_base(), \ prop_fns_(prop_fns_table<void>()) \ { \ } \ \ template <BOOST_ASIO_EXECUTION_EXECUTOR Executor> \ any_executor(Executor ex, \ typename enable_if< \ conditional< \ !is_same<Executor, any_executor>::value \ && !is_base_of<detail::any_executor_base, Executor>::value, \ detail::is_valid_target_executor< \ Executor, void(BOOST_ASIO_VARIADIC_TARGS(n))>, \ false_type \ >::type::value \ >::type* = 0) \ : detail::any_executor_base(BOOST_ASIO_MOVE_CAST( \ Executor)(ex), false_type()), \ prop_fns_(prop_fns_table<Executor>()) \ { \ } \ \ any_executor(const any_executor& other) BOOST_ASIO_NOEXCEPT \ : detail::any_executor_base( \ static_cast<const detail::any_executor_base&>(other)), \ prop_fns_(other.prop_fns_) \ { \ } \ \ any_executor(any_executor<> other) \ : detail::any_executor_base(BOOST_ASIO_MOVE_CAST( \ any_executor<>)(other), true_type()), \ prop_fns_(prop_fns_table<any_executor<> >()) \ { \ } \ \ template <typename OtherAnyExecutor> \ any_executor(OtherAnyExecutor other, \ typename enable_if< \ conditional< \ !is_same<OtherAnyExecutor, any_executor>::value \ && is_base_of<detail::any_executor_base, \ OtherAnyExecutor>::value, \ typename detail::supportable_properties< \ 0, void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ is_valid_target<OtherAnyExecutor>, \ false_type \ >::type::value \ >::type* = 0) \ : detail::any_executor_base(BOOST_ASIO_MOVE_CAST( \ OtherAnyExecutor)(other), true_type()), \ prop_fns_(prop_fns_table<OtherAnyExecutor>()) \ { \ } \ \ any_executor& operator=(const any_executor& other) BOOST_ASIO_NOEXCEPT \ { \ if (this != &other) \ { \ prop_fns_ = other.prop_fns_; \ detail::any_executor_base::operator=( \ static_cast<const detail::any_executor_base&>(other)); \ } \ return *this; \ } \ \ any_executor& operator=(nullptr_t p) BOOST_ASIO_NOEXCEPT \ { \ prop_fns_ = prop_fns_table<void>(); \ detail::any_executor_base::operator=(p); \ return *this; \ } \ \ BOOST_ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS \ \ void swap(any_executor& other) BOOST_ASIO_NOEXCEPT \ { \ if (this != &other) \ { \ detail::any_executor_base::swap( \ static_cast<detail::any_executor_base&>(other)); \ const prop_fns<any_executor>* tmp_prop_fns = other.prop_fns_; \ other.prop_fns_ = prop_fns_; \ prop_fns_ = tmp_prop_fns; \ } \ } \ \ using detail::any_executor_base::execute; \ using detail::any_executor_base::target; \ using detail::any_executor_base::target_type; \ using detail::any_executor_base::operator unspecified_bool_type; \ using detail::any_executor_base::operator!; \ \ bool equality_helper(const any_executor& other) const BOOST_ASIO_NOEXCEPT \ { \ return any_executor_base::equality_helper(other); \ } \ \ template <typename AnyExecutor1, typename AnyExecutor2> \ friend typename enable_if< \ is_same<AnyExecutor1, any_executor>::value \ || is_same<AnyExecutor2, any_executor>::value, \ bool \ >::type operator==(const AnyExecutor1& a, \ const AnyExecutor2& b) BOOST_ASIO_NOEXCEPT \ { \ return static_cast<const any_executor&>(a).equality_helper(b); \ } \ \ template <typename AnyExecutor> \ friend typename enable_if< \ is_same<AnyExecutor, any_executor>::value, \ bool \ >::type operator==(const AnyExecutor& a, nullptr_t) BOOST_ASIO_NOEXCEPT \ { \ return !a; \ } \ \ template <typename AnyExecutor> \ friend typename enable_if< \ is_same<AnyExecutor, any_executor>::value, \ bool \ >::type operator==(nullptr_t, const AnyExecutor& b) BOOST_ASIO_NOEXCEPT \ { \ return !b; \ } \ \ template <typename AnyExecutor1, typename AnyExecutor2> \ friend typename enable_if< \ is_same<AnyExecutor1, any_executor>::value \ || is_same<AnyExecutor2, any_executor>::value, \ bool \ >::type operator!=(const AnyExecutor1& a, \ const AnyExecutor2& b) BOOST_ASIO_NOEXCEPT \ { \ return !static_cast<const any_executor&>(a).equality_helper(b); \ } \ \ template <typename AnyExecutor> \ friend typename enable_if< \ is_same<AnyExecutor, any_executor>::value, \ bool \ >::type operator!=(const AnyExecutor& a, nullptr_t) BOOST_ASIO_NOEXCEPT \ { \ return !!a; \ } \ \ template <typename AnyExecutor> \ friend typename enable_if< \ is_same<AnyExecutor, any_executor>::value, \ bool \ >::type operator!=(nullptr_t, const AnyExecutor& b) BOOST_ASIO_NOEXCEPT \ { \ return !!b; \ } \ \ template <typename T> \ struct find_convertible_property : \ detail::supportable_properties< \ 0, void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ find_convertible_property<T> {}; \ \ template <typename Property> \ void query(const Property& p, \ typename enable_if< \ is_same< \ typename find_convertible_property<Property>::query_result_type, \ void \ >::value \ >::type* = 0) const \ { \ typedef find_convertible_property<Property> found; \ prop_fns_[found::index].query(0, object_fns_->target(*this), \ &static_cast<const typename found::type&>(p)); \ } \ \ template <typename Property> \ typename find_convertible_property<Property>::query_result_type \ query(const Property& p, \ typename enable_if< \ !is_same< \ typename find_convertible_property<Property>::query_result_type, \ void \ >::value \ && \ is_reference< \ typename find_convertible_property<Property>::query_result_type \ >::value \ >::type* = 0) const \ { \ typedef find_convertible_property<Property> found; \ typename remove_reference< \ typename found::query_result_type>::type* result; \ prop_fns_[found::index].query(&result, object_fns_->target(*this), \ &static_cast<const typename found::type&>(p)); \ return *result; \ } \ \ template <typename Property> \ typename find_convertible_property<Property>::query_result_type \ query(const Property& p, \ typename enable_if< \ !is_same< \ typename find_convertible_property<Property>::query_result_type, \ void \ >::value \ && \ is_scalar< \ typename find_convertible_property<Property>::query_result_type \ >::value \ >::type* = 0) const \ { \ typedef find_convertible_property<Property> found; \ typename found::query_result_type result; \ prop_fns_[found::index].query(&result, object_fns_->target(*this), \ &static_cast<const typename found::type&>(p)); \ return result; \ } \ \ template <typename Property> \ typename find_convertible_property<Property>::query_result_type \ query(const Property& p, \ typename enable_if< \ !is_same< \ typename find_convertible_property<Property>::query_result_type, \ void \ >::value \ && \ !is_reference< \ typename find_convertible_property<Property>::query_result_type \ >::value \ && \ !is_scalar< \ typename find_convertible_property<Property>::query_result_type \ >::value \ >::type* = 0) const \ { \ typedef find_convertible_property<Property> found; \ typename found::query_result_type* result; \ prop_fns_[found::index].query(&result, object_fns_->target(*this), \ &static_cast<const typename found::type&>(p)); \ return *boost::asio::detail::scoped_ptr< \ typename found::query_result_type>(result); \ } \ \ template <typename T> \ struct find_convertible_requirable_property : \ detail::supportable_properties< \ 0, void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ find_convertible_requirable_property<T> {}; \ \ template <typename Property> \ any_executor require(const Property& p, \ typename enable_if< \ find_convertible_requirable_property<Property>::value \ >::type* = 0) const \ { \ typedef find_convertible_requirable_property<Property> found; \ return prop_fns_[found::index].require(object_fns_->target(*this), \ &static_cast<const typename found::type&>(p)); \ } \ \ template <typename T> \ struct find_convertible_preferable_property : \ detail::supportable_properties< \ 0, void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ find_convertible_preferable_property<T> {}; \ \ template <typename Property> \ any_executor prefer(const Property& p, \ typename enable_if< \ find_convertible_preferable_property<Property>::value \ >::type* = 0) const \ { \ typedef find_convertible_preferable_property<Property> found; \ return prop_fns_[found::index].prefer(object_fns_->target(*this), \ &static_cast<const typename found::type&>(p)); \ } \ \ template <typename Ex> \ static const prop_fns<any_executor>* prop_fns_table() \ { \ static const prop_fns<any_executor> fns[] = \ { \ BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS(n) \ }; \ return fns; \ } \ \ const prop_fns<any_executor>* prop_fns_; \ typedef detail::supportable_properties<0, \ void(BOOST_ASIO_VARIADIC_TARGS(n))> supportable_properties_type; \ }; \ \ template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ inline void swap(any_executor<BOOST_ASIO_VARIADIC_TARGS(n)>& a, \ any_executor<BOOST_ASIO_VARIADIC_TARGS(n)>& b) BOOST_ASIO_NOEXCEPT \ { \ return a.swap(b); \ } \ /**/ BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_ANY_EXECUTOR_DEF) #undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_DEF #undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_MOVE_OPS #undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS #undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_1 #undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_2 #undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_3 #undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_4 #undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_5 #undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_6 #undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_7 #undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PROP_FNS_8 #endif // if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) } // namespace execution namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename... SupportableProperties> struct equality_comparable<execution::any_executor<SupportableProperties...> > { static const bool is_valid = true; static const bool is_noexcept = true; }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <> struct equality_comparable<execution::any_executor<> > { static const bool is_valid = true; static const bool is_noexcept = true; }; #define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_EQUALITY_COMPARABLE_DEF(n) \ template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ struct equality_comparable< \ execution::any_executor<BOOST_ASIO_VARIADIC_TARGS(n)> > \ { \ static const bool is_valid = true; \ static const bool is_noexcept = true; \ }; \ /**/ BOOST_ASIO_VARIADIC_GENERATE( BOOST_ASIO_PRIVATE_ANY_EXECUTOR_EQUALITY_COMPARABLE_DEF) #undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_EQUALITY_COMPARABLE_DEF #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename F, typename... SupportableProperties> struct execute_member<execution::any_executor<SupportableProperties...>, F> { static const bool is_valid = true; static const bool is_noexcept = false; typedef void result_type; }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename F> struct execute_member<execution::any_executor<>, F> { static const bool is_valid = true; static const bool is_noexcept = false; typedef void result_type; }; #define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_EXECUTE_MEMBER_DEF(n) \ template <typename F, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ struct execute_member< \ execution::any_executor<BOOST_ASIO_VARIADIC_TARGS(n)>, F> \ { \ static const bool is_valid = true; \ static const bool is_noexcept = false; \ typedef void result_type; \ }; \ /**/ BOOST_ASIO_VARIADIC_GENERATE( BOOST_ASIO_PRIVATE_ANY_EXECUTOR_EXECUTE_MEMBER_DEF) #undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_EXECUTE_MEMBER_DEF #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename Prop, typename... SupportableProperties> struct query_member< execution::any_executor<SupportableProperties...>, Prop, typename enable_if< execution::detail::supportable_properties< 0, void(SupportableProperties...)>::template find_convertible_property<Prop>::value >::type> { static const bool is_valid = true; static const bool is_noexcept = false; typedef typename execution::detail::supportable_properties< 0, void(SupportableProperties...)>::template find_convertible_property<Prop>::query_result_type result_type; }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_QUERY_MEMBER_DEF(n) \ template <typename Prop, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ struct query_member< \ execution::any_executor<BOOST_ASIO_VARIADIC_TARGS(n)>, Prop, \ typename enable_if< \ execution::detail::supportable_properties< \ 0, void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ find_convertible_property<Prop>::value \ >::type> \ { \ static const bool is_valid = true; \ static const bool is_noexcept = false; \ typedef typename execution::detail::supportable_properties< \ 0, void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ find_convertible_property<Prop>::query_result_type result_type; \ }; \ /**/ BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_ANY_EXECUTOR_QUERY_MEMBER_DEF) #undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_QUERY_MEMBER_DEF #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename Prop, typename... SupportableProperties> struct require_member< execution::any_executor<SupportableProperties...>, Prop, typename enable_if< execution::detail::supportable_properties< 0, void(SupportableProperties...)>::template find_convertible_requirable_property<Prop>::value >::type> { static const bool is_valid = true; static const bool is_noexcept = false; typedef execution::any_executor<SupportableProperties...> result_type; }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_REQUIRE_MEMBER_DEF(n) \ template <typename Prop, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ struct require_member< \ execution::any_executor<BOOST_ASIO_VARIADIC_TARGS(n)>, Prop, \ typename enable_if< \ execution::detail::supportable_properties< \ 0, void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ find_convertible_requirable_property<Prop>::value \ >::type> \ { \ static const bool is_valid = true; \ static const bool is_noexcept = false; \ typedef execution::any_executor<BOOST_ASIO_VARIADIC_TARGS(n)> result_type; \ }; \ /**/ BOOST_ASIO_VARIADIC_GENERATE( BOOST_ASIO_PRIVATE_ANY_EXECUTOR_REQUIRE_MEMBER_DEF) #undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_REQUIRE_MEMBER_DEF #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename Prop, typename... SupportableProperties> struct prefer_member< execution::any_executor<SupportableProperties...>, Prop, typename enable_if< execution::detail::supportable_properties< 0, void(SupportableProperties...)>::template find_convertible_preferable_property<Prop>::value >::type> { static const bool is_valid = true; static const bool is_noexcept = false; typedef execution::any_executor<SupportableProperties...> result_type; }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #define BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PREFER_FREE_DEF(n) \ template <typename Prop, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ struct prefer_member< \ execution::any_executor<BOOST_ASIO_VARIADIC_TARGS(n)>, Prop, \ typename enable_if< \ execution::detail::supportable_properties< \ 0, void(BOOST_ASIO_VARIADIC_TARGS(n))>::template \ find_convertible_preferable_property<Prop>::value \ >::type> \ { \ static const bool is_valid = true; \ static const bool is_noexcept = false; \ typedef execution::any_executor<BOOST_ASIO_VARIADIC_TARGS(n)> result_type; \ }; \ /**/ BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PREFER_FREE_DEF) #undef BOOST_ASIO_PRIVATE_ANY_EXECUTOR_PREFER_FREE_DEF #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) } // namespace traits #endif // defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_ANY_EXECUTOR_HPP execution/executor.hpp 0000644 00000015667 15125530236 0011137 0 ustar 00 // // execution/executor.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_EXECUTOR_HPP #define BOOST_ASIO_EXECUTION_EXECUTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/execute.hpp> #include <boost/asio/execution/invocable_archetype.hpp> #include <boost/asio/traits/equality_comparable.hpp> #if defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT) \ && defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) \ && defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) # define BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_EXECUTOR_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT) // && defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) // && defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace execution { namespace detail { template <typename T, typename F> struct is_executor_of_impl_base : integral_constant<bool, conditional<true, true_type, typename result_of<typename decay<F>::type&()>::type >::type::value && is_constructible<typename decay<F>::type, F>::value && is_move_constructible<typename decay<F>::type>::value #if defined(BOOST_ASIO_HAS_NOEXCEPT) && is_nothrow_copy_constructible<T>::value && is_nothrow_destructible<T>::value #else // defined(BOOST_ASIO_HAS_NOEXCEPT) && is_copy_constructible<T>::value && is_destructible<T>::value #endif // defined(BOOST_ASIO_HAS_NOEXCEPT) && traits::equality_comparable<T>::is_valid && traits::equality_comparable<T>::is_noexcept > { }; template <typename T, typename F> struct is_executor_of_impl : conditional< can_execute<typename add_const<T>::type, F>::value, is_executor_of_impl_base<T, F>, false_type >::type { }; template <typename T, typename = void> struct executor_shape { typedef std::size_t type; }; template <typename T> struct executor_shape<T, typename void_type< typename T::shape_type >::type> { typedef typename T::shape_type type; }; template <typename T, typename Default, typename = void> struct executor_index { typedef Default type; }; template <typename T, typename Default> struct executor_index<T, Default, typename void_type< typename T::index_type >::type> { typedef typename T::index_type type; }; } // namespace detail /// The is_executor trait detects whether a type T satisfies the /// execution::executor concept. /** * Class template @c is_executor is a UnaryTypeTrait that is derived from @c * true_type if the type @c T meets the concept definition for an executor, * otherwise @c false_type. */ template <typename T> struct is_executor : #if defined(GENERATING_DOCUMENTATION) integral_constant<bool, automatically_determined> #else // defined(GENERATING_DOCUMENTATION) detail::is_executor_of_impl<T, invocable_archetype> #endif // defined(GENERATING_DOCUMENTATION) { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_CONSTEXPR const bool is_executor_v = is_executor<T>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) #if defined(BOOST_ASIO_HAS_CONCEPTS) template <typename T> BOOST_ASIO_CONCEPT executor = is_executor<T>::value; #define BOOST_ASIO_EXECUTION_EXECUTOR ::boost::asio::execution::executor #else // defined(BOOST_ASIO_HAS_CONCEPTS) #define BOOST_ASIO_EXECUTION_EXECUTOR typename #endif // defined(BOOST_ASIO_HAS_CONCEPTS) /// The is_executor_of trait detects whether a type T satisfies the /// execution::executor_of concept for some set of value arguments. /** * Class template @c is_executor_of is a type trait that is derived from @c * true_type if the type @c T meets the concept definition for an executor * that is invocable with a function object of type @c F, otherwise @c * false_type. */ template <typename T, typename F> struct is_executor_of : #if defined(GENERATING_DOCUMENTATION) integral_constant<bool, automatically_determined> #else // defined(GENERATING_DOCUMENTATION) integral_constant<bool, is_executor<T>::value && detail::is_executor_of_impl<T, F>::value > #endif // defined(GENERATING_DOCUMENTATION) { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename F> BOOST_ASIO_CONSTEXPR const bool is_executor_of_v = is_executor_of<T, F>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) #if defined(BOOST_ASIO_HAS_CONCEPTS) template <typename T, typename F> BOOST_ASIO_CONCEPT executor_of = is_executor_of<T, F>::value; #define BOOST_ASIO_EXECUTION_EXECUTOR_OF(f) \ ::boost::asio::execution::executor_of<f> #else // defined(BOOST_ASIO_HAS_CONCEPTS) #define BOOST_ASIO_EXECUTION_EXECUTOR_OF typename #endif // defined(BOOST_ASIO_HAS_CONCEPTS) /// The executor_shape trait detects the type used by an executor to represent /// the shape of a bulk operation. /** * Class template @c executor_shape is a type trait with a nested type alias * @c type whose type is @c T::shape_type if @c T::shape_type is valid, * otherwise @c std::size_t. */ template <typename T> struct executor_shape #if !defined(GENERATING_DOCUMENTATION) : detail::executor_shape<T> #endif // !defined(GENERATING_DOCUMENTATION) { #if defined(GENERATING_DOCUMENTATION) /// @c T::shape_type if @c T::shape_type is valid, otherwise @c std::size_t. typedef automatically_determined type; #endif // defined(GENERATING_DOCUMENTATION) }; #if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) template <typename T> using executor_shape_t = typename executor_shape<T>::type; #endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) /// The executor_index trait detects the type used by an executor to represent /// an index within a bulk operation. /** * Class template @c executor_index is a type trait with a nested type alias * @c type whose type is @c T::index_type if @c T::index_type is valid, * otherwise @c executor_shape_t<T>. */ template <typename T> struct executor_index #if !defined(GENERATING_DOCUMENTATION) : detail::executor_index<T, typename executor_shape<T>::type> #endif // !defined(GENERATING_DOCUMENTATION) { #if defined(GENERATING_DOCUMENTATION) /// @c T::index_type if @c T::index_type is valid, otherwise /// @c executor_shape_t<T>. typedef automatically_determined type; #endif // defined(GENERATING_DOCUMENTATION) }; #if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) template <typename T> using executor_index_t = typename executor_index<T>::type; #endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) } // namespace execution } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_EXECUTOR_HPP execution/invocable_archetype.hpp 0000644 00000003765 15125530236 0013303 0 ustar 00 // // execution/invocable_archetype.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_INVOCABLE_ARCHETYPE_HPP #define BOOST_ASIO_EXECUTION_INVOCABLE_ARCHETYPE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/variadic_templates.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace execution { /// An archetypal function object used for determining adherence to the /// execution::executor concept. struct invocable_archetype { #if !defined(GENERATING_DOCUMENTATION) // Necessary for compatibility with a C++03 implementation of result_of. typedef void result_type; #endif // !defined(GENERATING_DOCUMENTATION) #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) \ || defined(GENERATING_DOCUMENTATION) /// Function call operator. template <typename... Args> void operator()(BOOST_ASIO_MOVE_ARG(Args)...) { } #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) // || defined(GENERATING_DOCUMENTATION) void operator()() { } #define BOOST_ASIO_PRIVATE_INVOCABLE_ARCHETYPE_CALL_DEF(n) \ template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ void operator()(BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS(n)) \ { \ } \ /**/ BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_INVOCABLE_ARCHETYPE_CALL_DEF) #undef BOOST_ASIO_PRIVATE_INVOCABLE_ARCHETYPE_CALL_DEF #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) // || defined(GENERATING_DOCUMENTATION) }; } // namespace execution } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_INVOCABLE_ARCHETYPE_HPP execution/receiver_invocation_error.hpp 0000644 00000002607 15125530236 0014535 0 ustar 00 // // execution/receiver_invocation_error.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_RECEIVER_INVOCATION_ERROR_HPP #define BOOST_ASIO_EXECUTION_RECEIVER_INVOCATION_ERROR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <stdexcept> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace execution { /// Exception reported via @c set_error when an exception escapes from /// @c set_value. class receiver_invocation_error : public std::runtime_error #if defined(BOOST_ASIO_HAS_STD_NESTED_EXCEPTION) , public std::nested_exception #endif // defined(BOOST_ASIO_HAS_STD_NESTED_EXCEPTION) { public: /// Constructor. BOOST_ASIO_DECL receiver_invocation_error(); }; } // namespace execution } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/execution/impl/receiver_invocation_error.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_EXECUTION_RECEIVER_INVOCATION_ERROR_HPP execution/blocking.hpp 0000644 00000120570 15125530236 0011057 0 ustar 00 // // execution/blocking.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_BLOCKING_HPP #define BOOST_ASIO_EXECUTION_BLOCKING_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/execute.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/scheduler.hpp> #include <boost/asio/execution/sender.hpp> #include <boost/asio/is_applicable_property.hpp> #include <boost/asio/prefer.hpp> #include <boost/asio/query.hpp> #include <boost/asio/require.hpp> #include <boost/asio/traits/query_free.hpp> #include <boost/asio/traits/query_member.hpp> #include <boost/asio/traits/query_static_constexpr_member.hpp> #include <boost/asio/traits/static_query.hpp> #include <boost/asio/traits/static_require.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if defined(GENERATING_DOCUMENTATION) namespace execution { /// A property to describe what guarantees an executor makes about the blocking /// behaviour of their execution functions. struct blocking_t { /// The blocking_t property applies to executors, senders, and schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The top-level blocking_t property cannot be required. static constexpr bool is_requirable = false; /// The top-level blocking_t property cannot be preferred. static constexpr bool is_preferable = false; /// The type returned by queries against an @c any_executor. typedef blocking_t polymorphic_query_result_type; /// A sub-property that indicates that invocation of an executor's execution /// function may block pending completion of one or more invocations of the /// submitted function object. struct possibly_t { /// The blocking_t::possibly_t property applies to executors, senders, and /// schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The blocking_t::possibly_t property can be required. static constexpr bool is_requirable = true; /// The blocking_t::possibly_t property can be preferred. static constexpr bool is_preferable = true; /// The type returned by queries against an @c any_executor. typedef blocking_t polymorphic_query_result_type; /// Default constructor. constexpr possibly_t(); /// Get the value associated with a property object. /** * @returns possibly_t(); */ static constexpr blocking_t value(); }; /// A sub-property that indicates that invocation of an executor's execution /// function shall block until completion of all invocations of the submitted /// function object. struct always_t { /// The blocking_t::always_t property applies to executors, senders, and /// schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The blocking_t::always_t property can be required. static constexpr bool is_requirable = true; /// The blocking_t::always_t property can be preferred. static constexpr bool is_preferable = false; /// The type returned by queries against an @c any_executor. typedef blocking_t polymorphic_query_result_type; /// Default constructor. constexpr always_t(); /// Get the value associated with a property object. /** * @returns always_t(); */ static constexpr blocking_t value(); }; /// A sub-property that indicates that invocation of an executor's execution /// function shall not block pending completion of the invocations of the /// submitted function object. struct never_t { /// The blocking_t::never_t property applies to executors, senders, and /// schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The blocking_t::never_t property can be required. static constexpr bool is_requirable = true; /// The blocking_t::never_t property can be preferred. static constexpr bool is_preferable = true; /// The type returned by queries against an @c any_executor. typedef blocking_t polymorphic_query_result_type; /// Default constructor. constexpr never_t(); /// Get the value associated with a property object. /** * @returns never_t(); */ static constexpr blocking_t value(); }; /// A special value used for accessing the blocking_t::possibly_t property. static constexpr possibly_t possibly; /// A special value used for accessing the blocking_t::always_t property. static constexpr always_t always; /// A special value used for accessing the blocking_t::never_t property. static constexpr never_t never; /// Default constructor. constexpr blocking_t(); /// Construct from a sub-property value. constexpr blocking_t(possibly_t); /// Construct from a sub-property value. constexpr blocking_t(always_t); /// Construct from a sub-property value. constexpr blocking_t(never_t); /// Compare property values for equality. friend constexpr bool operator==( const blocking_t& a, const blocking_t& b) noexcept; /// Compare property values for inequality. friend constexpr bool operator!=( const blocking_t& a, const blocking_t& b) noexcept; }; /// A special value used for accessing the blocking_t property. constexpr blocking_t blocking; } // namespace execution #else // defined(GENERATING_DOCUMENTATION) namespace execution { namespace detail { namespace blocking { template <int I> struct possibly_t; template <int I> struct always_t; template <int I> struct never_t; } // namespace blocking namespace blocking_adaptation { template <int I> struct allowed_t; template <typename Executor, typename Function> void blocking_execute( BOOST_ASIO_MOVE_ARG(Executor) ex, BOOST_ASIO_MOVE_ARG(Function) func); } // namespace blocking_adaptation template <int I = 0> struct blocking_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); typedef blocking_t polymorphic_query_result_type; typedef detail::blocking::possibly_t<I> possibly_t; typedef detail::blocking::always_t<I> always_t; typedef detail::blocking::never_t<I> never_t; BOOST_ASIO_CONSTEXPR blocking_t() : value_(-1) { } BOOST_ASIO_CONSTEXPR blocking_t(possibly_t) : value_(0) { } BOOST_ASIO_CONSTEXPR blocking_t(always_t) : value_(1) { } BOOST_ASIO_CONSTEXPR blocking_t(never_t) : value_(2) { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, blocking_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, blocking_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, blocking_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::static_query<T, possibly_t>::result_type static_query( typename enable_if< !traits::query_static_constexpr_member<T, blocking_t>::is_valid && !traits::query_member<T, blocking_t>::is_valid && traits::static_query<T, possibly_t>::is_valid >::type* = 0) BOOST_ASIO_NOEXCEPT { return traits::static_query<T, possibly_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::static_query<T, always_t>::result_type static_query( typename enable_if< !traits::query_static_constexpr_member<T, blocking_t>::is_valid && !traits::query_member<T, blocking_t>::is_valid && !traits::static_query<T, possibly_t>::is_valid && traits::static_query<T, always_t>::is_valid >::type* = 0) BOOST_ASIO_NOEXCEPT { return traits::static_query<T, always_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::static_query<T, never_t>::result_type static_query( typename enable_if< !traits::query_static_constexpr_member<T, blocking_t>::is_valid && !traits::query_member<T, blocking_t>::is_valid && !traits::static_query<T, possibly_t>::is_valid && !traits::static_query<T, always_t>::is_valid && traits::static_query<T, never_t>::is_valid >::type* = 0) BOOST_ASIO_NOEXCEPT { return traits::static_query<T, never_t>::value(); } template <typename E, typename T = decltype(blocking_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = blocking_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) friend BOOST_ASIO_CONSTEXPR bool operator==( const blocking_t& a, const blocking_t& b) { return a.value_ == b.value_; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const blocking_t& a, const blocking_t& b) { return a.value_ != b.value_; } struct convertible_from_blocking_t { BOOST_ASIO_CONSTEXPR convertible_from_blocking_t(blocking_t) {} }; template <typename Executor> friend BOOST_ASIO_CONSTEXPR blocking_t query( const Executor& ex, convertible_from_blocking_t, typename enable_if< can_query<const Executor&, possibly_t>::value >::type* = 0) #if !defined(__clang__) // Clang crashes if noexcept is used here. #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified. BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, blocking_t<>::possibly_t>::value)) #else // defined(BOOST_ASIO_MSVC) BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, possibly_t>::value)) #endif // defined(BOOST_ASIO_MSVC) #endif // !defined(__clang__) { return boost::asio::query(ex, possibly_t()); } template <typename Executor> friend BOOST_ASIO_CONSTEXPR blocking_t query( const Executor& ex, convertible_from_blocking_t, typename enable_if< !can_query<const Executor&, possibly_t>::value && can_query<const Executor&, always_t>::value >::type* = 0) #if !defined(__clang__) // Clang crashes if noexcept is used here. #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified. BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, blocking_t<>::always_t>::value)) #else // defined(BOOST_ASIO_MSVC) BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, always_t>::value)) #endif // defined(BOOST_ASIO_MSVC) #endif // !defined(__clang__) { return boost::asio::query(ex, always_t()); } template <typename Executor> friend BOOST_ASIO_CONSTEXPR blocking_t query( const Executor& ex, convertible_from_blocking_t, typename enable_if< !can_query<const Executor&, possibly_t>::value && !can_query<const Executor&, always_t>::value && can_query<const Executor&, never_t>::value >::type* = 0) #if !defined(__clang__) // Clang crashes if noexcept is used here. #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified. BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, blocking_t<>::never_t>::value)) #else // defined(BOOST_ASIO_MSVC) BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, never_t>::value)) #endif // defined(BOOST_ASIO_MSVC) #endif // !defined(__clang__) { return boost::asio::query(ex, never_t()); } BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(possibly_t, possibly); BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(always_t, always); BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(never_t, never); #if !defined(BOOST_ASIO_HAS_CONSTEXPR) static const blocking_t instance; #endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) private: int value_; }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T blocking_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if !defined(BOOST_ASIO_HAS_CONSTEXPR) template <int I> const blocking_t<I> blocking_t<I>::instance; #endif template <int I> const typename blocking_t<I>::possibly_t blocking_t<I>::possibly; template <int I> const typename blocking_t<I>::always_t blocking_t<I>::always; template <int I> const typename blocking_t<I>::never_t blocking_t<I>::never; namespace blocking { template <int I = 0> struct possibly_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); typedef blocking_t<I> polymorphic_query_result_type; BOOST_ASIO_CONSTEXPR possibly_t() { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, possibly_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, possibly_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, possibly_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR possibly_t static_query( typename enable_if< !traits::query_static_constexpr_member<T, possibly_t>::is_valid && !traits::query_member<T, possibly_t>::is_valid && !traits::query_free<T, possibly_t>::is_valid && !can_query<T, always_t<I> >::value && !can_query<T, never_t<I> >::value >::type* = 0) BOOST_ASIO_NOEXCEPT { return possibly_t(); } template <typename E, typename T = decltype(possibly_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = possibly_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) static BOOST_ASIO_CONSTEXPR blocking_t<I> value() { return possibly_t(); } friend BOOST_ASIO_CONSTEXPR bool operator==( const possibly_t&, const possibly_t&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const possibly_t&, const possibly_t&) { return false; } friend BOOST_ASIO_CONSTEXPR bool operator==( const possibly_t&, const always_t<I>&) { return false; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const possibly_t&, const always_t<I>&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator==( const possibly_t&, const never_t<I>&) { return false; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const possibly_t&, const never_t<I>&) { return true; } }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T possibly_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename Executor> class adapter { public: adapter(int, const Executor& e) BOOST_ASIO_NOEXCEPT : executor_(e) { } adapter(const adapter& other) BOOST_ASIO_NOEXCEPT : executor_(other.executor_) { } #if defined(BOOST_ASIO_HAS_MOVE) adapter(adapter&& other) BOOST_ASIO_NOEXCEPT : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)) { } #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) template <int I> static BOOST_ASIO_CONSTEXPR always_t<I> query( blocking_t<I>) BOOST_ASIO_NOEXCEPT { return always_t<I>(); } template <int I> static BOOST_ASIO_CONSTEXPR always_t<I> query( possibly_t<I>) BOOST_ASIO_NOEXCEPT { return always_t<I>(); } template <int I> static BOOST_ASIO_CONSTEXPR always_t<I> query( always_t<I>) BOOST_ASIO_NOEXCEPT { return always_t<I>(); } template <int I> static BOOST_ASIO_CONSTEXPR always_t<I> query( never_t<I>) BOOST_ASIO_NOEXCEPT { return always_t<I>(); } template <typename Property> typename enable_if< can_query<const Executor&, Property>::value, typename query_result<const Executor&, Property>::type >::type query(const Property& p) const BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, Property>::value)) { return boost::asio::query(executor_, p); } template <int I> typename enable_if< can_require<const Executor&, possibly_t<I> >::value, typename require_result<const Executor&, possibly_t<I> >::type >::type require(possibly_t<I>) const BOOST_ASIO_NOEXCEPT { return boost::asio::require(executor_, possibly_t<I>()); } template <int I> typename enable_if< can_require<const Executor&, never_t<I> >::value, typename require_result<const Executor&, never_t<I> >::type >::type require(never_t<I>) const BOOST_ASIO_NOEXCEPT { return boost::asio::require(executor_, never_t<I>()); } template <typename Property> typename enable_if< can_require<const Executor&, Property>::value, adapter<typename decay< typename require_result<const Executor&, Property>::type >::type> >::type require(const Property& p) const BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_require<const Executor&, Property>::value)) { return adapter<typename decay< typename require_result<const Executor&, Property>::type >::type>(0, boost::asio::require(executor_, p)); } template <typename Property> typename enable_if< can_prefer<const Executor&, Property>::value, adapter<typename decay< typename prefer_result<const Executor&, Property>::type >::type> >::type prefer(const Property& p) const BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_prefer<const Executor&, Property>::value)) { return adapter<typename decay< typename prefer_result<const Executor&, Property>::type >::type>(0, boost::asio::prefer(executor_, p)); } template <typename Function> typename enable_if< execution::can_execute<const Executor&, Function>::value >::type execute(BOOST_ASIO_MOVE_ARG(Function) f) const { blocking_adaptation::blocking_execute( executor_, BOOST_ASIO_MOVE_CAST(Function)(f)); } friend bool operator==(const adapter& a, const adapter& b) BOOST_ASIO_NOEXCEPT { return a.executor_ == b.executor_; } friend bool operator!=(const adapter& a, const adapter& b) BOOST_ASIO_NOEXCEPT { return a.executor_ != b.executor_; } private: Executor executor_; }; template <int I = 0> struct always_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); typedef blocking_t<I> polymorphic_query_result_type; BOOST_ASIO_CONSTEXPR always_t() { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, always_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, always_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, always_t>::value(); } template <typename E, typename T = decltype(always_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = always_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) static BOOST_ASIO_CONSTEXPR blocking_t<I> value() { return always_t(); } friend BOOST_ASIO_CONSTEXPR bool operator==( const always_t&, const always_t&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const always_t&, const always_t&) { return false; } friend BOOST_ASIO_CONSTEXPR bool operator==( const always_t&, const possibly_t<I>&) { return false; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const always_t&, const possibly_t<I>&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator==( const always_t&, const never_t<I>&) { return false; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const always_t&, const never_t<I>&) { return true; } template <typename Executor> friend adapter<Executor> require( const Executor& e, const always_t&, typename enable_if< is_executor<Executor>::value && traits::static_require< const Executor&, blocking_adaptation::allowed_t<0> >::is_valid >::type* = 0) { return adapter<Executor>(0, e); } }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T always_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> struct never_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); typedef blocking_t<I> polymorphic_query_result_type; BOOST_ASIO_CONSTEXPR never_t() { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, never_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, never_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, never_t>::value(); } template <typename E, typename T = decltype(never_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = never_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) static BOOST_ASIO_CONSTEXPR blocking_t<I> value() { return never_t(); } friend BOOST_ASIO_CONSTEXPR bool operator==( const never_t&, const never_t&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const never_t&, const never_t&) { return false; } friend BOOST_ASIO_CONSTEXPR bool operator==( const never_t&, const possibly_t<I>&) { return false; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const never_t&, const possibly_t<I>&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator==( const never_t&, const always_t<I>&) { return false; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const never_t&, const always_t<I>&) { return true; } }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T never_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) } // namespace blocking } // namespace detail typedef detail::blocking_t<> blocking_t; #if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) constexpr blocking_t blocking; #else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) namespace { static const blocking_t& blocking = blocking_t::instance; } #endif } // namespace execution #if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> struct is_applicable_property<T, execution::blocking_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; template <typename T> struct is_applicable_property<T, execution::blocking_t::possibly_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; template <typename T> struct is_applicable_property<T, execution::blocking_t::always_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; template <typename T> struct is_applicable_property<T, execution::blocking_t::never_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; #endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) template <typename T> struct query_free_default<T, execution::blocking_t, typename enable_if< can_query<T, execution::blocking_t::possibly_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<T, execution::blocking_t::possibly_t>::value)); typedef execution::blocking_t result_type; }; template <typename T> struct query_free_default<T, execution::blocking_t, typename enable_if< !can_query<T, execution::blocking_t::possibly_t>::value && can_query<T, execution::blocking_t::always_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<T, execution::blocking_t::always_t>::value)); typedef execution::blocking_t result_type; }; template <typename T> struct query_free_default<T, execution::blocking_t, typename enable_if< !can_query<T, execution::blocking_t::possibly_t>::value && !can_query<T, execution::blocking_t::always_t>::value && can_query<T, execution::blocking_t::never_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<T, execution::blocking_t::never_t>::value)); typedef execution::blocking_t result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> struct static_query<T, execution::blocking_t, typename enable_if< traits::query_static_constexpr_member<T, execution::blocking_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::blocking_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::blocking_t>::value(); } }; template <typename T> struct static_query<T, execution::blocking_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::blocking_t>::is_valid && !traits::query_member<T, execution::blocking_t>::is_valid && traits::static_query<T, execution::blocking_t::possibly_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::static_query<T, execution::blocking_t::possibly_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::static_query<T, execution::blocking_t::possibly_t>::value(); } }; template <typename T> struct static_query<T, execution::blocking_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::blocking_t>::is_valid && !traits::query_member<T, execution::blocking_t>::is_valid && !traits::static_query<T, execution::blocking_t::possibly_t>::is_valid && traits::static_query<T, execution::blocking_t::always_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::static_query<T, execution::blocking_t::always_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::static_query<T, execution::blocking_t::always_t>::value(); } }; template <typename T> struct static_query<T, execution::blocking_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::blocking_t>::is_valid && !traits::query_member<T, execution::blocking_t>::is_valid && !traits::static_query<T, execution::blocking_t::possibly_t>::is_valid && !traits::static_query<T, execution::blocking_t::always_t>::is_valid && traits::static_query<T, execution::blocking_t::never_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::static_query<T, execution::blocking_t::never_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::static_query<T, execution::blocking_t::never_t>::value(); } }; template <typename T> struct static_query<T, execution::blocking_t::possibly_t, typename enable_if< traits::query_static_constexpr_member<T, execution::blocking_t::possibly_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::blocking_t::possibly_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::blocking_t::possibly_t>::value(); } }; template <typename T> struct static_query<T, execution::blocking_t::possibly_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::blocking_t::possibly_t>::is_valid && !traits::query_member<T, execution::blocking_t::possibly_t>::is_valid && !traits::query_free<T, execution::blocking_t::possibly_t>::is_valid && !can_query<T, execution::blocking_t::always_t>::value && !can_query<T, execution::blocking_t::never_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef execution::blocking_t::possibly_t result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return result_type(); } }; template <typename T> struct static_query<T, execution::blocking_t::always_t, typename enable_if< traits::query_static_constexpr_member<T, execution::blocking_t::always_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::blocking_t::always_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::blocking_t::always_t>::value(); } }; template <typename T> struct static_query<T, execution::blocking_t::never_t, typename enable_if< traits::query_static_constexpr_member<T, execution::blocking_t::never_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::blocking_t::never_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::blocking_t::never_t>::value(); } }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) template <typename T> struct static_require<T, execution::blocking_t::possibly_t, typename enable_if< static_query<T, execution::blocking_t::possibly_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = (is_same<typename static_query<T, execution::blocking_t::possibly_t>::result_type, execution::blocking_t::possibly_t>::value)); }; template <typename T> struct static_require<T, execution::blocking_t::always_t, typename enable_if< static_query<T, execution::blocking_t::always_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = (is_same<typename static_query<T, execution::blocking_t::always_t>::result_type, execution::blocking_t::always_t>::value)); }; template <typename T> struct static_require<T, execution::blocking_t::never_t, typename enable_if< static_query<T, execution::blocking_t::never_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = (is_same<typename static_query<T, execution::blocking_t::never_t>::result_type, execution::blocking_t::never_t>::value)); }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) template <typename T> struct require_free_default<T, execution::blocking_t::always_t, typename enable_if< is_same<T, typename decay<T>::type>::value && execution::is_executor<T>::value && traits::static_require< const T&, execution::detail::blocking_adaptation::allowed_t<0> >::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef execution::detail::blocking::adapter<T> result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) template <typename Executor> struct equality_comparable< execution::detail::blocking::adapter<Executor> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) template <typename Executor, typename Function> struct execute_member< execution::detail::blocking::adapter<Executor>, Function> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) template <typename Executor, int I> struct query_static_constexpr_member< execution::detail::blocking::adapter<Executor>, execution::detail::blocking_t<I> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef execution::blocking_t::always_t result_type; static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT { return result_type(); } }; template <typename Executor, int I> struct query_static_constexpr_member< execution::detail::blocking::adapter<Executor>, execution::detail::blocking::always_t<I> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef execution::blocking_t::always_t result_type; static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT { return result_type(); } }; template <typename Executor, int I> struct query_static_constexpr_member< execution::detail::blocking::adapter<Executor>, execution::detail::blocking::possibly_t<I> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef execution::blocking_t::always_t result_type; static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT { return result_type(); } }; template <typename Executor, int I> struct query_static_constexpr_member< execution::detail::blocking::adapter<Executor>, execution::detail::blocking::never_t<I> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef execution::blocking_t::always_t result_type; static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT { return result_type(); } }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) template <typename Executor, typename Property> struct query_member< execution::detail::blocking::adapter<Executor>, Property, typename enable_if< can_query<const Executor&, Property>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<Executor, Property>::value)); typedef typename query_result<Executor, Property>::type result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) template <typename Executor, int I> struct require_member< execution::detail::blocking::adapter<Executor>, execution::detail::blocking::possibly_t<I>, typename enable_if< can_require< const Executor&, execution::detail::blocking::possibly_t<I> >::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_require<const Executor&, execution::detail::blocking::possibly_t<I> >::value)); typedef typename require_result<const Executor&, execution::detail::blocking::possibly_t<I> >::type result_type; }; template <typename Executor, int I> struct require_member< execution::detail::blocking::adapter<Executor>, execution::detail::blocking::never_t<I>, typename enable_if< can_require< const Executor&, execution::detail::blocking::never_t<I> >::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_require<const Executor&, execution::detail::blocking::never_t<I> >::value)); typedef typename require_result<const Executor&, execution::detail::blocking::never_t<I> >::type result_type; }; template <typename Executor, typename Property> struct require_member< execution::detail::blocking::adapter<Executor>, Property, typename enable_if< can_require<const Executor&, Property>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_require<Executor, Property>::value)); typedef execution::detail::blocking::adapter<typename decay< typename require_result<Executor, Property>::type >::type> result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) template <typename Executor, typename Property> struct prefer_member< execution::detail::blocking::adapter<Executor>, Property, typename enable_if< can_prefer<const Executor&, Property>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_prefer<Executor, Property>::value)); typedef execution::detail::blocking::adapter<typename decay< typename prefer_result<Executor, Property>::type >::type> result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) } // namespace traits #endif // defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_BLOCKING_HPP execution/receiver.hpp 0000644 00000022705 15125530236 0011074 0 ustar 00 // // execution/receiver.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_RECEIVER_HPP #define BOOST_ASIO_EXECUTION_RECEIVER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/variadic_templates.hpp> #include <boost/asio/execution/set_done.hpp> #include <boost/asio/execution/set_error.hpp> #include <boost/asio/execution/set_value.hpp> #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) # include <exception> #else // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) # include <boost/system/error_code.hpp> #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) #if defined(BOOST_ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT) \ && defined(BOOST_ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) \ && defined(BOOST_ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT) \ && defined(BOOST_ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) \ && defined(BOOST_ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT) \ && defined(BOOST_ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) \ && defined(BOOST_ASIO_HAS_DEDUCED_RECEIVER_OF_FREE_TRAIT) \ && defined(BOOST_ASIO_HAS_DEDUCED_RECEIVER_OF_MEMBER_TRAIT) # define BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_RECEIVER_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT) // && defined(BOOST_ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) // && defined(BOOST_ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT) // && defined(BOOST_ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) // && defined(BOOST_ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT) // && defined(BOOST_ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) // && defined(BOOST_ASIO_HAS_DEDUCED_RECEIVER_OF_FREE_TRAIT) // && defined(BOOST_ASIO_HAS_DEDUCED_RECEIVER_OF_MEMBER_TRAIT) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace execution { namespace detail { template <typename T, typename E> struct is_receiver_base : integral_constant<bool, is_move_constructible<typename remove_cvref<T>::type>::value && is_constructible<typename remove_cvref<T>::type, T>::value > { }; } // namespace detail #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) # define BOOST_ASIO_EXECUTION_RECEIVER_ERROR_DEFAULT = std::exception_ptr #else // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) # define BOOST_ASIO_EXECUTION_RECEIVER_ERROR_DEFAULT \ = ::boost::system::error_code #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) /// The is_receiver trait detects whether a type T satisfies the /// execution::receiver concept. /** * Class template @c is_receiver is a type trait that is derived from @c * true_type if the type @c T meets the concept definition for a receiver for * error type @c E, otherwise @c false_type. */ template <typename T, typename E BOOST_ASIO_EXECUTION_RECEIVER_ERROR_DEFAULT> struct is_receiver : #if defined(GENERATING_DOCUMENTATION) integral_constant<bool, automatically_determined> #else // defined(GENERATING_DOCUMENTATION) conditional< can_set_done<typename remove_cvref<T>::type>::value && is_nothrow_set_done<typename remove_cvref<T>::type>::value && can_set_error<typename remove_cvref<T>::type, E>::value && is_nothrow_set_error<typename remove_cvref<T>::type, E>::value, detail::is_receiver_base<T, E>, false_type >::type #endif // defined(GENERATING_DOCUMENTATION) { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename E BOOST_ASIO_EXECUTION_RECEIVER_ERROR_DEFAULT> BOOST_ASIO_CONSTEXPR const bool is_receiver_v = is_receiver<T, E>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) #if defined(BOOST_ASIO_HAS_CONCEPTS) template <typename T, typename E BOOST_ASIO_EXECUTION_RECEIVER_ERROR_DEFAULT> BOOST_ASIO_CONCEPT receiver = is_receiver<T, E>::value; #define BOOST_ASIO_EXECUTION_RECEIVER ::boost::asio::execution::receiver #else // defined(BOOST_ASIO_HAS_CONCEPTS) #define BOOST_ASIO_EXECUTION_RECEIVER typename #endif // defined(BOOST_ASIO_HAS_CONCEPTS) #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) \ || defined(GENERATING_DOCUMENTATION) /// The is_receiver_of trait detects whether a type T satisfies the /// execution::receiver_of concept for some set of value arguments. /** * Class template @c is_receiver_of is a type trait that is derived from @c * true_type if the type @c T meets the concept definition for a receiver for * value arguments @c Vs, otherwise @c false_type. */ template <typename T, typename... Vs> struct is_receiver_of : #if defined(GENERATING_DOCUMENTATION) integral_constant<bool, automatically_determined> #else // defined(GENERATING_DOCUMENTATION) conditional< is_receiver<T>::value, can_set_value<typename remove_cvref<T>::type, Vs...>, false_type >::type #endif // defined(GENERATING_DOCUMENTATION) { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename... Vs> BOOST_ASIO_CONSTEXPR const bool is_receiver_of_v = is_receiver_of<T, Vs...>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) #if defined(BOOST_ASIO_HAS_CONCEPTS) template <typename T, typename... Vs> BOOST_ASIO_CONCEPT receiver_of = is_receiver_of<T, Vs...>::value; #define BOOST_ASIO_EXECUTION_RECEIVER_OF_0 \ ::boost::asio::execution::receiver_of #define BOOST_ASIO_EXECUTION_RECEIVER_OF_1(v) \ ::boost::asio::execution::receiver_of<v> #else // defined(BOOST_ASIO_HAS_CONCEPTS) #define BOOST_ASIO_EXECUTION_RECEIVER_OF_0 typename #define BOOST_ASIO_EXECUTION_RECEIVER_OF_1(v) typename #endif // defined(BOOST_ASIO_HAS_CONCEPTS) #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) // || defined(GENERATING_DOCUMENTATION) template <typename T, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void> struct is_receiver_of; template <typename T> struct is_receiver_of<T> : conditional< is_receiver<T>::value, can_set_value<typename remove_cvref<T>::type>, false_type >::type { }; #define BOOST_ASIO_PRIVATE_RECEIVER_OF_TRAITS_DEF(n) \ template <typename T, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ struct is_receiver_of<T, BOOST_ASIO_VARIADIC_TARGS(n)> : \ conditional< \ conditional<true, is_receiver<T>, void>::type::value, \ can_set_value< \ typename remove_cvref<T>::type, \ BOOST_ASIO_VARIADIC_TARGS(n)>, \ false_type \ >::type \ { \ }; \ /**/ BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_RECEIVER_OF_TRAITS_DEF) #undef BOOST_ASIO_PRIVATE_RECEIVER_OF_TRAITS_DEF #define BOOST_ASIO_EXECUTION_RECEIVER_OF_0 typename #define BOOST_ASIO_EXECUTION_RECEIVER_OF_1(v) typename #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) // || defined(GENERATING_DOCUMENTATION) #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) \ || defined(GENERATING_DOCUMENTATION) /// The is_nothrow_receiver_of trait detects whether a type T satisfies the /// execution::receiver_of concept for some set of value arguments, with a /// noexcept @c set_value operation. /** * Class template @c is_nothrow_receiver_of is a type trait that is derived * from @c true_type if the type @c T meets the concept definition for a * receiver for value arguments @c Vs, and the expression * <tt>execution::set_value(declval<T>(), declval<Ts>()...)</tt> is noexcept, * otherwise @c false_type. */ template <typename T, typename... Vs> struct is_nothrow_receiver_of : #if defined(GENERATING_DOCUMENTATION) integral_constant<bool, automatically_determined> #else // defined(GENERATING_DOCUMENTATION) integral_constant<bool, is_receiver_of<T, Vs...>::value && is_nothrow_set_value<typename remove_cvref<T>::type, Vs...>::value > #endif // defined(GENERATING_DOCUMENTATION) { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename... Vs> BOOST_ASIO_CONSTEXPR const bool is_nothrow_receiver_of_v = is_nothrow_receiver_of<T, Vs...>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) // || defined(GENERATING_DOCUMENTATION) template <typename T, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void> struct is_nothrow_receiver_of; template <typename T> struct is_nothrow_receiver_of<T> : integral_constant<bool, is_receiver_of<T>::value && is_nothrow_set_value<typename remove_cvref<T>::type>::value > { }; #define BOOST_ASIO_PRIVATE_NOTHROW_RECEIVER_OF_TRAITS_DEF(n) \ template <typename T, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ struct is_nothrow_receiver_of<T, BOOST_ASIO_VARIADIC_TARGS(n)> : \ integral_constant<bool, \ is_receiver_of<T, BOOST_ASIO_VARIADIC_TARGS(n)>::value \ && is_nothrow_set_value<typename remove_cvref<T>::type, \ BOOST_ASIO_VARIADIC_TARGS(n)>::value \ > \ { \ }; \ /**/ BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_NOTHROW_RECEIVER_OF_TRAITS_DEF) #undef BOOST_ASIO_PRIVATE_NOTHROW_RECEIVER_OF_TRAITS_DEF #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) // || defined(GENERATING_DOCUMENTATION) } // namespace execution } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_RECEIVER_HPP execution/operation_state.hpp 0000644 00000005276 15125530236 0012474 0 ustar 00 // // execution/operation_state.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_OPERATION_STATE_HPP #define BOOST_ASIO_EXECUTION_OPERATION_STATE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/start.hpp> #if defined(BOOST_ASIO_HAS_DEDUCED_START_FREE_TRAIT) \ && defined(BOOST_ASIO_HAS_DEDUCED_START_MEMBER_TRAIT) # define BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_OPERATION_STATE_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DEDUCED_START_FREE_TRAIT) // && defined(BOOST_ASIO_HAS_DEDUCED_START_MEMBER_TRAIT) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace execution { namespace detail { template <typename T> struct is_operation_state_base : integral_constant<bool, is_destructible<T>::value && is_object<T>::value > { }; } // namespace detail /// The is_operation_state trait detects whether a type T satisfies the /// execution::operation_state concept. /** * Class template @c is_operation_state is a type trait that is derived from * @c true_type if the type @c T meets the concept definition for an * @c operation_state, otherwise @c false_type. */ template <typename T> struct is_operation_state : #if defined(GENERATING_DOCUMENTATION) integral_constant<bool, automatically_determined> #else // defined(GENERATING_DOCUMENTATION) conditional< can_start<typename add_lvalue_reference<T>::type>::value && is_nothrow_start<typename add_lvalue_reference<T>::type>::value, detail::is_operation_state_base<T>, false_type >::type #endif // defined(GENERATING_DOCUMENTATION) { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_CONSTEXPR const bool is_operation_state_v = is_operation_state<T>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) #if defined(BOOST_ASIO_HAS_CONCEPTS) template <typename T> BOOST_ASIO_CONCEPT operation_state = is_operation_state<T>::value; #define BOOST_ASIO_EXECUTION_OPERATION_STATE \ ::boost::asio::execution::operation_state #else // defined(BOOST_ASIO_HAS_CONCEPTS) #define BOOST_ASIO_EXECUTION_OPERATION_STATE typename #endif // defined(BOOST_ASIO_HAS_CONCEPTS) } // namespace execution } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_OPERATION_STATE_HPP execution/relationship.hpp 0000644 00000053766 15125530236 0012004 0 ustar 00 // // execution/relationship.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_RELATIONSHIP_HPP #define BOOST_ASIO_EXECUTION_RELATIONSHIP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/scheduler.hpp> #include <boost/asio/execution/sender.hpp> #include <boost/asio/is_applicable_property.hpp> #include <boost/asio/query.hpp> #include <boost/asio/traits/query_free.hpp> #include <boost/asio/traits/query_member.hpp> #include <boost/asio/traits/query_static_constexpr_member.hpp> #include <boost/asio/traits/static_query.hpp> #include <boost/asio/traits/static_require.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if defined(GENERATING_DOCUMENTATION) namespace execution { /// A property to describe whether submitted tasks represent continuations of /// the calling context. struct relationship_t { /// The relationship_t property applies to executors, senders, and schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The top-level relationship_t property cannot be required. static constexpr bool is_requirable = false; /// The top-level relationship_t property cannot be preferred. static constexpr bool is_preferable = false; /// The type returned by queries against an @c any_executor. typedef relationship_t polymorphic_query_result_type; /// A sub-property that indicates that the executor does not represent a /// continuation of the calling context. struct fork_t { /// The relationship_t::fork_t property applies to executors, senders, and /// schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The relationship_t::fork_t property can be required. static constexpr bool is_requirable = true; /// The relationship_t::fork_t property can be preferred. static constexpr bool is_preferable = true; /// The type returned by queries against an @c any_executor. typedef relationship_t polymorphic_query_result_type; /// Default constructor. constexpr fork_t(); /// Get the value associated with a property object. /** * @returns fork_t(); */ static constexpr relationship_t value(); }; /// A sub-property that indicates that the executor represents a continuation /// of the calling context. struct continuation_t { /// The relationship_t::continuation_t property applies to executors, /// senders, and schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The relationship_t::continuation_t property can be required. static constexpr bool is_requirable = true; /// The relationship_t::continuation_t property can be preferred. static constexpr bool is_preferable = true; /// The type returned by queries against an @c any_executor. typedef relationship_t polymorphic_query_result_type; /// Default constructor. constexpr continuation_t(); /// Get the value associated with a property object. /** * @returns continuation_t(); */ static constexpr relationship_t value(); }; /// A special value used for accessing the relationship_t::fork_t property. static constexpr fork_t fork; /// A special value used for accessing the relationship_t::continuation_t /// property. static constexpr continuation_t continuation; /// Default constructor. constexpr relationship_t(); /// Construct from a sub-property value. constexpr relationship_t(fork_t); /// Construct from a sub-property value. constexpr relationship_t(continuation_t); /// Compare property values for equality. friend constexpr bool operator==( const relationship_t& a, const relationship_t& b) noexcept; /// Compare property values for inequality. friend constexpr bool operator!=( const relationship_t& a, const relationship_t& b) noexcept; }; /// A special value used for accessing the relationship_t property. constexpr relationship_t relationship; } // namespace execution #else // defined(GENERATING_DOCUMENTATION) namespace execution { namespace detail { namespace relationship { template <int I> struct fork_t; template <int I> struct continuation_t; } // namespace relationship template <int I = 0> struct relationship_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); typedef relationship_t polymorphic_query_result_type; typedef detail::relationship::fork_t<I> fork_t; typedef detail::relationship::continuation_t<I> continuation_t; BOOST_ASIO_CONSTEXPR relationship_t() : value_(-1) { } BOOST_ASIO_CONSTEXPR relationship_t(fork_t) : value_(0) { } BOOST_ASIO_CONSTEXPR relationship_t(continuation_t) : value_(1) { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member< T, relationship_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member< T, relationship_t >::is_noexcept)) { return traits::query_static_constexpr_member< T, relationship_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::static_query<T, fork_t>::result_type static_query( typename enable_if< !traits::query_static_constexpr_member< T, relationship_t>::is_valid && !traits::query_member<T, relationship_t>::is_valid && traits::static_query<T, fork_t>::is_valid >::type* = 0) BOOST_ASIO_NOEXCEPT { return traits::static_query<T, fork_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::static_query<T, continuation_t>::result_type static_query( typename enable_if< !traits::query_static_constexpr_member< T, relationship_t>::is_valid && !traits::query_member<T, relationship_t>::is_valid && !traits::static_query<T, fork_t>::is_valid && traits::static_query<T, continuation_t>::is_valid >::type* = 0) BOOST_ASIO_NOEXCEPT { return traits::static_query<T, continuation_t>::value(); } template <typename E, typename T = decltype(relationship_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = relationship_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) friend BOOST_ASIO_CONSTEXPR bool operator==( const relationship_t& a, const relationship_t& b) { return a.value_ == b.value_; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const relationship_t& a, const relationship_t& b) { return a.value_ != b.value_; } struct convertible_from_relationship_t { BOOST_ASIO_CONSTEXPR convertible_from_relationship_t(relationship_t) { } }; template <typename Executor> friend BOOST_ASIO_CONSTEXPR relationship_t query( const Executor& ex, convertible_from_relationship_t, typename enable_if< can_query<const Executor&, fork_t>::value >::type* = 0) #if !defined(__clang__) // Clang crashes if noexcept is used here. #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified. BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, relationship_t<>::fork_t>::value)) #else // defined(BOOST_ASIO_MSVC) BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, fork_t>::value)) #endif // defined(BOOST_ASIO_MSVC) #endif // !defined(__clang__) { return boost::asio::query(ex, fork_t()); } template <typename Executor> friend BOOST_ASIO_CONSTEXPR relationship_t query( const Executor& ex, convertible_from_relationship_t, typename enable_if< !can_query<const Executor&, fork_t>::value && can_query<const Executor&, continuation_t>::value >::type* = 0) #if !defined(__clang__) // Clang crashes if noexcept is used here. #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified. BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, relationship_t<>::continuation_t>::value)) #else // defined(BOOST_ASIO_MSVC) BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, continuation_t>::value)) #endif // defined(BOOST_ASIO_MSVC) #endif // !defined(__clang__) { return boost::asio::query(ex, continuation_t()); } BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(fork_t, fork); BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(continuation_t, continuation); #if !defined(BOOST_ASIO_HAS_CONSTEXPR) static const relationship_t instance; #endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) private: int value_; }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T relationship_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if !defined(BOOST_ASIO_HAS_CONSTEXPR) template <int I> const relationship_t<I> relationship_t<I>::instance; #endif template <int I> const typename relationship_t<I>::fork_t relationship_t<I>::fork; template <int I> const typename relationship_t<I>::continuation_t relationship_t<I>::continuation; namespace relationship { template <int I = 0> struct fork_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); typedef relationship_t<I> polymorphic_query_result_type; BOOST_ASIO_CONSTEXPR fork_t() { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, fork_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, fork_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, fork_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR fork_t static_query( typename enable_if< !traits::query_static_constexpr_member<T, fork_t>::is_valid && !traits::query_member<T, fork_t>::is_valid && !traits::query_free<T, fork_t>::is_valid && !can_query<T, continuation_t<I> >::value >::type* = 0) BOOST_ASIO_NOEXCEPT { return fork_t(); } template <typename E, typename T = decltype(fork_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = fork_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) static BOOST_ASIO_CONSTEXPR relationship_t<I> value() { return fork_t(); } friend BOOST_ASIO_CONSTEXPR bool operator==( const fork_t&, const fork_t&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const fork_t&, const fork_t&) { return false; } }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T fork_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I = 0> struct continuation_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); typedef relationship_t<I> polymorphic_query_result_type; BOOST_ASIO_CONSTEXPR continuation_t() { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, continuation_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, continuation_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, continuation_t>::value(); } template <typename E, typename T = decltype(continuation_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = continuation_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) static BOOST_ASIO_CONSTEXPR relationship_t<I> value() { return continuation_t(); } friend BOOST_ASIO_CONSTEXPR bool operator==( const continuation_t&, const continuation_t&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const continuation_t&, const continuation_t&) { return false; } }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T continuation_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) } // namespace relationship } // namespace detail typedef detail::relationship_t<> relationship_t; #if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) constexpr relationship_t relationship; #else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) namespace { static const relationship_t& relationship = relationship_t::instance; } #endif } // namespace execution #if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> struct is_applicable_property<T, execution::relationship_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; template <typename T> struct is_applicable_property<T, execution::relationship_t::fork_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; template <typename T> struct is_applicable_property<T, execution::relationship_t::continuation_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; #endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) template <typename T> struct query_free_default<T, execution::relationship_t, typename enable_if< can_query<T, execution::relationship_t::fork_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<T, execution::relationship_t::fork_t>::value)); typedef execution::relationship_t result_type; }; template <typename T> struct query_free_default<T, execution::relationship_t, typename enable_if< !can_query<T, execution::relationship_t::fork_t>::value && can_query<T, execution::relationship_t::continuation_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<T, execution::relationship_t::continuation_t>::value)); typedef execution::relationship_t result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> struct static_query<T, execution::relationship_t, typename enable_if< traits::query_static_constexpr_member<T, execution::relationship_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::relationship_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::relationship_t>::value(); } }; template <typename T> struct static_query<T, execution::relationship_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::relationship_t>::is_valid && !traits::query_member<T, execution::relationship_t>::is_valid && traits::static_query<T, execution::relationship_t::fork_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::static_query<T, execution::relationship_t::fork_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::static_query<T, execution::relationship_t::fork_t>::value(); } }; template <typename T> struct static_query<T, execution::relationship_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::relationship_t>::is_valid && !traits::query_member<T, execution::relationship_t>::is_valid && !traits::static_query<T, execution::relationship_t::fork_t>::is_valid && traits::static_query<T, execution::relationship_t::continuation_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::static_query<T, execution::relationship_t::continuation_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::static_query<T, execution::relationship_t::continuation_t>::value(); } }; template <typename T> struct static_query<T, execution::relationship_t::fork_t, typename enable_if< traits::query_static_constexpr_member<T, execution::relationship_t::fork_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::relationship_t::fork_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::relationship_t::fork_t>::value(); } }; template <typename T> struct static_query<T, execution::relationship_t::fork_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::relationship_t::fork_t>::is_valid && !traits::query_member<T, execution::relationship_t::fork_t>::is_valid && !traits::query_free<T, execution::relationship_t::fork_t>::is_valid && !can_query<T, execution::relationship_t::continuation_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef execution::relationship_t::fork_t result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return result_type(); } }; template <typename T> struct static_query<T, execution::relationship_t::continuation_t, typename enable_if< traits::query_static_constexpr_member<T, execution::relationship_t::continuation_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::relationship_t::continuation_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::relationship_t::continuation_t>::value(); } }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) template <typename T> struct static_require<T, execution::relationship_t::fork_t, typename enable_if< static_query<T, execution::relationship_t::fork_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = (is_same<typename static_query<T, execution::relationship_t::fork_t>::result_type, execution::relationship_t::fork_t>::value)); }; template <typename T> struct static_require<T, execution::relationship_t::continuation_t, typename enable_if< static_query<T, execution::relationship_t::continuation_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = (is_same<typename static_query<T, execution::relationship_t::continuation_t>::result_type, execution::relationship_t::continuation_t>::value)); }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) } // namespace traits #endif // defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_RELATIONSHIP_HPP execution/bulk_guarantee.hpp 0000644 00000077245 15125530236 0012271 0 ustar 00 // // execution/bulk_guarantee.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_BULK_GUARANTEE_HPP #define BOOST_ASIO_EXECUTION_BULK_GUARANTEE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/scheduler.hpp> #include <boost/asio/execution/sender.hpp> #include <boost/asio/is_applicable_property.hpp> #include <boost/asio/query.hpp> #include <boost/asio/traits/query_free.hpp> #include <boost/asio/traits/query_member.hpp> #include <boost/asio/traits/query_static_constexpr_member.hpp> #include <boost/asio/traits/static_query.hpp> #include <boost/asio/traits/static_require.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if defined(GENERATING_DOCUMENTATION) namespace execution { /// A property to communicate the forward progress and ordering guarantees of /// execution agents associated with the bulk execution. struct bulk_guarantee_t { /// The bulk_guarantee_t property applies to executors, senders, and /// schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The top-level bulk_guarantee_t property cannot be required. static constexpr bool is_requirable = false; /// The top-level bulk_guarantee_t property cannot be preferred. static constexpr bool is_preferable = false; /// The type returned by queries against an @c any_executor. typedef bulk_guarantee_t polymorphic_query_result_type; /// A sub-property that indicates that execution agents within the same bulk /// execution may be parallelised and vectorised. struct unsequenced_t { /// The bulk_guarantee_t::unsequenced_t property applies to executors, /// senders, and schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The bulk_guarantee_t::unsequenced_t property can be required. static constexpr bool is_requirable = true; /// The bulk_guarantee_t::unsequenced_t property can be preferred. static constexpr bool is_preferable = true; /// The type returned by queries against an @c any_executor. typedef bulk_guarantee_t polymorphic_query_result_type; /// Default constructor. constexpr unsequenced_t(); /// Get the value associated with a property object. /** * @returns unsequenced_t(); */ static constexpr bulk_guarantee_t value(); }; /// A sub-property that indicates that execution agents within the same bulk /// execution may not be parallelised and vectorised. struct sequenced_t { /// The bulk_guarantee_t::sequenced_t property applies to executors, /// senders, and schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The bulk_guarantee_t::sequenced_t property can be required. static constexpr bool is_requirable = true; /// The bulk_guarantee_t::sequenced_t property can be preferred. static constexpr bool is_preferable = true; /// The type returned by queries against an @c any_executor. typedef bulk_guarantee_t polymorphic_query_result_type; /// Default constructor. constexpr sequenced_t(); /// Get the value associated with a property object. /** * @returns sequenced_t(); */ static constexpr bulk_guarantee_t value(); }; /// A sub-property that indicates that execution agents within the same bulk /// execution may be parallelised. struct parallel_t { /// The bulk_guarantee_t::parallel_t property applies to executors, /// senders, and schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The bulk_guarantee_t::parallel_t property can be required. static constexpr bool is_requirable = true; /// The bulk_guarantee_t::parallel_t property can be preferred. static constexpr bool is_preferable = true; /// The type returned by queries against an @c any_executor. typedef bulk_guarantee_t polymorphic_query_result_type; /// Default constructor. constexpr parallel_t(); /// Get the value associated with a property object. /** * @returns parallel_t(); */ static constexpr bulk_guarantee_t value(); }; /// A special value used for accessing the bulk_guarantee_t::unsequenced_t /// property. static constexpr unsequenced_t unsequenced; /// A special value used for accessing the bulk_guarantee_t::sequenced_t /// property. static constexpr sequenced_t sequenced; /// A special value used for accessing the bulk_guarantee_t::parallel_t /// property. static constexpr parallel_t parallel; /// Default constructor. constexpr bulk_guarantee_t(); /// Construct from a sub-property value. constexpr bulk_guarantee_t(unsequenced_t); /// Construct from a sub-property value. constexpr bulk_guarantee_t(sequenced_t); /// Construct from a sub-property value. constexpr bulk_guarantee_t(parallel_t); /// Compare property values for equality. friend constexpr bool operator==( const bulk_guarantee_t& a, const bulk_guarantee_t& b) noexcept; /// Compare property values for inequality. friend constexpr bool operator!=( const bulk_guarantee_t& a, const bulk_guarantee_t& b) noexcept; }; /// A special value used for accessing the bulk_guarantee_t property. constexpr bulk_guarantee_t bulk_guarantee; } // namespace execution #else // defined(GENERATING_DOCUMENTATION) namespace execution { namespace detail { namespace bulk_guarantee { template <int I> struct unsequenced_t; template <int I> struct sequenced_t; template <int I> struct parallel_t; } // namespace bulk_guarantee template <int I = 0> struct bulk_guarantee_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); typedef bulk_guarantee_t polymorphic_query_result_type; typedef detail::bulk_guarantee::unsequenced_t<I> unsequenced_t; typedef detail::bulk_guarantee::sequenced_t<I> sequenced_t; typedef detail::bulk_guarantee::parallel_t<I> parallel_t; BOOST_ASIO_CONSTEXPR bulk_guarantee_t() : value_(-1) { } BOOST_ASIO_CONSTEXPR bulk_guarantee_t(unsequenced_t) : value_(0) { } BOOST_ASIO_CONSTEXPR bulk_guarantee_t(sequenced_t) : value_(1) { } BOOST_ASIO_CONSTEXPR bulk_guarantee_t(parallel_t) : value_(2) { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member< T, bulk_guarantee_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, bulk_guarantee_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, bulk_guarantee_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::static_query<T, unsequenced_t>::result_type static_query( typename enable_if< !traits::query_static_constexpr_member<T, bulk_guarantee_t>::is_valid && !traits::query_member<T, bulk_guarantee_t>::is_valid && traits::static_query<T, unsequenced_t>::is_valid >::type* = 0) BOOST_ASIO_NOEXCEPT { return traits::static_query<T, unsequenced_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::static_query<T, sequenced_t>::result_type static_query( typename enable_if< !traits::query_static_constexpr_member<T, bulk_guarantee_t>::is_valid && !traits::query_member<T, bulk_guarantee_t>::is_valid && !traits::static_query<T, unsequenced_t>::is_valid && traits::static_query<T, sequenced_t>::is_valid >::type* = 0) BOOST_ASIO_NOEXCEPT { return traits::static_query<T, sequenced_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::static_query<T, parallel_t>::result_type static_query( typename enable_if< !traits::query_static_constexpr_member<T, bulk_guarantee_t>::is_valid && !traits::query_member<T, bulk_guarantee_t>::is_valid && !traits::static_query<T, unsequenced_t>::is_valid && !traits::static_query<T, sequenced_t>::is_valid && traits::static_query<T, parallel_t>::is_valid >::type* = 0) BOOST_ASIO_NOEXCEPT { return traits::static_query<T, parallel_t>::value(); } template <typename E, typename T = decltype(bulk_guarantee_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = bulk_guarantee_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) friend BOOST_ASIO_CONSTEXPR bool operator==( const bulk_guarantee_t& a, const bulk_guarantee_t& b) { return a.value_ == b.value_; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const bulk_guarantee_t& a, const bulk_guarantee_t& b) { return a.value_ != b.value_; } struct convertible_from_bulk_guarantee_t { BOOST_ASIO_CONSTEXPR convertible_from_bulk_guarantee_t(bulk_guarantee_t) {} }; template <typename Executor> friend BOOST_ASIO_CONSTEXPR bulk_guarantee_t query( const Executor& ex, convertible_from_bulk_guarantee_t, typename enable_if< can_query<const Executor&, unsequenced_t>::value >::type* = 0) #if !defined(__clang__) // Clang crashes if noexcept is used here. #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified. BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, bulk_guarantee_t<>::unsequenced_t>::value)) #else // defined(BOOST_ASIO_MSVC) BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, unsequenced_t>::value)) #endif // defined(BOOST_ASIO_MSVC) #endif // !defined(__clang__) { return boost::asio::query(ex, unsequenced_t()); } template <typename Executor> friend BOOST_ASIO_CONSTEXPR bulk_guarantee_t query( const Executor& ex, convertible_from_bulk_guarantee_t, typename enable_if< !can_query<const Executor&, unsequenced_t>::value && can_query<const Executor&, sequenced_t>::value >::type* = 0) #if !defined(__clang__) // Clang crashes if noexcept is used here. #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified. BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, bulk_guarantee_t<>::sequenced_t>::value)) #else // defined(BOOST_ASIO_MSVC) BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, sequenced_t>::value)) #endif // defined(BOOST_ASIO_MSVC) #endif // !defined(__clang__) { return boost::asio::query(ex, sequenced_t()); } template <typename Executor> friend BOOST_ASIO_CONSTEXPR bulk_guarantee_t query( const Executor& ex, convertible_from_bulk_guarantee_t, typename enable_if< !can_query<const Executor&, unsequenced_t>::value && !can_query<const Executor&, sequenced_t>::value && can_query<const Executor&, parallel_t>::value >::type* = 0) #if !defined(__clang__) // Clang crashes if noexcept is used here. #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified. BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, bulk_guarantee_t<>::parallel_t>::value)) #else // defined(BOOST_ASIO_MSVC) BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, parallel_t>::value)) #endif // defined(BOOST_ASIO_MSVC) #endif // !defined(__clang__) { return boost::asio::query(ex, parallel_t()); } BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(unsequenced_t, unsequenced); BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(sequenced_t, sequenced); BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(parallel_t, parallel); #if !defined(BOOST_ASIO_HAS_CONSTEXPR) static const bulk_guarantee_t instance; #endif // !defined(BOOST_ASIO_HAS_CONSTEXPR) private: int value_; }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T bulk_guarantee_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if !defined(BOOST_ASIO_HAS_CONSTEXPR) template <int I> const bulk_guarantee_t<I> bulk_guarantee_t<I>::instance; #endif template <int I> const typename bulk_guarantee_t<I>::unsequenced_t bulk_guarantee_t<I>::unsequenced; template <int I> const typename bulk_guarantee_t<I>::sequenced_t bulk_guarantee_t<I>::sequenced; template <int I> const typename bulk_guarantee_t<I>::parallel_t bulk_guarantee_t<I>::parallel; namespace bulk_guarantee { template <int I = 0> struct unsequenced_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); typedef bulk_guarantee_t<I> polymorphic_query_result_type; BOOST_ASIO_CONSTEXPR unsequenced_t() { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, unsequenced_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, unsequenced_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, unsequenced_t>::value(); } template <typename T> static BOOST_ASIO_CONSTEXPR unsequenced_t static_query( typename enable_if< !traits::query_static_constexpr_member<T, unsequenced_t>::is_valid && !traits::query_member<T, unsequenced_t>::is_valid && !traits::query_free<T, unsequenced_t>::is_valid && !can_query<T, sequenced_t<I> >::value && !can_query<T, parallel_t<I> >::value >::type* = 0) BOOST_ASIO_NOEXCEPT { return unsequenced_t(); } template <typename E, typename T = decltype(unsequenced_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = unsequenced_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) static BOOST_ASIO_CONSTEXPR bulk_guarantee_t<I> value() { return unsequenced_t(); } friend BOOST_ASIO_CONSTEXPR bool operator==( const unsequenced_t&, const unsequenced_t&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const unsequenced_t&, const unsequenced_t&) { return false; } friend BOOST_ASIO_CONSTEXPR bool operator==( const unsequenced_t&, const sequenced_t<I>&) { return false; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const unsequenced_t&, const sequenced_t<I>&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator==( const unsequenced_t&, const parallel_t<I>&) { return false; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const unsequenced_t&, const parallel_t<I>&) { return true; } }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T unsequenced_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I = 0> struct sequenced_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); typedef bulk_guarantee_t<I> polymorphic_query_result_type; BOOST_ASIO_CONSTEXPR sequenced_t() { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, sequenced_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, sequenced_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, sequenced_t>::value(); } template <typename E, typename T = decltype(sequenced_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = sequenced_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) static BOOST_ASIO_CONSTEXPR bulk_guarantee_t<I> value() { return sequenced_t(); } friend BOOST_ASIO_CONSTEXPR bool operator==( const sequenced_t&, const sequenced_t&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const sequenced_t&, const sequenced_t&) { return false; } friend BOOST_ASIO_CONSTEXPR bool operator==( const sequenced_t&, const unsequenced_t<I>&) { return false; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const sequenced_t&, const unsequenced_t<I>&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator==( const sequenced_t&, const parallel_t<I>&) { return false; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const sequenced_t&, const parallel_t<I>&) { return true; } }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T sequenced_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> struct parallel_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<T>::value || is_sender<T>::value || is_scheduler<T>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = true); typedef bulk_guarantee_t<I> polymorphic_query_result_type; BOOST_ASIO_CONSTEXPR parallel_t() { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<T, parallel_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<T, parallel_t>::is_noexcept)) { return traits::query_static_constexpr_member<T, parallel_t>::value(); } template <typename E, typename T = decltype(parallel_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const T static_query_v = parallel_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) static BOOST_ASIO_CONSTEXPR bulk_guarantee_t<I> value() { return parallel_t(); } friend BOOST_ASIO_CONSTEXPR bool operator==( const parallel_t&, const parallel_t&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const parallel_t&, const parallel_t&) { return false; } friend BOOST_ASIO_CONSTEXPR bool operator==( const parallel_t&, const unsequenced_t<I>&) { return false; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const parallel_t&, const unsequenced_t<I>&) { return true; } friend BOOST_ASIO_CONSTEXPR bool operator==( const parallel_t&, const sequenced_t<I>&) { return false; } friend BOOST_ASIO_CONSTEXPR bool operator!=( const parallel_t&, const sequenced_t<I>&) { return true; } }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <int I> template <typename E, typename T> const T parallel_t<I>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) } // namespace bulk_guarantee } // namespace detail typedef detail::bulk_guarantee_t<> bulk_guarantee_t; #if defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) constexpr bulk_guarantee_t bulk_guarantee; #else // defined(BOOST_ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION) namespace { static const bulk_guarantee_t& bulk_guarantee = bulk_guarantee_t::instance; } #endif } // namespace execution #if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> struct is_applicable_property<T, execution::bulk_guarantee_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; template <typename T> struct is_applicable_property<T, execution::bulk_guarantee_t::unsequenced_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; template <typename T> struct is_applicable_property<T, execution::bulk_guarantee_t::sequenced_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; template <typename T> struct is_applicable_property<T, execution::bulk_guarantee_t::parallel_t> : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; #endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) template <typename T> struct query_free_default<T, execution::bulk_guarantee_t, typename enable_if< can_query<T, execution::bulk_guarantee_t::unsequenced_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<T, execution::bulk_guarantee_t::unsequenced_t>::value)); typedef execution::bulk_guarantee_t result_type; }; template <typename T> struct query_free_default<T, execution::bulk_guarantee_t, typename enable_if< !can_query<T, execution::bulk_guarantee_t::unsequenced_t>::value && can_query<T, execution::bulk_guarantee_t::sequenced_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<T, execution::bulk_guarantee_t::sequenced_t>::value)); typedef execution::bulk_guarantee_t result_type; }; template <typename T> struct query_free_default<T, execution::bulk_guarantee_t, typename enable_if< !can_query<T, execution::bulk_guarantee_t::unsequenced_t>::value && !can_query<T, execution::bulk_guarantee_t::sequenced_t>::value && can_query<T, execution::bulk_guarantee_t::parallel_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<T, execution::bulk_guarantee_t::parallel_t>::value)); typedef execution::bulk_guarantee_t result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> struct static_query<T, execution::bulk_guarantee_t, typename enable_if< traits::query_static_constexpr_member<T, execution::bulk_guarantee_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::bulk_guarantee_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::bulk_guarantee_t>::value(); } }; template <typename T> struct static_query<T, execution::bulk_guarantee_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::bulk_guarantee_t>::is_valid && !traits::query_member<T, execution::bulk_guarantee_t>::is_valid && traits::static_query<T, execution::bulk_guarantee_t::unsequenced_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::static_query<T, execution::bulk_guarantee_t::unsequenced_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::static_query<T, execution::bulk_guarantee_t::unsequenced_t>::value(); } }; template <typename T> struct static_query<T, execution::bulk_guarantee_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::bulk_guarantee_t>::is_valid && !traits::query_member<T, execution::bulk_guarantee_t>::is_valid && !traits::static_query<T, execution::bulk_guarantee_t::unsequenced_t>::is_valid && traits::static_query<T, execution::bulk_guarantee_t::sequenced_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::static_query<T, execution::bulk_guarantee_t::sequenced_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::static_query<T, execution::bulk_guarantee_t::sequenced_t>::value(); } }; template <typename T> struct static_query<T, execution::bulk_guarantee_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::bulk_guarantee_t>::is_valid && !traits::query_member<T, execution::bulk_guarantee_t>::is_valid && !traits::static_query<T, execution::bulk_guarantee_t::unsequenced_t>::is_valid && !traits::static_query<T, execution::bulk_guarantee_t::sequenced_t>::is_valid && traits::static_query<T, execution::bulk_guarantee_t::parallel_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::static_query<T, execution::bulk_guarantee_t::parallel_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::static_query<T, execution::bulk_guarantee_t::parallel_t>::value(); } }; template <typename T> struct static_query<T, execution::bulk_guarantee_t::unsequenced_t, typename enable_if< traits::query_static_constexpr_member<T, execution::bulk_guarantee_t::unsequenced_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::bulk_guarantee_t::unsequenced_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::bulk_guarantee_t::unsequenced_t>::value(); } }; template <typename T> struct static_query<T, execution::bulk_guarantee_t::unsequenced_t, typename enable_if< !traits::query_static_constexpr_member<T, execution::bulk_guarantee_t::unsequenced_t>::is_valid && !traits::query_member<T, execution::bulk_guarantee_t::unsequenced_t>::is_valid && !traits::query_free<T, execution::bulk_guarantee_t::unsequenced_t>::is_valid && !can_query<T, execution::bulk_guarantee_t::sequenced_t>::value && !can_query<T, execution::bulk_guarantee_t::parallel_t>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef execution::bulk_guarantee_t::unsequenced_t result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return result_type(); } }; template <typename T> struct static_query<T, execution::bulk_guarantee_t::sequenced_t, typename enable_if< traits::query_static_constexpr_member<T, execution::bulk_guarantee_t::sequenced_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::bulk_guarantee_t::sequenced_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::bulk_guarantee_t::sequenced_t>::value(); } }; template <typename T> struct static_query<T, execution::bulk_guarantee_t::parallel_t, typename enable_if< traits::query_static_constexpr_member<T, execution::bulk_guarantee_t::parallel_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef typename traits::query_static_constexpr_member<T, execution::bulk_guarantee_t::parallel_t>::result_type result_type; static BOOST_ASIO_CONSTEXPR result_type value() { return traits::query_static_constexpr_member<T, execution::bulk_guarantee_t::parallel_t>::value(); } }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) template <typename T> struct static_require<T, execution::bulk_guarantee_t::unsequenced_t, typename enable_if< static_query<T, execution::bulk_guarantee_t::unsequenced_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = (is_same<typename static_query<T, execution::bulk_guarantee_t::unsequenced_t>::result_type, execution::bulk_guarantee_t::unsequenced_t>::value)); }; template <typename T> struct static_require<T, execution::bulk_guarantee_t::sequenced_t, typename enable_if< static_query<T, execution::bulk_guarantee_t::sequenced_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = (is_same<typename static_query<T, execution::bulk_guarantee_t::sequenced_t>::result_type, execution::bulk_guarantee_t::sequenced_t>::value)); }; template <typename T> struct static_require<T, execution::bulk_guarantee_t::parallel_t, typename enable_if< static_query<T, execution::bulk_guarantee_t::parallel_t>::is_valid >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = (is_same<typename static_query<T, execution::bulk_guarantee_t::parallel_t>::result_type, execution::bulk_guarantee_t::parallel_t>::value)); }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) } // namespace traits #endif // defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_BULK_GUARANTEE_HPP execution/execute.hpp 0000644 00000016633 15125530236 0010735 0 ustar 00 // // execution/execute.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_EXECUTE_HPP #define BOOST_ASIO_EXECUTION_EXECUTE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/detail/as_invocable.hpp> #include <boost/asio/execution/detail/as_receiver.hpp> #include <boost/asio/traits/execute_member.hpp> #include <boost/asio/traits/execute_free.hpp> #include <boost/asio/detail/push_options.hpp> #if defined(GENERATING_DOCUMENTATION) namespace boost { namespace asio { namespace execution { /// A customisation point that executes a function on an executor. /** * The name <tt>execution::execute</tt> denotes a customisation point object. * * For some subexpressions <tt>e</tt> and <tt>f</tt>, let <tt>E</tt> be a type * such that <tt>decltype((e))</tt> is <tt>E</tt> and let <tt>F</tt> be a type * such that <tt>decltype((f))</tt> is <tt>F</tt>. The expression * <tt>execution::execute(e, f)</tt> is ill-formed if <tt>F</tt> does not model * <tt>invocable</tt>, or if <tt>E</tt> does not model either <tt>executor</tt> * or <tt>sender</tt>. Otherwise, it is expression-equivalent to: * * @li <tt>e.execute(f)</tt>, if that expression is valid. If the function * selected does not execute the function object <tt>f</tt> on the executor * <tt>e</tt>, the program is ill-formed with no diagnostic required. * * @li Otherwise, <tt>execute(e, f)</tt>, if that expression is valid, with * overload resolution performed in a context that includes the declaration * <tt>void execute();</tt> and that does not include a declaration of * <tt>execution::execute</tt>. If the function selected by overload * resolution does not execute the function object <tt>f</tt> on the executor * <tt>e</tt>, the program is ill-formed with no diagnostic required. */ inline constexpr unspecified execute = unspecified; /// A type trait that determines whether a @c execute expression is well-formed. /** * Class template @c can_execute is a trait that is derived from * @c true_type if the expression <tt>execution::execute(std::declval<T>(), * std::declval<F>())</tt> is well formed; otherwise @c false_type. */ template <typename T, typename F> struct can_execute : integral_constant<bool, automatically_determined> { }; } // namespace execution } // namespace asio } // namespace boost #else // defined(GENERATING_DOCUMENTATION) namespace boost { namespace asio { namespace execution { template <typename T, typename R> struct is_sender_to; namespace detail { template <typename S, typename R> void submit_helper(BOOST_ASIO_MOVE_ARG(S) s, BOOST_ASIO_MOVE_ARG(R) r); } // namespace detail } // namespace execution } // namespace asio } // namespace boost namespace asio_execution_execute_fn { using boost::asio::conditional; using boost::asio::decay; using boost::asio::declval; using boost::asio::enable_if; using boost::asio::execution::detail::as_receiver; using boost::asio::execution::detail::is_as_invocable; using boost::asio::execution::is_sender_to; using boost::asio::false_type; using boost::asio::result_of; using boost::asio::traits::execute_free; using boost::asio::traits::execute_member; using boost::asio::true_type; void execute(); enum overload_type { call_member, call_free, adapter, ill_formed }; template <typename T, typename F, typename = void> struct call_traits { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); }; template <typename T, typename F> struct call_traits<T, void(F), typename enable_if< ( execute_member<T, F>::is_valid ) >::type> : execute_member<T, F> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); }; template <typename T, typename F> struct call_traits<T, void(F), typename enable_if< ( !execute_member<T, F>::is_valid && execute_free<T, F>::is_valid ) >::type> : execute_free<T, F> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); }; template <typename T, typename F> struct call_traits<T, void(F), typename enable_if< ( !execute_member<T, F>::is_valid && !execute_free<T, F>::is_valid && conditional<true, true_type, typename result_of<typename decay<F>::type&()>::type >::type::value && conditional< !is_as_invocable< typename decay<F>::type >::value, is_sender_to< T, as_receiver<typename decay<F>::type, T> >, false_type >::type::value ) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = adapter); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; struct impl { template <typename T, typename F> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(F)>::overload == call_member, typename call_traits<T, void(F)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(F) f) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(F)>::is_noexcept)) { return BOOST_ASIO_MOVE_CAST(T)(t).execute(BOOST_ASIO_MOVE_CAST(F)(f)); } template <typename T, typename F> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(F)>::overload == call_free, typename call_traits<T, void(F)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(F) f) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(F)>::is_noexcept)) { return execute(BOOST_ASIO_MOVE_CAST(T)(t), BOOST_ASIO_MOVE_CAST(F)(f)); } template <typename T, typename F> BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(F)>::overload == adapter, typename call_traits<T, void(F)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(F) f) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(F)>::is_noexcept)) { return boost::asio::execution::detail::submit_helper( BOOST_ASIO_MOVE_CAST(T)(t), as_receiver<typename decay<F>::type, T>( BOOST_ASIO_MOVE_CAST(F)(f), 0)); } }; template <typename T = impl> struct static_instance { static const T instance; }; template <typename T> const T static_instance<T>::instance = {}; } // namespace asio_execution_execute_fn namespace boost { namespace asio { namespace execution { namespace { static BOOST_ASIO_CONSTEXPR const asio_execution_execute_fn::impl& execute = asio_execution_execute_fn::static_instance<>::instance; } // namespace template <typename T, typename F> struct can_execute : integral_constant<bool, asio_execution_execute_fn::call_traits<T, void(F)>::overload != asio_execution_execute_fn::ill_formed> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename F> constexpr bool can_execute_v = can_execute<T, F>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) } // namespace execution } // namespace asio } // namespace boost #endif // defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_EXECUTE_HPP execution/sender.hpp 0000644 00000020533 15125530236 0010545 0 ustar 00 // // execution/sender.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_SENDER_HPP #define BOOST_ASIO_EXECUTION_SENDER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/detail/as_invocable.hpp> #include <boost/asio/execution/detail/void_receiver.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/receiver.hpp> #include <boost/asio/detail/push_options.hpp> #if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) \ && defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) \ && defined(BOOST_ASIO_HAS_DECLTYPE) \ && !defined(BOOST_ASIO_MSVC) || (_MSC_VER >= 1910) # define BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) // && defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) // && defined(BOOST_ASIO_HAS_DECLTYPE) // && !defined(BOOST_ASIO_MSVC) || (_MSC_VER >= 1910) namespace boost { namespace asio { namespace execution { namespace detail { namespace sender_base_ns { struct sender_base {}; } template <typename S, typename = void> struct sender_traits_base { typedef void asio_execution_sender_traits_base_is_unspecialised; }; template <typename S> struct sender_traits_base<S, typename enable_if< is_base_of<sender_base_ns::sender_base, S>::value >::type> { }; template <typename S, typename = void, typename = void, typename = void> struct has_sender_types : false_type { }; #if defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT) template < template < template <typename...> class Tuple, template <typename...> class Variant > class> struct has_value_types { typedef void type; }; template < template < template <typename...> class Variant > class> struct has_error_types { typedef void type; }; template <typename S> struct has_sender_types<S, typename has_value_types<S::template value_types>::type, typename has_error_types<S::template error_types>::type, typename conditional<S::sends_done, void, void>::type> : true_type { }; template <typename S> struct sender_traits_base<S, typename enable_if< has_sender_types<S>::value >::type> { template < template <typename...> class Tuple, template <typename...> class Variant> using value_types = typename S::template value_types<Tuple, Variant>; template <template <typename...> class Variant> using error_types = typename S::template error_types<Variant>; BOOST_ASIO_STATIC_CONSTEXPR(bool, sends_done = S::sends_done); }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT) template <typename S> struct sender_traits_base<S, typename enable_if< !has_sender_types<S>::value && detail::is_executor_of_impl<S, as_invocable<void_receiver, S> >::value >::type> { #if defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT) \ && defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) template < template <typename...> class Tuple, template <typename...> class Variant> using value_types = Variant<Tuple<>>; template <template <typename...> class Variant> using error_types = Variant<std::exception_ptr>; BOOST_ASIO_STATIC_CONSTEXPR(bool, sends_done = true); #endif // defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT) // && defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) }; } // namespace detail /// Base class used for tagging senders. #if defined(GENERATING_DOCUMENTATION) typedef unspecified sender_base; #else // defined(GENERATING_DOCUMENTATION) typedef detail::sender_base_ns::sender_base sender_base; #endif // defined(GENERATING_DOCUMENTATION) /// Traits for senders. template <typename S> struct sender_traits #if !defined(GENERATING_DOCUMENTATION) : detail::sender_traits_base<S> #endif // !defined(GENERATING_DOCUMENTATION) { }; namespace detail { template <typename S, typename = void> struct has_sender_traits : true_type { }; template <typename S> struct has_sender_traits<S, typename enable_if< is_same< typename boost::asio::execution::sender_traits< S>::asio_execution_sender_traits_base_is_unspecialised, void >::value >::type> : false_type { }; } // namespace detail /// The is_sender trait detects whether a type T satisfies the /// execution::sender concept. /** * Class template @c is_sender is a type trait that is derived from @c * true_type if the type @c T meets the concept definition for a sender, * otherwise @c false_type. */ template <typename T> struct is_sender : #if defined(GENERATING_DOCUMENTATION) integral_constant<bool, automatically_determined> #else // defined(GENERATING_DOCUMENTATION) conditional< detail::has_sender_traits<typename remove_cvref<T>::type>::value, is_move_constructible<typename remove_cvref<T>::type>, false_type >::type #endif // defined(GENERATING_DOCUMENTATION) { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_CONSTEXPR const bool is_sender_v = is_sender<T>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) #if defined(BOOST_ASIO_HAS_CONCEPTS) template <typename T> BOOST_ASIO_CONCEPT sender = is_sender<T>::value; #define BOOST_ASIO_EXECUTION_SENDER ::boost::asio::execution::sender #else // defined(BOOST_ASIO_HAS_CONCEPTS) #define BOOST_ASIO_EXECUTION_SENDER typename #endif // defined(BOOST_ASIO_HAS_CONCEPTS) template <typename S, typename R> struct can_connect; /// The is_sender_to trait detects whether a type T satisfies the /// execution::sender_to concept for some receiver. /** * Class template @c is_sender_to is a type trait that is derived from @c * true_type if the type @c T meets the concept definition for a sender * for some receiver type R, otherwise @c false. */ template <typename T, typename R> struct is_sender_to : #if defined(GENERATING_DOCUMENTATION) integral_constant<bool, automatically_determined> #else // defined(GENERATING_DOCUMENTATION) integral_constant<bool, is_sender<T>::value && is_receiver<R>::value && can_connect<T, R>::value > #endif // defined(GENERATING_DOCUMENTATION) { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename R> BOOST_ASIO_CONSTEXPR const bool is_sender_to_v = is_sender_to<T, R>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) #if defined(BOOST_ASIO_HAS_CONCEPTS) template <typename T, typename R> BOOST_ASIO_CONCEPT sender_to = is_sender_to<T, R>::value; #define BOOST_ASIO_EXECUTION_SENDER_TO(r) \ ::boost::asio::execution::sender_to<r> #else // defined(BOOST_ASIO_HAS_CONCEPTS) #define BOOST_ASIO_EXECUTION_SENDER_TO(r) typename #endif // defined(BOOST_ASIO_HAS_CONCEPTS) /// The is_typed_sender trait detects whether a type T satisfies the /// execution::typed_sender concept. /** * Class template @c is_typed_sender is a type trait that is derived from @c * true_type if the type @c T meets the concept definition for a typed sender, * otherwise @c false. */ template <typename T> struct is_typed_sender : #if defined(GENERATING_DOCUMENTATION) integral_constant<bool, automatically_determined> #else // defined(GENERATING_DOCUMENTATION) integral_constant<bool, is_sender<T>::value && detail::has_sender_types< sender_traits<typename remove_cvref<T>::type> >::value > #endif // defined(GENERATING_DOCUMENTATION) { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_CONSTEXPR const bool is_typed_sender_v = is_typed_sender<T>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) #if defined(BOOST_ASIO_HAS_CONCEPTS) template <typename T> BOOST_ASIO_CONCEPT typed_sender = is_typed_sender<T>::value; #define BOOST_ASIO_EXECUTION_TYPED_SENDER \ ::boost::asio::execution::typed_sender #else // defined(BOOST_ASIO_HAS_CONCEPTS) #define BOOST_ASIO_EXECUTION_TYPED_SENDER typename #endif // defined(BOOST_ASIO_HAS_CONCEPTS) } // namespace execution } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/execution/connect.hpp> #endif // BOOST_ASIO_EXECUTION_SENDER_HPP execution/scheduler.hpp 0000644 00000004506 15125530236 0011245 0 ustar 00 // // execution/scheduler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_SCHEDULER_HPP #define BOOST_ASIO_EXECUTION_SCHEDULER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/schedule.hpp> #include <boost/asio/traits/equality_comparable.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace execution { namespace detail { template <typename T> struct is_scheduler_base : integral_constant<bool, is_copy_constructible<typename remove_cvref<T>::type>::value && traits::equality_comparable<typename remove_cvref<T>::type>::is_valid > { }; } // namespace detail /// The is_scheduler trait detects whether a type T satisfies the /// execution::scheduler concept. /** * Class template @c is_scheduler is a type trait that is derived from @c * true_type if the type @c T meets the concept definition for a scheduler for * error type @c E, otherwise @c false_type. */ template <typename T> struct is_scheduler : #if defined(GENERATING_DOCUMENTATION) integral_constant<bool, automatically_determined> #else // defined(GENERATING_DOCUMENTATION) conditional< can_schedule<T>::value, detail::is_scheduler_base<T>, false_type >::type #endif // defined(GENERATING_DOCUMENTATION) { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T> BOOST_ASIO_CONSTEXPR const bool is_scheduler_v = is_scheduler<T>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) #if defined(BOOST_ASIO_HAS_CONCEPTS) template <typename T> BOOST_ASIO_CONCEPT scheduler = is_scheduler<T>::value; #define BOOST_ASIO_EXECUTION_SCHEDULER ::boost::asio::execution::scheduler #else // defined(BOOST_ASIO_HAS_CONCEPTS) #define BOOST_ASIO_EXECUTION_SCHEDULER typename #endif // defined(BOOST_ASIO_HAS_CONCEPTS) } // namespace execution } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_SCHEDULER_HPP execution/context_as.hpp 0000644 00000014270 15125530236 0011435 0 ustar 00 // // execution/context_as.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_AS_HPP #define BOOST_ASIO_EXECUTION_CONTEXT_AS_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/context.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/scheduler.hpp> #include <boost/asio/execution/sender.hpp> #include <boost/asio/is_applicable_property.hpp> #include <boost/asio/query.hpp> #include <boost/asio/traits/query_static_constexpr_member.hpp> #include <boost/asio/traits/static_query.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if defined(GENERATING_DOCUMENTATION) namespace execution { /// A property that is used to obtain the execution context that is associated /// with an executor. template <typename U> struct context_as_t { /// The context_as_t property applies to executors, senders, and schedulers. template <typename T> static constexpr bool is_applicable_property_v = is_executor_v<T> || is_sender_v<T> || is_scheduler_v<T>; /// The context_t property cannot be required. static constexpr bool is_requirable = false; /// The context_t property cannot be preferred. static constexpr bool is_preferable = false; /// The type returned by queries against an @c any_executor. typedef T polymorphic_query_result_type; }; /// A special value used for accessing the context_as_t property. template <typename U> constexpr context_as_t context_as; } // namespace execution #else // defined(GENERATING_DOCUMENTATION) namespace execution { template <typename T> struct context_as_t { #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename U> BOOST_ASIO_STATIC_CONSTEXPR(bool, is_applicable_property_v = is_executor<U>::value || is_sender<U>::value || is_scheduler<U>::value); #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) BOOST_ASIO_STATIC_CONSTEXPR(bool, is_requirable = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_preferable = false); typedef T polymorphic_query_result_type; BOOST_ASIO_CONSTEXPR context_as_t() { } BOOST_ASIO_CONSTEXPR context_as_t(context_t) { } #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename E> static BOOST_ASIO_CONSTEXPR typename traits::query_static_constexpr_member<E, context_t>::result_type static_query() BOOST_ASIO_NOEXCEPT_IF(( traits::query_static_constexpr_member<E, context_t>::is_noexcept)) { return traits::query_static_constexpr_member<E, context_t>::value(); } template <typename E, typename U = decltype(context_as_t::static_query<E>())> static BOOST_ASIO_CONSTEXPR const U static_query_v = context_as_t::static_query<E>(); #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename Executor, typename U> friend BOOST_ASIO_CONSTEXPR U query( const Executor& ex, const context_as_t<U>&, typename enable_if< is_same<T, U>::value && can_query<const Executor&, const context_t&>::value >::type* = 0) #if !defined(__clang__) // Clang crashes if noexcept is used here. #if defined(BOOST_ASIO_MSVC) // Visual C++ wants the type to be qualified. BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, const context_t&>::value)) #else // defined(BOOST_ASIO_MSVC) BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, const context_t&>::value)) #endif // defined(BOOST_ASIO_MSVC) #endif // !defined(__clang__) { return boost::asio::query(ex, context); } }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T> template <typename E, typename U> const U context_as_t<T>::static_query_v; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // && defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if (defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) \ && defined(BOOST_ASIO_HAS_CONSTEXPR)) \ || defined(GENERATING_DOCUMENTATION) template <typename T> constexpr context_as_t<T> context_as{}; #endif // (defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) // && defined(BOOST_ASIO_HAS_CONSTEXPR)) // || defined(GENERATING_DOCUMENTATION) } // namespace execution #if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename U> struct is_applicable_property<T, execution::context_as_t<U> > : integral_constant<bool, execution::is_executor<T>::value || execution::is_sender<T>::value || execution::is_scheduler<T>::value> { }; #endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) \ || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) template <typename T, typename U> struct static_query<T, execution::context_as_t<U>, typename enable_if< static_query<T, execution::context_t>::is_valid >::type> : static_query<T, execution::context_t> { }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) // || !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) template <typename T, typename U> struct query_free<T, execution::context_as_t<U>, typename enable_if< can_query<const T&, const execution::context_t&>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<const T&, const execution::context_t&>::value)); typedef U result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) } // namespace traits #endif // defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_EXECUTION_CONTEXT_AS_HPP bind_executor.hpp 0000644 00000040176 15125530236 0010121 0 ustar 00 // // bind_executor.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/variadic_templates.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/associated_allocator.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/is_executor.hpp> #include <boost/asio/uses_executor.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { // Helper to automatically define nested typedef result_type. template <typename T, typename = void> struct executor_binder_result_type { protected: typedef void result_type_or_void; }; template <typename T> struct executor_binder_result_type<T, typename void_type<typename T::result_type>::type> { typedef typename T::result_type result_type; protected: typedef result_type result_type_or_void; }; template <typename R> struct executor_binder_result_type<R(*)()> { typedef R result_type; protected: typedef result_type result_type_or_void; }; template <typename R> struct executor_binder_result_type<R(&)()> { typedef R result_type; protected: typedef result_type result_type_or_void; }; template <typename R, typename A1> struct executor_binder_result_type<R(*)(A1)> { typedef R result_type; protected: typedef result_type result_type_or_void; }; template <typename R, typename A1> struct executor_binder_result_type<R(&)(A1)> { typedef R result_type; protected: typedef result_type result_type_or_void; }; template <typename R, typename A1, typename A2> struct executor_binder_result_type<R(*)(A1, A2)> { typedef R result_type; protected: typedef result_type result_type_or_void; }; template <typename R, typename A1, typename A2> struct executor_binder_result_type<R(&)(A1, A2)> { typedef R result_type; protected: typedef result_type result_type_or_void; }; // Helper to automatically define nested typedef argument_type. template <typename T, typename = void> struct executor_binder_argument_type {}; template <typename T> struct executor_binder_argument_type<T, typename void_type<typename T::argument_type>::type> { typedef typename T::argument_type argument_type; }; template <typename R, typename A1> struct executor_binder_argument_type<R(*)(A1)> { typedef A1 argument_type; }; template <typename R, typename A1> struct executor_binder_argument_type<R(&)(A1)> { typedef A1 argument_type; }; // Helper to automatically define nested typedefs first_argument_type and // second_argument_type. template <typename T, typename = void> struct executor_binder_argument_types {}; template <typename T> struct executor_binder_argument_types<T, typename void_type<typename T::first_argument_type>::type> { typedef typename T::first_argument_type first_argument_type; typedef typename T::second_argument_type second_argument_type; }; template <typename R, typename A1, typename A2> struct executor_binder_argument_type<R(*)(A1, A2)> { typedef A1 first_argument_type; typedef A2 second_argument_type; }; template <typename R, typename A1, typename A2> struct executor_binder_argument_type<R(&)(A1, A2)> { typedef A1 first_argument_type; typedef A2 second_argument_type; }; // Helper to perform uses_executor construction of the target type, if // required. template <typename T, typename Executor, bool UsesExecutor> class executor_binder_base; template <typename T, typename Executor> class executor_binder_base<T, Executor, true> { protected: template <typename E, typename U> 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 <typename T, typename Executor> class executor_binder_base<T, Executor, false> { protected: template <typename E, typename U> 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 <typename T, typename = void> struct executor_binder_result_of0 { typedef void type; }; template <typename T> struct executor_binder_result_of0<T, typename void_type<typename result_of<T()>::type>::type> { typedef typename result_of<T()>::type type; }; } // namespace detail /// A call wrapper type to bind an executor of type @c Executor to an object of /// type @c T. template <typename T, typename Executor> class executor_binder #if !defined(GENERATING_DOCUMENTATION) : public detail::executor_binder_result_type<T>, public detail::executor_binder_argument_type<T>, public detail::executor_binder_argument_types<T>, private detail::executor_binder_base< T, Executor, uses_executor<T, 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 <typename U> 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 <typename U, typename OtherExecutor> executor_binder(const executor_binder<U, OtherExecutor>& 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 <typename U, typename OtherExecutor> executor_binder(executor_arg_t, const executor_type& e, const executor_binder<U, OtherExecutor>& 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 <typename U, typename OtherExecutor> executor_binder(executor_binder<U, OtherExecutor>&& 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 <typename U, typename OtherExecutor> executor_binder(executor_arg_t, const executor_type& e, executor_binder<U, OtherExecutor>&& 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 <typename... Args> auto operator()(Args&& ...); template <typename... Args> auto operator()(Args&& ...) const; #elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) /// Forwarding function call operator. template <typename... Args> typename result_of<T(Args...)>::type operator()( BOOST_ASIO_MOVE_ARG(Args)... args) { return this->target_(BOOST_ASIO_MOVE_CAST(Args)(args)...); } /// Forwarding function call operator. template <typename... Args> typename result_of<T(Args...)>::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<T>::type operator()() { return this->target_(); } typename detail::executor_binder_result_of0<T>::type operator()() const { return this->target_(); } #define BOOST_ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF(n) \ template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ typename result_of<T(BOOST_ASIO_VARIADIC_TARGS(n))>::type operator()( \ BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ { \ return this->target_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ } \ \ template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ typename result_of<T(BOOST_ASIO_VARIADIC_TARGS(n))>::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<T>::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 <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ result_type_or_void operator()( \ BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ { \ return this->target_(BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ } \ \ template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ 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<T, Executor, uses_executor<T, Executor>::value> base_type; }; /// Associate an object of type @c T with an executor of type @c Executor. template <typename Executor, typename T> inline executor_binder<typename decay<T>::type, Executor> bind_executor(const Executor& ex, BOOST_ASIO_MOVE_ARG(T) t, typename enable_if< is_executor<Executor>::value || execution::is_executor<Executor>::value >::type* = 0) { return executor_binder<typename decay<T>::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 <typename ExecutionContext, typename T> inline executor_binder<typename decay<T>::type, typename ExecutionContext::executor_type> bind_executor(ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(T) t, typename enable_if<is_convertible< ExecutionContext&, execution_context&>::value>::type* = 0) { return executor_binder<typename decay<T>::type, typename ExecutionContext::executor_type>( executor_arg_t(), ctx.get_executor(), BOOST_ASIO_MOVE_CAST(T)(t)); } #if !defined(GENERATING_DOCUMENTATION) template <typename T, typename Executor> struct uses_executor<executor_binder<T, Executor>, Executor> : true_type {}; template <typename T, typename Executor, typename Signature> class async_result<executor_binder<T, Executor>, Signature> { public: typedef executor_binder< typename async_result<T, Signature>::completion_handler_type, Executor> completion_handler_type; typedef typename async_result<T, Signature>::return_type return_type; explicit async_result(executor_binder<T, Executor>& 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<T, Signature> target_; }; template <typename T, typename Executor, typename Allocator> struct associated_allocator<executor_binder<T, Executor>, Allocator> { typedef typename associated_allocator<T, Allocator>::type type; static type get(const executor_binder<T, Executor>& b, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<T, Allocator>::get(b.get(), a); } }; template <typename T, typename Executor, typename Executor1> struct associated_executor<executor_binder<T, Executor>, Executor1> { typedef Executor type; static type get(const executor_binder<T, Executor>& b, const Executor1& = Executor1()) BOOST_ASIO_NOEXCEPT { return b.get_executor(); } }; #endif // !defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_BIND_EXECUTOR_HPP basic_waitable_timer.hpp 0000644 00000067560 15125530236 0011426 0 ustar 00 // // basic_waitable_timer.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/any_io_executor.hpp> #include <boost/asio/detail/chrono_time_traits.hpp> #include <boost/asio/detail/deadline_timer_service.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/io_object_impl.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/wait_traits.hpp> #if defined(BOOST_ASIO_HAS_MOVE) # include <utility> #endif // defined(BOOST_ASIO_HAS_MOVE) #include <boost/asio/detail/push_options.hpp> 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 Clock, typename WaitTraits = boost::asio::wait_traits<Clock>, typename Executor = any_io_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 <typename Clock, typename WaitTraits, typename Executor> class basic_waitable_timer { public: /// The type of the executor associated with the object. typedef Executor executor_type; /// Rebinds the timer type to another executor. template <typename Executor1> struct rebind_executor { /// The timer type when rebound to the specified executor. typedef basic_waitable_timer<Clock, WaitTraits, Executor1> other; }; /// 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 <typename ExecutionContext> explicit basic_waitable_timer(ExecutionContext& context, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename ExecutionContext> explicit basic_waitable_timer(ExecutionContext& context, const time_point& expiry_time, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename ExecutionContext> explicit basic_waitable_timer(ExecutionContext& context, const duration& expiry_time, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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; } // All timers have access to each other's implementations. template <typename Clock1, typename WaitTraits1, typename Executor1> friend class basic_waitable_timer; /// 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. */ template <typename Executor1> basic_waitable_timer( basic_waitable_timer<Clock, WaitTraits, Executor1>&& other, typename enable_if< is_convertible<Executor1, Executor>::value >::type* = 0) : 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. */ template <typename Executor1> typename enable_if< is_convertible<Executor1, Executor>::value, basic_waitable_timer& >::type operator=(basic_waitable_timer<Clock, WaitTraits, Executor1>&& other) { basic_waitable_timer tmp(std::move(other)); impl_ = std::move(tmp.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_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) WaitHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (boost::system::error_code)) async_wait( BOOST_ASIO_MOVE_ARG(WaitHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WaitHandler, void (boost::system::error_code)>( initiate_async_wait(this), handler); } 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; class initiate_async_wait { public: typedef Executor executor_type; explicit initiate_async_wait(basic_waitable_timer* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename WaitHandler> void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler) 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<WaitHandler> handler2(handler); self_->impl_.get_service().async_wait( self_->impl_.get_implementation(), handler2.value, self_->impl_.get_executor()); } private: basic_waitable_timer* self_; }; detail::io_object_impl< detail::deadline_timer_service< detail::chrono_time_traits<Clock, WaitTraits> >, executor_type > impl_; }; } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_BASIC_WAITABLE_TIMER_HPP multiple_exceptions.hpp 0000644 00000003137 15125530236 0011357 0 ustar 00 // // multiple_exceptions.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_MULTIPLE_EXCEPTIONS_HPP #define BOOST_ASIO_MULTIPLE_EXCEPTIONS_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <exception> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ || defined(GENERATING_DOCUMENTATION) /// Exception thrown when there are multiple pending exceptions to rethrow. class multiple_exceptions : public std::exception { public: /// Constructor. BOOST_ASIO_DECL multiple_exceptions( std::exception_ptr first) BOOST_ASIO_NOEXCEPT; /// Obtain message associated with exception. BOOST_ASIO_DECL virtual const char* what() const BOOST_ASIO_NOEXCEPT_OR_NOTHROW; /// Obtain a pointer to the first exception. BOOST_ASIO_DECL std::exception_ptr first_exception() const; private: std::exception_ptr first_; }; #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) // || defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/impl/multiple_exceptions.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_MULTIPLE_EXCEPTIONS_HPP uses_executor.hpp 0000644 00000004454 15125530236 0010163 0 ustar 00 // // uses_executor.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename T, typename Executor> struct uses_executor : false_type {}; } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_USES_EXECUTOR_HPP require_concept.hpp 0000644 00000022002 15125530236 0010442 0 ustar 00 // // require_concept.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_REQUIRE_CONCEPT_HPP #define BOOST_ASIO_REQUIRE_CONCEPT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/is_applicable_property.hpp> #include <boost/asio/traits/require_concept_member.hpp> #include <boost/asio/traits/require_concept_free.hpp> #include <boost/asio/traits/static_require_concept.hpp> #include <boost/asio/detail/push_options.hpp> #if defined(GENERATING_DOCUMENTATION) namespace boost { namespace asio { /// A customisation point that applies a concept-enforcing property to an /// object. /** * The name <tt>require_concept</tt> denotes a customization point object. The * expression <tt>boost::asio::require_concept(E, P)</tt> for some * subexpressions <tt>E</tt> and <tt>P</tt> (with types <tt>T = * decay_t<decltype(E)></tt> and <tt>Prop = decay_t<decltype(P)></tt>) is * expression-equivalent to: * * @li If <tt>is_applicable_property_v<T, Prop> && * Prop::is_requirable_concept</tt> is not a well-formed constant expression * with value <tt>true</tt>, <tt>boost::asio::require_concept(E, P)</tt> is * ill-formed. * * @li Otherwise, <tt>E</tt> if the expression <tt>Prop::template * static_query_v<T> == Prop::value()</tt> is a well-formed constant * expression with value <tt>true</tt>. * * @li Otherwise, <tt>(E).require_concept(P)</tt> if the expression * <tt>(E).require_concept(P)</tt> is well-formed. * * @li Otherwise, <tt>require_concept(E, P)</tt> if the expression * <tt>require_concept(E, P)</tt> is a valid expression with overload * resolution performed in a context that does not include the declaration * of the <tt>require_concept</tt> customization point object. * * @li Otherwise, <tt>boost::asio::require_concept(E, P)</tt> is ill-formed. */ inline constexpr unspecified require_concept = unspecified; /// A type trait that determines whether a @c require_concept expression is /// well-formed. /** * Class template @c can_require_concept is a trait that is derived from * @c true_type if the expression * <tt>boost::asio::require_concept(std::declval<T>(), * std::declval<Property>())</tt> is well formed; otherwise @c false_type. */ template <typename T, typename Property> struct can_require_concept : integral_constant<bool, automatically_determined> { }; /// A type trait that determines whether a @c require_concept expression will /// not throw. /** * Class template @c is_nothrow_require_concept is a trait that is derived from * @c true_type if the expression * <tt>boost::asio::require_concept(std::declval<T>(), * std::declval<Property>())</tt> is @c noexcept; otherwise @c false_type. */ template <typename T, typename Property> struct is_nothrow_require_concept : integral_constant<bool, automatically_determined> { }; /// A type trait that determines the result type of a @c require_concept /// expression. /** * Class template @c require_concept_result is a trait that determines the * result type of the expression * <tt>boost::asio::require_concept(std::declval<T>(), * std::declval<Property>())</tt>. */ template <typename T, typename Property> struct require_concept_result { /// The result of the @c require_concept expression. typedef automatically_determined type; }; } // namespace asio } // namespace boost #else // defined(GENERATING_DOCUMENTATION) namespace asio_require_concept_fn { using boost::asio::decay; using boost::asio::declval; using boost::asio::enable_if; using boost::asio::is_applicable_property; using boost::asio::traits::require_concept_free; using boost::asio::traits::require_concept_member; using boost::asio::traits::static_require_concept; void require_concept(); enum overload_type { identity, call_member, call_free, ill_formed }; template <typename T, typename Properties, typename = void> struct call_traits { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; template <typename T, typename Property> struct call_traits<T, void(Property), typename enable_if< ( is_applicable_property< typename decay<T>::type, typename decay<Property>::type >::value && decay<Property>::type::is_requirable_concept && static_require_concept<T, Property>::is_valid ) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = identity); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef BOOST_ASIO_MOVE_ARG(T) result_type; }; template <typename T, typename Property> struct call_traits<T, void(Property), typename enable_if< ( is_applicable_property< typename decay<T>::type, typename decay<Property>::type >::value && decay<Property>::type::is_requirable_concept && !static_require_concept<T, Property>::is_valid && require_concept_member<T, Property>::is_valid ) >::type> : require_concept_member<T, Property> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); }; template <typename T, typename Property> struct call_traits<T, void(Property), typename enable_if< ( is_applicable_property< typename decay<T>::type, typename decay<Property>::type >::value && decay<Property>::type::is_requirable_concept && !static_require_concept<T, Property>::is_valid && !require_concept_member<T, Property>::is_valid && require_concept_free<T, Property>::is_valid ) >::type> : require_concept_free<T, Property> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); }; struct impl { template <typename T, typename Property> BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(Property)>::overload == identity, typename call_traits<T, void(Property)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(Property)) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(Property)>::is_noexcept)) { return BOOST_ASIO_MOVE_CAST(T)(t); } template <typename T, typename Property> BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(Property)>::overload == call_member, typename call_traits<T, void(Property)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(Property) p) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(Property)>::is_noexcept)) { return BOOST_ASIO_MOVE_CAST(T)(t).require_concept( BOOST_ASIO_MOVE_CAST(Property)(p)); } template <typename T, typename Property> BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(Property)>::overload == call_free, typename call_traits<T, void(Property)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(Property) p) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(Property)>::is_noexcept)) { return require_concept( BOOST_ASIO_MOVE_CAST(T)(t), BOOST_ASIO_MOVE_CAST(Property)(p)); } }; template <typename T = impl> struct static_instance { static const T instance; }; template <typename T> const T static_instance<T>::instance = {}; } // namespace asio_require_concept_fn namespace boost { namespace asio { namespace { static BOOST_ASIO_CONSTEXPR const asio_require_concept_fn::impl& require_concept = asio_require_concept_fn::static_instance<>::instance; } // namespace template <typename T, typename Property> struct can_require_concept : integral_constant<bool, asio_require_concept_fn::call_traits<T, void(Property)>::overload != asio_require_concept_fn::ill_formed> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename Property> constexpr bool can_require_concept_v = can_require_concept<T, Property>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename Property> struct is_nothrow_require_concept : integral_constant<bool, asio_require_concept_fn::call_traits<T, void(Property)>::is_noexcept> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename Property> constexpr bool is_nothrow_require_concept_v = is_nothrow_require_concept<T, Property>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename Property> struct require_concept_result { typedef typename asio_require_concept_fn::call_traits< T, void(Property)>::result_type type; }; } // namespace asio } // namespace boost #endif // defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_REQUIRE_CONCEPT_HPP strand.hpp 0000644 00000041615 15125530236 0006561 0 ustar 00 // // strand.hpp // ~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/strand_executor_service.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/is_executor.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { /// Provides serialised function invocation for any executor type. template <typename Executor> 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_(strand::create_implementation(executor_)) { } /// Construct a strand for the specified executor. template <typename Executor1> explicit strand(const Executor1& e, typename enable_if< conditional< !is_same<Executor1, strand>::value, is_convertible<Executor1, Executor>, false_type >::type::value >::type* = 0) : executor_(e), impl_(strand::create_implementation(executor_)) { } /// 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 <class OtherExecutor> strand( const strand<OtherExecutor>& 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 <class OtherExecutor> strand& operator=( const strand<OtherExecutor>& 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 <class OtherExecutor> strand(strand<OtherExecutor>&& other) BOOST_ASIO_NOEXCEPT : executor_(BOOST_ASIO_MOVE_CAST(OtherExecutor)(other.executor_)), 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.executor_); 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 <class OtherExecutor> strand& operator=(strand<OtherExecutor>&& other) BOOST_ASIO_NOEXCEPT { executor_ = BOOST_ASIO_MOVE_CAST(OtherExecutor)(other.executor_); impl_ = BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_); return *this; } #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Destructor. ~strand() BOOST_ASIO_NOEXCEPT { } /// Obtain the underlying executor. inner_executor_type get_inner_executor() const BOOST_ASIO_NOEXCEPT { return executor_; } /// Forward a query to the underlying executor. /** * Do not call this function directly. It is intended for use with the * execution::execute customisation point. * * For example: * @code boost::asio::strand<my_executor_type> ex = ...; * if (boost::asio::query(ex, boost::asio::execution::blocking) * == boost::asio::execution::blocking.never) * ... @endcode */ template <typename Property> typename enable_if< can_query<const Executor&, Property>::value, typename query_result<const Executor&, Property>::type >::type query(const Property& p) const BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_query<const Executor&, Property>::value)) { return boost::asio::query(executor_, p); } /// Forward a requirement to the underlying executor. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code boost::asio::strand<my_executor_type> ex1 = ...; * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::blocking.never); @endcode */ template <typename Property> typename enable_if< can_require<const Executor&, Property>::value, strand<typename decay< typename require_result<const Executor&, Property>::type >::type> >::type require(const Property& p) const BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_require<const Executor&, Property>::value)) { return strand<typename decay< typename require_result<const Executor&, Property>::type >::type>(boost::asio::require(executor_, p), impl_); } /// Forward a preference to the underlying executor. /** * Do not call this function directly. It is intended for use with the * boost::asio::prefer customisation point. * * For example: * @code boost::asio::strand<my_executor_type> ex1 = ...; * auto ex2 = boost::asio::prefer(ex1, * boost::asio::execution::blocking.never); @endcode */ template <typename Property> typename enable_if< can_prefer<const Executor&, Property>::value, strand<typename decay< typename prefer_result<const Executor&, Property>::type >::type> >::type prefer(const Property& p) const BOOST_ASIO_NOEXCEPT_IF(( is_nothrow_prefer<const Executor&, Property>::value)) { return strand<typename decay< typename prefer_result<const Executor&, Property>::type >::type>(boost::asio::prefer(executor_, p), impl_); } #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// 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(); } #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// Request the strand to invoke the given function object. /** * Do not call this function directly. It is intended for use with the * execution::execute customisation point. * * For example: * @code boost::asio::strand<my_executor_type> ex = ...; * execution::execute(ex, my_function_object); @endcode * * This function is used to ask the strand to execute the given function * object on its underlying executor. The function object will be executed * according to the properties of the underlying executor. * * @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 */ template <typename Function> typename enable_if< execution::can_execute<const Executor&, Function>::value >::type execute(BOOST_ASIO_MOVE_ARG(Function) f) const { detail::strand_executor_service::execute(impl_, executor_, BOOST_ASIO_MOVE_CAST(Function)(f)); } #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// 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 <typename Function, typename Allocator> 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 <typename Function, typename Allocator> 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 <typename Function, typename Allocator> 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); } #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// 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_; } #if defined(GENERATING_DOCUMENTATION) private: #endif // defined(GENERATING_DOCUMENTATION) typedef detail::strand_executor_service::implementation_type implementation_type; template <typename InnerExecutor> static implementation_type create_implementation(const InnerExecutor& ex, typename enable_if< can_query<InnerExecutor, execution::context_t>::value >::type* = 0) { return use_service<detail::strand_executor_service>( boost::asio::query(ex, execution::context)).create_implementation(); } template <typename InnerExecutor> static implementation_type create_implementation(const InnerExecutor& ex, typename enable_if< !can_query<InnerExecutor, execution::context_t>::value >::type* = 0) { return use_service<detail::strand_executor_service>( ex.context()).create_implementation(); } strand(const Executor& ex, const implementation_type& impl) : executor_(ex), impl_(impl) { } Executor executor_; 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 <typename Executor> inline strand<Executor> make_strand(const Executor& ex, typename enable_if< is_executor<Executor>::value || execution::is_executor<Executor>::value >::type* = 0) { return strand<Executor>(ex); } /// Create a @ref strand object for an execution context. template <typename ExecutionContext> inline strand<typename ExecutionContext::executor_type> make_strand(ExecutionContext& ctx, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) { return strand<typename ExecutionContext::executor_type>(ctx.get_executor()); } /*@}*/ #if !defined(GENERATING_DOCUMENTATION) namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) template <typename Executor> struct equality_comparable<strand<Executor> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) template <typename Executor, typename Function> struct execute_member<strand<Executor>, Function, typename enable_if< execution::can_execute<const Executor&, Function>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) template <typename Executor, typename Property> struct query_member<strand<Executor>, Property, typename enable_if< can_query<const Executor&, Property>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_query<Executor, Property>::value)); typedef typename query_result<Executor, Property>::type result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) template <typename Executor, typename Property> struct require_member<strand<Executor>, Property, typename enable_if< can_require<const Executor&, Property>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_require<Executor, Property>::value)); typedef strand<typename decay< typename require_result<Executor, Property>::type >::type> result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) template <typename Executor, typename Property> struct prefer_member<strand<Executor>, Property, typename enable_if< can_prefer<const Executor&, Property>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = (is_nothrow_prefer<Executor, Property>::value)); typedef strand<typename decay< typename prefer_result<Executor, Property>::type >::type> result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) } // namespace traits #endif // !defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> // 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 <boost/asio/io_context_strand.hpp> # endif // defined(BOOST_ASIO_IO_CONTEXT_HPP) #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) #endif // BOOST_ASIO_STRAND_HPP basic_socket_acceptor.hpp 0000644 00000253776 15125530236 0011614 0 ustar 00 // // basic_socket_acceptor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/any_io_executor.hpp> #include <boost/asio/basic_socket.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/io_object_impl.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/socket_base.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <boost/asio/detail/null_socket_service.hpp> #elif defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/win_iocp_socket_service.hpp> #else # include <boost/asio/detail/reactive_socket_service.hpp> #endif #if defined(BOOST_ASIO_HAS_MOVE) # include <utility> #endif // defined(BOOST_ASIO_HAS_MOVE) #include <boost/asio/detail/push_options.hpp> 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 <typename Protocol, typename Executor = any_io_executor> 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 <typename Protocol, typename Executor> class basic_socket_acceptor : public socket_base { public: /// The type of the executor associated with the object. typedef Executor executor_type; /// Rebinds the acceptor type to another executor. template <typename Executor1> struct rebind_executor { /// The socket type when rebound to the specified executor. typedef basic_socket_acceptor<Protocol, Executor1> other; }; /// 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 <typename ExecutionContext> explicit basic_socket_acceptor(ExecutionContext& context, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename ExecutionContext> basic_socket_acceptor(ExecutionContext& context, const protocol_type& protocol, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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<Protocol> 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<Protocol> 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 <typename ExecutionContext> basic_socket_acceptor(ExecutionContext& context, const endpoint_type& endpoint, bool reuse_addr = true, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename ExecutionContext> basic_socket_acceptor(ExecutionContext& context, const protocol_type& protocol, const native_handle_type& native_acceptor, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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) BOOST_ASIO_NOEXCEPT : 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 <typename Protocol1, typename Executor1> 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 <typename Protocol1, typename Executor1> basic_socket_acceptor(basic_socket_acceptor<Protocol1, Executor1>&& other, typename enable_if< is_convertible<Protocol1, Protocol>::value && is_convertible<Executor1, Executor>::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 Protocol1, typename Executor1> typename enable_if< is_convertible<Protocol1, Protocol>::value && is_convertible<Executor1, Executor>::value, basic_socket_acceptor& >::type operator=(basic_socket_acceptor<Protocol1, Executor1>&& 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 <typename SettableSocketOption> 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 <typename SettableSocketOption> 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 <typename GettableSocketOption> 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 <typename GettableSocketOption> 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 <typename IoControlCommand> 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 <typename IoControlCommand> 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_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) WaitHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (boost::system::error_code)) async_wait(wait_type w, BOOST_ASIO_MOVE_ARG(WaitHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WaitHandler, void (boost::system::error_code)>( initiate_async_wait(this), handler, 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 <typename Protocol1, typename Executor1> void accept(basic_socket<Protocol1, Executor1>& peer, typename enable_if< is_convertible<Protocol, Protocol1>::value >::type* = 0) { boost::system::error_code ec; impl_.get_service().accept(impl_.get_implementation(), peer, static_cast<endpoint_type*>(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 <typename Protocol1, typename Executor1> BOOST_ASIO_SYNC_OP_VOID accept( basic_socket<Protocol1, Executor1>& peer, boost::system::error_code& ec, typename enable_if< is_convertible<Protocol, Protocol1>::value >::type* = 0) { impl_.get_service().accept(impl_.get_implementation(), peer, static_cast<endpoint_type*>(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 <typename Protocol1, typename Executor1, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) AcceptHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(AcceptHandler, void (boost::system::error_code)) async_accept(basic_socket<Protocol1, Executor1>& peer, BOOST_ASIO_MOVE_ARG(AcceptHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type), typename enable_if< is_convertible<Protocol, Protocol1>::value >::type* = 0) { return async_initiate<AcceptHandler, void (boost::system::error_code)>( initiate_async_accept(this), handler, &peer, static_cast<endpoint_type*>(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 <typename Executor1> void accept(basic_socket<protocol_type, Executor1>& 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 <typename Executor1> BOOST_ASIO_SYNC_OP_VOID accept(basic_socket<protocol_type, Executor1>& 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 <typename Executor1, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) AcceptHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(AcceptHandler, void (boost::system::error_code)) async_accept(basic_socket<protocol_type, Executor1>& peer, endpoint_type& peer_endpoint, BOOST_ASIO_MOVE_ARG(AcceptHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<AcceptHandler, void (boost::system::error_code)>( initiate_async_accept(this), handler, &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::template rebind_executor<executor_type>::other accept() { boost::system::error_code ec; typename Protocol::socket::template rebind_executor< executor_type>::other 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::template rebind_executor<executor_type>::other accept(boost::system::error_code& ec) { typename Protocol::socket::template rebind_executor< executor_type>::other 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( * // Result of operation. * const boost::system::error_code& error, * // On success, the newly accepted socket. * typename Protocol::socket::template * rebind_executor<executor_type>::other peer * ); @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_COMPLETION_TOKEN_FOR(void (boost::system::error_code, typename Protocol::socket::template rebind_executor< executor_type>::other)) MoveAcceptHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler, void (boost::system::error_code, typename Protocol::socket::template rebind_executor<executor_type>::other)) async_accept( BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<MoveAcceptHandler, void (boost::system::error_code, typename Protocol::socket::template rebind_executor<executor_type>::other)>( initiate_async_move_accept(this), handler, impl_.get_executor(), static_cast<endpoint_type*>(0), static_cast<typename Protocol::socket::template rebind_executor<executor_type>::other*>(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 Executor1> typename Protocol::socket::template rebind_executor<Executor1>::other accept(const Executor1& ex, typename enable_if< is_executor<Executor1>::value || execution::is_executor<Executor1>::value >::type* = 0) { boost::system::error_code ec; typename Protocol::socket::template rebind_executor<Executor1>::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 ExecutionContext> typename Protocol::socket::template rebind_executor< typename ExecutionContext::executor_type>::other accept(ExecutionContext& context, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 Executor1> typename Protocol::socket::template rebind_executor<Executor1>::other accept(const Executor1& ex, boost::system::error_code& ec, typename enable_if< is_executor<Executor1>::value || execution::is_executor<Executor1>::value >::type* = 0) { typename Protocol::socket::template rebind_executor<Executor1>::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 ExecutionContext> typename Protocol::socket::template rebind_executor< typename ExecutionContext::executor_type>::other accept(ExecutionContext& context, boost::system::error_code& ec, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename Executor1, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, typename Protocol::socket::template rebind_executor< Executor1>::other)) MoveAcceptHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type), typename enable_if< is_executor<Executor1>::value || execution::is_executor<Executor1>::value >::type* = 0) { typedef typename Protocol::socket::template rebind_executor< Executor1>::other other_socket_type; return async_initiate<MoveAcceptHandler, void (boost::system::error_code, other_socket_type)>( initiate_async_move_accept(this), handler, ex, static_cast<endpoint_type*>(0), static_cast<other_socket_type*>(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 <typename ExecutionContext, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, typename Protocol::socket::template rebind_executor< typename ExecutionContext::executor_type>::other)) MoveAcceptHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type), typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) { typedef typename Protocol::socket::template rebind_executor< typename ExecutionContext::executor_type>::other other_socket_type; return async_initiate<MoveAcceptHandler, void (boost::system::error_code, other_socket_type)>( initiate_async_move_accept(this), handler, context.get_executor(), static_cast<endpoint_type*>(0), static_cast<other_socket_type*>(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::template rebind_executor<executor_type>::other accept(endpoint_type& peer_endpoint) { boost::system::error_code ec; typename Protocol::socket::template rebind_executor< executor_type>::other 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::template rebind_executor<executor_type>::other accept(endpoint_type& peer_endpoint, boost::system::error_code& ec) { typename Protocol::socket::template rebind_executor< executor_type>::other 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( * // Result of operation. * const boost::system::error_code& error, * // On success, the newly accepted socket. * typename Protocol::socket::template * rebind_executor<executor_type>::other peer * ); @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_COMPLETION_TOKEN_FOR(void (boost::system::error_code, typename Protocol::socket::template rebind_executor< executor_type>::other)) MoveAcceptHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(MoveAcceptHandler, void (boost::system::error_code, typename Protocol::socket::template rebind_executor<executor_type>::other)) async_accept(endpoint_type& peer_endpoint, BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<MoveAcceptHandler, void (boost::system::error_code, typename Protocol::socket::template rebind_executor<executor_type>::other)>( initiate_async_move_accept(this), handler, impl_.get_executor(), &peer_endpoint, static_cast<typename Protocol::socket::template rebind_executor<executor_type>::other*>(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 Executor1> typename Protocol::socket::template rebind_executor<Executor1>::other accept(const Executor1& ex, endpoint_type& peer_endpoint, typename enable_if< is_executor<Executor1>::value || execution::is_executor<Executor1>::value >::type* = 0) { boost::system::error_code ec; typename Protocol::socket::template rebind_executor<Executor1>::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 ExecutionContext> typename Protocol::socket::template rebind_executor< typename ExecutionContext::executor_type>::other accept(ExecutionContext& context, endpoint_type& peer_endpoint, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 Executor1> typename Protocol::socket::template rebind_executor<Executor1>::other accept(const executor_type& ex, endpoint_type& peer_endpoint, boost::system::error_code& ec, typename enable_if< is_executor<Executor1>::value || execution::is_executor<Executor1>::value >::type* = 0) { typename Protocol::socket::template rebind_executor<Executor1>::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 ExecutionContext> 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<ExecutionContext&, execution_context&>::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 <typename Executor1, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, typename Protocol::socket::template rebind_executor< Executor1>::other)) MoveAcceptHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type), typename enable_if< is_executor<Executor1>::value || execution::is_executor<Executor1>::value >::type* = 0) { typedef typename Protocol::socket::template rebind_executor< Executor1>::other other_socket_type; return async_initiate<MoveAcceptHandler, void (boost::system::error_code, other_socket_type)>( initiate_async_move_accept(this), handler, ex, &peer_endpoint, static_cast<other_socket_type*>(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 <typename ExecutionContext, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, typename Protocol::socket::template rebind_executor< typename ExecutionContext::executor_type>::other)) MoveAcceptHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type), typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) { typedef typename Protocol::socket::template rebind_executor< typename ExecutionContext::executor_type>::other other_socket_type; return async_initiate<MoveAcceptHandler, void (boost::system::error_code, other_socket_type)>( initiate_async_move_accept(this), handler, context.get_executor(), &peer_endpoint, static_cast<other_socket_type*>(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; class initiate_async_wait { public: typedef Executor executor_type; explicit initiate_async_wait(basic_socket_acceptor* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename WaitHandler> void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler, 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<WaitHandler> handler2(handler); self_->impl_.get_service().async_wait( self_->impl_.get_implementation(), w, handler2.value, self_->impl_.get_executor()); } private: basic_socket_acceptor* self_; }; class initiate_async_accept { public: typedef Executor executor_type; explicit initiate_async_accept(basic_socket_acceptor* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename AcceptHandler, typename Protocol1, typename Executor1> void operator()(BOOST_ASIO_MOVE_ARG(AcceptHandler) handler, basic_socket<Protocol1, Executor1>* 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<AcceptHandler> handler2(handler); self_->impl_.get_service().async_accept( self_->impl_.get_implementation(), *peer, peer_endpoint, handler2.value, self_->impl_.get_executor()); } private: basic_socket_acceptor* self_; }; class initiate_async_move_accept { public: typedef Executor executor_type; explicit initiate_async_move_accept(basic_socket_acceptor* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename MoveAcceptHandler, typename Executor1, typename Socket> void operator()(BOOST_ASIO_MOVE_ARG(MoveAcceptHandler) handler, 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<MoveAcceptHandler> handler2(handler); self_->impl_.get_service().async_move_accept( self_->impl_.get_implementation(), peer_ex, peer_endpoint, handler2.value, self_->impl_.get_executor()); } private: basic_socket_acceptor* self_; }; #if defined(BOOST_ASIO_WINDOWS_RUNTIME) detail::io_object_impl< detail::null_socket_service<Protocol>, Executor> impl_; #elif defined(BOOST_ASIO_HAS_IOCP) detail::io_object_impl< detail::win_iocp_socket_service<Protocol>, Executor> impl_; #else detail::io_object_impl< detail::reactive_socket_service<Protocol>, Executor> impl_; #endif }; } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_HPP buffered_stream_fwd.hpp 0000644 00000001235 15125530236 0011255 0 ustar 00 // // buffered_stream_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <typename Stream> class buffered_stream; } // namespace asio } // namespace boost #endif // BOOST_ASIO_BUFFERED_STREAM_FWD_HPP basic_io_object.hpp 0000644 00000017640 15125530236 0010365 0 ustar 00 // // basic_io_object.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/io_context.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if defined(BOOST_ASIO_HAS_MOVE) namespace detail { // Type trait used to determine whether a service supports move. template <typename IoObjectService> class service_has_move { private: typedef IoObjectService service_type; typedef typename service_type::implementation_type implementation_type; template <typename T, typename U> 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<service_type*>(0), static_cast<implementation_type*>(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 <typename IoObjectService> #else template <typename IoObjectService, bool Movable = detail::service_has_move<IoObjectService>::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<IoObjectService>(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 <typename IoObjectService1> 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 <typename IoObjectService> class basic_io_object<IoObjectService, true> { 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<IoObjectService>(io_context)) { service_->construct(implementation_); } basic_io_object(basic_io_object&& other) : service_(&other.get_service()) { service_->move_construct(implementation_, other.implementation_); } template <typename IoObjectService1> basic_io_object(IoObjectService1& other_service, typename IoObjectService1::implementation_type& other_implementation) : service_(&boost::asio::use_service<IoObjectService>( 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_BASIC_IO_OBJECT_HPP execution_context.hpp 0000644 00000034005 15125530236 0011030 0 ustar 00 // // execution_context.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <stdexcept> #include <typeinfo> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/variadic_templates.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { class execution_context; class io_context; #if !defined(GENERATING_DOCUMENTATION) template <typename Service> Service& use_service(execution_context&); template <typename Service> Service& use_service(io_context&); template <typename Service> void add_service(execution_context&, Service*); template <typename Service> 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<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>(). * * Service objects may be explicitly added to an execution_context using the * function template @c add_service<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 * <tt>execution_context::shutdown()</tt> followed by * <tt>execution_context::destroy()</tt>. * * 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 * <tt>delete static_cast<execution_context::service*>(svc)</tt>. */ 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 <tt>svc->notify_fork();</tt>. 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 <typename Service> 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 <typename Service> 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 <typename Service, typename... Args> friend Service& make_service(execution_context& e, Args&&... args); #elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename Service, typename... Args> friend Service& make_service(execution_context& e, BOOST_ASIO_MOVE_ARG(Args)... args); #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename Service> friend Service& make_service(execution_context& e); #define BOOST_ASIO_PRIVATE_MAKE_SERVICE_DEF(n) \ template <typename Service, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ 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<execution_context::service*>(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 <typename Service> 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 <typename Service> 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 <typename Type> class service_id : public execution_context::id { }; // Special service base class to keep classes header-file only. template <typename Type> class execution_context_service_base : public execution_context::service { public: static service_id<Type> id; // Constructor. execution_context_service_base(execution_context& e) : execution_context::service(e) { } }; template <typename Type> service_id<Type> execution_context_service_base<Type>::id; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/execution_context.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/impl/execution_context.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_EXECUTION_CONTEXT_HPP connect.hpp 0000644 00000124225 15125530236 0006716 0 ustar 00 // // connect.hpp // ~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/basic_socket.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { char (&has_iterator_helper(...))[2]; template <typename T> char has_iterator_helper(T*, typename T::iterator* = 0); template <typename T> 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 <typename T> 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<T>::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, typename Executor, typename EndpointSequence> typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, typename enable_if<is_endpoint_sequence< EndpointSequence>::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, typename Executor, typename EndpointSequence> typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, boost::system::error_code& ec, typename enable_if<is_endpoint_sequence< EndpointSequence>::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 <typename Protocol, typename Executor, typename Iterator> Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, typename enable_if<!is_endpoint_sequence<Iterator>::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 <typename Protocol, typename Executor, typename Iterator> Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, boost::system::error_code& ec, typename enable_if<!is_endpoint_sequence<Iterator>::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 <typename Protocol, typename Executor, typename Iterator> Iterator connect(basic_socket<Protocol, Executor>& 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 <typename Protocol, typename Executor, typename Iterator> Iterator connect(basic_socket<Protocol, Executor>& 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, typename Executor, typename EndpointSequence, typename ConnectCondition> typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition connect_condition, typename enable_if<is_endpoint_sequence< EndpointSequence>::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, typename Executor, typename EndpointSequence, typename ConnectCondition> typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition connect_condition, boost::system::error_code& ec, typename enable_if<is_endpoint_sequence< EndpointSequence>::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 <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, ConnectCondition connect_condition, typename enable_if<!is_endpoint_sequence<Iterator>::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 <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, ConnectCondition connect_condition, boost::system::error_code& ec, typename enable_if<!is_endpoint_sequence<Iterator>::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 <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> Iterator connect(basic_socket<Protocol, Executor>& 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 <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> Iterator connect(basic_socket<Protocol, Executor>& 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 <typename Protocol, typename Executor, typename EndpointSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, typename Protocol::endpoint)) RangeConnectHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler, void (boost::system::error_code, typename Protocol::endpoint)) async_connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if<is_endpoint_sequence< EndpointSequence>::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 <typename Protocol, typename Executor, typename Iterator, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, Iterator)) IteratorConnectHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if<!is_endpoint_sequence<Iterator>::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<tcp::endpoint> 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<tcp::endpoint>::iterator i) * { * // ... * } @endcode */ template <typename Protocol, typename Executor, typename Iterator, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, Iterator)) IteratorConnectHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end, BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor)); /// 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 <typename Protocol, typename Executor, typename EndpointSequence, typename ConnectCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, typename Protocol::endpoint)) RangeConnectHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler, void (boost::system::error_code, typename Protocol::endpoint)) async_connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition connect_condition, BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if<is_endpoint_sequence< EndpointSequence>::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 <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, Iterator)) IteratorConnectHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, ConnectCondition connect_condition, BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if<!is_endpoint_sequence<Iterator>::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 <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, Iterator)) IteratorConnectHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end, ConnectCondition connect_condition, BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor)); /*@}*/ } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/connect.hpp> #endif awaitable.hpp 0000644 00000006306 15125530236 0007215 0 ustar 00 // // awaitable.hpp // ~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) #if defined(BOOST_ASIO_HAS_STD_COROUTINE) # include <coroutine> #else // defined(BOOST_ASIO_HAS_STD_COROUTINE) # include <experimental/coroutine> #endif // defined(BOOST_ASIO_HAS_STD_COROUTINE) #include <boost/asio/any_io_executor.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { #if defined(BOOST_ASIO_HAS_STD_COROUTINE) using std::coroutine_handle; using std::suspend_always; #else // defined(BOOST_ASIO_HAS_STD_COROUTINE) using std::experimental::coroutine_handle; using std::experimental::suspend_always; #endif // defined(BOOST_ASIO_HAS_STD_COROUTINE) template <typename> class awaitable_thread; template <typename, typename> class awaitable_frame; } // namespace detail /// The return type of a coroutine or asynchronous operation. template <typename T, typename Executor = any_io_executor> 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 <class U> void await_suspend( detail::coroutine_handle<detail::awaitable_frame<U, Executor>> h) { frame_->push_frame(&h.promise()); } // Support for co_await keyword. T await_resume() { return awaitable(static_cast<awaitable&&>(*this)).frame_->get(); } #endif // !defined(GENERATING_DOCUMENTATION) private: template <typename> friend class detail::awaitable_thread; template <typename, typename> 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<T, Executor>* a) : frame_(a) { } detail::awaitable_frame<T, Executor>* frame_; }; } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/awaitable.hpp> #endif // defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_AWAITABLE_HPP coroutine.hpp 0000644 00000023251 15125530236 0007271 0 ustar 00 // // coroutine.hpp // ~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/yield.hpp>@endcode * * and may conversely be undefined as follows: * * @code #include <boost/asio/unyield.hpp>@endcode * * <b>reenter</b> * * 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. * * <b>yield <em>statement</em></b> * * 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 * * <b>yield return <em>expression</em> ;</b> * * 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. * * <b>yield ;</b> * * 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 * * <b>yield break ;</b> * * 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. * * <b>fork <em>statement</em></b> * * 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 basic_serial_port.hpp 0000644 00000076250 15125530236 0010755 0 ustar 00 // // basic_serial_port.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) #include <string> #include <boost/asio/any_io_executor.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/io_object_impl.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/serial_port_base.hpp> #if defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/win_iocp_serial_port_service.hpp> #else # include <boost/asio/detail/reactive_serial_port_service.hpp> #endif #if defined(BOOST_ASIO_HAS_MOVE) # include <utility> #endif // defined(BOOST_ASIO_HAS_MOVE) #include <boost/asio/detail/push_options.hpp> 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 <typename Executor = any_io_executor> class basic_serial_port : public serial_port_base { public: /// The type of the executor associated with the object. typedef Executor executor_type; /// Rebinds the serial port type to another executor. template <typename Executor1> struct rebind_executor { /// The serial port type when rebound to the specified executor. typedef basic_serial_port<Executor1> other; }; /// 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 <typename ExecutionContext> explicit basic_serial_port(ExecutionContext& context, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename ExecutionContext> basic_serial_port(ExecutionContext& context, const char* device, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename ExecutionContext> basic_serial_port(ExecutionContext& context, const std::string& device, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename ExecutionContext> basic_serial_port(ExecutionContext& context, const native_handle_type& native_serial_port, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename SettableSerialPortOption> 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 <typename SettableSerialPortOption> 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 <typename GettableSerialPortOption> 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 <typename GettableSerialPortOption> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_some(const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( initiate_async_write_some(this), handler, 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_some(const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( initiate_async_read_some(this), handler, 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; class initiate_async_write_some { public: typedef Executor executor_type; explicit initiate_async_write_some(basic_serial_port* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename WriteHandler, typename ConstBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, 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<WriteHandler> handler2(handler); self_->impl_.get_service().async_write_some( self_->impl_.get_implementation(), buffers, handler2.value, self_->impl_.get_executor()); } private: basic_serial_port* self_; }; class initiate_async_read_some { public: typedef Executor executor_type; explicit initiate_async_read_some(basic_serial_port* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename ReadHandler, typename MutableBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); self_->impl_.get_service().async_read_some( self_->impl_.get_implementation(), buffers, handler2.value, self_->impl_.get_executor()); } private: basic_serial_port* self_; }; #if defined(BOOST_ASIO_HAS_IOCP) detail::io_object_impl<detail::win_iocp_serial_port_service, Executor> impl_; #else detail::io_object_impl<detail::reactive_serial_port_service, Executor> impl_; #endif }; } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_BASIC_SERIAL_PORT_HPP compose.hpp 0000644 00000010764 15125530236 0006734 0 ustar 00 // // compose.hpp // ~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Self> * 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 <typename CompletionToken> * auto async_echo(tcp::socket& socket, * boost::asio::mutable_buffer buffer, * CompletionToken&& token) -> * typename boost::asio::async_result< * typename std::decay<CompletionToken>::type, * void(boost::system::error_code, std::size_t)>::return_type * { * return boost::asio::async_compose<CompletionToken, * void(boost::system::error_code, std::size_t)>( * async_echo_implementation{socket, buffer, * async_echo_implementation::starting}, * token, socket); * } @endcode */ template <typename CompletionToken, typename Signature, typename Implementation, typename... IoObjectsOrExecutors> BOOST_ASIO_INITFN_AUTO_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 <typename CompletionToken, typename Signature, typename Implementation> BOOST_ASIO_INITFN_AUTO_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 <typename CompletionToken, typename Signature, \ typename Implementation, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ BOOST_ASIO_INITFN_AUTO_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 <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/compose.hpp> #endif // BOOST_ASIO_COMPOSE_HPP ssl/rfc2818_verification.hpp 0000644 00000005653 15125530236 0011730 0 ustar 00 // // ssl/rfc2818_verification.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_RFC2818_VERIFICATION_HPP #define BOOST_ASIO_SSL_RFC2818_VERIFICATION_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_NO_DEPRECATED) #include <string> #include <boost/asio/ssl/detail/openssl_types.hpp> #include <boost/asio/ssl/verify_context.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { /// (Deprecated. Use ssl::host_name_verification.) Verifies a certificate /// against a hostname according to the rules described in RFC 2818. /** * @par Example * The following example shows how to synchronously open a secure connection to * a given host name: * @code * using boost::asio::ip::tcp; * namespace ssl = boost::asio::ssl; * typedef ssl::stream<tcp::socket> ssl_socket; * * // Create a context that uses the default paths for finding CA certificates. * ssl::context ctx(ssl::context::sslv23); * ctx.set_default_verify_paths(); * * // Open a socket and connect it to the remote host. * boost::asio::io_context io_context; * ssl_socket sock(io_context, ctx); * tcp::resolver resolver(io_context); * tcp::resolver::query query("host.name", "https"); * boost::asio::connect(sock.lowest_layer(), resolver.resolve(query)); * sock.lowest_layer().set_option(tcp::no_delay(true)); * * // Perform SSL handshake and verify the remote host's certificate. * sock.set_verify_mode(ssl::verify_peer); * sock.set_verify_callback(ssl::rfc2818_verification("host.name")); * sock.handshake(ssl_socket::client); * * // ... read and write as normal ... * @endcode */ class rfc2818_verification { public: /// The type of the function object's result. typedef bool result_type; /// Constructor. explicit rfc2818_verification(const std::string& host) : host_(host) { } /// Perform certificate verification. BOOST_ASIO_DECL bool operator()(bool preverified, verify_context& ctx) const; private: // Helper function to check a host name against a pattern. BOOST_ASIO_DECL static bool match_pattern(const char* pattern, std::size_t pattern_length, const char* host); // Helper function to check a host name against an IPv4 address // The host name to be checked. std::string host_; }; } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/ssl/impl/rfc2818_verification.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // !defined(BOOST_ASIO_NO_DEPRECATED) #endif // BOOST_ASIO_SSL_RFC2818_VERIFICATION_HPP ssl/impl/error.ipp 0000644 00000004307 15125530236 0010157 0 ustar 00 // // ssl/impl/error.ipp // ~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_IMPL_ERROR_IPP #define BOOST_ASIO_SSL_IMPL_ERROR_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/ssl/error.hpp> #include <boost/asio/ssl/detail/openssl_init.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace error { namespace detail { class ssl_category : public boost::system::error_category { public: const char* name() const BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT { return "asio.ssl"; } std::string message(int value) const { const char* s = ::ERR_reason_error_string(value); return s ? s : "asio.ssl error"; } }; } // namespace detail const boost::system::error_category& get_ssl_category() { static detail::ssl_category instance; return instance; } } // namespace error namespace ssl { namespace error { #if (OPENSSL_VERSION_NUMBER < 0x10100000L) && !defined(OPENSSL_IS_BORINGSSL) const boost::system::error_category& get_stream_category() { return boost::asio::error::get_ssl_category(); } #else namespace detail { class stream_category : public boost::system::error_category { public: const char* name() const BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT { return "asio.ssl.stream"; } std::string message(int value) const { switch (value) { case stream_truncated: return "stream truncated"; case unspecified_system_error: return "unspecified system error"; case unexpected_result: return "unexpected result"; default: return "asio.ssl.stream error"; } } }; } // namespace detail const boost::system::error_category& get_stream_category() { static detail::stream_category instance; return instance; } #endif } // namespace error } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_IMPL_ERROR_IPP ssl/impl/context.ipp 0000644 00000104263 15125530236 0010514 0 ustar 00 // // ssl/impl/context.ipp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_IMPL_CONTEXT_IPP #define BOOST_ASIO_SSL_IMPL_CONTEXT_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <cstring> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/ssl/context.hpp> #include <boost/asio/ssl/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { struct context::bio_cleanup { BIO* p; ~bio_cleanup() { if (p) ::BIO_free(p); } }; struct context::x509_cleanup { X509* p; ~x509_cleanup() { if (p) ::X509_free(p); } }; struct context::evp_pkey_cleanup { EVP_PKEY* p; ~evp_pkey_cleanup() { if (p) ::EVP_PKEY_free(p); } }; struct context::rsa_cleanup { RSA* p; ~rsa_cleanup() { if (p) ::RSA_free(p); } }; struct context::dh_cleanup { DH* p; ~dh_cleanup() { if (p) ::DH_free(p); } }; context::context(context::method m) : handle_(0) { ::ERR_clear_error(); switch (m) { // SSL v2. #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(OPENSSL_NO_SSL2) case context::sslv2: case context::sslv2_client: case context::sslv2_server: boost::asio::detail::throw_error( boost::asio::error::invalid_argument, "context"); break; #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(OPENSSL_NO_SSL2) case context::sslv2: handle_ = ::SSL_CTX_new(::SSLv2_method()); break; case context::sslv2_client: handle_ = ::SSL_CTX_new(::SSLv2_client_method()); break; case context::sslv2_server: handle_ = ::SSL_CTX_new(::SSLv2_server_method()); break; #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) || defined(OPENSSL_NO_SSL2) // SSL v3. #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) case context::sslv3: handle_ = ::SSL_CTX_new(::TLS_method()); if (handle_) { SSL_CTX_set_min_proto_version(handle_, SSL3_VERSION); SSL_CTX_set_max_proto_version(handle_, SSL3_VERSION); } break; case context::sslv3_client: handle_ = ::SSL_CTX_new(::TLS_client_method()); if (handle_) { SSL_CTX_set_min_proto_version(handle_, SSL3_VERSION); SSL_CTX_set_max_proto_version(handle_, SSL3_VERSION); } break; case context::sslv3_server: handle_ = ::SSL_CTX_new(::TLS_server_method()); if (handle_) { SSL_CTX_set_min_proto_version(handle_, SSL3_VERSION); SSL_CTX_set_max_proto_version(handle_, SSL3_VERSION); } break; #elif defined(OPENSSL_NO_SSL3) case context::sslv3: case context::sslv3_client: case context::sslv3_server: boost::asio::detail::throw_error( boost::asio::error::invalid_argument, "context"); break; #else // defined(OPENSSL_NO_SSL3) case context::sslv3: handle_ = ::SSL_CTX_new(::SSLv3_method()); break; case context::sslv3_client: handle_ = ::SSL_CTX_new(::SSLv3_client_method()); break; case context::sslv3_server: handle_ = ::SSL_CTX_new(::SSLv3_server_method()); break; #endif // defined(OPENSSL_NO_SSL3) // TLS v1.0. #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) case context::tlsv1: handle_ = ::SSL_CTX_new(::TLS_method()); if (handle_) { SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION); SSL_CTX_set_max_proto_version(handle_, TLS1_VERSION); } break; case context::tlsv1_client: handle_ = ::SSL_CTX_new(::TLS_client_method()); if (handle_) { SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION); SSL_CTX_set_max_proto_version(handle_, TLS1_VERSION); } break; case context::tlsv1_server: handle_ = ::SSL_CTX_new(::TLS_server_method()); if (handle_) { SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION); SSL_CTX_set_max_proto_version(handle_, TLS1_VERSION); } break; #elif defined(SSL_TXT_TLSV1) case context::tlsv1: handle_ = ::SSL_CTX_new(::TLSv1_method()); break; case context::tlsv1_client: handle_ = ::SSL_CTX_new(::TLSv1_client_method()); break; case context::tlsv1_server: handle_ = ::SSL_CTX_new(::TLSv1_server_method()); break; #else // defined(SSL_TXT_TLSV1) case context::tlsv1: case context::tlsv1_client: case context::tlsv1_server: boost::asio::detail::throw_error( boost::asio::error::invalid_argument, "context"); break; #endif // defined(SSL_TXT_TLSV1) // TLS v1.1. #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) case context::tlsv11: handle_ = ::SSL_CTX_new(::TLS_method()); if (handle_) { SSL_CTX_set_min_proto_version(handle_, TLS1_1_VERSION); SSL_CTX_set_max_proto_version(handle_, TLS1_1_VERSION); } break; case context::tlsv11_client: handle_ = ::SSL_CTX_new(::TLS_client_method()); if (handle_) { SSL_CTX_set_min_proto_version(handle_, TLS1_1_VERSION); SSL_CTX_set_max_proto_version(handle_, TLS1_1_VERSION); } break; case context::tlsv11_server: handle_ = ::SSL_CTX_new(::TLS_server_method()); if (handle_) { SSL_CTX_set_min_proto_version(handle_, TLS1_1_VERSION); SSL_CTX_set_max_proto_version(handle_, TLS1_1_VERSION); } break; #elif defined(SSL_TXT_TLSV1_1) case context::tlsv11: handle_ = ::SSL_CTX_new(::TLSv1_1_method()); break; case context::tlsv11_client: handle_ = ::SSL_CTX_new(::TLSv1_1_client_method()); break; case context::tlsv11_server: handle_ = ::SSL_CTX_new(::TLSv1_1_server_method()); break; #else // defined(SSL_TXT_TLSV1_1) case context::tlsv11: case context::tlsv11_client: case context::tlsv11_server: boost::asio::detail::throw_error( boost::asio::error::invalid_argument, "context"); break; #endif // defined(SSL_TXT_TLSV1_1) // TLS v1.2. #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) case context::tlsv12: handle_ = ::SSL_CTX_new(::TLS_method()); if (handle_) { SSL_CTX_set_min_proto_version(handle_, TLS1_2_VERSION); SSL_CTX_set_max_proto_version(handle_, TLS1_2_VERSION); } break; case context::tlsv12_client: handle_ = ::SSL_CTX_new(::TLS_client_method()); if (handle_) { SSL_CTX_set_min_proto_version(handle_, TLS1_2_VERSION); SSL_CTX_set_max_proto_version(handle_, TLS1_2_VERSION); } break; case context::tlsv12_server: handle_ = ::SSL_CTX_new(::TLS_server_method()); if (handle_) { SSL_CTX_set_min_proto_version(handle_, TLS1_2_VERSION); SSL_CTX_set_max_proto_version(handle_, TLS1_2_VERSION); } break; #elif defined(SSL_TXT_TLSV1_2) case context::tlsv12: handle_ = ::SSL_CTX_new(::TLSv1_2_method()); break; case context::tlsv12_client: handle_ = ::SSL_CTX_new(::TLSv1_2_client_method()); break; case context::tlsv12_server: handle_ = ::SSL_CTX_new(::TLSv1_2_server_method()); break; #else // defined(SSL_TXT_TLSV1_2) case context::tlsv12: case context::tlsv12_client: case context::tlsv12_server: boost::asio::detail::throw_error( boost::asio::error::invalid_argument, "context"); break; #endif // defined(SSL_TXT_TLSV1_2) // TLS v1.3. #if (OPENSSL_VERSION_NUMBER >= 0x10101000L) \ && !defined(LIBRESSL_VERSION_NUMBER) case context::tlsv13: handle_ = ::SSL_CTX_new(::TLS_method()); if (handle_) { SSL_CTX_set_min_proto_version(handle_, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(handle_, TLS1_3_VERSION); } break; case context::tlsv13_client: handle_ = ::SSL_CTX_new(::TLS_client_method()); if (handle_) { SSL_CTX_set_min_proto_version(handle_, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(handle_, TLS1_3_VERSION); } break; case context::tlsv13_server: handle_ = ::SSL_CTX_new(::TLS_server_method()); if (handle_) { SSL_CTX_set_min_proto_version(handle_, TLS1_3_VERSION); SSL_CTX_set_max_proto_version(handle_, TLS1_3_VERSION); } break; #else // (OPENSSL_VERSION_NUMBER >= 0x10101000L) // && !defined(LIBRESSL_VERSION_NUMBER) case context::tlsv13: case context::tlsv13_client: case context::tlsv13_server: boost::asio::detail::throw_error( boost::asio::error::invalid_argument, "context"); break; #endif // (OPENSSL_VERSION_NUMBER >= 0x10101000L) // && !defined(LIBRESSL_VERSION_NUMBER) // Any supported SSL/TLS version. case context::sslv23: handle_ = ::SSL_CTX_new(::SSLv23_method()); break; case context::sslv23_client: handle_ = ::SSL_CTX_new(::SSLv23_client_method()); break; case context::sslv23_server: handle_ = ::SSL_CTX_new(::SSLv23_server_method()); break; // Any supported TLS version. #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER) case context::tls: handle_ = ::SSL_CTX_new(::TLS_method()); if (handle_) SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION); break; case context::tls_client: handle_ = ::SSL_CTX_new(::TLS_client_method()); if (handle_) SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION); break; case context::tls_server: handle_ = ::SSL_CTX_new(::TLS_server_method()); if (handle_) SSL_CTX_set_min_proto_version(handle_, TLS1_VERSION); break; #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) case context::tls: handle_ = ::SSL_CTX_new(::SSLv23_method()); if (handle_) SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); break; case context::tls_client: handle_ = ::SSL_CTX_new(::SSLv23_client_method()); if (handle_) SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); break; case context::tls_server: handle_ = ::SSL_CTX_new(::SSLv23_server_method()); if (handle_) SSL_CTX_set_options(handle_, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); break; #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) default: handle_ = ::SSL_CTX_new(0); break; } if (handle_ == 0) { boost::system::error_code ec( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); boost::asio::detail::throw_error(ec, "context"); } set_options(no_compression); } context::context(context::native_handle_type native_handle) : handle_(native_handle) { if (!handle_) { boost::asio::detail::throw_error( boost::asio::error::invalid_argument, "context"); } } #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) context::context(context&& other) { handle_ = other.handle_; other.handle_ = 0; } context& context::operator=(context&& other) { context tmp(BOOST_ASIO_MOVE_CAST(context)(*this)); handle_ = other.handle_; other.handle_ = 0; return *this; } #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) context::~context() { if (handle_) { #if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \ && !defined(LIBRESSL_VERSION_NUMBER)) \ || defined(BOOST_ASIO_USE_WOLFSSL) void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_); #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) void* cb_userdata = handle_->default_passwd_callback_userdata; #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) if (cb_userdata) { detail::password_callback_base* callback = static_cast<detail::password_callback_base*>( cb_userdata); delete callback; #if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \ && !defined(LIBRESSL_VERSION_NUMBER)) \ || defined(BOOST_ASIO_USE_WOLFSSL) ::SSL_CTX_set_default_passwd_cb_userdata(handle_, 0); #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) handle_->default_passwd_callback_userdata = 0; #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) } if (SSL_CTX_get_app_data(handle_)) { detail::verify_callback_base* callback = static_cast<detail::verify_callback_base*>( SSL_CTX_get_app_data(handle_)); delete callback; SSL_CTX_set_app_data(handle_, 0); } ::SSL_CTX_free(handle_); } } context::native_handle_type context::native_handle() { return handle_; } void context::clear_options(context::options o) { boost::system::error_code ec; clear_options(o, ec); boost::asio::detail::throw_error(ec, "clear_options"); } BOOST_ASIO_SYNC_OP_VOID context::clear_options( context::options o, boost::system::error_code& ec) { #if (OPENSSL_VERSION_NUMBER >= 0x009080DFL) \ && (OPENSSL_VERSION_NUMBER != 0x00909000L) # if !defined(SSL_OP_NO_COMPRESSION) if ((o & context::no_compression) != 0) { # if (OPENSSL_VERSION_NUMBER >= 0x00908000L) handle_->comp_methods = SSL_COMP_get_compression_methods(); # endif // (OPENSSL_VERSION_NUMBER >= 0x00908000L) o ^= context::no_compression; } # endif // !defined(SSL_OP_NO_COMPRESSION) ::SSL_CTX_clear_options(handle_, o); ec = boost::system::error_code(); #else // (OPENSSL_VERSION_NUMBER >= 0x009080DFL) // && (OPENSSL_VERSION_NUMBER != 0x00909000L) (void)o; ec = boost::asio::error::operation_not_supported; #endif // (OPENSSL_VERSION_NUMBER >= 0x009080DFL) // && (OPENSSL_VERSION_NUMBER != 0x00909000L) BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::set_options(context::options o) { boost::system::error_code ec; set_options(o, ec); boost::asio::detail::throw_error(ec, "set_options"); } BOOST_ASIO_SYNC_OP_VOID context::set_options( context::options o, boost::system::error_code& ec) { #if !defined(SSL_OP_NO_COMPRESSION) if ((o & context::no_compression) != 0) { #if (OPENSSL_VERSION_NUMBER >= 0x00908000L) handle_->comp_methods = boost::asio::ssl::detail::openssl_init<>::get_null_compression_methods(); #endif // (OPENSSL_VERSION_NUMBER >= 0x00908000L) o ^= context::no_compression; } #endif // !defined(SSL_OP_NO_COMPRESSION) ::SSL_CTX_set_options(handle_, o); ec = boost::system::error_code(); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::set_verify_mode(verify_mode v) { boost::system::error_code ec; set_verify_mode(v, ec); boost::asio::detail::throw_error(ec, "set_verify_mode"); } BOOST_ASIO_SYNC_OP_VOID context::set_verify_mode( verify_mode v, boost::system::error_code& ec) { ::SSL_CTX_set_verify(handle_, v, ::SSL_CTX_get_verify_callback(handle_)); ec = boost::system::error_code(); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::set_verify_depth(int depth) { boost::system::error_code ec; set_verify_depth(depth, ec); boost::asio::detail::throw_error(ec, "set_verify_depth"); } BOOST_ASIO_SYNC_OP_VOID context::set_verify_depth( int depth, boost::system::error_code& ec) { ::SSL_CTX_set_verify_depth(handle_, depth); ec = boost::system::error_code(); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::load_verify_file(const std::string& filename) { boost::system::error_code ec; load_verify_file(filename, ec); boost::asio::detail::throw_error(ec, "load_verify_file"); } BOOST_ASIO_SYNC_OP_VOID context::load_verify_file( const std::string& filename, boost::system::error_code& ec) { ::ERR_clear_error(); if (::SSL_CTX_load_verify_locations(handle_, filename.c_str(), 0) != 1) { ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } ec = boost::system::error_code(); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::add_certificate_authority(const const_buffer& ca) { boost::system::error_code ec; add_certificate_authority(ca, ec); boost::asio::detail::throw_error(ec, "add_certificate_authority"); } BOOST_ASIO_SYNC_OP_VOID context::add_certificate_authority( const const_buffer& ca, boost::system::error_code& ec) { ::ERR_clear_error(); bio_cleanup bio = { make_buffer_bio(ca) }; if (bio.p) { if (X509_STORE* store = ::SSL_CTX_get_cert_store(handle_)) { for (bool added = false;; added = true) { x509_cleanup cert = { ::PEM_read_bio_X509(bio.p, 0, 0, 0) }; if (!cert.p) { unsigned long err = ::ERR_get_error(); if (added && ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) break; ec = boost::system::error_code( static_cast<int>(err), boost::asio::error::get_ssl_category()); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } if (::X509_STORE_add_cert(store, cert.p) != 1) { ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } } } ec = boost::system::error_code(); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::set_default_verify_paths() { boost::system::error_code ec; set_default_verify_paths(ec); boost::asio::detail::throw_error(ec, "set_default_verify_paths"); } BOOST_ASIO_SYNC_OP_VOID context::set_default_verify_paths( boost::system::error_code& ec) { ::ERR_clear_error(); if (::SSL_CTX_set_default_verify_paths(handle_) != 1) { ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } ec = boost::system::error_code(); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::add_verify_path(const std::string& path) { boost::system::error_code ec; add_verify_path(path, ec); boost::asio::detail::throw_error(ec, "add_verify_path"); } BOOST_ASIO_SYNC_OP_VOID context::add_verify_path( const std::string& path, boost::system::error_code& ec) { ::ERR_clear_error(); if (::SSL_CTX_load_verify_locations(handle_, 0, path.c_str()) != 1) { ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } ec = boost::system::error_code(); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::use_certificate( const const_buffer& certificate, file_format format) { boost::system::error_code ec; use_certificate(certificate, format, ec); boost::asio::detail::throw_error(ec, "use_certificate"); } BOOST_ASIO_SYNC_OP_VOID context::use_certificate( const const_buffer& certificate, file_format format, boost::system::error_code& ec) { ::ERR_clear_error(); if (format == context_base::asn1) { if (::SSL_CTX_use_certificate_ASN1(handle_, static_cast<int>(certificate.size()), static_cast<const unsigned char*>(certificate.data())) == 1) { ec = boost::system::error_code(); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } else if (format == context_base::pem) { bio_cleanup bio = { make_buffer_bio(certificate) }; if (bio.p) { x509_cleanup cert = { ::PEM_read_bio_X509(bio.p, 0, 0, 0) }; if (cert.p) { if (::SSL_CTX_use_certificate(handle_, cert.p) == 1) { ec = boost::system::error_code(); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } } } else { ec = boost::asio::error::invalid_argument; BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::use_certificate_file( const std::string& filename, file_format format) { boost::system::error_code ec; use_certificate_file(filename, format, ec); boost::asio::detail::throw_error(ec, "use_certificate_file"); } BOOST_ASIO_SYNC_OP_VOID context::use_certificate_file( const std::string& filename, file_format format, boost::system::error_code& ec) { int file_type; switch (format) { case context_base::asn1: file_type = SSL_FILETYPE_ASN1; break; case context_base::pem: file_type = SSL_FILETYPE_PEM; break; default: { ec = boost::asio::error::invalid_argument; BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } ::ERR_clear_error(); if (::SSL_CTX_use_certificate_file(handle_, filename.c_str(), file_type) != 1) { ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } ec = boost::system::error_code(); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::use_certificate_chain(const const_buffer& chain) { boost::system::error_code ec; use_certificate_chain(chain, ec); boost::asio::detail::throw_error(ec, "use_certificate_chain"); } BOOST_ASIO_SYNC_OP_VOID context::use_certificate_chain( const const_buffer& chain, boost::system::error_code& ec) { ::ERR_clear_error(); bio_cleanup bio = { make_buffer_bio(chain) }; if (bio.p) { #if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \ && !defined(LIBRESSL_VERSION_NUMBER)) \ || defined(BOOST_ASIO_USE_WOLFSSL) pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_); void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_); #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) pem_password_cb* callback = handle_->default_passwd_callback; void* cb_userdata = handle_->default_passwd_callback_userdata; #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) x509_cleanup cert = { ::PEM_read_bio_X509_AUX(bio.p, 0, callback, cb_userdata) }; if (!cert.p) { ec = boost::system::error_code(ERR_R_PEM_LIB, boost::asio::error::get_ssl_category()); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } int result = ::SSL_CTX_use_certificate(handle_, cert.p); if (result == 0 || ::ERR_peek_error() != 0) { ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } #if ((OPENSSL_VERSION_NUMBER >= 0x10002000L) \ && !defined(LIBRESSL_VERSION_NUMBER)) \ || defined(BOOST_ASIO_USE_WOLFSSL) ::SSL_CTX_clear_chain_certs(handle_); #else if (handle_->extra_certs) { ::sk_X509_pop_free(handle_->extra_certs, X509_free); handle_->extra_certs = 0; } #endif // (OPENSSL_VERSION_NUMBER >= 0x10002000L) while (X509* cacert = ::PEM_read_bio_X509(bio.p, 0, callback, cb_userdata)) { if (!::SSL_CTX_add_extra_chain_cert(handle_, cacert)) { ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } result = ::ERR_peek_last_error(); if ((ERR_GET_LIB(result) == ERR_LIB_PEM) && (ERR_GET_REASON(result) == PEM_R_NO_START_LINE)) { ::ERR_clear_error(); ec = boost::system::error_code(); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::use_certificate_chain_file(const std::string& filename) { boost::system::error_code ec; use_certificate_chain_file(filename, ec); boost::asio::detail::throw_error(ec, "use_certificate_chain_file"); } BOOST_ASIO_SYNC_OP_VOID context::use_certificate_chain_file( const std::string& filename, boost::system::error_code& ec) { ::ERR_clear_error(); if (::SSL_CTX_use_certificate_chain_file(handle_, filename.c_str()) != 1) { ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } ec = boost::system::error_code(); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::use_private_key( const const_buffer& private_key, context::file_format format) { boost::system::error_code ec; use_private_key(private_key, format, ec); boost::asio::detail::throw_error(ec, "use_private_key"); } BOOST_ASIO_SYNC_OP_VOID context::use_private_key( const const_buffer& private_key, context::file_format format, boost::system::error_code& ec) { ::ERR_clear_error(); #if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \ && !defined(LIBRESSL_VERSION_NUMBER)) \ || defined(BOOST_ASIO_USE_WOLFSSL) pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_); void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_); #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) pem_password_cb* callback = handle_->default_passwd_callback; void* cb_userdata = handle_->default_passwd_callback_userdata; #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) bio_cleanup bio = { make_buffer_bio(private_key) }; if (bio.p) { evp_pkey_cleanup evp_private_key = { 0 }; switch (format) { case context_base::asn1: evp_private_key.p = ::d2i_PrivateKey_bio(bio.p, 0); break; case context_base::pem: evp_private_key.p = ::PEM_read_bio_PrivateKey( bio.p, 0, callback, cb_userdata); break; default: { ec = boost::asio::error::invalid_argument; BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } if (evp_private_key.p) { if (::SSL_CTX_use_PrivateKey(handle_, evp_private_key.p) == 1) { ec = boost::system::error_code(); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } } ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::use_private_key_file( const std::string& filename, context::file_format format) { boost::system::error_code ec; use_private_key_file(filename, format, ec); boost::asio::detail::throw_error(ec, "use_private_key_file"); } void context::use_rsa_private_key( const const_buffer& private_key, context::file_format format) { boost::system::error_code ec; use_rsa_private_key(private_key, format, ec); boost::asio::detail::throw_error(ec, "use_rsa_private_key"); } BOOST_ASIO_SYNC_OP_VOID context::use_rsa_private_key( const const_buffer& private_key, context::file_format format, boost::system::error_code& ec) { ::ERR_clear_error(); #if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \ && !defined(LIBRESSL_VERSION_NUMBER)) \ || defined(BOOST_ASIO_USE_WOLFSSL) pem_password_cb* callback = ::SSL_CTX_get_default_passwd_cb(handle_); void* cb_userdata = ::SSL_CTX_get_default_passwd_cb_userdata(handle_); #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) pem_password_cb* callback = handle_->default_passwd_callback; void* cb_userdata = handle_->default_passwd_callback_userdata; #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) bio_cleanup bio = { make_buffer_bio(private_key) }; if (bio.p) { rsa_cleanup rsa_private_key = { 0 }; switch (format) { case context_base::asn1: rsa_private_key.p = ::d2i_RSAPrivateKey_bio(bio.p, 0); break; case context_base::pem: rsa_private_key.p = ::PEM_read_bio_RSAPrivateKey( bio.p, 0, callback, cb_userdata); break; default: { ec = boost::asio::error::invalid_argument; BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } if (rsa_private_key.p) { if (::SSL_CTX_use_RSAPrivateKey(handle_, rsa_private_key.p) == 1) { ec = boost::system::error_code(); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } } ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } BOOST_ASIO_SYNC_OP_VOID context::use_private_key_file( const std::string& filename, context::file_format format, boost::system::error_code& ec) { int file_type; switch (format) { case context_base::asn1: file_type = SSL_FILETYPE_ASN1; break; case context_base::pem: file_type = SSL_FILETYPE_PEM; break; default: { ec = boost::asio::error::invalid_argument; BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } ::ERR_clear_error(); if (::SSL_CTX_use_PrivateKey_file(handle_, filename.c_str(), file_type) != 1) { ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } ec = boost::system::error_code(); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::use_rsa_private_key_file( const std::string& filename, context::file_format format) { boost::system::error_code ec; use_rsa_private_key_file(filename, format, ec); boost::asio::detail::throw_error(ec, "use_rsa_private_key_file"); } BOOST_ASIO_SYNC_OP_VOID context::use_rsa_private_key_file( const std::string& filename, context::file_format format, boost::system::error_code& ec) { int file_type; switch (format) { case context_base::asn1: file_type = SSL_FILETYPE_ASN1; break; case context_base::pem: file_type = SSL_FILETYPE_PEM; break; default: { ec = boost::asio::error::invalid_argument; BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } ::ERR_clear_error(); if (::SSL_CTX_use_RSAPrivateKey_file( handle_, filename.c_str(), file_type) != 1) { ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } ec = boost::system::error_code(); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::use_tmp_dh(const const_buffer& dh) { boost::system::error_code ec; use_tmp_dh(dh, ec); boost::asio::detail::throw_error(ec, "use_tmp_dh"); } BOOST_ASIO_SYNC_OP_VOID context::use_tmp_dh( const const_buffer& dh, boost::system::error_code& ec) { ::ERR_clear_error(); bio_cleanup bio = { make_buffer_bio(dh) }; if (bio.p) { return do_use_tmp_dh(bio.p, ec); } ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } void context::use_tmp_dh_file(const std::string& filename) { boost::system::error_code ec; use_tmp_dh_file(filename, ec); boost::asio::detail::throw_error(ec, "use_tmp_dh_file"); } BOOST_ASIO_SYNC_OP_VOID context::use_tmp_dh_file( const std::string& filename, boost::system::error_code& ec) { ::ERR_clear_error(); bio_cleanup bio = { ::BIO_new_file(filename.c_str(), "r") }; if (bio.p) { return do_use_tmp_dh(bio.p, ec); } ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } BOOST_ASIO_SYNC_OP_VOID context::do_use_tmp_dh( BIO* bio, boost::system::error_code& ec) { ::ERR_clear_error(); dh_cleanup dh = { ::PEM_read_bio_DHparams(bio, 0, 0, 0) }; if (dh.p) { if (::SSL_CTX_set_tmp_dh(handle_, dh.p) == 1) { ec = boost::system::error_code(); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } ec = boost::system::error_code( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } BOOST_ASIO_SYNC_OP_VOID context::do_set_verify_callback( detail::verify_callback_base* callback, boost::system::error_code& ec) { if (SSL_CTX_get_app_data(handle_)) { delete static_cast<detail::verify_callback_base*>( SSL_CTX_get_app_data(handle_)); } SSL_CTX_set_app_data(handle_, callback); ::SSL_CTX_set_verify(handle_, ::SSL_CTX_get_verify_mode(handle_), &context::verify_callback_function); ec = boost::system::error_code(); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } int context::verify_callback_function(int preverified, X509_STORE_CTX* ctx) { if (ctx) { if (SSL* ssl = static_cast<SSL*>( ::X509_STORE_CTX_get_ex_data( ctx, ::SSL_get_ex_data_X509_STORE_CTX_idx()))) { if (SSL_CTX* handle = ::SSL_get_SSL_CTX(ssl)) { if (SSL_CTX_get_app_data(handle)) { detail::verify_callback_base* callback = static_cast<detail::verify_callback_base*>( SSL_CTX_get_app_data(handle)); verify_context verify_ctx(ctx); return callback->call(preverified != 0, verify_ctx) ? 1 : 0; } } } } return 0; } BOOST_ASIO_SYNC_OP_VOID context::do_set_password_callback( detail::password_callback_base* callback, boost::system::error_code& ec) { #if ((OPENSSL_VERSION_NUMBER >= 0x10100000L) \ && !defined(LIBRESSL_VERSION_NUMBER)) \ || defined(BOOST_ASIO_USE_WOLFSSL) void* old_callback = ::SSL_CTX_get_default_passwd_cb_userdata(handle_); ::SSL_CTX_set_default_passwd_cb_userdata(handle_, callback); #else // (OPENSSL_VERSION_NUMBER >= 0x10100000L) void* old_callback = handle_->default_passwd_callback_userdata; handle_->default_passwd_callback_userdata = callback; #endif // (OPENSSL_VERSION_NUMBER >= 0x10100000L) if (old_callback) delete static_cast<detail::password_callback_base*>( old_callback); SSL_CTX_set_default_passwd_cb(handle_, &context::password_callback_function); ec = boost::system::error_code(); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } int context::password_callback_function( char* buf, int size, int purpose, void* data) { using namespace std; // For strncat and strlen. if (data) { detail::password_callback_base* callback = static_cast<detail::password_callback_base*>(data); std::string passwd = callback->call(static_cast<std::size_t>(size), purpose ? context_base::for_writing : context_base::for_reading); #if defined(BOOST_ASIO_HAS_SECURE_RTL) strcpy_s(buf, size, passwd.c_str()); #else // defined(BOOST_ASIO_HAS_SECURE_RTL) *buf = '\0'; if (size > 0) strncat(buf, passwd.c_str(), size - 1); #endif // defined(BOOST_ASIO_HAS_SECURE_RTL) return static_cast<int>(strlen(buf)); } return 0; } BIO* context::make_buffer_bio(const const_buffer& b) { return ::BIO_new_mem_buf( const_cast<void*>(b.data()), static_cast<int>(b.size())); } } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_IMPL_CONTEXT_IPP ssl/impl/host_name_verification.ipp 0000644 00000004054 15125530236 0013544 0 ustar 00 // // ssl/impl/host_name_verification.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_IMPL_HOST_NAME_VERIFICATION_IPP #define BOOST_ASIO_SSL_IMPL_HOST_NAME_VERIFICATION_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <cctype> #include <cstring> #include <boost/asio/ip/address.hpp> #include <boost/asio/ssl/host_name_verification.hpp> #include <boost/asio/ssl/detail/openssl_types.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { bool host_name_verification::operator()( bool preverified, verify_context& ctx) const { using namespace std; // For memcmp. // Don't bother looking at certificates that have failed pre-verification. if (!preverified) return false; // We're only interested in checking the certificate at the end of the chain. int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle()); if (depth > 0) return true; // Try converting the host name to an address. If it is an address then we // need to look for an IP address in the certificate rather than a host name. boost::system::error_code ec; ip::address address = ip::make_address(host_, ec); const bool is_address = !ec; (void)address; X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); if (is_address) { return X509_check_ip_asc(cert, host_.c_str(), 0) == 1; } else { char* peername = 0; const int result = X509_check_host(cert, host_.c_str(), host_.size(), 0, &peername); OPENSSL_free(peername); return result == 1; } } } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_IMPL_HOST_NAME_VERIFICATION_IPP ssl/impl/context.hpp 0000644 00000003641 15125530236 0010511 0 ustar 00 // // ssl/impl/context.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_IMPL_CONTEXT_HPP #define BOOST_ASIO_SSL_IMPL_CONTEXT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { template <typename VerifyCallback> void context::set_verify_callback(VerifyCallback callback) { boost::system::error_code ec; this->set_verify_callback(callback, ec); boost::asio::detail::throw_error(ec, "set_verify_callback"); } template <typename VerifyCallback> BOOST_ASIO_SYNC_OP_VOID context::set_verify_callback( VerifyCallback callback, boost::system::error_code& ec) { do_set_verify_callback( new detail::verify_callback<VerifyCallback>(callback), ec); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } template <typename PasswordCallback> void context::set_password_callback(PasswordCallback callback) { boost::system::error_code ec; this->set_password_callback(callback, ec); boost::asio::detail::throw_error(ec, "set_password_callback"); } template <typename PasswordCallback> BOOST_ASIO_SYNC_OP_VOID context::set_password_callback( PasswordCallback callback, boost::system::error_code& ec) { do_set_password_callback( new detail::password_callback<PasswordCallback>(callback), ec); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_IMPL_CONTEXT_HPP ssl/impl/src.hpp 0000644 00000001572 15125530236 0007615 0 ustar 00 // // impl/ssl/src.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_IMPL_SRC_HPP #define BOOST_ASIO_SSL_IMPL_SRC_HPP #define BOOST_ASIO_SOURCE #include <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # error Do not compile Asio library source with BOOST_ASIO_HEADER_ONLY defined #endif #include <boost/asio/ssl/impl/context.ipp> #include <boost/asio/ssl/impl/error.ipp> #include <boost/asio/ssl/detail/impl/engine.ipp> #include <boost/asio/ssl/detail/impl/openssl_init.ipp> #include <boost/asio/ssl/impl/host_name_verification.ipp> #include <boost/asio/ssl/impl/rfc2818_verification.ipp> #endif // BOOST_ASIO_SSL_IMPL_SRC_HPP ssl/impl/rfc2818_verification.ipp 0000644 00000011347 15125530236 0012667 0 ustar 00 // // ssl/impl/rfc2818_verification.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_IMPL_RFC2818_VERIFICATION_IPP #define BOOST_ASIO_SSL_IMPL_RFC2818_VERIFICATION_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_NO_DEPRECATED) #include <cctype> #include <cstring> #include <boost/asio/ip/address.hpp> #include <boost/asio/ssl/rfc2818_verification.hpp> #include <boost/asio/ssl/detail/openssl_types.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { bool rfc2818_verification::operator()( bool preverified, verify_context& ctx) const { using namespace std; // For memcmp. // Don't bother looking at certificates that have failed pre-verification. if (!preverified) return false; // We're only interested in checking the certificate at the end of the chain. int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle()); if (depth > 0) return true; // Try converting the host name to an address. If it is an address then we // need to look for an IP address in the certificate rather than a host name. boost::system::error_code ec; ip::address address = ip::make_address(host_, ec); bool is_address = !ec; X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); // Go through the alternate names in the certificate looking for matching DNS // or IP address entries. GENERAL_NAMES* gens = static_cast<GENERAL_NAMES*>( X509_get_ext_d2i(cert, NID_subject_alt_name, 0, 0)); for (int i = 0; i < sk_GENERAL_NAME_num(gens); ++i) { GENERAL_NAME* gen = sk_GENERAL_NAME_value(gens, i); if (gen->type == GEN_DNS && !is_address) { ASN1_IA5STRING* domain = gen->d.dNSName; if (domain->type == V_ASN1_IA5STRING && domain->data && domain->length) { const char* pattern = reinterpret_cast<const char*>(domain->data); std::size_t pattern_length = domain->length; if (match_pattern(pattern, pattern_length, host_.c_str())) { GENERAL_NAMES_free(gens); return true; } } } else if (gen->type == GEN_IPADD && is_address) { ASN1_OCTET_STRING* ip_address = gen->d.iPAddress; if (ip_address->type == V_ASN1_OCTET_STRING && ip_address->data) { if (address.is_v4() && ip_address->length == 4) { ip::address_v4::bytes_type bytes = address.to_v4().to_bytes(); if (memcmp(bytes.data(), ip_address->data, 4) == 0) { GENERAL_NAMES_free(gens); return true; } } else if (address.is_v6() && ip_address->length == 16) { ip::address_v6::bytes_type bytes = address.to_v6().to_bytes(); if (memcmp(bytes.data(), ip_address->data, 16) == 0) { GENERAL_NAMES_free(gens); return true; } } } } } GENERAL_NAMES_free(gens); // No match in the alternate names, so try the common names. We should only // use the "most specific" common name, which is the last one in the list. X509_NAME* name = X509_get_subject_name(cert); int i = -1; ASN1_STRING* common_name = 0; while ((i = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0) { X509_NAME_ENTRY* name_entry = X509_NAME_get_entry(name, i); common_name = X509_NAME_ENTRY_get_data(name_entry); } if (common_name && common_name->data && common_name->length) { const char* pattern = reinterpret_cast<const char*>(common_name->data); std::size_t pattern_length = common_name->length; if (match_pattern(pattern, pattern_length, host_.c_str())) return true; } return false; } bool rfc2818_verification::match_pattern(const char* pattern, std::size_t pattern_length, const char* host) { using namespace std; // For tolower. const char* p = pattern; const char* p_end = p + pattern_length; const char* h = host; while (p != p_end && *h) { if (*p == '*') { ++p; while (*h && *h != '.') if (match_pattern(p, p_end - p, h++)) return true; } else if (tolower(*p) == tolower(*h)) { ++p; ++h; } else { return false; } } return p == p_end && !*h; } } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_NO_DEPRECATED) #endif // BOOST_ASIO_SSL_IMPL_RFC2818_VERIFICATION_IPP ssl/host_name_verification.hpp 0000644 00000005205 15125530236 0012601 0 ustar 00 // // ssl/host_name_verification.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_HOST_NAME_VERIFICATION_HPP #define BOOST_ASIO_SSL_HOST_NAME_VERIFICATION_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <string> #include <boost/asio/ssl/detail/openssl_types.hpp> #include <boost/asio/ssl/verify_context.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { /// Verifies a certificate against a host_name according to the rules described /// in RFC 6125. /** * @par Example * The following example shows how to synchronously open a secure connection to * a given host name: * @code * using boost::asio::ip::tcp; * namespace ssl = boost::asio::ssl; * typedef ssl::stream<tcp::socket> ssl_socket; * * // Create a context that uses the default paths for finding CA certificates. * ssl::context ctx(ssl::context::sslv23); * ctx.set_default_verify_paths(); * * // Open a socket and connect it to the remote host. * boost::asio::io_context io_context; * ssl_socket sock(io_context, ctx); * tcp::resolver resolver(io_context); * tcp::resolver::query query("host.name", "https"); * boost::asio::connect(sock.lowest_layer(), resolver.resolve(query)); * sock.lowest_layer().set_option(tcp::no_delay(true)); * * // Perform SSL handshake and verify the remote host's certificate. * sock.set_verify_mode(ssl::verify_peer); * sock.set_verify_callback(ssl::host_name_verification("host.name")); * sock.handshake(ssl_socket::client); * * // ... read and write as normal ... * @endcode */ class host_name_verification { public: /// The type of the function object's result. typedef bool result_type; /// Constructor. explicit host_name_verification(const std::string& host) : host_(host) { } /// Perform certificate verification. BOOST_ASIO_DECL bool operator()(bool preverified, verify_context& ctx) const; private: // Helper function to check a host name against an IPv4 address // The host name to be checked. std::string host_; }; } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/ssl/impl/host_name_verification.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_SSL_HOST_NAME_VERIFICATION_HPP ssl/verify_mode.hpp 0000644 00000003336 15125530236 0010375 0 ustar 00 // // ssl/verify_mode.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_VERIFY_MODE_HPP #define BOOST_ASIO_SSL_VERIFY_MODE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/ssl/detail/openssl_types.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { /// Bitmask type for peer verification. /** * Possible values are: * * @li @ref verify_none * @li @ref verify_peer * @li @ref verify_fail_if_no_peer_cert * @li @ref verify_client_once */ typedef int verify_mode; #if defined(GENERATING_DOCUMENTATION) /// No verification. const int verify_none = implementation_defined; /// Verify the peer. const int verify_peer = implementation_defined; /// Fail verification if the peer has no certificate. Ignored unless /// @ref verify_peer is set. const int verify_fail_if_no_peer_cert = implementation_defined; /// Do not request client certificate on renegotiation. Ignored unless /// @ref verify_peer is set. const int verify_client_once = implementation_defined; #else const int verify_none = SSL_VERIFY_NONE; const int verify_peer = SSL_VERIFY_PEER; const int verify_fail_if_no_peer_cert = SSL_VERIFY_FAIL_IF_NO_PEER_CERT; const int verify_client_once = SSL_VERIFY_CLIENT_ONCE; #endif } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_VERIFY_MODE_HPP ssl/stream.hpp 0000644 00000074514 15125530236 0007366 0 ustar 00 // // ssl/stream.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_STREAM_HPP #define BOOST_ASIO_SSL_STREAM_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/ssl/context.hpp> #include <boost/asio/ssl/detail/buffered_handshake_op.hpp> #include <boost/asio/ssl/detail/handshake_op.hpp> #include <boost/asio/ssl/detail/io.hpp> #include <boost/asio/ssl/detail/read_op.hpp> #include <boost/asio/ssl/detail/shutdown_op.hpp> #include <boost/asio/ssl/detail/stream_core.hpp> #include <boost/asio/ssl/detail/write_op.hpp> #include <boost/asio/ssl/stream_base.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { /// Provides stream-oriented functionality using SSL. /** * The stream class template provides asynchronous and blocking stream-oriented * functionality using SSL. * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. The application must also ensure that all * asynchronous operations are performed within the same implicit or explicit * strand. * * @par Example * To use the SSL stream template with an ip::tcp::socket, you would write: * @code * boost::asio::io_context my_context; * boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23); * boost::asio::ssl::stream<asio:ip::tcp::socket> sock(my_context, ctx); * @endcode * * @par Concepts: * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. */ template <typename Stream> class stream : public stream_base, private noncopyable { public: /// The native handle type of the SSL stream. typedef SSL* native_handle_type; /// Structure for use with deprecated impl_type. struct impl_struct { SSL* ssl; }; /// The type of the next layer. typedef typename remove_reference<Stream>::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(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Construct a stream. /** * This constructor creates a stream and initialises the underlying stream * object. * * @param arg The argument to be passed to initialise the underlying stream. * * @param ctx The SSL context to be used for the stream. */ template <typename Arg> stream(Arg&& arg, context& ctx) : next_layer_(BOOST_ASIO_MOVE_CAST(Arg)(arg)), core_(ctx.native_handle(), next_layer_.lowest_layer().get_executor()) { } #else // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) template <typename Arg> stream(Arg& arg, context& ctx) : next_layer_(arg), core_(ctx.native_handle(), next_layer_.lowest_layer().get_executor()) { } #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move-construct a stream from another. /** * @param other The other stream object from which the move will occur. Must * have no outstanding asynchronous operations associated with it. Following * the move, @c other has a valid but unspecified state where the only safe * operation is destruction. */ stream(stream&& other) : next_layer_(BOOST_ASIO_MOVE_CAST(Stream)(other.next_layer_)), core_(BOOST_ASIO_MOVE_CAST(detail::stream_core)(other.core_)) { } #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Destructor. /** * @note A @c stream object must not be destroyed while there are pending * asynchronous operations associated with it. */ ~stream() { } /// Get the executor associated with the object. /** * This function may be used to obtain the executor object that the stream * uses to dispatch handlers for asynchronous operations. * * @return A copy of the executor that stream will use to dispatch handlers. */ executor_type get_executor() BOOST_ASIO_NOEXCEPT { return next_layer_.lowest_layer().get_executor(); } /// Get the underlying implementation in the native type. /** * This function may be used to obtain the underlying implementation of the * context. This is intended to allow access to context functionality that is * not otherwise provided. * * @par Example * The native_handle() function returns a pointer of type @c SSL* that is * suitable for passing to functions such as @c SSL_get_verify_result and * @c SSL_get_peer_certificate: * @code * boost::asio::ssl::stream<asio:ip::tcp::socket> sock(my_context, ctx); * * // ... establish connection and perform handshake ... * * if (X509* cert = SSL_get_peer_certificate(sock.native_handle())) * { * if (SSL_get_verify_result(sock.native_handle()) == X509_V_OK) * { * // ... * } * } * @endcode */ native_handle_type native_handle() { return core_.engine_.native_handle(); } /// Get a reference to the next layer. /** * This function returns a reference to the next layer in a stack of stream * layers. * * @return A reference to the next layer in the stack of stream layers. * Ownership is not transferred to the caller. */ const next_layer_type& next_layer() const { return next_layer_; } /// Get a reference to the next layer. /** * This function returns a reference to the next layer in a stack of stream * layers. * * @return A reference to the next layer in the stack of stream layers. * Ownership is not transferred to the caller. */ next_layer_type& next_layer() { return next_layer_; } /// Get a reference to the lowest layer. /** * This function returns a reference to the lowest layer in a stack of * stream layers. * * @return A reference to the lowest layer in the stack of stream layers. * Ownership is not transferred to the caller. */ lowest_layer_type& lowest_layer() { return next_layer_.lowest_layer(); } /// Get a reference to the lowest layer. /** * This function returns a reference to the lowest layer in a stack of * stream layers. * * @return A reference to the lowest layer in the stack of stream layers. * Ownership is not transferred to the caller. */ const lowest_layer_type& lowest_layer() const { return next_layer_.lowest_layer(); } /// Set the peer verification mode. /** * This function may be used to configure the peer verification mode used by * the stream. The new mode will override the mode inherited from the context. * * @param v A bitmask of peer verification modes. See @ref verify_mode for * available values. * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_set_verify. */ void set_verify_mode(verify_mode v) { boost::system::error_code ec; set_verify_mode(v, ec); boost::asio::detail::throw_error(ec, "set_verify_mode"); } /// Set the peer verification mode. /** * This function may be used to configure the peer verification mode used by * the stream. The new mode will override the mode inherited from the context. * * @param v A bitmask of peer verification modes. See @ref verify_mode for * available values. * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_set_verify. */ BOOST_ASIO_SYNC_OP_VOID set_verify_mode( verify_mode v, boost::system::error_code& ec) { core_.engine_.set_verify_mode(v, ec); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Set the peer verification depth. /** * This function may be used to configure the maximum verification depth * allowed by the stream. * * @param depth Maximum depth for the certificate chain verification that * shall be allowed. * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_set_verify_depth. */ void set_verify_depth(int depth) { boost::system::error_code ec; set_verify_depth(depth, ec); boost::asio::detail::throw_error(ec, "set_verify_depth"); } /// Set the peer verification depth. /** * This function may be used to configure the maximum verification depth * allowed by the stream. * * @param depth Maximum depth for the certificate chain verification that * shall be allowed. * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_set_verify_depth. */ BOOST_ASIO_SYNC_OP_VOID set_verify_depth( int depth, boost::system::error_code& ec) { core_.engine_.set_verify_depth(depth, ec); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Set the callback used to verify peer certificates. /** * This function is used to specify a callback function that will be called * by the implementation when it needs to verify a peer certificate. * * @param callback The function object to be used for verifying a certificate. * The function signature of the handler must be: * @code bool verify_callback( * bool preverified, // True if the certificate passed pre-verification. * verify_context& ctx // The peer certificate and other context. * ); @endcode * The return value of the callback is true if the certificate has passed * verification, false otherwise. * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_set_verify. */ template <typename VerifyCallback> void set_verify_callback(VerifyCallback callback) { boost::system::error_code ec; this->set_verify_callback(callback, ec); boost::asio::detail::throw_error(ec, "set_verify_callback"); } /// Set the callback used to verify peer certificates. /** * This function is used to specify a callback function that will be called * by the implementation when it needs to verify a peer certificate. * * @param callback The function object to be used for verifying a certificate. * The function signature of the handler must be: * @code bool verify_callback( * bool preverified, // True if the certificate passed pre-verification. * verify_context& ctx // The peer certificate and other context. * ); @endcode * The return value of the callback is true if the certificate has passed * verification, false otherwise. * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_set_verify. */ template <typename VerifyCallback> BOOST_ASIO_SYNC_OP_VOID set_verify_callback(VerifyCallback callback, boost::system::error_code& ec) { core_.engine_.set_verify_callback( new detail::verify_callback<VerifyCallback>(callback), ec); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Perform SSL handshaking. /** * This function is used to perform SSL handshaking on the stream. The * function call will block until handshaking is complete or an error occurs. * * @param type The type of handshaking to be performed, i.e. as a client or as * a server. * * @throws boost::system::system_error Thrown on failure. */ void handshake(handshake_type type) { boost::system::error_code ec; handshake(type, ec); boost::asio::detail::throw_error(ec, "handshake"); } /// Perform SSL handshaking. /** * This function is used to perform SSL handshaking on the stream. The * function call will block until handshaking is complete or an error occurs. * * @param type The type of handshaking to be performed, i.e. as a client or as * a server. * * @param ec Set to indicate what error occurred, if any. */ BOOST_ASIO_SYNC_OP_VOID handshake(handshake_type type, boost::system::error_code& ec) { detail::io(next_layer_, core_, detail::handshake_op(type), ec); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Perform SSL handshaking. /** * This function is used to perform SSL handshaking on the stream. The * function call will block until handshaking is complete or an error occurs. * * @param type The type of handshaking to be performed, i.e. as a client or as * a server. * * @param buffers The buffered data to be reused for the handshake. * * @throws boost::system::system_error Thrown on failure. */ template <typename ConstBufferSequence> void handshake(handshake_type type, const ConstBufferSequence& buffers) { boost::system::error_code ec; handshake(type, buffers, ec); boost::asio::detail::throw_error(ec, "handshake"); } /// Perform SSL handshaking. /** * This function is used to perform SSL handshaking on the stream. The * function call will block until handshaking is complete or an error occurs. * * @param type The type of handshaking to be performed, i.e. as a client or as * a server. * * @param buffers The buffered data to be reused for the handshake. * * @param ec Set to indicate what error occurred, if any. */ template <typename ConstBufferSequence> BOOST_ASIO_SYNC_OP_VOID handshake(handshake_type type, const ConstBufferSequence& buffers, boost::system::error_code& ec) { detail::io(next_layer_, core_, detail::buffered_handshake_op<ConstBufferSequence>(type, buffers), ec); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Start an asynchronous SSL handshake. /** * This function is used to asynchronously perform an SSL handshake on the * stream. This function call always returns immediately. * * @param type The type of handshaking to be performed, i.e. as a client or as * a server. * * @param handler The handler to be called when the handshake operation * completes. Copies will be made of the handler as required. The equivalent * function signature of the handler must be: * @code void handler( * const boost::system::error_code& error // Result of operation. * ); @endcode */ template < BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) HandshakeHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(HandshakeHandler, void (boost::system::error_code)) async_handshake(handshake_type type, BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<HandshakeHandler, void (boost::system::error_code)>( initiate_async_handshake(this), handler, type); } /// Start an asynchronous SSL handshake. /** * This function is used to asynchronously perform an SSL handshake on the * stream. This function call always returns immediately. * * @param type The type of handshaking to be performed, i.e. as a client or as * a server. * * @param buffers The buffered data to be reused for the handshake. Although * the buffers object may be copied as necessary, ownership of the underlying * buffers 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 handshake operation * completes. Copies will be made of the handler as required. The equivalent * function signature of the handler must be: * @code void handler( * const boost::system::error_code& error, // Result of operation. * std::size_t bytes_transferred // Amount of buffers used in handshake. * ); @endcode */ template <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) BufferedHandshakeHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(BufferedHandshakeHandler, void (boost::system::error_code, std::size_t)) async_handshake(handshake_type type, const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(BufferedHandshakeHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<BufferedHandshakeHandler, void (boost::system::error_code, std::size_t)>( initiate_async_buffered_handshake(this), handler, type, buffers); } /// Shut down SSL on the stream. /** * This function is used to shut down SSL on the stream. The function call * will block until SSL has been shut down or an error occurs. * * @throws boost::system::system_error Thrown on failure. */ void shutdown() { boost::system::error_code ec; shutdown(ec); boost::asio::detail::throw_error(ec, "shutdown"); } /// Shut down SSL on the stream. /** * This function is used to shut down SSL on the stream. The function call * will block until SSL has been shut down or an error occurs. * * @param ec Set to indicate what error occurred, if any. */ BOOST_ASIO_SYNC_OP_VOID shutdown(boost::system::error_code& ec) { detail::io(next_layer_, core_, detail::shutdown_op(), ec); BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); } /// Asynchronously shut down SSL on the stream. /** * This function is used to asynchronously shut down SSL on the stream. This * function call always returns immediately. * * @param handler The handler to be called when the handshake operation * completes. Copies will be made of the handler as required. The equivalent * function signature of the handler must be: * @code void handler( * const boost::system::error_code& error // Result of operation. * ); @endcode */ template < BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) ShutdownHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ShutdownHandler, void (boost::system::error_code)) async_shutdown( BOOST_ASIO_MOVE_ARG(ShutdownHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<ShutdownHandler, void (boost::system::error_code)>( initiate_async_shutdown(this), handler); } /// Write some data to the stream. /** * This function is used to write data on the stream. The function call will * block until one or more bytes of data has been written successfully, or * until an error occurs. * * @param buffers The data to be written. * * @returns The number of bytes written. * * @throws boost::system::system_error Thrown on failure. * * @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 <typename ConstBufferSequence> std::size_t write_some(const ConstBufferSequence& buffers) { boost::system::error_code ec; std::size_t n = write_some(buffers, ec); boost::asio::detail::throw_error(ec, "write_some"); return n; } /// Write some data to the stream. /** * This function is used to write data on the stream. The function call will * block until one or more bytes of data has been written successfully, or * until an error occurs. * * @param buffers The data to be written to the stream. * * @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 <typename ConstBufferSequence> std::size_t write_some(const ConstBufferSequence& buffers, boost::system::error_code& ec) { return detail::io(next_layer_, core_, detail::write_op<ConstBufferSequence>(buffers), ec); } /// Start an asynchronous write. /** * This function is used to asynchronously write one or more bytes of data to * the stream. The function call always returns immediately. * * @param buffers The data to be written to the stream. Although the buffers * object may be copied as necessary, ownership of the underlying buffers 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 equivalent 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 * * @note The async_write_some 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. */ template <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_some(const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( initiate_async_write_some(this), handler, buffers); } /// Read some data from the stream. /** * This function is used to read data from the stream. The function call will * block until one or more bytes of data has been read successfully, or until * an error occurs. * * @param buffers The buffers into which the data will be read. * * @returns The number of bytes read. * * @throws boost::system::system_error Thrown on failure. * * @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 <typename MutableBufferSequence> std::size_t read_some(const MutableBufferSequence& buffers) { boost::system::error_code ec; std::size_t n = read_some(buffers, ec); boost::asio::detail::throw_error(ec, "read_some"); return n; } /// Read some data from the stream. /** * This function is used to read data from the stream. The function call will * block until one or more bytes of data has been read successfully, or until * an error occurs. * * @param buffers The 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 <typename MutableBufferSequence> std::size_t read_some(const MutableBufferSequence& buffers, boost::system::error_code& ec) { return detail::io(next_layer_, core_, detail::read_op<MutableBufferSequence>(buffers), ec); } /// Start an asynchronous read. /** * This function is used to asynchronously read one or more bytes of data from * the stream. The function call always returns immediately. * * @param buffers The buffers into which the data will be read. Although the * buffers object may be copied as necessary, ownership of the underlying * buffers 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 equivalent 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 * * @note The async_read_some 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. */ template <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_some(const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( initiate_async_read_some(this), handler, buffers); } private: class initiate_async_handshake { public: typedef typename stream::executor_type executor_type; explicit initiate_async_handshake(stream* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename HandshakeHandler> void operator()(BOOST_ASIO_MOVE_ARG(HandshakeHandler) handler, handshake_type type) const { // If you get an error on the following line it means that your handler // does not meet the documented type requirements for a HandshakeHandler. BOOST_ASIO_HANDSHAKE_HANDLER_CHECK(HandshakeHandler, handler) type_check; boost::asio::detail::non_const_lvalue<HandshakeHandler> handler2(handler); detail::async_io(self_->next_layer_, self_->core_, detail::handshake_op(type), handler2.value); } private: stream* self_; }; class initiate_async_buffered_handshake { public: typedef typename stream::executor_type executor_type; explicit initiate_async_buffered_handshake(stream* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename BufferedHandshakeHandler, typename ConstBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(BufferedHandshakeHandler) handler, handshake_type type, 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 // BufferedHandshakeHandler. BOOST_ASIO_BUFFERED_HANDSHAKE_HANDLER_CHECK( BufferedHandshakeHandler, handler) type_check; boost::asio::detail::non_const_lvalue< BufferedHandshakeHandler> handler2(handler); detail::async_io(self_->next_layer_, self_->core_, detail::buffered_handshake_op<ConstBufferSequence>(type, buffers), handler2.value); } private: stream* self_; }; class initiate_async_shutdown { public: typedef typename stream::executor_type executor_type; explicit initiate_async_shutdown(stream* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename ShutdownHandler> void operator()(BOOST_ASIO_MOVE_ARG(ShutdownHandler) handler) const { // If you get an error on the following line it means that your handler // does not meet the documented type requirements for a ShutdownHandler. BOOST_ASIO_HANDSHAKE_HANDLER_CHECK(ShutdownHandler, handler) type_check; boost::asio::detail::non_const_lvalue<ShutdownHandler> handler2(handler); detail::async_io(self_->next_layer_, self_->core_, detail::shutdown_op(), handler2.value); } private: stream* self_; }; class initiate_async_write_some { public: typedef typename stream::executor_type executor_type; explicit initiate_async_write_some(stream* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename WriteHandler, typename ConstBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, 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; boost::asio::detail::non_const_lvalue<WriteHandler> handler2(handler); detail::async_io(self_->next_layer_, self_->core_, detail::write_op<ConstBufferSequence>(buffers), handler2.value); } private: stream* self_; }; class initiate_async_read_some { public: typedef typename stream::executor_type executor_type; explicit initiate_async_read_some(stream* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename ReadHandler, typename MutableBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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; boost::asio::detail::non_const_lvalue<ReadHandler> handler2(handler); detail::async_io(self_->next_layer_, self_->core_, detail::read_op<MutableBufferSequence>(buffers), handler2.value); } private: stream* self_; }; Stream next_layer_; detail::stream_core core_; }; } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_STREAM_HPP ssl/error.hpp 0000644 00000006066 15125530236 0007221 0 ustar 00 // // ssl/error.hpp // ~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_ERROR_HPP #define BOOST_ASIO_SSL_ERROR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/system/error_code.hpp> #include <boost/asio/ssl/detail/openssl_types.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace error { enum ssl_errors { // Error numbers are those produced by openssl. }; extern BOOST_ASIO_DECL const boost::system::error_category& get_ssl_category(); static const boost::system::error_category& ssl_category BOOST_ASIO_UNUSED_VARIABLE = boost::asio::error::get_ssl_category(); } // namespace error namespace ssl { namespace error { enum stream_errors { #if defined(GENERATING_DOCUMENTATION) /// The underlying stream closed before the ssl stream gracefully shut down. stream_truncated, /// The underlying SSL library returned a system error without providing /// further information. unspecified_system_error, /// The underlying SSL library generated an unexpected result from a function /// call. unexpected_result #else // defined(GENERATING_DOCUMENTATION) # if (OPENSSL_VERSION_NUMBER < 0x10100000L) \ && !defined(OPENSSL_IS_BORINGSSL) \ && !defined(BOOST_ASIO_USE_WOLFSSL) stream_truncated = ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHORT_READ), # else stream_truncated = 1, # endif unspecified_system_error = 2, unexpected_result = 3 #endif // defined(GENERATING_DOCUMENTATION) }; extern BOOST_ASIO_DECL const boost::system::error_category& get_stream_category(); static const boost::system::error_category& stream_category BOOST_ASIO_UNUSED_VARIABLE = boost::asio::ssl::error::get_stream_category(); } // namespace error } // namespace ssl } // namespace asio } // namespace boost namespace boost { namespace system { template<> struct is_error_code_enum<boost::asio::error::ssl_errors> { static const bool value = true; }; template<> struct is_error_code_enum<boost::asio::ssl::error::stream_errors> { static const bool value = true; }; } // namespace system } // namespace boost namespace boost { namespace asio { namespace error { inline boost::system::error_code make_error_code(ssl_errors e) { return boost::system::error_code( static_cast<int>(e), get_ssl_category()); } } // namespace error namespace ssl { namespace error { inline boost::system::error_code make_error_code(stream_errors e) { return boost::system::error_code( static_cast<int>(e), get_stream_category()); } } // namespace error } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/ssl/impl/error.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_SSL_ERROR_HPP ssl/verify_context.hpp 0000644 00000003321 15125530236 0011127 0 ustar 00 // // ssl/verify_context.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_VERIFY_CONTEXT_HPP #define BOOST_ASIO_SSL_VERIFY_CONTEXT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/ssl/detail/openssl_types.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { /// A simple wrapper around the X509_STORE_CTX type, used during verification of /// a peer certificate. /** * @note The verify_context does not own the underlying X509_STORE_CTX object. */ class verify_context : private noncopyable { public: /// The native handle type of the verification context. typedef X509_STORE_CTX* native_handle_type; /// Constructor. explicit verify_context(native_handle_type handle) : handle_(handle) { } /// Get the underlying implementation in the native type. /** * This function may be used to obtain the underlying implementation of the * context. This is intended to allow access to context functionality that is * not otherwise provided. */ native_handle_type native_handle() { return handle_; } private: // The underlying native implementation. native_handle_type handle_; }; } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_VERIFY_CONTEXT_HPP ssl/context.hpp 0000644 00000064175 15125530236 0007561 0 ustar 00 // // ssl/context.hpp // ~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_CONTEXT_HPP #define BOOST_ASIO_SSL_CONTEXT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <string> #include <boost/asio/buffer.hpp> #include <boost/asio/io_context.hpp> #include <boost/asio/ssl/context_base.hpp> #include <boost/asio/ssl/detail/openssl_types.hpp> #include <boost/asio/ssl/detail/openssl_init.hpp> #include <boost/asio/ssl/detail/password_callback.hpp> #include <boost/asio/ssl/detail/verify_callback.hpp> #include <boost/asio/ssl/verify_mode.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { class context : public context_base, private noncopyable { public: /// The native handle type of the SSL context. typedef SSL_CTX* native_handle_type; /// Constructor. BOOST_ASIO_DECL explicit context(method m); /// Construct to take ownership of a native handle. BOOST_ASIO_DECL explicit context(native_handle_type native_handle); #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move-construct a context from another. /** * This constructor moves an SSL context from one object to another. * * @param other The other context object from which the move will occur. * * @note Following the move, the following operations only are valid for the * moved-from object: * @li Destruction. * @li As a target for move-assignment. */ BOOST_ASIO_DECL context(context&& other); /// Move-assign a context from another. /** * This assignment operator moves an SSL context from one object to another. * * @param other The other context object from which the move will occur. * * @note Following the move, the following operations only are valid for the * moved-from object: * @li Destruction. * @li As a target for move-assignment. */ BOOST_ASIO_DECL context& operator=(context&& other); #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Destructor. BOOST_ASIO_DECL ~context(); /// Get the underlying implementation in the native type. /** * This function may be used to obtain the underlying implementation of the * context. This is intended to allow access to context functionality that is * not otherwise provided. */ BOOST_ASIO_DECL native_handle_type native_handle(); /// Clear options on the context. /** * This function may be used to configure the SSL options used by the context. * * @param o A bitmask of options. The available option values are defined in * the context_base class. The specified options, if currently enabled on the * context, are cleared. * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_clear_options. */ BOOST_ASIO_DECL void clear_options(options o); /// Clear options on the context. /** * This function may be used to configure the SSL options used by the context. * * @param o A bitmask of options. The available option values are defined in * the context_base class. The specified options, if currently enabled on the * context, are cleared. * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_clear_options. */ BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID clear_options(options o, boost::system::error_code& ec); /// Set options on the context. /** * This function may be used to configure the SSL options used by the context. * * @param o A bitmask of options. The available option values are defined in * the context_base class. The options are bitwise-ored with any existing * value for the options. * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_set_options. */ BOOST_ASIO_DECL void set_options(options o); /// Set options on the context. /** * This function may be used to configure the SSL options used by the context. * * @param o A bitmask of options. The available option values are defined in * the context_base class. The options are bitwise-ored with any existing * value for the options. * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_set_options. */ BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID set_options(options o, boost::system::error_code& ec); /// Set the peer verification mode. /** * This function may be used to configure the peer verification mode used by * the context. * * @param v A bitmask of peer verification modes. See @ref verify_mode for * available values. * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_set_verify. */ BOOST_ASIO_DECL void set_verify_mode(verify_mode v); /// Set the peer verification mode. /** * This function may be used to configure the peer verification mode used by * the context. * * @param v A bitmask of peer verification modes. See @ref verify_mode for * available values. * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_set_verify. */ BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID set_verify_mode( verify_mode v, boost::system::error_code& ec); /// Set the peer verification depth. /** * This function may be used to configure the maximum verification depth * allowed by the context. * * @param depth Maximum depth for the certificate chain verification that * shall be allowed. * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_set_verify_depth. */ BOOST_ASIO_DECL void set_verify_depth(int depth); /// Set the peer verification depth. /** * This function may be used to configure the maximum verification depth * allowed by the context. * * @param depth Maximum depth for the certificate chain verification that * shall be allowed. * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_set_verify_depth. */ BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID set_verify_depth( int depth, boost::system::error_code& ec); /// Set the callback used to verify peer certificates. /** * This function is used to specify a callback function that will be called * by the implementation when it needs to verify a peer certificate. * * @param callback The function object to be used for verifying a certificate. * The function signature of the handler must be: * @code bool verify_callback( * bool preverified, // True if the certificate passed pre-verification. * verify_context& ctx // The peer certificate and other context. * ); @endcode * The return value of the callback is true if the certificate has passed * verification, false otherwise. * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_set_verify. */ template <typename VerifyCallback> void set_verify_callback(VerifyCallback callback); /// Set the callback used to verify peer certificates. /** * This function is used to specify a callback function that will be called * by the implementation when it needs to verify a peer certificate. * * @param callback The function object to be used for verifying a certificate. * The function signature of the handler must be: * @code bool verify_callback( * bool preverified, // True if the certificate passed pre-verification. * verify_context& ctx // The peer certificate and other context. * ); @endcode * The return value of the callback is true if the certificate has passed * verification, false otherwise. * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_set_verify. */ template <typename VerifyCallback> BOOST_ASIO_SYNC_OP_VOID set_verify_callback(VerifyCallback callback, boost::system::error_code& ec); /// Load a certification authority file for performing verification. /** * This function is used to load one or more trusted certification authorities * from a file. * * @param filename The name of a file containing certification authority * certificates in PEM format. * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_load_verify_locations. */ BOOST_ASIO_DECL void load_verify_file(const std::string& filename); /// Load a certification authority file for performing verification. /** * This function is used to load the certificates for one or more trusted * certification authorities from a file. * * @param filename The name of a file containing certification authority * certificates in PEM format. * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_load_verify_locations. */ BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID load_verify_file( const std::string& filename, boost::system::error_code& ec); /// Add certification authority for performing verification. /** * This function is used to add one trusted certification authority * from a memory buffer. * * @param ca The buffer containing the certification authority certificate. * The certificate must use the PEM format. * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_get_cert_store and @c X509_STORE_add_cert. */ BOOST_ASIO_DECL void add_certificate_authority(const const_buffer& ca); /// Add certification authority for performing verification. /** * This function is used to add one trusted certification authority * from a memory buffer. * * @param ca The buffer containing the certification authority certificate. * The certificate must use the PEM format. * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_get_cert_store and @c X509_STORE_add_cert. */ BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID add_certificate_authority( const const_buffer& ca, boost::system::error_code& ec); /// Configures the context to use the default directories for finding /// certification authority certificates. /** * This function specifies that the context should use the default, * system-dependent directories for locating certification authority * certificates. * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_set_default_verify_paths. */ BOOST_ASIO_DECL void set_default_verify_paths(); /// Configures the context to use the default directories for finding /// certification authority certificates. /** * This function specifies that the context should use the default, * system-dependent directories for locating certification authority * certificates. * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_set_default_verify_paths. */ BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID set_default_verify_paths( boost::system::error_code& ec); /// Add a directory containing certificate authority files to be used for /// performing verification. /** * This function is used to specify the name of a directory containing * certification authority certificates. Each file in the directory must * contain a single certificate. The files must be named using the subject * name's hash and an extension of ".0". * * @param path The name of a directory containing the certificates. * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_load_verify_locations. */ BOOST_ASIO_DECL void add_verify_path(const std::string& path); /// Add a directory containing certificate authority files to be used for /// performing verification. /** * This function is used to specify the name of a directory containing * certification authority certificates. Each file in the directory must * contain a single certificate. The files must be named using the subject * name's hash and an extension of ".0". * * @param path The name of a directory containing the certificates. * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_load_verify_locations. */ BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID add_verify_path( const std::string& path, boost::system::error_code& ec); /// Use a certificate from a memory buffer. /** * This function is used to load a certificate into the context from a buffer. * * @param certificate The buffer containing the certificate. * * @param format The certificate format (ASN.1 or PEM). * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_use_certificate or SSL_CTX_use_certificate_ASN1. */ BOOST_ASIO_DECL void use_certificate( const const_buffer& certificate, file_format format); /// Use a certificate from a memory buffer. /** * This function is used to load a certificate into the context from a buffer. * * @param certificate The buffer containing the certificate. * * @param format The certificate format (ASN.1 or PEM). * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_use_certificate or SSL_CTX_use_certificate_ASN1. */ BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_certificate( const const_buffer& certificate, file_format format, boost::system::error_code& ec); /// Use a certificate from a file. /** * This function is used to load a certificate into the context from a file. * * @param filename The name of the file containing the certificate. * * @param format The file format (ASN.1 or PEM). * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_use_certificate_file. */ BOOST_ASIO_DECL void use_certificate_file( const std::string& filename, file_format format); /// Use a certificate from a file. /** * This function is used to load a certificate into the context from a file. * * @param filename The name of the file containing the certificate. * * @param format The file format (ASN.1 or PEM). * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_use_certificate_file. */ BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_certificate_file( const std::string& filename, file_format format, boost::system::error_code& ec); /// Use a certificate chain from a memory buffer. /** * This function is used to load a certificate chain into the context from a * buffer. * * @param chain The buffer containing the certificate chain. The certificate * chain must use the PEM format. * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_use_certificate and SSL_CTX_add_extra_chain_cert. */ BOOST_ASIO_DECL void use_certificate_chain(const const_buffer& chain); /// Use a certificate chain from a memory buffer. /** * This function is used to load a certificate chain into the context from a * buffer. * * @param chain The buffer containing the certificate chain. The certificate * chain must use the PEM format. * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_use_certificate and SSL_CTX_add_extra_chain_cert. */ BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_certificate_chain( const const_buffer& chain, boost::system::error_code& ec); /// Use a certificate chain from a file. /** * This function is used to load a certificate chain into the context from a * file. * * @param filename The name of the file containing the certificate. The file * must use the PEM format. * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_use_certificate_chain_file. */ BOOST_ASIO_DECL void use_certificate_chain_file(const std::string& filename); /// Use a certificate chain from a file. /** * This function is used to load a certificate chain into the context from a * file. * * @param filename The name of the file containing the certificate. The file * must use the PEM format. * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_use_certificate_chain_file. */ BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_certificate_chain_file( const std::string& filename, boost::system::error_code& ec); /// Use a private key from a memory buffer. /** * This function is used to load a private key into the context from a buffer. * * @param private_key The buffer containing the private key. * * @param format The private key format (ASN.1 or PEM). * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_use_PrivateKey or SSL_CTX_use_PrivateKey_ASN1. */ BOOST_ASIO_DECL void use_private_key( const const_buffer& private_key, file_format format); /// Use a private key from a memory buffer. /** * This function is used to load a private key into the context from a buffer. * * @param private_key The buffer containing the private key. * * @param format The private key format (ASN.1 or PEM). * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_use_PrivateKey or SSL_CTX_use_PrivateKey_ASN1. */ BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_private_key( const const_buffer& private_key, file_format format, boost::system::error_code& ec); /// Use a private key from a file. /** * This function is used to load a private key into the context from a file. * * @param filename The name of the file containing the private key. * * @param format The file format (ASN.1 or PEM). * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_use_PrivateKey_file. */ BOOST_ASIO_DECL void use_private_key_file( const std::string& filename, file_format format); /// Use a private key from a file. /** * This function is used to load a private key into the context from a file. * * @param filename The name of the file containing the private key. * * @param format The file format (ASN.1 or PEM). * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_use_PrivateKey_file. */ BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_private_key_file( const std::string& filename, file_format format, boost::system::error_code& ec); /// Use an RSA private key from a memory buffer. /** * This function is used to load an RSA private key into the context from a * buffer. * * @param private_key The buffer containing the RSA private key. * * @param format The private key format (ASN.1 or PEM). * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_use_RSAPrivateKey or SSL_CTX_use_RSAPrivateKey_ASN1. */ BOOST_ASIO_DECL void use_rsa_private_key( const const_buffer& private_key, file_format format); /// Use an RSA private key from a memory buffer. /** * This function is used to load an RSA private key into the context from a * buffer. * * @param private_key The buffer containing the RSA private key. * * @param format The private key format (ASN.1 or PEM). * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_use_RSAPrivateKey or SSL_CTX_use_RSAPrivateKey_ASN1. */ BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_rsa_private_key( const const_buffer& private_key, file_format format, boost::system::error_code& ec); /// Use an RSA private key from a file. /** * This function is used to load an RSA private key into the context from a * file. * * @param filename The name of the file containing the RSA private key. * * @param format The file format (ASN.1 or PEM). * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_use_RSAPrivateKey_file. */ BOOST_ASIO_DECL void use_rsa_private_key_file( const std::string& filename, file_format format); /// Use an RSA private key from a file. /** * This function is used to load an RSA private key into the context from a * file. * * @param filename The name of the file containing the RSA private key. * * @param format The file format (ASN.1 or PEM). * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_use_RSAPrivateKey_file. */ BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_rsa_private_key_file( const std::string& filename, file_format format, boost::system::error_code& ec); /// Use the specified memory buffer to obtain the temporary Diffie-Hellman /// parameters. /** * This function is used to load Diffie-Hellman parameters into the context * from a buffer. * * @param dh The memory buffer containing the Diffie-Hellman parameters. The * buffer must use the PEM format. * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_set_tmp_dh. */ BOOST_ASIO_DECL void use_tmp_dh(const const_buffer& dh); /// Use the specified memory buffer to obtain the temporary Diffie-Hellman /// parameters. /** * This function is used to load Diffie-Hellman parameters into the context * from a buffer. * * @param dh The memory buffer containing the Diffie-Hellman parameters. The * buffer must use the PEM format. * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_set_tmp_dh. */ BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_tmp_dh( const const_buffer& dh, boost::system::error_code& ec); /// Use the specified file to obtain the temporary Diffie-Hellman parameters. /** * This function is used to load Diffie-Hellman parameters into the context * from a file. * * @param filename The name of the file containing the Diffie-Hellman * parameters. The file must use the PEM format. * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_set_tmp_dh. */ BOOST_ASIO_DECL void use_tmp_dh_file(const std::string& filename); /// Use the specified file to obtain the temporary Diffie-Hellman parameters. /** * This function is used to load Diffie-Hellman parameters into the context * from a file. * * @param filename The name of the file containing the Diffie-Hellman * parameters. The file must use the PEM format. * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_set_tmp_dh. */ BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID use_tmp_dh_file( const std::string& filename, boost::system::error_code& ec); /// Set the password callback. /** * This function is used to specify a callback function to obtain password * information about an encrypted key in PEM format. * * @param callback The function object to be used for obtaining the password. * The function signature of the handler must be: * @code std::string password_callback( * std::size_t max_length, // The maximum size for a password. * password_purpose purpose // Whether password is for reading or writing. * ); @endcode * The return value of the callback is a string containing the password. * * @throws boost::system::system_error Thrown on failure. * * @note Calls @c SSL_CTX_set_default_passwd_cb. */ template <typename PasswordCallback> void set_password_callback(PasswordCallback callback); /// Set the password callback. /** * This function is used to specify a callback function to obtain password * information about an encrypted key in PEM format. * * @param callback The function object to be used for obtaining the password. * The function signature of the handler must be: * @code std::string password_callback( * std::size_t max_length, // The maximum size for a password. * password_purpose purpose // Whether password is for reading or writing. * ); @endcode * The return value of the callback is a string containing the password. * * @param ec Set to indicate what error occurred, if any. * * @note Calls @c SSL_CTX_set_default_passwd_cb. */ template <typename PasswordCallback> BOOST_ASIO_SYNC_OP_VOID set_password_callback(PasswordCallback callback, boost::system::error_code& ec); private: struct bio_cleanup; struct x509_cleanup; struct evp_pkey_cleanup; struct rsa_cleanup; struct dh_cleanup; // Helper function used to set a peer certificate verification callback. BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID do_set_verify_callback( detail::verify_callback_base* callback, boost::system::error_code& ec); // Callback used when the SSL implementation wants to verify a certificate. BOOST_ASIO_DECL static int verify_callback_function( int preverified, X509_STORE_CTX* ctx); // Helper function used to set a password callback. BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID do_set_password_callback( detail::password_callback_base* callback, boost::system::error_code& ec); // Callback used when the SSL implementation wants a password. BOOST_ASIO_DECL static int password_callback_function( char* buf, int size, int purpose, void* data); // Helper function to set the temporary Diffie-Hellman parameters from a BIO. BOOST_ASIO_DECL BOOST_ASIO_SYNC_OP_VOID do_use_tmp_dh( BIO* bio, boost::system::error_code& ec); // Helper function to make a BIO from a memory buffer. BOOST_ASIO_DECL BIO* make_buffer_bio(const const_buffer& b); // The underlying native implementation. native_handle_type handle_; // Ensure openssl is initialised. boost::asio::ssl::detail::openssl_init<> init_; }; } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/ssl/impl/context.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/ssl/impl/context.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_SSL_CONTEXT_HPP ssl/detail/stream_core.hpp 0000644 00000012505 15125530236 0011630 0 ustar 00 // // ssl/detail/stream_core.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_DETAIL_STREAM_CORE_HPP #define BOOST_ASIO_SSL_DETAIL_STREAM_CORE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) # include <boost/asio/deadline_timer.hpp> #else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) # include <boost/asio/steady_timer.hpp> #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) #include <boost/asio/ssl/detail/engine.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { namespace detail { struct stream_core { // According to the OpenSSL documentation, this is the buffer size that is // sufficient to hold the largest possible TLS record. enum { max_tls_record_size = 17 * 1024 }; template <typename Executor> stream_core(SSL_CTX* context, const Executor& ex) : engine_(context), pending_read_(ex), pending_write_(ex), output_buffer_space_(max_tls_record_size), output_buffer_(boost::asio::buffer(output_buffer_space_)), input_buffer_space_(max_tls_record_size), input_buffer_(boost::asio::buffer(input_buffer_space_)) { pending_read_.expires_at(neg_infin()); pending_write_.expires_at(neg_infin()); } #if defined(BOOST_ASIO_HAS_MOVE) stream_core(stream_core&& other) : engine_(BOOST_ASIO_MOVE_CAST(engine)(other.engine_)), #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) pending_read_( BOOST_ASIO_MOVE_CAST(boost::asio::deadline_timer)( other.pending_read_)), pending_write_( BOOST_ASIO_MOVE_CAST(boost::asio::deadline_timer)( other.pending_write_)), #else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) pending_read_( BOOST_ASIO_MOVE_CAST(boost::asio::steady_timer)( other.pending_read_)), pending_write_( BOOST_ASIO_MOVE_CAST(boost::asio::steady_timer)( other.pending_write_)), #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) output_buffer_space_( BOOST_ASIO_MOVE_CAST(std::vector<unsigned char>)( other.output_buffer_space_)), output_buffer_(other.output_buffer_), input_buffer_space_( BOOST_ASIO_MOVE_CAST(std::vector<unsigned char>)( other.input_buffer_space_)), input_buffer_(other.input_buffer_), input_(other.input_) { other.output_buffer_ = boost::asio::mutable_buffer(0, 0); other.input_buffer_ = boost::asio::mutable_buffer(0, 0); other.input_ = boost::asio::const_buffer(0, 0); } #endif // defined(BOOST_ASIO_HAS_MOVE) ~stream_core() { } // The SSL engine. engine engine_; #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) // Timer used for storing queued read operations. boost::asio::deadline_timer pending_read_; // Timer used for storing queued write operations. boost::asio::deadline_timer pending_write_; // Helper function for obtaining a time value that always fires. static boost::asio::deadline_timer::time_type neg_infin() { return boost::posix_time::neg_infin; } // Helper function for obtaining a time value that never fires. static boost::asio::deadline_timer::time_type pos_infin() { return boost::posix_time::pos_infin; } // Helper function to get a timer's expiry time. static boost::asio::deadline_timer::time_type expiry( const boost::asio::deadline_timer& timer) { return timer.expires_at(); } #else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) // Timer used for storing queued read operations. boost::asio::steady_timer pending_read_; // Timer used for storing queued write operations. boost::asio::steady_timer pending_write_; // Helper function for obtaining a time value that always fires. static boost::asio::steady_timer::time_point neg_infin() { return (boost::asio::steady_timer::time_point::min)(); } // Helper function for obtaining a time value that never fires. static boost::asio::steady_timer::time_point pos_infin() { return (boost::asio::steady_timer::time_point::max)(); } // Helper function to get a timer's expiry time. static boost::asio::steady_timer::time_point expiry( const boost::asio::steady_timer& timer) { return timer.expiry(); } #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) // Buffer space used to prepare output intended for the transport. std::vector<unsigned char> output_buffer_space_; // A buffer that may be used to prepare output intended for the transport. boost::asio::mutable_buffer output_buffer_; // Buffer space used to read input intended for the engine. std::vector<unsigned char> input_buffer_space_; // A buffer that may be used to read input intended for the engine. boost::asio::mutable_buffer input_buffer_; // The buffer pointing to the engine's unconsumed input. boost::asio::const_buffer input_; }; } // namespace detail } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_DETAIL_STREAM_CORE_HPP ssl/detail/openssl_types.hpp 0000644 00000002016 15125530236 0012230 0 ustar 00 // // ssl/detail/openssl_types.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP #define BOOST_ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/socket_types.hpp> #if defined(BOOST_ASIO_USE_WOLFSSL) # include <wolfssl/options.h> #endif // defined(BOOST_ASIO_USE_WOLFSSL) #include <openssl/conf.h> #include <openssl/ssl.h> #if !defined(OPENSSL_NO_ENGINE) # include <openssl/engine.h> #endif // !defined(OPENSSL_NO_ENGINE) #include <openssl/dh.h> #include <openssl/err.h> #include <openssl/rsa.h> #include <openssl/x509.h> #include <openssl/x509v3.h> #endif // BOOST_ASIO_SSL_DETAIL_OPENSSL_TYPES_HPP ssl/detail/engine.hpp 0000644 00000013614 15125530236 0010574 0 ustar 00 // // ssl/detail/engine.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_DETAIL_ENGINE_HPP #define BOOST_ASIO_SSL_DETAIL_ENGINE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/detail/static_mutex.hpp> #include <boost/asio/ssl/detail/openssl_types.hpp> #include <boost/asio/ssl/detail/verify_callback.hpp> #include <boost/asio/ssl/stream_base.hpp> #include <boost/asio/ssl/verify_mode.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { namespace detail { class engine { public: enum want { // Returned by functions to indicate that the engine wants input. The input // buffer should be updated to point to the data. The engine then needs to // be called again to retry the operation. want_input_and_retry = -2, // Returned by functions to indicate that the engine wants to write output. // The output buffer points to the data to be written. The engine then // needs to be called again to retry the operation. want_output_and_retry = -1, // Returned by functions to indicate that the engine doesn't need input or // output. want_nothing = 0, // Returned by functions to indicate that the engine wants to write output. // The output buffer points to the data to be written. After that the // operation is complete, and the engine does not need to be called again. want_output = 1 }; // Construct a new engine for the specified context. BOOST_ASIO_DECL explicit engine(SSL_CTX* context); #if defined(BOOST_ASIO_HAS_MOVE) // Move construct from another engine. BOOST_ASIO_DECL engine(engine&& other) BOOST_ASIO_NOEXCEPT; #endif // defined(BOOST_ASIO_HAS_MOVE) // Destructor. BOOST_ASIO_DECL ~engine(); // Get the underlying implementation in the native type. BOOST_ASIO_DECL SSL* native_handle(); // Set the peer verification mode. BOOST_ASIO_DECL boost::system::error_code set_verify_mode( verify_mode v, boost::system::error_code& ec); // Set the peer verification depth. BOOST_ASIO_DECL boost::system::error_code set_verify_depth( int depth, boost::system::error_code& ec); // Set a peer certificate verification callback. BOOST_ASIO_DECL boost::system::error_code set_verify_callback( verify_callback_base* callback, boost::system::error_code& ec); // Perform an SSL handshake using either SSL_connect (client-side) or // SSL_accept (server-side). BOOST_ASIO_DECL want handshake( stream_base::handshake_type type, boost::system::error_code& ec); // Perform a graceful shutdown of the SSL session. BOOST_ASIO_DECL want shutdown(boost::system::error_code& ec); // Write bytes to the SSL session. BOOST_ASIO_DECL want write(const boost::asio::const_buffer& data, boost::system::error_code& ec, std::size_t& bytes_transferred); // Read bytes from the SSL session. BOOST_ASIO_DECL want read(const boost::asio::mutable_buffer& data, boost::system::error_code& ec, std::size_t& bytes_transferred); // Get output data to be written to the transport. BOOST_ASIO_DECL boost::asio::mutable_buffer get_output( const boost::asio::mutable_buffer& data); // Put input data that was read from the transport. BOOST_ASIO_DECL boost::asio::const_buffer put_input( const boost::asio::const_buffer& data); // Map an error::eof code returned by the underlying transport according to // the type and state of the SSL session. Returns a const reference to the // error code object, suitable for passing to a completion handler. BOOST_ASIO_DECL const boost::system::error_code& map_error_code( boost::system::error_code& ec) const; private: // Disallow copying and assignment. engine(const engine&); engine& operator=(const engine&); // Callback used when the SSL implementation wants to verify a certificate. BOOST_ASIO_DECL static int verify_callback_function( int preverified, X509_STORE_CTX* ctx); #if (OPENSSL_VERSION_NUMBER < 0x10000000L) // The SSL_accept function may not be thread safe. This mutex is used to // protect all calls to the SSL_accept function. BOOST_ASIO_DECL static boost::asio::detail::static_mutex& accept_mutex(); #endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) // Perform one operation. Returns >= 0 on success or error, want_read if the // operation needs more input, or want_write if it needs to write some output // before the operation can complete. BOOST_ASIO_DECL want perform(int (engine::* op)(void*, std::size_t), void* data, std::size_t length, boost::system::error_code& ec, std::size_t* bytes_transferred); // Adapt the SSL_accept function to the signature needed for perform(). BOOST_ASIO_DECL int do_accept(void*, std::size_t); // Adapt the SSL_connect function to the signature needed for perform(). BOOST_ASIO_DECL int do_connect(void*, std::size_t); // Adapt the SSL_shutdown function to the signature needed for perform(). BOOST_ASIO_DECL int do_shutdown(void*, std::size_t); // Adapt the SSL_read function to the signature needed for perform(). BOOST_ASIO_DECL int do_read(void* data, std::size_t length); // Adapt the SSL_write function to the signature needed for perform(). BOOST_ASIO_DECL int do_write(void* data, std::size_t length); SSL* ssl_; BIO* ext_bio_; }; } // namespace detail } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/ssl/detail/impl/engine.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_SSL_DETAIL_ENGINE_HPP ssl/detail/handshake_op.hpp 0000644 00000002762 15125530236 0011755 0 ustar 00 // // ssl/detail/handshake_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_DETAIL_HANDSHAKE_OP_HPP #define BOOST_ASIO_SSL_DETAIL_HANDSHAKE_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/ssl/detail/engine.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { namespace detail { class handshake_op { public: static BOOST_ASIO_CONSTEXPR const char* tracking_name() { return "ssl::stream<>::async_handshake"; } handshake_op(stream_base::handshake_type type) : type_(type) { } engine::want operator()(engine& eng, boost::system::error_code& ec, std::size_t& bytes_transferred) const { bytes_transferred = 0; return eng.handshake(type_, ec); } template <typename Handler> void call_handler(Handler& handler, const boost::system::error_code& ec, const std::size_t&) const { handler(ec); } private: stream_base::handshake_type type_; }; } // namespace detail } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_DETAIL_HANDSHAKE_OP_HPP ssl/detail/impl/engine.ipp 0000644 00000021517 15125530236 0011537 0 ustar 00 // // ssl/detail/impl/engine.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_DETAIL_IMPL_ENGINE_IPP #define BOOST_ASIO_SSL_DETAIL_IMPL_ENGINE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/ssl/detail/engine.hpp> #include <boost/asio/ssl/error.hpp> #include <boost/asio/ssl/verify_context.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { namespace detail { engine::engine(SSL_CTX* context) : ssl_(::SSL_new(context)) { if (!ssl_) { boost::system::error_code ec( static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category()); boost::asio::detail::throw_error(ec, "engine"); } #if (OPENSSL_VERSION_NUMBER < 0x10000000L) accept_mutex().init(); #endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) ::SSL_set_mode(ssl_, SSL_MODE_ENABLE_PARTIAL_WRITE); ::SSL_set_mode(ssl_, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); #if defined(SSL_MODE_RELEASE_BUFFERS) ::SSL_set_mode(ssl_, SSL_MODE_RELEASE_BUFFERS); #endif // defined(SSL_MODE_RELEASE_BUFFERS) ::BIO* int_bio = 0; ::BIO_new_bio_pair(&int_bio, 0, &ext_bio_, 0); ::SSL_set_bio(ssl_, int_bio, int_bio); } #if defined(BOOST_ASIO_HAS_MOVE) engine::engine(engine&& other) BOOST_ASIO_NOEXCEPT : ssl_(other.ssl_), ext_bio_(other.ext_bio_) { other.ssl_ = 0; other.ext_bio_ = 0; } #endif // defined(BOOST_ASIO_HAS_MOVE) engine::~engine() { if (ssl_ && SSL_get_app_data(ssl_)) { delete static_cast<verify_callback_base*>(SSL_get_app_data(ssl_)); SSL_set_app_data(ssl_, 0); } if (ext_bio_) ::BIO_free(ext_bio_); if (ssl_) ::SSL_free(ssl_); } SSL* engine::native_handle() { return ssl_; } boost::system::error_code engine::set_verify_mode( verify_mode v, boost::system::error_code& ec) { ::SSL_set_verify(ssl_, v, ::SSL_get_verify_callback(ssl_)); ec = boost::system::error_code(); return ec; } boost::system::error_code engine::set_verify_depth( int depth, boost::system::error_code& ec) { ::SSL_set_verify_depth(ssl_, depth); ec = boost::system::error_code(); return ec; } boost::system::error_code engine::set_verify_callback( verify_callback_base* callback, boost::system::error_code& ec) { if (SSL_get_app_data(ssl_)) delete static_cast<verify_callback_base*>(SSL_get_app_data(ssl_)); SSL_set_app_data(ssl_, callback); ::SSL_set_verify(ssl_, ::SSL_get_verify_mode(ssl_), &engine::verify_callback_function); ec = boost::system::error_code(); return ec; } int engine::verify_callback_function(int preverified, X509_STORE_CTX* ctx) { if (ctx) { if (SSL* ssl = static_cast<SSL*>( ::X509_STORE_CTX_get_ex_data( ctx, ::SSL_get_ex_data_X509_STORE_CTX_idx()))) { if (SSL_get_app_data(ssl)) { verify_callback_base* callback = static_cast<verify_callback_base*>( SSL_get_app_data(ssl)); verify_context verify_ctx(ctx); return callback->call(preverified != 0, verify_ctx) ? 1 : 0; } } } return 0; } engine::want engine::handshake( stream_base::handshake_type type, boost::system::error_code& ec) { return perform((type == boost::asio::ssl::stream_base::client) ? &engine::do_connect : &engine::do_accept, 0, 0, ec, 0); } engine::want engine::shutdown(boost::system::error_code& ec) { return perform(&engine::do_shutdown, 0, 0, ec, 0); } engine::want engine::write(const boost::asio::const_buffer& data, boost::system::error_code& ec, std::size_t& bytes_transferred) { if (data.size() == 0) { ec = boost::system::error_code(); return engine::want_nothing; } return perform(&engine::do_write, const_cast<void*>(data.data()), data.size(), ec, &bytes_transferred); } engine::want engine::read(const boost::asio::mutable_buffer& data, boost::system::error_code& ec, std::size_t& bytes_transferred) { if (data.size() == 0) { ec = boost::system::error_code(); return engine::want_nothing; } return perform(&engine::do_read, data.data(), data.size(), ec, &bytes_transferred); } boost::asio::mutable_buffer engine::get_output( const boost::asio::mutable_buffer& data) { int length = ::BIO_read(ext_bio_, data.data(), static_cast<int>(data.size())); return boost::asio::buffer(data, length > 0 ? static_cast<std::size_t>(length) : 0); } boost::asio::const_buffer engine::put_input( const boost::asio::const_buffer& data) { int length = ::BIO_write(ext_bio_, data.data(), static_cast<int>(data.size())); return boost::asio::buffer(data + (length > 0 ? static_cast<std::size_t>(length) : 0)); } const boost::system::error_code& engine::map_error_code( boost::system::error_code& ec) const { // We only want to map the error::eof code. if (ec != boost::asio::error::eof) return ec; // If there's data yet to be read, it's an error. if (BIO_wpending(ext_bio_)) { ec = boost::asio::ssl::error::stream_truncated; return ec; } // SSL v2 doesn't provide a protocol-level shutdown, so an eof on the // underlying transport is passed through. #if (OPENSSL_VERSION_NUMBER < 0x10100000L) if (SSL_version(ssl_) == SSL2_VERSION) return ec; #endif // (OPENSSL_VERSION_NUMBER < 0x10100000L) // Otherwise, the peer should have negotiated a proper shutdown. if ((::SSL_get_shutdown(ssl_) & SSL_RECEIVED_SHUTDOWN) == 0) { ec = boost::asio::ssl::error::stream_truncated; } return ec; } #if (OPENSSL_VERSION_NUMBER < 0x10000000L) boost::asio::detail::static_mutex& engine::accept_mutex() { static boost::asio::detail::static_mutex mutex = BOOST_ASIO_STATIC_MUTEX_INIT; return mutex; } #endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) engine::want engine::perform(int (engine::* op)(void*, std::size_t), void* data, std::size_t length, boost::system::error_code& ec, std::size_t* bytes_transferred) { std::size_t pending_output_before = ::BIO_ctrl_pending(ext_bio_); ::ERR_clear_error(); int result = (this->*op)(data, length); int ssl_error = ::SSL_get_error(ssl_, result); int sys_error = static_cast<int>(::ERR_get_error()); std::size_t pending_output_after = ::BIO_ctrl_pending(ext_bio_); if (ssl_error == SSL_ERROR_SSL) { ec = boost::system::error_code(sys_error, boost::asio::error::get_ssl_category()); return pending_output_after > pending_output_before ? want_output : want_nothing; } if (ssl_error == SSL_ERROR_SYSCALL) { if (sys_error == 0) { ec = boost::asio::ssl::error::unspecified_system_error; } else { ec = boost::system::error_code(sys_error, boost::asio::error::get_ssl_category()); } return pending_output_after > pending_output_before ? want_output : want_nothing; } if (result > 0 && bytes_transferred) *bytes_transferred = static_cast<std::size_t>(result); if (ssl_error == SSL_ERROR_WANT_WRITE) { ec = boost::system::error_code(); return want_output_and_retry; } else if (pending_output_after > pending_output_before) { ec = boost::system::error_code(); return result > 0 ? want_output : want_output_and_retry; } else if (ssl_error == SSL_ERROR_WANT_READ) { ec = boost::system::error_code(); return want_input_and_retry; } else if (ssl_error == SSL_ERROR_ZERO_RETURN) { ec = boost::asio::error::eof; return want_nothing; } else if (ssl_error == SSL_ERROR_NONE) { ec = boost::system::error_code(); return want_nothing; } else { ec = boost::asio::ssl::error::unexpected_result; return want_nothing; } } int engine::do_accept(void*, std::size_t) { #if (OPENSSL_VERSION_NUMBER < 0x10000000L) boost::asio::detail::static_mutex::scoped_lock lock(accept_mutex()); #endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) return ::SSL_accept(ssl_); } int engine::do_connect(void*, std::size_t) { return ::SSL_connect(ssl_); } int engine::do_shutdown(void*, std::size_t) { int result = ::SSL_shutdown(ssl_); if (result == 0) result = ::SSL_shutdown(ssl_); return result; } int engine::do_read(void* data, std::size_t length) { return ::SSL_read(ssl_, data, length < INT_MAX ? static_cast<int>(length) : INT_MAX); } int engine::do_write(void* data, std::size_t length) { return ::SSL_write(ssl_, data, length < INT_MAX ? static_cast<int>(length) : INT_MAX); } } // namespace detail } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_DETAIL_IMPL_ENGINE_IPP ssl/detail/impl/openssl_init.ipp 0000644 00000012541 15125530236 0012775 0 ustar 00 // // ssl/detail/impl/openssl_init.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2005 Voipster / Indrek dot Juhani at voipster dot com // Copyright (c) 2005-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_DETAIL_IMPL_OPENSSL_INIT_IPP #define BOOST_ASIO_SSL_DETAIL_IMPL_OPENSSL_INIT_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <vector> #include <boost/asio/detail/assert.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/tss_ptr.hpp> #include <boost/asio/ssl/detail/openssl_init.hpp> #include <boost/asio/ssl/detail/openssl_types.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { namespace detail { class openssl_init_base::do_init { public: do_init() { #if (OPENSSL_VERSION_NUMBER < 0x10100000L) ::SSL_library_init(); ::SSL_load_error_strings(); ::OpenSSL_add_all_algorithms(); mutexes_.resize(::CRYPTO_num_locks()); for (size_t i = 0; i < mutexes_.size(); ++i) mutexes_[i].reset(new boost::asio::detail::mutex); ::CRYPTO_set_locking_callback(&do_init::openssl_locking_func); #endif // (OPENSSL_VERSION_NUMBER < 0x10100000L) #if (OPENSSL_VERSION_NUMBER < 0x10000000L) ::CRYPTO_set_id_callback(&do_init::openssl_id_func); #endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) #if !defined(SSL_OP_NO_COMPRESSION) \ && (OPENSSL_VERSION_NUMBER >= 0x00908000L) null_compression_methods_ = sk_SSL_COMP_new_null(); #endif // !defined(SSL_OP_NO_COMPRESSION) // && (OPENSSL_VERSION_NUMBER >= 0x00908000L) } ~do_init() { #if !defined(SSL_OP_NO_COMPRESSION) \ && (OPENSSL_VERSION_NUMBER >= 0x00908000L) sk_SSL_COMP_free(null_compression_methods_); #endif // !defined(SSL_OP_NO_COMPRESSION) // && (OPENSSL_VERSION_NUMBER >= 0x00908000L) #if (OPENSSL_VERSION_NUMBER < 0x10000000L) ::CRYPTO_set_id_callback(0); #endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) #if (OPENSSL_VERSION_NUMBER < 0x10100000L) ::CRYPTO_set_locking_callback(0); ::ERR_free_strings(); ::EVP_cleanup(); ::CRYPTO_cleanup_all_ex_data(); #endif // (OPENSSL_VERSION_NUMBER < 0x10100000L) #if (OPENSSL_VERSION_NUMBER < 0x10000000L) ::ERR_remove_state(0); #elif (OPENSSL_VERSION_NUMBER < 0x10100000L) ::ERR_remove_thread_state(NULL); #endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) #if (OPENSSL_VERSION_NUMBER >= 0x10002000L) \ && (OPENSSL_VERSION_NUMBER < 0x10100000L) \ && !defined(SSL_OP_NO_COMPRESSION) ::SSL_COMP_free_compression_methods(); #endif // (OPENSSL_VERSION_NUMBER >= 0x10002000L) // && (OPENSSL_VERSION_NUMBER < 0x10100000L) // && !defined(SSL_OP_NO_COMPRESSION) #if !defined(OPENSSL_IS_BORINGSSL) && !defined(BOOST_ASIO_USE_WOLFSSL) ::CONF_modules_unload(1); #endif // !defined(OPENSSL_IS_BORINGSSL) && !defined(BOOST_ASIO_USE_WOLFSSL) #if !defined(OPENSSL_NO_ENGINE) \ && (OPENSSL_VERSION_NUMBER < 0x10100000L) ::ENGINE_cleanup(); #endif // !defined(OPENSSL_NO_ENGINE) // && (OPENSSL_VERSION_NUMBER < 0x10100000L) } #if !defined(SSL_OP_NO_COMPRESSION) \ && (OPENSSL_VERSION_NUMBER >= 0x00908000L) STACK_OF(SSL_COMP)* get_null_compression_methods() const { return null_compression_methods_; } #endif // !defined(SSL_OP_NO_COMPRESSION) // && (OPENSSL_VERSION_NUMBER >= 0x00908000L) private: #if (OPENSSL_VERSION_NUMBER < 0x10000000L) static unsigned long openssl_id_func() { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) return ::GetCurrentThreadId(); #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) void* id = &errno; BOOST_ASIO_ASSERT(sizeof(unsigned long) >= sizeof(void*)); return reinterpret_cast<unsigned long>(id); #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) } #endif // (OPENSSL_VERSION_NUMBER < 0x10000000L) #if (OPENSSL_VERSION_NUMBER < 0x10100000L) static void openssl_locking_func(int mode, int n, const char* /*file*/, int /*line*/) { if (mode & CRYPTO_LOCK) instance()->mutexes_[n]->lock(); else instance()->mutexes_[n]->unlock(); } // Mutexes to be used in locking callbacks. std::vector<boost::asio::detail::shared_ptr< boost::asio::detail::mutex> > mutexes_; #endif // (OPENSSL_VERSION_NUMBER < 0x10100000L) #if !defined(SSL_OP_NO_COMPRESSION) \ && (OPENSSL_VERSION_NUMBER >= 0x00908000L) STACK_OF(SSL_COMP)* null_compression_methods_; #endif // !defined(SSL_OP_NO_COMPRESSION) // && (OPENSSL_VERSION_NUMBER >= 0x00908000L) }; boost::asio::detail::shared_ptr<openssl_init_base::do_init> openssl_init_base::instance() { static boost::asio::detail::shared_ptr<do_init> init(new do_init); return init; } #if !defined(SSL_OP_NO_COMPRESSION) \ && (OPENSSL_VERSION_NUMBER >= 0x00908000L) STACK_OF(SSL_COMP)* openssl_init_base::get_null_compression_methods() { return instance()->get_null_compression_methods(); } #endif // !defined(SSL_OP_NO_COMPRESSION) // && (OPENSSL_VERSION_NUMBER >= 0x00908000L) } // namespace detail } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_DETAIL_IMPL_OPENSSL_INIT_IPP ssl/detail/verify_callback.hpp 0000644 00000002560 15125530236 0012445 0 ustar 00 // // ssl/detail/verify_callback.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_DETAIL_VERIFY_CALLBACK_HPP #define BOOST_ASIO_SSL_DETAIL_VERIFY_CALLBACK_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/ssl/verify_context.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { namespace detail { class verify_callback_base { public: virtual ~verify_callback_base() { } virtual bool call(bool preverified, verify_context& ctx) = 0; }; template <typename VerifyCallback> class verify_callback : public verify_callback_base { public: explicit verify_callback(VerifyCallback callback) : callback_(callback) { } virtual bool call(bool preverified, verify_context& ctx) { return callback_(preverified, ctx); } private: VerifyCallback callback_; }; } // namespace detail } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_DETAIL_VERIFY_CALLBACK_HPP ssl/detail/password_callback.hpp 0000644 00000002750 15125530236 0013004 0 ustar 00 // // ssl/detail/password_callback.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_DETAIL_PASSWORD_CALLBACK_HPP #define BOOST_ASIO_SSL_DETAIL_PASSWORD_CALLBACK_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <cstddef> #include <string> #include <boost/asio/ssl/context_base.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { namespace detail { class password_callback_base { public: virtual ~password_callback_base() { } virtual std::string call(std::size_t size, context_base::password_purpose purpose) = 0; }; template <typename PasswordCallback> class password_callback : public password_callback_base { public: explicit password_callback(PasswordCallback callback) : callback_(callback) { } virtual std::string call(std::size_t size, context_base::password_purpose purpose) { return callback_(size, purpose); } private: PasswordCallback callback_; }; } // namespace detail } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_DETAIL_PASSWORD_CALLBACK_HPP ssl/detail/write_op.hpp 0000644 00000003701 15125530236 0011153 0 ustar 00 // // ssl/detail/write_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_DETAIL_WRITE_OP_HPP #define BOOST_ASIO_SSL_DETAIL_WRITE_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/ssl/detail/engine.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { namespace detail { template <typename ConstBufferSequence> class write_op { public: static BOOST_ASIO_CONSTEXPR const char* tracking_name() { return "ssl::stream<>::async_write_some"; } write_op(const ConstBufferSequence& buffers) : buffers_(buffers) { } engine::want operator()(engine& eng, boost::system::error_code& ec, std::size_t& bytes_transferred) const { unsigned char storage[ boost::asio::detail::buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence>::linearisation_storage_size]; boost::asio::const_buffer buffer = boost::asio::detail::buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence>::linearise(buffers_, boost::asio::buffer(storage)); return eng.write(buffer, ec, bytes_transferred); } template <typename Handler> void call_handler(Handler& handler, const boost::system::error_code& ec, const std::size_t& bytes_transferred) const { handler(ec, bytes_transferred); } private: ConstBufferSequence buffers_; }; } // namespace detail } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_DETAIL_WRITE_OP_HPP ssl/detail/io.hpp 0000644 00000031753 15125530236 0007742 0 ustar 00 // // ssl/detail/io.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_DETAIL_IO_HPP #define BOOST_ASIO_SSL_DETAIL_IO_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/handler_tracking.hpp> #include <boost/asio/ssl/detail/engine.hpp> #include <boost/asio/ssl/detail/stream_core.hpp> #include <boost/asio/write.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { namespace detail { template <typename Stream, typename Operation> std::size_t io(Stream& next_layer, stream_core& core, const Operation& op, boost::system::error_code& ec) { boost::system::error_code io_ec; std::size_t bytes_transferred = 0; do switch (op(core.engine_, ec, bytes_transferred)) { case engine::want_input_and_retry: // If the input buffer is empty then we need to read some more data from // the underlying transport. if (core.input_.size() == 0) { core.input_ = boost::asio::buffer(core.input_buffer_, next_layer.read_some(core.input_buffer_, io_ec)); if (!ec) ec = io_ec; } // Pass the new input data to the engine. core.input_ = core.engine_.put_input(core.input_); // Try the operation again. continue; case engine::want_output_and_retry: // Get output data from the engine and write it to the underlying // transport. boost::asio::write(next_layer, core.engine_.get_output(core.output_buffer_), io_ec); if (!ec) ec = io_ec; // Try the operation again. continue; case engine::want_output: // Get output data from the engine and write it to the underlying // transport. boost::asio::write(next_layer, core.engine_.get_output(core.output_buffer_), io_ec); if (!ec) ec = io_ec; // Operation is complete. Return result to caller. core.engine_.map_error_code(ec); return bytes_transferred; default: // Operation is complete. Return result to caller. core.engine_.map_error_code(ec); return bytes_transferred; } while (!ec); // Operation failed. Return result to caller. core.engine_.map_error_code(ec); return 0; } template <typename Stream, typename Operation, typename Handler> class io_op { public: io_op(Stream& next_layer, stream_core& core, const Operation& op, Handler& handler) : next_layer_(next_layer), core_(core), op_(op), start_(0), want_(engine::want_nothing), bytes_transferred_(0), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)) { } #if defined(BOOST_ASIO_HAS_MOVE) io_op(const io_op& other) : next_layer_(other.next_layer_), core_(other.core_), op_(other.op_), start_(other.start_), want_(other.want_), ec_(other.ec_), bytes_transferred_(other.bytes_transferred_), handler_(other.handler_) { } io_op(io_op&& other) : next_layer_(other.next_layer_), core_(other.core_), op_(BOOST_ASIO_MOVE_CAST(Operation)(other.op_)), start_(other.start_), want_(other.want_), ec_(other.ec_), bytes_transferred_(other.bytes_transferred_), handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)) { } #endif // defined(BOOST_ASIO_HAS_MOVE) void operator()(boost::system::error_code ec, std::size_t bytes_transferred = ~std::size_t(0), int start = 0) { switch (start_ = start) { case 1: // Called after at least one async operation. do { switch (want_ = op_(core_.engine_, ec_, bytes_transferred_)) { case engine::want_input_and_retry: // If the input buffer already has data in it we can pass it to the // engine and then retry the operation immediately. if (core_.input_.size() != 0) { core_.input_ = core_.engine_.put_input(core_.input_); continue; } // The engine wants more data to be read from input. However, we // cannot allow more than one read operation at a time on the // underlying transport. The pending_read_ timer's expiry is set to // pos_infin if a read is in progress, and neg_infin otherwise. if (core_.expiry(core_.pending_read_) == core_.neg_infin()) { // Prevent other read operations from being started. core_.pending_read_.expires_at(core_.pos_infin()); BOOST_ASIO_HANDLER_LOCATION(( __FILE__, __LINE__, Operation::tracking_name())); // Start reading some data from the underlying transport. next_layer_.async_read_some( boost::asio::buffer(core_.input_buffer_), BOOST_ASIO_MOVE_CAST(io_op)(*this)); } else { BOOST_ASIO_HANDLER_LOCATION(( __FILE__, __LINE__, Operation::tracking_name())); // Wait until the current read operation completes. core_.pending_read_.async_wait(BOOST_ASIO_MOVE_CAST(io_op)(*this)); } // Yield control until asynchronous operation completes. Control // resumes at the "default:" label below. return; case engine::want_output_and_retry: case engine::want_output: // The engine wants some data to be written to the output. However, we // cannot allow more than one write operation at a time on the // underlying transport. The pending_write_ timer's expiry is set to // pos_infin if a write is in progress, and neg_infin otherwise. if (core_.expiry(core_.pending_write_) == core_.neg_infin()) { // Prevent other write operations from being started. core_.pending_write_.expires_at(core_.pos_infin()); BOOST_ASIO_HANDLER_LOCATION(( __FILE__, __LINE__, Operation::tracking_name())); // Start writing all the data to the underlying transport. boost::asio::async_write(next_layer_, core_.engine_.get_output(core_.output_buffer_), BOOST_ASIO_MOVE_CAST(io_op)(*this)); } else { BOOST_ASIO_HANDLER_LOCATION(( __FILE__, __LINE__, Operation::tracking_name())); // Wait until the current write operation completes. core_.pending_write_.async_wait(BOOST_ASIO_MOVE_CAST(io_op)(*this)); } // Yield control until asynchronous operation completes. Control // resumes at the "default:" label below. return; default: // The SSL operation is done and we can invoke the handler, but we // have to keep in mind that this function might be being called from // the async operation's initiating function. In this case we're not // allowed to call the handler directly. Instead, issue a zero-sized // read so the handler runs "as-if" posted using io_context::post(). if (start) { BOOST_ASIO_HANDLER_LOCATION(( __FILE__, __LINE__, Operation::tracking_name())); next_layer_.async_read_some( boost::asio::buffer(core_.input_buffer_, 0), BOOST_ASIO_MOVE_CAST(io_op)(*this)); // Yield control until asynchronous operation completes. Control // resumes at the "default:" label below. return; } else { // Continue on to run handler directly. break; } } default: if (bytes_transferred == ~std::size_t(0)) bytes_transferred = 0; // Timer cancellation, no data transferred. else if (!ec_) ec_ = ec; switch (want_) { case engine::want_input_and_retry: // Add received data to the engine's input. core_.input_ = boost::asio::buffer( core_.input_buffer_, bytes_transferred); core_.input_ = core_.engine_.put_input(core_.input_); // Release any waiting read operations. core_.pending_read_.expires_at(core_.neg_infin()); // Try the operation again. continue; case engine::want_output_and_retry: // Release any waiting write operations. core_.pending_write_.expires_at(core_.neg_infin()); // Try the operation again. continue; case engine::want_output: // Release any waiting write operations. core_.pending_write_.expires_at(core_.neg_infin()); // Fall through to call handler. default: // Pass the result to the handler. op_.call_handler(handler_, core_.engine_.map_error_code(ec_), ec_ ? 0 : bytes_transferred_); // Our work here is done. return; } } while (!ec_); // Operation failed. Pass the result to the handler. op_.call_handler(handler_, core_.engine_.map_error_code(ec_), 0); } } //private: Stream& next_layer_; stream_core& core_; Operation op_; int start_; engine::want want_; boost::system::error_code ec_; std::size_t bytes_transferred_; Handler handler_; }; template <typename Stream, typename Operation, typename Handler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, io_op<Stream, Operation, Handler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Stream, typename Operation, typename Handler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, io_op<Stream, Operation, Handler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Stream, typename Operation, typename Handler> inline bool asio_handler_is_continuation( io_op<Stream, Operation, Handler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation(this_handler->handler_); } template <typename Function, typename Stream, typename Operation, typename Handler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, io_op<Stream, Operation, Handler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename Stream, typename Operation, typename Handler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, io_op<Stream, Operation, Handler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Stream, typename Operation, typename Handler> inline void async_io(Stream& next_layer, stream_core& core, const Operation& op, Handler& handler) { io_op<Stream, Operation, Handler>( next_layer, core, op, handler)( boost::system::error_code(), 0, 1); } } // namespace detail } // namespace ssl template <typename Stream, typename Operation, typename Handler, typename Allocator> struct associated_allocator< ssl::detail::io_op<Stream, Operation, Handler>, Allocator> { typedef typename associated_allocator<Handler, Allocator>::type type; static type get(const ssl::detail::io_op<Stream, Operation, Handler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<Handler, Allocator>::get(h.handler_, a); } }; template <typename Stream, typename Operation, typename Handler, typename Executor> struct associated_executor< ssl::detail::io_op<Stream, Operation, Handler>, Executor> : detail::associated_executor_forwarding_base<Handler, Executor> { typedef typename associated_executor<Handler, Executor>::type type; static type get(const ssl::detail::io_op<Stream, Operation, Handler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<Handler, Executor>::get(h.handler_, ex); } }; } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_DETAIL_IO_HPP ssl/detail/buffered_handshake_op.hpp 0000644 00000006504 15125530236 0013615 0 ustar 00 // // ssl/detail/buffered_handshake_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_DETAIL_BUFFERED_HANDSHAKE_OP_HPP #define BOOST_ASIO_SSL_DETAIL_BUFFERED_HANDSHAKE_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/ssl/detail/engine.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { namespace detail { template <typename ConstBufferSequence> class buffered_handshake_op { public: static BOOST_ASIO_CONSTEXPR const char* tracking_name() { return "ssl::stream<>::async_buffered_handshake"; } buffered_handshake_op(stream_base::handshake_type type, const ConstBufferSequence& buffers) : type_(type), buffers_(buffers), total_buffer_size_(boost::asio::buffer_size(buffers_)) { } engine::want operator()(engine& eng, boost::system::error_code& ec, std::size_t& bytes_transferred) const { return this->process(eng, ec, bytes_transferred, boost::asio::buffer_sequence_begin(buffers_), boost::asio::buffer_sequence_end(buffers_)); } template <typename Handler> void call_handler(Handler& handler, const boost::system::error_code& ec, const std::size_t& bytes_transferred) const { handler(ec, bytes_transferred); } private: template <typename Iterator> engine::want process(engine& eng, boost::system::error_code& ec, std::size_t& bytes_transferred, Iterator begin, Iterator end) const { Iterator iter = begin; std::size_t accumulated_size = 0; for (;;) { engine::want want = eng.handshake(type_, ec); if (want != engine::want_input_and_retry || bytes_transferred == total_buffer_size_) return want; // Find the next buffer piece to be fed to the engine. while (iter != end) { const_buffer buffer(*iter); // Skip over any buffers which have already been consumed by the engine. if (bytes_transferred >= accumulated_size + buffer.size()) { accumulated_size += buffer.size(); ++iter; continue; } // The current buffer may have been partially consumed by the engine on // a previous iteration. If so, adjust the buffer to point to the // unused portion. if (bytes_transferred > accumulated_size) buffer = buffer + (bytes_transferred - accumulated_size); // Pass the buffer to the engine, and update the bytes transferred to // reflect the total number of bytes consumed so far. bytes_transferred += buffer.size(); buffer = eng.put_input(buffer); bytes_transferred -= buffer.size(); break; } } } stream_base::handshake_type type_; ConstBufferSequence buffers_; std::size_t total_buffer_size_; }; } // namespace detail } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_DETAIL_BUFFERED_HANDSHAKE_OP_HPP ssl/detail/openssl_init.hpp 0000644 00000005763 15125530236 0012043 0 ustar 00 // // ssl/detail/openssl_init.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_DETAIL_OPENSSL_INIT_HPP #define BOOST_ASIO_SSL_DETAIL_OPENSSL_INIT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <cstring> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/ssl/detail/openssl_types.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { namespace detail { class openssl_init_base : private noncopyable { protected: // Class that performs the actual initialisation. class do_init; // Helper function to manage a do_init singleton. The static instance of the // openssl_init object ensures that this function is always called before // main, and therefore before any other threads can get started. The do_init // instance must be static in this function to ensure that it gets // initialised before any other global objects try to use it. BOOST_ASIO_DECL static boost::asio::detail::shared_ptr<do_init> instance(); #if !defined(SSL_OP_NO_COMPRESSION) \ && (OPENSSL_VERSION_NUMBER >= 0x00908000L) // Get an empty stack of compression methods, to be used when disabling // compression. BOOST_ASIO_DECL static STACK_OF(SSL_COMP)* get_null_compression_methods(); #endif // !defined(SSL_OP_NO_COMPRESSION) // && (OPENSSL_VERSION_NUMBER >= 0x00908000L) }; template <bool Do_Init = true> class openssl_init : private openssl_init_base { public: // Constructor. openssl_init() : ref_(instance()) { using namespace std; // For memmove. // Ensure openssl_init::instance_ is linked in. openssl_init* tmp = &instance_; memmove(&tmp, &tmp, sizeof(openssl_init*)); } // Destructor. ~openssl_init() { } #if !defined(SSL_OP_NO_COMPRESSION) \ && (OPENSSL_VERSION_NUMBER >= 0x00908000L) using openssl_init_base::get_null_compression_methods; #endif // !defined(SSL_OP_NO_COMPRESSION) // && (OPENSSL_VERSION_NUMBER >= 0x00908000L) private: // Instance to force initialisation of openssl at global scope. static openssl_init instance_; // Reference to singleton do_init object to ensure that openssl does not get // cleaned up until the last user has finished with it. boost::asio::detail::shared_ptr<do_init> ref_; }; template <bool Do_Init> openssl_init<Do_Init> openssl_init<Do_Init>::instance_; } // namespace detail } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/ssl/detail/impl/openssl_init.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_SSL_DETAIL_OPENSSL_INIT_HPP ssl/detail/shutdown_op.hpp 0000644 00000003306 15125530236 0011675 0 ustar 00 // // ssl/detail/shutdown_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_DETAIL_SHUTDOWN_OP_HPP #define BOOST_ASIO_SSL_DETAIL_SHUTDOWN_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/ssl/detail/engine.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { namespace detail { class shutdown_op { public: static BOOST_ASIO_CONSTEXPR const char* tracking_name() { return "ssl::stream<>::async_shutdown"; } engine::want operator()(engine& eng, boost::system::error_code& ec, std::size_t& bytes_transferred) const { bytes_transferred = 0; return eng.shutdown(ec); } template <typename Handler> void call_handler(Handler& handler, const boost::system::error_code& ec, const std::size_t&) const { if (ec == boost::asio::error::eof) { // The engine only generates an eof when the shutdown notification has // been received from the peer. This indicates that the shutdown has // completed successfully, and thus need not be passed on to the handler. handler(boost::system::error_code()); } else { handler(ec); } } }; } // namespace detail } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_DETAIL_SHUTDOWN_OP_HPP ssl/detail/read_op.hpp 0000644 00000003375 15125530236 0010743 0 ustar 00 // // ssl/detail/read_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_DETAIL_READ_OP_HPP #define BOOST_ASIO_SSL_DETAIL_READ_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/ssl/detail/engine.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { namespace detail { template <typename MutableBufferSequence> class read_op { public: static BOOST_ASIO_CONSTEXPR const char* tracking_name() { return "ssl::stream<>::async_read_some"; } read_op(const MutableBufferSequence& buffers) : buffers_(buffers) { } engine::want operator()(engine& eng, boost::system::error_code& ec, std::size_t& bytes_transferred) const { boost::asio::mutable_buffer buffer = boost::asio::detail::buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence>::first(buffers_); return eng.read(buffer, ec, bytes_transferred); } template <typename Handler> void call_handler(Handler& handler, const boost::system::error_code& ec, const std::size_t& bytes_transferred) const { handler(ec, bytes_transferred); } private: MutableBufferSequence buffers_; }; } // namespace detail } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_DETAIL_READ_OP_HPP ssl/context_base.hpp 0000644 00000012475 15125530236 0010547 0 ustar 00 // // ssl/context_base.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_CONTEXT_BASE_HPP #define BOOST_ASIO_SSL_CONTEXT_BASE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/ssl/detail/openssl_types.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { /// The context_base class is used as a base for the basic_context class /// template so that we have a common place to define various enums. class context_base { public: /// Different methods supported by a context. enum method { /// Generic SSL version 2. sslv2, /// SSL version 2 client. sslv2_client, /// SSL version 2 server. sslv2_server, /// Generic SSL version 3. sslv3, /// SSL version 3 client. sslv3_client, /// SSL version 3 server. sslv3_server, /// Generic TLS version 1. tlsv1, /// TLS version 1 client. tlsv1_client, /// TLS version 1 server. tlsv1_server, /// Generic SSL/TLS. sslv23, /// SSL/TLS client. sslv23_client, /// SSL/TLS server. sslv23_server, /// Generic TLS version 1.1. tlsv11, /// TLS version 1.1 client. tlsv11_client, /// TLS version 1.1 server. tlsv11_server, /// Generic TLS version 1.2. tlsv12, /// TLS version 1.2 client. tlsv12_client, /// TLS version 1.2 server. tlsv12_server, /// Generic TLS version 1.3. tlsv13, /// TLS version 1.3 client. tlsv13_client, /// TLS version 1.3 server. tlsv13_server, /// Generic TLS. tls, /// TLS client. tls_client, /// TLS server. tls_server }; /// Bitmask type for SSL options. typedef long options; #if defined(GENERATING_DOCUMENTATION) /// Implement various bug workarounds. static const long default_workarounds = implementation_defined; /// Always create a new key when using tmp_dh parameters. static const long single_dh_use = implementation_defined; /// Disable SSL v2. static const long no_sslv2 = implementation_defined; /// Disable SSL v3. static const long no_sslv3 = implementation_defined; /// Disable TLS v1. static const long no_tlsv1 = implementation_defined; /// Disable TLS v1.1. static const long no_tlsv1_1 = implementation_defined; /// Disable TLS v1.2. static const long no_tlsv1_2 = implementation_defined; /// Disable TLS v1.3. static const long no_tlsv1_3 = implementation_defined; /// Disable compression. Compression is disabled by default. static const long no_compression = implementation_defined; #else BOOST_ASIO_STATIC_CONSTANT(long, default_workarounds = SSL_OP_ALL); BOOST_ASIO_STATIC_CONSTANT(long, single_dh_use = SSL_OP_SINGLE_DH_USE); BOOST_ASIO_STATIC_CONSTANT(long, no_sslv2 = SSL_OP_NO_SSLv2); BOOST_ASIO_STATIC_CONSTANT(long, no_sslv3 = SSL_OP_NO_SSLv3); BOOST_ASIO_STATIC_CONSTANT(long, no_tlsv1 = SSL_OP_NO_TLSv1); # if defined(SSL_OP_NO_TLSv1_1) BOOST_ASIO_STATIC_CONSTANT(long, no_tlsv1_1 = SSL_OP_NO_TLSv1_1); # else // defined(SSL_OP_NO_TLSv1_1) BOOST_ASIO_STATIC_CONSTANT(long, no_tlsv1_1 = 0x10000000L); # endif // defined(SSL_OP_NO_TLSv1_1) # if defined(SSL_OP_NO_TLSv1_2) BOOST_ASIO_STATIC_CONSTANT(long, no_tlsv1_2 = SSL_OP_NO_TLSv1_2); # else // defined(SSL_OP_NO_TLSv1_2) BOOST_ASIO_STATIC_CONSTANT(long, no_tlsv1_2 = 0x08000000L); # endif // defined(SSL_OP_NO_TLSv1_2) # if defined(SSL_OP_NO_TLSv1_3) BOOST_ASIO_STATIC_CONSTANT(long, no_tlsv1_3 = SSL_OP_NO_TLSv1_3); # else // defined(SSL_OP_NO_TLSv1_3) BOOST_ASIO_STATIC_CONSTANT(long, no_tlsv1_3 = 0x20000000L); # endif // defined(SSL_OP_NO_TLSv1_3) # if defined(SSL_OP_NO_COMPRESSION) BOOST_ASIO_STATIC_CONSTANT(long, no_compression = SSL_OP_NO_COMPRESSION); # else // defined(SSL_OP_NO_COMPRESSION) BOOST_ASIO_STATIC_CONSTANT(long, no_compression = 0x20000L); # endif // defined(SSL_OP_NO_COMPRESSION) #endif /// File format types. enum file_format { /// ASN.1 file. asn1, /// PEM file. pem }; #if !defined(GENERATING_DOCUMENTATION) // The following types and constants are preserved for backward compatibility. // New programs should use the equivalents of the same names that are defined // in the boost::asio::ssl namespace. typedef int verify_mode; BOOST_ASIO_STATIC_CONSTANT(int, verify_none = SSL_VERIFY_NONE); BOOST_ASIO_STATIC_CONSTANT(int, verify_peer = SSL_VERIFY_PEER); BOOST_ASIO_STATIC_CONSTANT(int, verify_fail_if_no_peer_cert = SSL_VERIFY_FAIL_IF_NO_PEER_CERT); BOOST_ASIO_STATIC_CONSTANT(int, verify_client_once = SSL_VERIFY_CLIENT_ONCE); #endif /// Purpose of PEM password. enum password_purpose { /// The password is needed for reading/decryption. for_reading, /// The password is needed for writing/encryption. for_writing }; protected: /// Protected destructor to prevent deletion through this type. ~context_base() { } }; } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_CONTEXT_BASE_HPP ssl/stream_base.hpp 0000644 00000002310 15125530236 0010341 0 ustar 00 // // ssl/stream_base.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_STREAM_BASE_HPP #define BOOST_ASIO_SSL_STREAM_BASE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ssl { /// The stream_base class is used as a base for the boost::asio::ssl::stream /// class template so that we have a common place to define various enums. class stream_base { public: /// Different handshake types. enum handshake_type { /// Perform handshaking as a client. client, /// Perform handshaking as a server. server }; protected: /// Protected destructor to prevent deletion through this type. ~stream_base() { } }; } // namespace ssl } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SSL_STREAM_BASE_HPP signal_set.hpp 0000644 00000001354 15125530236 0007412 0 ustar 00 // // signal_set.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/basic_signal_set.hpp> 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 yield.hpp 0000644 00000000742 15125530236 0006370 0 ustar 00 // // yield.hpp // ~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #include "coroutine.hpp" #ifndef reenter # define reenter(c) BOOST_ASIO_CORO_REENTER(c) #endif #ifndef yield # define yield BOOST_ASIO_CORO_YIELD #endif #ifndef fork # define fork BOOST_ASIO_CORO_FORK #endif ts/buffer.hpp 0000644 00000001237 15125530236 0007161 0 ustar 00 // // ts/buffer.hpp // ~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TS_BUFFER_HPP #define BOOST_ASIO_TS_BUFFER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/buffer.hpp> #include <boost/asio/completion_condition.hpp> #include <boost/asio/read.hpp> #include <boost/asio/write.hpp> #include <boost/asio/read_until.hpp> #endif // BOOST_ASIO_TS_BUFFER_HPP ts/timer.hpp 0000644 00000001342 15125530236 0007025 0 ustar 00 // // ts/timer.hpp // ~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TS_TIMER_HPP #define BOOST_ASIO_TS_TIMER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/chrono.hpp> #include <boost/asio/wait_traits.hpp> #include <boost/asio/basic_waitable_timer.hpp> #include <boost/asio/system_timer.hpp> #include <boost/asio/steady_timer.hpp> #include <boost/asio/high_resolution_timer.hpp> #endif // BOOST_ASIO_TS_TIMER_HPP ts/internet.hpp 0000644 00000002561 15125530236 0007541 0 ustar 00 // // ts/internet.hpp // ~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TS_INTERNET_HPP #define BOOST_ASIO_TS_INTERNET_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/ip/address.hpp> #include <boost/asio/ip/address_v4.hpp> #include <boost/asio/ip/address_v4_iterator.hpp> #include <boost/asio/ip/address_v4_range.hpp> #include <boost/asio/ip/address_v6.hpp> #include <boost/asio/ip/address_v6_iterator.hpp> #include <boost/asio/ip/address_v6_range.hpp> #include <boost/asio/ip/bad_address_cast.hpp> #include <boost/asio/ip/basic_endpoint.hpp> #include <boost/asio/ip/basic_resolver_query.hpp> #include <boost/asio/ip/basic_resolver_entry.hpp> #include <boost/asio/ip/basic_resolver_iterator.hpp> #include <boost/asio/ip/basic_resolver.hpp> #include <boost/asio/ip/host_name.hpp> #include <boost/asio/ip/network_v4.hpp> #include <boost/asio/ip/network_v6.hpp> #include <boost/asio/ip/tcp.hpp> #include <boost/asio/ip/udp.hpp> #include <boost/asio/ip/v6_only.hpp> #include <boost/asio/ip/unicast.hpp> #include <boost/asio/ip/multicast.hpp> #endif // BOOST_ASIO_TS_INTERNET_HPP ts/executor.hpp 0000644 00000002150 15125530236 0007541 0 ustar 00 // // ts/executor.hpp // ~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TS_EXECUTOR_HPP #define BOOST_ASIO_TS_EXECUTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/async_result.hpp> #include <boost/asio/associated_allocator.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/is_executor.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/bind_executor.hpp> #include <boost/asio/executor_work_guard.hpp> #include <boost/asio/system_executor.hpp> #include <boost/asio/executor.hpp> #include <boost/asio/any_io_executor.hpp> #include <boost/asio/dispatch.hpp> #include <boost/asio/post.hpp> #include <boost/asio/defer.hpp> #include <boost/asio/strand.hpp> #include <boost/asio/packaged_task.hpp> #include <boost/asio/use_future.hpp> #endif // BOOST_ASIO_TS_EXECUTOR_HPP ts/socket.hpp 0000644 00000001511 15125530236 0007173 0 ustar 00 // // ts/socket.hpp // ~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TS_SOCKET_HPP #define BOOST_ASIO_TS_SOCKET_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/socket_base.hpp> #include <boost/asio/basic_socket.hpp> #include <boost/asio/basic_datagram_socket.hpp> #include <boost/asio/basic_stream_socket.hpp> #include <boost/asio/basic_socket_acceptor.hpp> #include <boost/asio/basic_socket_streambuf.hpp> #include <boost/asio/basic_socket_iostream.hpp> #include <boost/asio/connect.hpp> #endif // BOOST_ASIO_TS_SOCKET_HPP ts/netfwd.hpp 0000644 00000015774 15125530236 0007212 0 ustar 00 // // ts/netfwd.hpp // ~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TS_NETFWD_HPP #define BOOST_ASIO_TS_NETFWD_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_CHRONO) # include <boost/asio/detail/chrono.hpp> #endif // defined(BOOST_ASIO_HAS_CHRONO) #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) # include <boost/asio/detail/date_time_fwd.hpp> #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) #if !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) #include <boost/asio/execution/blocking.hpp> #include <boost/asio/execution/outstanding_work.hpp> #include <boost/asio/execution/relationship.hpp> #endif // !defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) #if !defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { class execution_context; template <typename T, typename Executor> class executor_binder; #if !defined(BOOST_ASIO_EXECUTOR_WORK_GUARD_DECL) #define BOOST_ASIO_EXECUTOR_WORK_GUARD_DECL template <typename Executor, typename = void> class executor_work_guard; #endif // !defined(BOOST_ASIO_EXECUTOR_WORK_GUARD_DECL) template <typename Blocking, typename Relationship, typename Allocator> class basic_system_executor; #if defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) class executor; typedef executor any_io_executor; #else // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) namespace execution { #if !defined(BOOST_ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL) #define BOOST_ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename... SupportableProperties> class any_executor; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename = void, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void, typename = void> class any_executor; #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #endif // !defined(BOOST_ASIO_EXECUTION_ANY_EXECUTOR_FWD_DECL) template <typename U> struct context_as_t; template <typename Property> struct prefer_only; } // namespace execution typedef execution::any_executor< execution::context_as_t<execution_context&>, execution::blocking_t::never_t, execution::prefer_only<execution::blocking_t::possibly_t>, execution::prefer_only<execution::outstanding_work_t::tracked_t>, execution::prefer_only<execution::outstanding_work_t::untracked_t>, execution::prefer_only<execution::relationship_t::fork_t>, execution::prefer_only<execution::relationship_t::continuation_t> > any_io_executor; #endif // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) template <typename Executor> class strand; class io_context; template <typename Clock> struct wait_traits; #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) template <typename Time> struct time_traits; #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) #if !defined(BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL) #define BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL template <typename Clock, typename WaitTraits = wait_traits<Clock>, typename Executor = any_io_executor> class basic_waitable_timer; #endif // !defined(BOOST_ASIO_BASIC_WAITABLE_TIMER_FWD_DECL) #if defined(BOOST_ASIO_HAS_CHRONO) typedef basic_waitable_timer<chrono::system_clock> system_timer; typedef basic_waitable_timer<chrono::steady_clock> steady_timer; typedef basic_waitable_timer<chrono::high_resolution_clock> high_resolution_timer; #endif // defined(BOOST_ASIO_HAS_CHRONO) #if !defined(BOOST_ASIO_BASIC_SOCKET_FWD_DECL) #define BOOST_ASIO_BASIC_SOCKET_FWD_DECL template <typename Protocol, typename Executor = any_io_executor> class basic_socket; #endif // !defined(BOOST_ASIO_BASIC_SOCKET_FWD_DECL) #if !defined(BOOST_ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL) #define BOOST_ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL template <typename Protocol, typename Executor = any_io_executor> class basic_datagram_socket; #endif // !defined(BOOST_ASIO_BASIC_DATAGRAM_SOCKET_FWD_DECL) #if !defined(BOOST_ASIO_BASIC_STREAM_SOCKET_FWD_DECL) #define BOOST_ASIO_BASIC_STREAM_SOCKET_FWD_DECL // Forward declaration with defaulted arguments. template <typename Protocol, typename Executor = any_io_executor> class basic_stream_socket; #endif // !defined(BOOST_ASIO_BASIC_STREAM_SOCKET_FWD_DECL) #if !defined(BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL) #define BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL template <typename Protocol, typename Executor = any_io_executor> class basic_socket_acceptor; #endif // !defined(BOOST_ASIO_BASIC_SOCKET_ACCEPTOR_FWD_DECL) #if !defined(BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL) #define BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL // Forward declaration with defaulted arguments. template <typename Protocol, #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ || defined(GENERATING_DOCUMENTATION) typename Clock = boost::posix_time::ptime, typename WaitTraits = time_traits<Clock> > #else typename Clock = chrono::steady_clock, typename WaitTraits = wait_traits<Clock> > #endif class basic_socket_streambuf; #endif // !defined(BOOST_ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL) #if !defined(BOOST_ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL) #define BOOST_ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL // Forward declaration with defaulted arguments. template <typename Protocol, #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ || defined(GENERATING_DOCUMENTATION) typename Clock = boost::posix_time::ptime, typename WaitTraits = time_traits<Clock> > #else typename Clock = chrono::steady_clock, typename WaitTraits = wait_traits<Clock> > #endif class basic_socket_iostream; #endif // !defined(BOOST_ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL) namespace ip { class address; class address_v4; class address_v6; template <typename Address> class basic_address_iterator; typedef basic_address_iterator<address_v4> address_v4_iterator; typedef basic_address_iterator<address_v6> address_v6_iterator; template <typename Address> class basic_address_range; typedef basic_address_range<address_v4> address_v4_range; typedef basic_address_range<address_v6> address_v6_range; class network_v4; class network_v6; template <typename InternetProtocol> class basic_endpoint; template <typename InternetProtocol> class basic_resolver_entry; template <typename InternetProtocol> class basic_resolver_results; #if !defined(BOOST_ASIO_IP_BASIC_RESOLVER_FWD_DECL) #define BOOST_ASIO_IP_BASIC_RESOLVER_FWD_DECL template <typename InternetProtocol, typename Executor = any_io_executor> class basic_resolver; #endif // !defined(BOOST_ASIO_IP_BASIC_RESOLVER_FWD_DECL) class tcp; class udp; } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // !defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_TS_NETFWD_HPP ts/io_context.hpp 0000644 00000001044 15125530236 0010057 0 ustar 00 // // ts/io_context.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TS_IO_CONTEXT_HPP #define BOOST_ASIO_TS_IO_CONTEXT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/io_context.hpp> #endif // BOOST_ASIO_TS_IO_CONTEXT_HPP ts/net.hpp 0000644 00000001337 15125530236 0006477 0 ustar 00 // // ts/net.hpp // ~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TS_NET_HPP #define BOOST_ASIO_TS_NET_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/ts/netfwd.hpp> #include <boost/asio/ts/executor.hpp> #include <boost/asio/ts/io_context.hpp> #include <boost/asio/ts/timer.hpp> #include <boost/asio/ts/buffer.hpp> #include <boost/asio/ts/socket.hpp> #include <boost/asio/ts/internet.hpp> #endif // BOOST_ASIO_TS_NET_HPP impl/executor.ipp 0000644 00000001752 15125530236 0010064 0 ustar 00 // // impl/executor.ipp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) #include <boost/asio/executor.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) #endif // BOOST_ASIO_IMPL_EXECUTOR_IPP impl/execution_context.hpp 0000644 00000006257 15125530236 0012001 0 ustar 00 // // impl/execution_context.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/scoped_ptr.hpp> #include <boost/asio/detail/service_registry.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if !defined(GENERATING_DOCUMENTATION) template <typename Service> inline Service& use_service(execution_context& e) { // Check that Service meets the necessary type requirements. (void)static_cast<execution_context::service*>(static_cast<Service*>(0)); return e.service_registry_->template use_service<Service>(); } #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename Service, typename... Args> Service& make_service(execution_context& e, BOOST_ASIO_MOVE_ARG(Args)... args) { detail::scoped_ptr<Service> svc( new Service(e, BOOST_ASIO_MOVE_CAST(Args)(args)...)); e.service_registry_->template add_service<Service>(svc.get()); Service& result = *svc; svc.release(); return result; } #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename Service> Service& make_service(execution_context& e) { detail::scoped_ptr<Service> svc(new Service(e)); e.service_registry_->template add_service<Service>(svc.get()); Service& result = *svc; svc.release(); return result; } #define BOOST_ASIO_PRIVATE_MAKE_SERVICE_DEF(n) \ template <typename Service, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ Service& make_service(execution_context& e, \ BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ { \ detail::scoped_ptr<Service> svc( \ new Service(e, BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \ e.service_registry_->template add_service<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 <typename Service> inline void add_service(execution_context& e, Service* svc) { // Check that Service meets the necessary type requirements. (void)static_cast<execution_context::service*>(static_cast<Service*>(0)); e.service_registry_->template add_service<Service>(svc); } template <typename Service> inline bool has_service(execution_context& e) { // Check that Service meets the necessary type requirements. (void)static_cast<execution_context::service*>(static_cast<Service*>(0)); return e.service_registry_->template has_service<Service>(); } #endif // !defined(GENERATING_DOCUMENTATION) inline execution_context& execution_context::service::context() { return owner_; } } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_EXECUTION_CONTEXT_HPP impl/connect.hpp 0000644 00000076752 15125530236 0007672 0 ustar 00 // // impl/connect.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <algorithm> #include <boost/asio/associated_allocator.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_tracking.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/post.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { struct default_connect_condition { template <typename Endpoint> bool operator()(const boost::system::error_code&, const Endpoint&) { return true; } }; template <typename Protocol, typename Iterator> inline typename Protocol::endpoint deref_connect_result( Iterator iter, boost::system::error_code& ec) { return ec ? typename Protocol::endpoint() : *iter; } template <typename T, typename Iterator> struct legacy_connect_condition_helper : T { typedef char (*fallback_func_type)(...); operator fallback_func_type() const; }; template <typename R, typename Arg1, typename Arg2, typename Iterator> struct legacy_connect_condition_helper<R (*)(Arg1, Arg2), Iterator> { R operator()(Arg1, Arg2) const; char operator()(...) const; }; template <typename T, typename Iterator> 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<legacy_connect_condition_helper<T, Iterator>*>(0))( *static_cast<const boost::system::error_code*>(0), *static_cast<const Iterator*>(0)))) != 1; }; template <typename ConnectCondition, typename Iterator> inline Iterator call_connect_condition(ConnectCondition& connect_condition, const boost::system::error_code& ec, Iterator next, Iterator end, typename enable_if<is_legacy_connect_condition< ConnectCondition, Iterator>::value>::type* = 0) { if (next != end) return connect_condition(ec, next); return end; } template <typename ConnectCondition, typename Iterator> inline Iterator call_connect_condition(ConnectCondition& connect_condition, const boost::system::error_code& ec, Iterator next, Iterator end, typename enable_if<!is_legacy_connect_condition< ConnectCondition, Iterator>::value>::type* = 0) { for (;next != end; ++next) if (connect_condition(ec, *next)) return next; return end; } } template <typename Protocol, typename Executor, typename EndpointSequence> typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, typename enable_if<is_endpoint_sequence< EndpointSequence>::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, typename Executor, typename EndpointSequence> typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, boost::system::error_code& ec, typename enable_if<is_endpoint_sequence< EndpointSequence>::value>::type*) { return detail::deref_connect_result<Protocol>( connect(s, endpoints.begin(), endpoints.end(), detail::default_connect_condition(), ec), ec); } #if !defined(BOOST_ASIO_NO_DEPRECATED) template <typename Protocol, typename Executor, typename Iterator> Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) { boost::system::error_code ec; Iterator result = connect(s, begin, ec); boost::asio::detail::throw_error(ec, "connect"); return result; } template <typename Protocol, typename Executor, typename Iterator> inline Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, boost::system::error_code& ec, typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) { return connect(s, begin, Iterator(), detail::default_connect_condition(), ec); } #endif // !defined(BOOST_ASIO_NO_DEPRECATED) template <typename Protocol, typename Executor, typename Iterator> Iterator connect(basic_socket<Protocol, Executor>& 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 <typename Protocol, typename Executor, typename Iterator> inline Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end, boost::system::error_code& ec) { return connect(s, begin, end, detail::default_connect_condition(), ec); } template <typename Protocol, typename Executor, typename EndpointSequence, typename ConnectCondition> typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition connect_condition, typename enable_if<is_endpoint_sequence< EndpointSequence>::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, typename Executor, typename EndpointSequence, typename ConnectCondition> typename Protocol::endpoint connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition connect_condition, boost::system::error_code& ec, typename enable_if<is_endpoint_sequence< EndpointSequence>::value>::type*) { return detail::deref_connect_result<Protocol>( connect(s, endpoints.begin(), endpoints.end(), connect_condition, ec), ec); } #if !defined(BOOST_ASIO_NO_DEPRECATED) template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, ConnectCondition connect_condition, typename enable_if<!is_endpoint_sequence<Iterator>::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 <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> inline Iterator connect(basic_socket<Protocol, Executor>& s, Iterator begin, ConnectCondition connect_condition, boost::system::error_code& ec, typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) { return connect(s, begin, Iterator(), connect_condition, ec); } #endif // !defined(BOOST_ASIO_NO_DEPRECATED) template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> Iterator connect(basic_socket<Protocol, Executor>& 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 <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition> Iterator connect(basic_socket<Protocol, Executor>& 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 <typename ConnectCondition> class base_from_connect_condition { protected: explicit base_from_connect_condition( const ConnectCondition& connect_condition) : connect_condition_(connect_condition) { } template <typename Iterator> 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<default_connect_condition> { protected: explicit base_from_connect_condition(const default_connect_condition&) { } template <typename Iterator> void check_condition(const boost::system::error_code&, Iterator&, Iterator&) { } }; template <typename Protocol, typename Executor, typename EndpointSequence, typename ConnectCondition, typename RangeConnectHandler> class range_connect_op : base_from_connect_condition<ConnectCondition> { public: range_connect_op(basic_socket<Protocol, Executor>& sock, const EndpointSequence& endpoints, const ConnectCondition& connect_condition, RangeConnectHandler& handler) : base_from_connect_condition<ConnectCondition>(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<ConnectCondition>(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<ConnectCondition>(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<const EndpointSequence&>(endpoints_).begin(), const_cast<const EndpointSequence&>(endpoints_).end()); } //private: template <typename Iterator> 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); BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect")); socket_.async_connect(*iter, BOOST_ASIO_MOVE_CAST(range_connect_op)(*this)); return; } if (start) { ec = boost::asio::error::not_found; BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect")); 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<const boost::system::error_code&>(ec), static_cast<const typename Protocol::endpoint&>( ec || iter == end ? typename Protocol::endpoint() : *iter)); } } basic_socket<Protocol, Executor>& socket_; EndpointSequence endpoints_; std::size_t index_; int start_; RangeConnectHandler handler_; }; template <typename Protocol, typename Executor, typename EndpointSequence, typename ConnectCondition, typename RangeConnectHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, RangeConnectHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Protocol, typename Executor, typename EndpointSequence, typename ConnectCondition, typename RangeConnectHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, RangeConnectHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Protocol, typename Executor, typename EndpointSequence, typename ConnectCondition, typename RangeConnectHandler> inline bool asio_handler_is_continuation( range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, RangeConnectHandler>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename Executor, typename Protocol, typename EndpointSequence, typename ConnectCondition, typename RangeConnectHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, RangeConnectHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename Executor, typename Protocol, typename EndpointSequence, typename ConnectCondition, typename RangeConnectHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, RangeConnectHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Protocol, typename Executor> class initiate_async_range_connect { public: typedef Executor executor_type; explicit initiate_async_range_connect(basic_socket<Protocol, Executor>& s) : socket_(s) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return socket_.get_executor(); } template <typename RangeConnectHandler, typename EndpointSequence, typename ConnectCondition> void operator()(BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler, 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<RangeConnectHandler> handler2(handler); range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, typename decay<RangeConnectHandler>::type>(socket_, endpoints, connect_condition, handler2.value)(boost::system::error_code(), 1); } private: basic_socket<Protocol, Executor>& socket_; }; template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition, typename IteratorConnectHandler> class iterator_connect_op : base_from_connect_condition<ConnectCondition> { public: iterator_connect_op(basic_socket<Protocol, Executor>& sock, const Iterator& begin, const Iterator& end, const ConnectCondition& connect_condition, IteratorConnectHandler& handler) : base_from_connect_condition<ConnectCondition>(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<ConnectCondition>(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<ConnectCondition>(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); BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect")); socket_.async_connect(*iter_, BOOST_ASIO_MOVE_CAST(iterator_connect_op)(*this)); return; } if (start) { ec = boost::asio::error::not_found; BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_connect")); 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<const boost::system::error_code&>(ec), static_cast<const Iterator&>(iter_)); } } //private: basic_socket<Protocol, Executor>& socket_; Iterator iter_; Iterator end_; int start_; IteratorConnectHandler handler_; }; template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition, typename IteratorConnectHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, IteratorConnectHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition, typename IteratorConnectHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, IteratorConnectHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition, typename IteratorConnectHandler> inline bool asio_handler_is_continuation( iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, IteratorConnectHandler>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename Executor, typename Protocol, typename Iterator, typename ConnectCondition, typename IteratorConnectHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, IteratorConnectHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename Executor, typename Protocol, typename Iterator, typename ConnectCondition, typename IteratorConnectHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, IteratorConnectHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Protocol, typename Executor> class initiate_async_iterator_connect { public: typedef Executor executor_type; explicit initiate_async_iterator_connect( basic_socket<Protocol, Executor>& s) : socket_(s) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return socket_.get_executor(); } template <typename IteratorConnectHandler, typename Iterator, typename ConnectCondition> void operator()(BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, 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<IteratorConnectHandler> handler2(handler); iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, typename decay<IteratorConnectHandler>::type>(socket_, begin, end, connect_condition, handler2.value)(boost::system::error_code(), 1); } private: basic_socket<Protocol, Executor>& socket_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename Protocol, typename Executor, typename EndpointSequence, typename ConnectCondition, typename RangeConnectHandler, typename Allocator> struct associated_allocator< detail::range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, RangeConnectHandler>, Allocator> { typedef typename associated_allocator< RangeConnectHandler, Allocator>::type type; static type get( const detail::range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, RangeConnectHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<RangeConnectHandler, Allocator>::get(h.handler_, a); } }; template <typename Protocol, typename Executor, typename EndpointSequence, typename ConnectCondition, typename RangeConnectHandler, typename Executor1> struct associated_executor< detail::range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, RangeConnectHandler>, Executor1> : detail::associated_executor_forwarding_base<RangeConnectHandler, Executor1> { typedef typename associated_executor< RangeConnectHandler, Executor1>::type type; static type get( const detail::range_connect_op<Protocol, Executor, EndpointSequence, ConnectCondition, RangeConnectHandler>& h, const Executor1& ex = Executor1()) BOOST_ASIO_NOEXCEPT { return associated_executor<RangeConnectHandler, Executor1>::get(h.handler_, ex); } }; template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition, typename IteratorConnectHandler, typename Allocator> struct associated_allocator< detail::iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, IteratorConnectHandler>, Allocator> { typedef typename associated_allocator< IteratorConnectHandler, Allocator>::type type; static type get( const detail::iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, IteratorConnectHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<IteratorConnectHandler, Allocator>::get(h.handler_, a); } }; template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition, typename IteratorConnectHandler, typename Executor1> struct associated_executor< detail::iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, IteratorConnectHandler>, Executor1> : detail::associated_executor_forwarding_base< IteratorConnectHandler, Executor1> { typedef typename associated_executor< IteratorConnectHandler, Executor1>::type type; static type get( const detail::iterator_connect_op<Protocol, Executor, Iterator, ConnectCondition, IteratorConnectHandler>& h, const Executor1& ex = Executor1()) BOOST_ASIO_NOEXCEPT { return associated_executor<IteratorConnectHandler, Executor1>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename Protocol, typename Executor, typename EndpointSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, typename Protocol::endpoint)) RangeConnectHandler> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler, void (boost::system::error_code, typename Protocol::endpoint)) async_connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler, typename enable_if<is_endpoint_sequence< EndpointSequence>::value>::type*) { return async_initiate<RangeConnectHandler, void (boost::system::error_code, typename Protocol::endpoint)>( detail::initiate_async_range_connect<Protocol, Executor>(s), handler, endpoints, detail::default_connect_condition()); } #if !defined(BOOST_ASIO_NO_DEPRECATED) template <typename Protocol, typename Executor, typename Iterator, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, Iterator)) IteratorConnectHandler> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) { return async_initiate<IteratorConnectHandler, void (boost::system::error_code, Iterator)>( detail::initiate_async_iterator_connect<Protocol, Executor>(s), handler, begin, Iterator(), detail::default_connect_condition()); } #endif // !defined(BOOST_ASIO_NO_DEPRECATED) template <typename Protocol, typename Executor, typename Iterator, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, Iterator)) IteratorConnectHandler> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end, BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler) { return async_initiate<IteratorConnectHandler, void (boost::system::error_code, Iterator)>( detail::initiate_async_iterator_connect<Protocol, Executor>(s), handler, begin, end, detail::default_connect_condition()); } template <typename Protocol, typename Executor, typename EndpointSequence, typename ConnectCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, typename Protocol::endpoint)) RangeConnectHandler> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler, void (boost::system::error_code, typename Protocol::endpoint)) async_connect(basic_socket<Protocol, Executor>& s, const EndpointSequence& endpoints, ConnectCondition connect_condition, BOOST_ASIO_MOVE_ARG(RangeConnectHandler) handler, typename enable_if<is_endpoint_sequence< EndpointSequence>::value>::type*) { return async_initiate<RangeConnectHandler, void (boost::system::error_code, typename Protocol::endpoint)>( detail::initiate_async_range_connect<Protocol, Executor>(s), handler, endpoints, connect_condition); } #if !defined(BOOST_ASIO_NO_DEPRECATED) template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, Iterator)) IteratorConnectHandler> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, ConnectCondition connect_condition, BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler, typename enable_if<!is_endpoint_sequence<Iterator>::value>::type*) { return async_initiate<IteratorConnectHandler, void (boost::system::error_code, Iterator)>( detail::initiate_async_iterator_connect<Protocol, Executor>(s), handler, begin, Iterator(), connect_condition); } #endif // !defined(BOOST_ASIO_NO_DEPRECATED) template <typename Protocol, typename Executor, typename Iterator, typename ConnectCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, Iterator)) IteratorConnectHandler> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler, void (boost::system::error_code, Iterator)) async_connect(basic_socket<Protocol, Executor>& s, Iterator begin, Iterator end, ConnectCondition connect_condition, BOOST_ASIO_MOVE_ARG(IteratorConnectHandler) handler) { return async_initiate<IteratorConnectHandler, void (boost::system::error_code, Iterator)>( detail::initiate_async_iterator_connect<Protocol, Executor>(s), handler, begin, end, connect_condition); } } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_CONNECT_HPP impl/awaitable.hpp 0000644 00000026752 15125530236 0010165 0 ustar 00 // // impl/awaitable.hpp // ~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <exception> #include <new> #include <tuple> #include <utility> #include <boost/asio/detail/thread_context.hpp> #include <boost/asio/detail/thread_info_base.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/post.hpp> #include <boost/system/system_error.hpp> #include <boost/asio/this_coro.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Executor> 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<void>) noexcept { this->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 <typename T> auto await_transform(awaitable<T, Executor> 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<void>) 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 <typename Function> auto await_transform(Function f, typename enable_if< is_convertible< typename result_of<Function(awaitable_frame_base*)>::type, awaitable_thread<Executor>* >::value >::type* = 0) { struct result { Function function_; awaitable_frame_base* this_; bool await_ready() const noexcept { return false; } void await_suspend(coroutine_handle<void>) noexcept { function_(this_); } void await_resume() const noexcept { } }; return result{std::move(f), this}; } void attach_thread(awaitable_thread<Executor>* handler) noexcept { attached_thread_ = handler; } awaitable_thread<Executor>* detach_thread() noexcept { return std::exchange(attached_thread_, nullptr); } void push_frame(awaitable_frame_base<Executor>* 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<void> coro_ = nullptr; awaitable_thread<Executor>* attached_thread_ = nullptr; awaitable_frame_base<Executor>* caller_ = nullptr; std::exception_ptr pending_exception_ = nullptr; }; template <typename T, typename Executor> class awaitable_frame : public awaitable_frame_base<Executor> { public: awaitable_frame() noexcept { } awaitable_frame(awaitable_frame&& other) noexcept : awaitable_frame_base<Executor>(std::move(other)) { } ~awaitable_frame() { if (has_result_) static_cast<T*>(static_cast<void*>(result_))->~T(); } awaitable<T, Executor> get_return_object() noexcept { this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this); return awaitable<T, Executor>(this); }; template <typename U> void return_value(U&& u) { new (&result_) T(std::forward<U>(u)); has_result_ = true; } template <typename... Us> void return_values(Us&&... us) { this->return_value(std::forward_as_tuple(std::forward<Us>(us)...)); } T get() { this->caller_ = nullptr; this->rethrow_exception(); return std::move(*static_cast<T*>(static_cast<void*>(result_))); } private: alignas(T) unsigned char result_[sizeof(T)]; bool has_result_ = false; }; template <typename Executor> class awaitable_frame<void, Executor> : public awaitable_frame_base<Executor> { public: awaitable<void, Executor> get_return_object() { this->coro_ = coroutine_handle<awaitable_frame>::from_promise(*this); return awaitable<void, Executor>(this); }; void return_void() { } void get() { this->caller_ = nullptr; this->rethrow_exception(); } }; template <typename Executor> class awaitable_thread { public: typedef Executor executor_type; // Construct from the entry point of a new thread of execution. awaitable_thread(awaitable<void, Executor> 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<void, Executor>(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 <typename> 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<void, Executor> a(std::move(bottom_of_stack_)); a.frame_->rethrow_exception(); } } awaitable<void, Executor> bottom_of_stack_; awaitable_frame_base<Executor>* top_of_stack_; executor_type executor_; }; } // namespace detail } // namespace asio } // namespace boost #if !defined(GENERATING_DOCUMENTATION) # if defined(BOOST_ASIO_HAS_STD_COROUTINE) namespace std { template <typename T, typename Executor, typename... Args> struct coroutine_traits<boost::asio::awaitable<T, Executor>, Args...> { typedef boost::asio::detail::awaitable_frame<T, Executor> promise_type; }; } // namespace std # else // defined(BOOST_ASIO_HAS_STD_COROUTINE) namespace std { namespace experimental { template <typename T, typename Executor, typename... Args> struct coroutine_traits<boost::asio::awaitable<T, Executor>, Args...> { typedef boost::asio::detail::awaitable_frame<T, Executor> promise_type; }; }} // namespace std::experimental # endif // defined(BOOST_ASIO_HAS_STD_COROUTINE) #endif // !defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_AWAITABLE_HPP impl/serial_port_base.ipp 0000644 00000032017 15125530236 0011541 0 ustar 00 // // impl/serial_port_base.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_SERIAL_PORT) #include <stdexcept> #include <boost/asio/error.hpp> #include <boost/asio/serial_port_base.hpp> #include <boost/asio/detail/throw_exception.hpp> #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 <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #undef BOOST_ASIO_OPTION_STORAGE #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) #endif // BOOST_ASIO_IMPL_SERIAL_PORT_BASE_IPP impl/compose.hpp 0000644 00000047755 15125530236 0007707 0 ustar 00 // // impl/compose.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/variadic_templates.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/outstanding_work.hpp> #include <boost/asio/executor_work_guard.hpp> #include <boost/asio/is_executor.hpp> #include <boost/asio/system_executor.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Executor, typename = void> class composed_work_guard { public: typedef typename decay< typename prefer_result<Executor, execution::outstanding_work_t::tracked_t >::type >::type executor_type; composed_work_guard(const Executor& ex) : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) { } void reset() { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return executor_; } private: executor_type executor_; }; #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) template <typename Executor> struct composed_work_guard<Executor, typename enable_if< !execution::is_executor<Executor>::value >::type> : executor_work_guard<Executor> { composed_work_guard(const Executor& ex) : executor_work_guard<Executor>(ex) { } }; #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) template <typename> struct composed_io_executors; template <> struct composed_io_executors<void()> { composed_io_executors() BOOST_ASIO_NOEXCEPT : head_(system_executor()) { } typedef system_executor head_type; system_executor head_; }; inline composed_io_executors<void()> make_composed_io_executors() { return composed_io_executors<void()>(); } template <typename Head> struct composed_io_executors<void(Head)> { explicit composed_io_executors(const Head& ex) BOOST_ASIO_NOEXCEPT : head_(ex) { } typedef Head head_type; Head head_; }; template <typename Head> inline composed_io_executors<void(Head)> make_composed_io_executors(const Head& head) { return composed_io_executors<void(Head)>(head); } #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename Head, typename... Tail> struct composed_io_executors<void(Head, Tail...)> { explicit composed_io_executors(const Head& head, const Tail&... tail) BOOST_ASIO_NOEXCEPT : head_(head), tail_(tail...) { } void reset() { head_.reset(); tail_.reset(); } typedef Head head_type; Head head_; composed_io_executors<void(Tail...)> tail_; }; template <typename Head, typename... Tail> inline composed_io_executors<void(Head, Tail...)> make_composed_io_executors(const Head& head, const Tail&... tail) { return composed_io_executors<void(Head, Tail...)>(head, tail...); } #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #define BOOST_ASIO_PRIVATE_COMPOSED_IO_EXECUTORS_DEF(n) \ template <typename Head, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ struct composed_io_executors<void(Head, BOOST_ASIO_VARIADIC_TARGS(n))> \ { \ explicit composed_io_executors(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; \ Head head_; \ composed_io_executors<void(BOOST_ASIO_VARIADIC_TARGS(n))> tail_; \ }; \ \ template <typename Head, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ inline composed_io_executors<void(Head, BOOST_ASIO_VARIADIC_TARGS(n))> \ make_composed_io_executors(const Head& head, \ BOOST_ASIO_VARIADIC_CONSTREF_PARAMS(n)) \ { \ return composed_io_executors< \ void(Head, BOOST_ASIO_VARIADIC_TARGS(n))>( \ head, BOOST_ASIO_VARIADIC_BYVAL_ARGS(n)); \ } \ /**/ BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_COMPOSED_IO_EXECUTORS_DEF) #undef BOOST_ASIO_PRIVATE_COMPOSED_IO_EXECUTORS_DEF #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename> struct composed_work; template <> struct composed_work<void()> { typedef composed_io_executors<void()> executors_type; composed_work(const executors_type&) BOOST_ASIO_NOEXCEPT : head_(system_executor()) { } void reset() { head_.reset(); } typedef system_executor head_type; composed_work_guard<system_executor> head_; }; template <typename Head> struct composed_work<void(Head)> { typedef composed_io_executors<void(Head)> executors_type; explicit composed_work(const executors_type& ex) BOOST_ASIO_NOEXCEPT : head_(ex.head_) { } void reset() { head_.reset(); } typedef Head head_type; composed_work_guard<Head> head_; }; #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename Head, typename... Tail> struct composed_work<void(Head, Tail...)> { typedef composed_io_executors<void(Head, Tail...)> executors_type; explicit composed_work(const executors_type& ex) BOOST_ASIO_NOEXCEPT : head_(ex.head_), tail_(ex.tail_) { } void reset() { head_.reset(); tail_.reset(); } typedef Head head_type; composed_work_guard<Head> head_; composed_work<void(Tail...)> tail_; }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #define BOOST_ASIO_PRIVATE_COMPOSED_WORK_DEF(n) \ template <typename Head, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ struct composed_work<void(Head, BOOST_ASIO_VARIADIC_TARGS(n))> \ { \ typedef composed_io_executors<void(Head, \ BOOST_ASIO_VARIADIC_TARGS(n))> executors_type; \ \ explicit composed_work(const executors_type& ex) BOOST_ASIO_NOEXCEPT \ : head_(ex.head_), \ tail_(ex.tail_) \ { \ } \ \ void reset() \ { \ head_.reset(); \ tail_.reset(); \ } \ \ typedef Head head_type; \ composed_work_guard<Head> head_; \ composed_work<void(BOOST_ASIO_VARIADIC_TARGS(n))> tail_; \ }; \ /**/ 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 <typename Impl, typename Work, typename Handler, typename Signature> class composed_op; template <typename Impl, typename Work, typename Handler, typename R, typename... Args> class composed_op<Impl, Work, Handler, R(Args...)> #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename Impl, typename Work, typename Handler, typename Signature> class composed_op #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) { public: template <typename I, typename W, typename H> composed_op(BOOST_ASIO_MOVE_ARG(I) impl, BOOST_ASIO_MOVE_ARG(W) work, BOOST_ASIO_MOVE_ARG(H) handler) : impl_(BOOST_ASIO_MOVE_CAST(I)(impl)), work_(BOOST_ASIO_MOVE_CAST(W)(work)), handler_(BOOST_ASIO_MOVE_CAST(H)(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<Handler, typename composed_work_guard< typename Work::head_type >::executor_type >::type executor_type; executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return (get_associated_executor)(handler_, work_.head_.get_executor()); } typedef typename associated_allocator<Handler, std::allocator<void> >::type allocator_type; allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT { return (get_associated_allocator)(handler_, std::allocator<void>()); } #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template<typename... T> void operator()(BOOST_ASIO_MOVE_ARG(T)... t) { if (invocations_ < ~0u) ++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_ < ~0u) ++invocations_; impl_(*this); } void complete() { this->work_.reset(); this->handler_(); } #define BOOST_ASIO_PRIVATE_COMPOSED_OP_DEF(n) \ template<BOOST_ASIO_VARIADIC_TPARAMS(n)> \ void operator()(BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ { \ if (invocations_ < ~0u) \ ++invocations_; \ impl_(*this, BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ } \ \ template<BOOST_ASIO_VARIADIC_TPARAMS(n)> \ 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 <typename Impl, typename Work, typename Handler, typename Signature> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, composed_op<Impl, Work, Handler, Signature>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Impl, typename Work, typename Handler, typename Signature> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, composed_op<Impl, Work, Handler, Signature>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Impl, typename Work, typename Handler, typename Signature> inline bool asio_handler_is_continuation( composed_op<Impl, Work, Handler, Signature>* this_handler) { return this_handler->invocations_ > 1 ? true : boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename Impl, typename Work, typename Handler, typename Signature> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, composed_op<Impl, Work, Handler, Signature>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename Impl, typename Work, typename Handler, typename Signature> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, composed_op<Impl, Work, Handler, Signature>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Signature, typename Executors> class initiate_composed_op { public: typedef typename composed_io_executors<Executors>::head_type executor_type; template <typename T> explicit initiate_composed_op(int, BOOST_ASIO_MOVE_ARG(T) executors) : executors_(BOOST_ASIO_MOVE_CAST(T)(executors)) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return executors_.head_; } template <typename Handler, typename Impl> void operator()(BOOST_ASIO_MOVE_ARG(Handler) handler, BOOST_ASIO_MOVE_ARG(Impl) impl) const { composed_op<typename decay<Impl>::type, composed_work<Executors>, typename decay<Handler>::type, Signature>( BOOST_ASIO_MOVE_CAST(Impl)(impl), composed_work<Executors>(executors_), BOOST_ASIO_MOVE_CAST(Handler)(handler))(); } private: composed_io_executors<Executors> executors_; }; template <typename Signature, typename Executors> inline initiate_composed_op<Signature, Executors> make_initiate_composed_op( BOOST_ASIO_MOVE_ARG(composed_io_executors<Executors>) executors) { return initiate_composed_op<Signature, Executors>(0, BOOST_ASIO_MOVE_CAST(composed_io_executors<Executors>)(executors)); } template <typename IoObject> inline typename IoObject::executor_type get_composed_io_executor(IoObject& io_object, typename enable_if< !is_executor<IoObject>::value && !execution::is_executor<IoObject>::value >::type* = 0) { return io_object.get_executor(); } template <typename Executor> inline const Executor& get_composed_io_executor(const Executor& ex, typename enable_if< is_executor<Executor>::value || execution::is_executor<Executor>::value >::type* = 0) { return ex; } } // namespace detail #if !defined(GENERATING_DOCUMENTATION) #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename CompletionToken, typename Signature, typename Implementation, typename... IoObjectsOrExecutors> BOOST_ASIO_INITFN_AUTO_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<CompletionToken, Signature>( detail::make_initiate_composed_op<Signature>( detail::make_composed_io_executors( detail::get_composed_io_executor( BOOST_ASIO_MOVE_CAST(IoObjectsOrExecutors)( io_objects_or_executors))...)), token, BOOST_ASIO_MOVE_CAST(Implementation)(implementation)); } #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename CompletionToken, typename Signature, typename Implementation> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature) async_compose(BOOST_ASIO_MOVE_ARG(Implementation) implementation, BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token) { return async_initiate<CompletionToken, Signature>( detail::make_initiate_composed_op<Signature>( detail::make_composed_io_executors()), token, BOOST_ASIO_MOVE_CAST(Implementation)(implementation)); } # 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_GET_COMPOSED_IO_EXECUTOR_6 \ 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)), \ detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T6)(x6)) # define BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_7 \ 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)), \ detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T6)(x6)), \ detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T7)(x7)) # define BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_8 \ 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)), \ detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T6)(x6)), \ detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T7)(x7)), \ detail::get_composed_io_executor(BOOST_ASIO_MOVE_CAST(T8)(x8)) #define BOOST_ASIO_PRIVATE_ASYNC_COMPOSE_DEF(n) \ template <typename CompletionToken, typename Signature, \ typename Implementation, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ BOOST_ASIO_INITFN_AUTO_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<CompletionToken, Signature>( \ detail::make_initiate_composed_op<Signature>( \ detail::make_composed_io_executors( \ BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR(n))), \ token, BOOST_ASIO_MOVE_CAST(Implementation)(implementation)); \ } \ /**/ 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 #undef BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_6 #undef BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_7 #undef BOOST_ASIO_PRIVATE_GET_COMPOSED_IO_EXECUTOR_8 #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #endif // !defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_COMPOSE_HPP impl/execution_context.ipp 0000644 00000003411 15125530236 0011767 0 ustar 00 // // impl/execution_context.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/detail/service_registry.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_EXECUTION_CONTEXT_IPP impl/write.hpp 0000644 00000120163 15125530236 0007355 0 ustar 00 // // impl/write.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/associated_allocator.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/completion_condition.hpp> #include <boost/asio/detail/array_fwd.hpp> #include <boost/asio/detail/base_from_completion_cond.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/consuming_buffers.hpp> #include <boost/asio/detail/dependent_type.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_tracking.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename SyncWriteStream, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition> 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<const_buffer, ConstBufferSequence, ConstBufferIterator> 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 <typename SyncWriteStream, typename ConstBufferSequence, typename CompletionCondition> 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<ConstBufferSequence>::value >::type*) { return detail::write_buffer_sequence(s, buffers, boost::asio::buffer_sequence_begin(buffers), BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); } template <typename SyncWriteStream, typename ConstBufferSequence> inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, typename enable_if< is_const_buffer_sequence<ConstBufferSequence>::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 <typename SyncWriteStream, typename ConstBufferSequence> inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, boost::system::error_code& ec, typename enable_if< is_const_buffer_sequence<ConstBufferSequence>::value >::type*) { return write(s, buffers, transfer_all(), ec); } template <typename SyncWriteStream, typename ConstBufferSequence, typename CompletionCondition> inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, typename enable_if< is_const_buffer_sequence<ConstBufferSequence>::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 <typename SyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition> 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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { typename decay<DynamicBuffer_v1>::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 <typename SyncWriteStream, typename DynamicBuffer_v1> inline std::size_t write(SyncWriteStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, typename enable_if< is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncWriteStream, typename DynamicBuffer_v1> 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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { return write(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), transfer_all(), ec); } template <typename SyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition> inline std::size_t write(SyncWriteStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, CompletionCondition completion_condition, typename enable_if< is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncWriteStream, typename Allocator, typename CompletionCondition> inline std::size_t write(SyncWriteStream& s, boost::asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition, boost::system::error_code& ec) { return write(s, basic_streambuf_ref<Allocator>(b), BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); } template <typename SyncWriteStream, typename Allocator> inline std::size_t write(SyncWriteStream& s, boost::asio::basic_streambuf<Allocator>& b) { return write(s, basic_streambuf_ref<Allocator>(b)); } template <typename SyncWriteStream, typename Allocator> inline std::size_t write(SyncWriteStream& s, boost::asio::basic_streambuf<Allocator>& b, boost::system::error_code& ec) { return write(s, basic_streambuf_ref<Allocator>(b), ec); } template <typename SyncWriteStream, typename Allocator, typename CompletionCondition> inline std::size_t write(SyncWriteStream& s, boost::asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition) { return write(s, basic_streambuf_ref<Allocator>(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 <typename SyncWriteStream, typename DynamicBuffer_v2, typename CompletionCondition> std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, CompletionCondition completion_condition, boost::system::error_code& ec, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <typename SyncWriteStream, typename DynamicBuffer_v2> inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <typename SyncWriteStream, typename DynamicBuffer_v2> inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, boost::system::error_code& ec, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_v2>::value >::type*) { return write(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), transfer_all(), ec); } template <typename SyncWriteStream, typename DynamicBuffer_v2, typename CompletionCondition> inline std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, CompletionCondition completion_condition, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <typename AsyncWriteStream, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> class write_op : detail::base_from_completion_cond<CompletionCondition> { 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<CompletionCondition>(other), stream_(other.stream_), buffers_(other.buffers_), start_(other.start_), handler_(other.handler_) { } write_op(write_op&& other) : detail::base_from_completion_cond<CompletionCondition>( 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 { { BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_write")); 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<const_buffer, ConstBufferSequence, ConstBufferIterator> buffers_type; AsyncWriteStream& stream_; buffers_type buffers_; int start_; WriteHandler handler_; }; template <typename AsyncWriteStream, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncWriteStream, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncWriteStream, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> inline bool asio_handler_is_continuation( write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename AsyncWriteStream, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename AsyncWriteStream, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncWriteStream, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> inline void start_write_buffer_sequence_op(AsyncWriteStream& stream, const ConstBufferSequence& buffers, const ConstBufferIterator&, CompletionCondition& completion_condition, WriteHandler& handler) { detail::write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>( stream, buffers, completion_condition, handler)( boost::system::error_code(), 0, 1); } template <typename AsyncWriteStream> class initiate_async_write_buffer_sequence { public: typedef typename AsyncWriteStream::executor_type executor_type; explicit initiate_async_write_buffer_sequence(AsyncWriteStream& stream) : stream_(stream) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return stream_.get_executor(); } template <typename WriteHandler, typename ConstBufferSequence, typename CompletionCondition> void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, 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<WriteHandler> handler2(handler); non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); start_write_buffer_sequence_op(stream_, buffers, boost::asio::buffer_sequence_begin(buffers), completion_cond2.value, handler2.value); } private: AsyncWriteStream& stream_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename AsyncWriteStream, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler, typename Allocator> struct associated_allocator< detail::write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>, Allocator> { typedef typename associated_allocator<WriteHandler, Allocator>::type type; static type get( const detail::write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); } }; template <typename AsyncWriteStream, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler, typename Executor> struct associated_executor< detail::write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>, Executor> : detail::associated_executor_forwarding_base<WriteHandler, Executor> { typedef typename associated_executor<WriteHandler, Executor>::type type; static type get( const detail::write_op<AsyncWriteStream, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncWriteStream, typename ConstBufferSequence, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler> inline BOOST_ASIO_INITFN_AUTO_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<ConstBufferSequence>::value >::type*) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_write_buffer_sequence<AsyncWriteStream>(s), handler, buffers, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } template <typename AsyncWriteStream, typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler> inline BOOST_ASIO_INITFN_AUTO_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<ConstBufferSequence>::value >::type*) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_write_buffer_sequence<AsyncWriteStream>(s), handler, buffers, transfer_all()); } #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) namespace detail { template <typename AsyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition, typename WriteHandler> class write_dynbuf_v1_op { public: template <typename BufferSequence> 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<const std::size_t&>(bytes_transferred)); } } //private: AsyncWriteStream& stream_; DynamicBuffer_v1 buffers_; CompletionCondition completion_condition_; WriteHandler handler_; }; template <typename AsyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition, typename WriteHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1, CompletionCondition, WriteHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition, typename WriteHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition, typename WriteHandler> inline bool asio_handler_is_continuation( write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1, CompletionCondition, WriteHandler>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename AsyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition, typename WriteHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename AsyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition, typename WriteHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncWriteStream> class initiate_async_write_dynbuf_v1 { public: typedef typename AsyncWriteStream::executor_type executor_type; explicit initiate_async_write_dynbuf_v1(AsyncWriteStream& stream) : stream_(stream) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return stream_.get_executor(); } template <typename WriteHandler, typename DynamicBuffer_v1, typename CompletionCondition> void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, 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<WriteHandler> handler2(handler); non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); write_dynbuf_v1_op<AsyncWriteStream, typename decay<DynamicBuffer_v1>::type, CompletionCondition, typename decay<WriteHandler>::type>( stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), completion_cond2.value, handler2.value)( boost::system::error_code(), 0, 1); } private: AsyncWriteStream& stream_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename AsyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition, typename WriteHandler, typename Allocator> struct associated_allocator< detail::write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1, CompletionCondition, WriteHandler>, Allocator> { typedef typename associated_allocator<WriteHandler, Allocator>::type type; static type get( const detail::write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1, CompletionCondition, WriteHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); } }; template <typename AsyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition, typename WriteHandler, typename Executor> struct associated_executor< detail::write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1, CompletionCondition, WriteHandler>, Executor> : detail::associated_executor_forwarding_base<WriteHandler, Executor> { typedef typename associated_executor<WriteHandler, Executor>::type type; static type get( const detail::write_dynbuf_v1_op<AsyncWriteStream, DynamicBuffer_v1, CompletionCondition, WriteHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncWriteStream, typename DynamicBuffer_v1, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler> inline BOOST_ASIO_INITFN_AUTO_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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { return async_write(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), transfer_all(), BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); } template <typename AsyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler> inline BOOST_ASIO_INITFN_AUTO_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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_write_dynbuf_v1<AsyncWriteStream>(s), handler, 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 <typename AsyncWriteStream, typename Allocator, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, boost::asio::basic_streambuf<Allocator>& b, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { return async_write(s, basic_streambuf_ref<Allocator>(b), BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); } template <typename AsyncWriteStream, typename Allocator, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, boost::asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { return async_write(s, basic_streambuf_ref<Allocator>(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 <typename AsyncWriteStream, typename DynamicBuffer_v2, typename CompletionCondition, typename WriteHandler> class write_dynbuf_v2_op { public: template <typename BufferSequence> 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<const std::size_t&>(bytes_transferred)); } } //private: AsyncWriteStream& stream_; DynamicBuffer_v2 buffers_; CompletionCondition completion_condition_; WriteHandler handler_; }; template <typename AsyncWriteStream, typename DynamicBuffer_v2, typename CompletionCondition, typename WriteHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2, CompletionCondition, WriteHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncWriteStream, typename DynamicBuffer_v2, typename CompletionCondition, typename WriteHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncWriteStream, typename DynamicBuffer_v2, typename CompletionCondition, typename WriteHandler> inline bool asio_handler_is_continuation( write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2, CompletionCondition, WriteHandler>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename AsyncWriteStream, typename DynamicBuffer_v2, typename CompletionCondition, typename WriteHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename AsyncWriteStream, typename DynamicBuffer_v2, typename CompletionCondition, typename WriteHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncWriteStream> class initiate_async_write_dynbuf_v2 { public: typedef typename AsyncWriteStream::executor_type executor_type; explicit initiate_async_write_dynbuf_v2(AsyncWriteStream& stream) : stream_(stream) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return stream_.get_executor(); } template <typename WriteHandler, typename DynamicBuffer_v2, typename CompletionCondition> void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, 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<WriteHandler> handler2(handler); non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); write_dynbuf_v2_op<AsyncWriteStream, typename decay<DynamicBuffer_v2>::type, CompletionCondition, typename decay<WriteHandler>::type>( stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), completion_cond2.value, handler2.value)( boost::system::error_code(), 0, 1); } private: AsyncWriteStream& stream_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename AsyncWriteStream, typename DynamicBuffer_v2, typename CompletionCondition, typename WriteHandler, typename Allocator> struct associated_allocator< detail::write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2, CompletionCondition, WriteHandler>, Allocator> { typedef typename associated_allocator<WriteHandler, Allocator>::type type; static type get( const detail::write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2, CompletionCondition, WriteHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); } }; template <typename AsyncWriteStream, typename DynamicBuffer_v2, typename CompletionCondition, typename WriteHandler, typename Executor> struct associated_executor< detail::write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2, CompletionCondition, WriteHandler>, Executor> : detail::associated_executor_forwarding_base<WriteHandler, Executor> { typedef typename associated_executor<WriteHandler, Executor>::type type; static type get( const detail::write_dynbuf_v2_op<AsyncWriteStream, DynamicBuffer_v2, CompletionCondition, WriteHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncWriteStream, typename DynamicBuffer_v2, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler> inline BOOST_ASIO_INITFN_AUTO_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<DynamicBuffer_v2>::value >::type*) { return async_write(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), transfer_all(), BOOST_ASIO_MOVE_CAST(WriteHandler)(handler)); } template <typename AsyncWriteStream, typename DynamicBuffer_v2, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler> inline BOOST_ASIO_INITFN_AUTO_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<DynamicBuffer_v2>::value >::type*) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_write_dynbuf_v2<AsyncWriteStream>(s), handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_WRITE_HPP impl/error.ipp 0000644 00000005776 15125530236 0007371 0 ustar 00 // // impl/error.ipp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <string> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_ERROR_IPP impl/post.hpp 0000644 00000017122 15125530236 0007210 0 ustar 00 // // impl/post.hpp // ~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/associated_allocator.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/detail/work_dispatcher.hpp> #include <boost/asio/execution/allocator.hpp> #include <boost/asio/execution/blocking.hpp> #include <boost/asio/execution/relationship.hpp> #include <boost/asio/prefer.hpp> #include <boost/asio/require.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class initiate_post { public: template <typename CompletionHandler> void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, typename enable_if< execution::is_executor< typename associated_executor< typename decay<CompletionHandler>::type >::type >::value >::type* = 0) const { typedef typename decay<CompletionHandler>::type handler_t; typename associated_executor<handler_t>::type ex( (get_associated_executor)(handler)); typename associated_allocator<handler_t>::type alloc( (get_associated_allocator)(handler)); execution::execute( boost::asio::prefer( boost::asio::require(ex, execution::blocking.never), execution::relationship.fork, execution::allocator(alloc)), BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); } template <typename CompletionHandler> void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, typename enable_if< !execution::is_executor< typename associated_executor< typename decay<CompletionHandler>::type >::type >::value >::type* = 0) const { typedef typename decay<CompletionHandler>::type handler_t; typename associated_executor<handler_t>::type ex( (get_associated_executor)(handler)); typename associated_allocator<handler_t>::type alloc( (get_associated_allocator)(handler)); ex.post(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); } }; template <typename Executor> class initiate_post_with_executor { public: typedef Executor executor_type; explicit initiate_post_with_executor(const Executor& ex) : ex_(ex) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return ex_; } template <typename CompletionHandler> void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, typename enable_if< execution::is_executor< typename conditional<true, executor_type, CompletionHandler>::type >::value && !detail::is_work_dispatcher_required< typename decay<CompletionHandler>::type, Executor >::value >::type* = 0) const { typedef typename decay<CompletionHandler>::type handler_t; typename associated_allocator<handler_t>::type alloc( (get_associated_allocator)(handler)); execution::execute( boost::asio::prefer( boost::asio::require(ex_, execution::blocking.never), execution::relationship.fork, execution::allocator(alloc)), BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); } template <typename CompletionHandler> void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, typename enable_if< execution::is_executor< typename conditional<true, executor_type, CompletionHandler>::type >::value && detail::is_work_dispatcher_required< typename decay<CompletionHandler>::type, Executor >::value >::type* = 0) const { typedef typename decay<CompletionHandler>::type handler_t; typedef typename associated_executor< handler_t, Executor>::type handler_ex_t; handler_ex_t handler_ex((get_associated_executor)(handler, ex_)); typename associated_allocator<handler_t>::type alloc( (get_associated_allocator)(handler)); execution::execute( boost::asio::prefer( boost::asio::require(ex_, execution::blocking.never), execution::relationship.fork, execution::allocator(alloc)), detail::work_dispatcher<handler_t, handler_ex_t>( BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), handler_ex)); } template <typename CompletionHandler> void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, typename enable_if< !execution::is_executor< typename conditional<true, executor_type, CompletionHandler>::type >::value && !detail::is_work_dispatcher_required< typename decay<CompletionHandler>::type, Executor >::value >::type* = 0) const { typedef typename decay<CompletionHandler>::type handler_t; typename associated_allocator<handler_t>::type alloc( (get_associated_allocator)(handler)); ex_.post(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); } template <typename CompletionHandler> void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, typename enable_if< !execution::is_executor< typename conditional<true, executor_type, CompletionHandler>::type >::value && detail::is_work_dispatcher_required< typename decay<CompletionHandler>::type, Executor >::value >::type* = 0) const { typedef typename decay<CompletionHandler>::type handler_t; typedef typename associated_executor< handler_t, Executor>::type handler_ex_t; handler_ex_t handler_ex((get_associated_executor)(handler, ex_)); typename associated_allocator<handler_t>::type alloc( (get_associated_allocator)(handler)); ex_.post(detail::work_dispatcher<handler_t, handler_ex_t>( BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), handler_ex), alloc); } private: Executor ex_; }; } // namespace detail template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post( BOOST_ASIO_MOVE_ARG(CompletionToken) token) { return async_initiate<CompletionToken, void()>( detail::initiate_post(), token); } template <typename Executor, BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post( const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, typename enable_if< execution::is_executor<Executor>::value || is_executor<Executor>::value >::type*) { return async_initiate<CompletionToken, void()>( detail::initiate_post_with_executor<Executor>(ex), token); } template <typename ExecutionContext, BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post( ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, typename enable_if<is_convertible< ExecutionContext&, execution_context&>::value>::type*) { return async_initiate<CompletionToken, void()>( detail::initiate_post_with_executor< typename ExecutionContext::executor_type>( ctx.get_executor()), token); } } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_POST_HPP impl/serial_port_base.hpp 0000644 00000002537 15125530236 0011544 0 ustar 00 // // impl/serial_port_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_SERIAL_PORT_BASE_HPP impl/buffered_write_stream.hpp 0000644 00000040275 15125530236 0012577 0 ustar 00 // // impl/buffered_write_stream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/associated_allocator.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { template <typename Stream> std::size_t buffered_write_stream<Stream>::flush() { std::size_t bytes_written = write(next_layer_, buffer(storage_.data(), storage_.size())); storage_.consume(bytes_written); return bytes_written; } template <typename Stream> std::size_t buffered_write_stream<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 <typename WriteHandler> 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 <typename WriteHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, buffered_flush_handler<WriteHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename WriteHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, buffered_flush_handler<WriteHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename WriteHandler> inline bool asio_handler_is_continuation( buffered_flush_handler<WriteHandler>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename WriteHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, buffered_flush_handler<WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename WriteHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, buffered_flush_handler<WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Stream> class initiate_async_buffered_flush { public: typedef typename remove_reference< Stream>::type::lowest_layer_type::executor_type executor_type; explicit initiate_async_buffered_flush( typename remove_reference<Stream>::type& next_layer) : next_layer_(next_layer) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return next_layer_.lowest_layer().get_executor(); } template <typename WriteHandler> void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, buffered_stream_storage* storage) 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<WriteHandler> handler2(handler); async_write(next_layer_, buffer(storage->data(), storage->size()), buffered_flush_handler<typename decay<WriteHandler>::type>( *storage, handler2.value)); } private: typename remove_reference<Stream>::type& next_layer_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename WriteHandler, typename Allocator> struct associated_allocator< detail::buffered_flush_handler<WriteHandler>, Allocator> { typedef typename associated_allocator<WriteHandler, Allocator>::type type; static type get(const detail::buffered_flush_handler<WriteHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); } }; template <typename WriteHandler, typename Executor> struct associated_executor< detail::buffered_flush_handler<WriteHandler>, Executor> : detail::associated_executor_forwarding_base<WriteHandler, Executor> { typedef typename associated_executor<WriteHandler, Executor>::type type; static type get(const detail::buffered_flush_handler<WriteHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename Stream> template < BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) buffered_write_stream<Stream>::async_flush( BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_buffered_flush<Stream>(next_layer_), handler, &storage_); } template <typename Stream> template <typename ConstBufferSequence> std::size_t buffered_write_stream<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 <typename Stream> template <typename ConstBufferSequence> std::size_t buffered_write_stream<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 <typename ConstBufferSequence, typename WriteHandler> 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 <typename ConstBufferSequence, typename WriteHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, buffered_write_some_handler< ConstBufferSequence, WriteHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename ConstBufferSequence, typename WriteHandler> inline asio_handler_deallocate_is_deprecated 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_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename ConstBufferSequence, typename WriteHandler> 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 <typename Function, typename ConstBufferSequence, typename WriteHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, buffered_write_some_handler< ConstBufferSequence, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename ConstBufferSequence, typename WriteHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, buffered_write_some_handler< ConstBufferSequence, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Stream> class initiate_async_buffered_write_some { public: typedef typename remove_reference< Stream>::type::lowest_layer_type::executor_type executor_type; explicit initiate_async_buffered_write_some( typename remove_reference<Stream>::type& next_layer) : next_layer_(next_layer) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return next_layer_.lowest_layer().get_executor(); } template <typename WriteHandler, typename ConstBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, buffered_stream_storage* storage, 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<WriteHandler> 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<ConstBufferSequence, typename decay<WriteHandler>::type>( *storage, buffers, handler2.value)); } else { initiate_async_buffered_flush<Stream>(this->next_layer_)( buffered_write_some_handler<ConstBufferSequence, typename decay<WriteHandler>::type>( *storage, buffers, handler2.value), storage); } } private: typename remove_reference<Stream>::type& next_layer_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename ConstBufferSequence, typename WriteHandler, typename Allocator> struct associated_allocator< detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>, Allocator> { typedef typename associated_allocator<WriteHandler, 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<WriteHandler, Allocator>::get(h.handler_, a); } }; template <typename ConstBufferSequence, typename WriteHandler, typename Executor> struct associated_executor< detail::buffered_write_some_handler<ConstBufferSequence, WriteHandler>, Executor> : detail::associated_executor_forwarding_base<WriteHandler, Executor> { typedef typename associated_executor<WriteHandler, 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<WriteHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename Stream> template <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) buffered_write_stream<Stream>::async_write_some( const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_buffered_write_some<Stream>(next_layer_), handler, &storage_, buffers); } template <typename Stream> template <typename ConstBufferSequence> std::size_t buffered_write_stream<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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_BUFFERED_WRITE_STREAM_HPP impl/handler_alloc_hook.ipp 0000644 00000003700 15125530236 0012030 0 ustar 00 // // impl/handler_alloc_hook.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/thread_context.hpp> #include <boost/asio/detail/thread_info_base.hpp> #include <boost/asio/handler_alloc_hook.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, ...) { #if defined(BOOST_ASIO_NO_DEPRECATED) (void)size; return asio_handler_allocate_is_no_longer_used(); #elif !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) } asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, ...) { #if defined(BOOST_ASIO_NO_DEPRECATED) (void)pointer; (void)size; return asio_handler_deallocate_is_no_longer_used(); #elif !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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_HANDLER_ALLOC_HOOK_IPP impl/thread_pool.hpp 0000644 00000025145 15125530236 0010527 0 ustar 00 // // impl/thread_pool.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/blocking_executor_op.hpp> #include <boost/asio/detail/bulk_executor_op.hpp> #include <boost/asio/detail/executor_op.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/recycling_allocator.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { inline thread_pool::executor_type thread_pool::get_executor() BOOST_ASIO_NOEXCEPT { return executor_type(*this); } inline thread_pool::executor_type thread_pool::executor() BOOST_ASIO_NOEXCEPT { return executor_type(*this); } inline thread_pool::scheduler_type thread_pool::scheduler() BOOST_ASIO_NOEXCEPT { return scheduler_type(*this); } template <typename Allocator, unsigned int Bits> thread_pool::basic_executor_type<Allocator, Bits>& thread_pool::basic_executor_type<Allocator, Bits>::operator=( const basic_executor_type& other) BOOST_ASIO_NOEXCEPT { if (this != &other) { thread_pool* old_thread_pool = pool_; pool_ = other.pool_; allocator_ = other.allocator_; bits_ = other.bits_; if (Bits & outstanding_work_tracked) { if (pool_) pool_->scheduler_.work_started(); if (old_thread_pool) old_thread_pool->scheduler_.work_finished(); } } return *this; } #if defined(BOOST_ASIO_HAS_MOVE) template <typename Allocator, unsigned int Bits> thread_pool::basic_executor_type<Allocator, Bits>& thread_pool::basic_executor_type<Allocator, Bits>::operator=( basic_executor_type&& other) BOOST_ASIO_NOEXCEPT { if (this != &other) { pool_ = other.pool_; allocator_ = std::move(other.allocator_); bits_ = other.bits_; if (Bits & outstanding_work_tracked) other.pool_ = 0; } return *this; } #endif // defined(BOOST_ASIO_HAS_MOVE) template <typename Allocator, unsigned int Bits> inline bool thread_pool::basic_executor_type<Allocator, Bits>::running_in_this_thread() const BOOST_ASIO_NOEXCEPT { return pool_->scheduler_.can_dispatch(); } template <typename Allocator, unsigned int Bits> template <typename Function> void thread_pool::basic_executor_type<Allocator, Bits>::do_execute(BOOST_ASIO_MOVE_ARG(Function) f, false_type) const { typedef typename decay<Function>::type function_type; // Invoke immediately if the blocking.possibly property is enabled and we are // already inside the thread pool. if ((bits_ & blocking_never) == 0 && pool_->scheduler_.can_dispatch()) { // Make a local, non-const copy of the function. function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ && !defined(BOOST_ASIO_NO_EXCEPTIONS) try { #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) // && !defined(BOOST_ASIO_NO_EXCEPTIONS) detail::fenced_block b(detail::fenced_block::full); boost_asio_handler_invoke_helpers::invoke(tmp, tmp); return; #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ && !defined(BOOST_ASIO_NO_EXCEPTIONS) } catch (...) { pool_->scheduler_.capture_current_exception(); return; } #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) // && !defined(BOOST_ASIO_NO_EXCEPTIONS) } // Allocate and construct an operation to wrap the function. typedef detail::executor_op<function_type, Allocator> op; typename op::ptr p = { detail::addressof(allocator_), op::ptr::allocate(allocator_), 0 }; p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), allocator_); if ((bits_ & relationship_continuation) != 0) { BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p, "thread_pool", pool_, 0, "execute(blk=never,rel=cont)")); } else { BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p, "thread_pool", pool_, 0, "execute(blk=never,rel=fork)")); } pool_->scheduler_.post_immediate_completion(p.p, (bits_ & relationship_continuation) != 0); p.v = p.p = 0; } template <typename Allocator, unsigned int Bits> template <typename Function> void thread_pool::basic_executor_type<Allocator, Bits>::do_execute(BOOST_ASIO_MOVE_ARG(Function) f, true_type) const { // Obtain a non-const instance of the function. detail::non_const_lvalue<Function> f2(f); // Invoke immediately if we are already inside the thread pool. if (pool_->scheduler_.can_dispatch()) { #if !defined(BOOST_ASIO_NO_EXCEPTIONS) try { #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) detail::fenced_block b(detail::fenced_block::full); boost_asio_handler_invoke_helpers::invoke(f2.value, f2.value); return; #if !defined(BOOST_ASIO_NO_EXCEPTIONS) } catch (...) { std::terminate(); } #endif // !defined(BOOST_ASIO_NO_EXCEPTIONS) } // Construct an operation to wrap the function. typedef typename decay<Function>::type function_type; detail::blocking_executor_op<function_type> op(f2.value); BOOST_ASIO_HANDLER_CREATION((*pool_, op, "thread_pool", pool_, 0, "execute(blk=always)")); pool_->scheduler_.post_immediate_completion(&op, false); op.wait(); } template <typename Allocator, unsigned int Bits> template <typename Function> void thread_pool::basic_executor_type<Allocator, Bits>::do_bulk_execute( BOOST_ASIO_MOVE_ARG(Function) f, std::size_t n, false_type) const { typedef typename decay<Function>::type function_type; typedef detail::bulk_executor_op<function_type, Allocator> op; // Allocate and construct operations to wrap the function. detail::op_queue<detail::scheduler_operation> ops; for (std::size_t i = 0; i < n; ++i) { typename op::ptr p = { detail::addressof(allocator_), op::ptr::allocate(allocator_), 0 }; p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), allocator_, i); ops.push(p.p); if ((bits_ & relationship_continuation) != 0) { BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p, "thread_pool", pool_, 0, "bulk_execute(blk=never,rel=cont)")); } else { BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p, "thread_pool", pool_, 0, "bulk)execute(blk=never,rel=fork)")); } p.v = p.p = 0; } pool_->scheduler_.post_immediate_completions(n, ops, (bits_ & relationship_continuation) != 0); } template <typename Function> struct thread_pool_always_blocking_function_adapter { typename decay<Function>::type* f; std::size_t n; void operator()() { for (std::size_t i = 0; i < n; ++i) { (*f)(i); } } }; template <typename Allocator, unsigned int Bits> template <typename Function> void thread_pool::basic_executor_type<Allocator, Bits>::do_bulk_execute( BOOST_ASIO_MOVE_ARG(Function) f, std::size_t n, true_type) const { // Obtain a non-const instance of the function. detail::non_const_lvalue<Function> f2(f); thread_pool_always_blocking_function_adapter<Function> adapter = { detail::addressof(f2.value), n }; this->do_execute(adapter, true_type()); } #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) template <typename Allocator, unsigned int Bits> inline thread_pool& thread_pool::basic_executor_type< Allocator, Bits>::context() const BOOST_ASIO_NOEXCEPT { return *pool_; } template <typename Allocator, unsigned int Bits> inline void thread_pool::basic_executor_type<Allocator, Bits>::on_work_started() const BOOST_ASIO_NOEXCEPT { pool_->scheduler_.work_started(); } template <typename Allocator, unsigned int Bits> inline void thread_pool::basic_executor_type<Allocator, Bits>::on_work_finished() const BOOST_ASIO_NOEXCEPT { pool_->scheduler_.work_finished(); } template <typename Allocator, unsigned int Bits> template <typename Function, typename OtherAllocator> void thread_pool::basic_executor_type<Allocator, Bits>::dispatch( BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const { typedef typename decay<Function>::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<function_type, OtherAllocator> 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", pool_, 0, "dispatch")); pool_->scheduler_.post_immediate_completion(p.p, false); p.v = p.p = 0; } template <typename Allocator, unsigned int Bits> template <typename Function, typename OtherAllocator> void thread_pool::basic_executor_type<Allocator, Bits>::post( BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const { typedef typename decay<Function>::type function_type; // Allocate and construct an operation to wrap the function. typedef detail::executor_op<function_type, OtherAllocator> 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", pool_, 0, "post")); pool_->scheduler_.post_immediate_completion(p.p, false); p.v = p.p = 0; } template <typename Allocator, unsigned int Bits> template <typename Function, typename OtherAllocator> void thread_pool::basic_executor_type<Allocator, Bits>::defer( BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const { typedef typename decay<Function>::type function_type; // Allocate and construct an operation to wrap the function. typedef detail::executor_op<function_type, OtherAllocator> 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", pool_, 0, "defer")); pool_->scheduler_.post_immediate_completion(p.p, true); p.v = p.p = 0; } #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_THREAD_POOL_HPP impl/redirect_error.hpp 0000644 00000027462 15125530236 0011245 0 ustar 00 // impl/redirect_error.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/associated_allocator.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/variadic_templates.hpp> #include <boost/system/system_error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { // Class to adapt a redirect_error_t as a completion handler. template <typename Handler> class redirect_error_handler { public: typedef void result_type; template <typename CompletionToken> redirect_error_handler(redirect_error_t<CompletionToken> e) : ec_(e.ec_), handler_(BOOST_ASIO_MOVE_CAST(CompletionToken)(e.token_)) { } template <typename RedirectedHandler> 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 Arg, typename... Args> typename enable_if< !is_same<typename decay<Arg>::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 <typename... Args> 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 Arg> typename enable_if< !is_same<typename decay<Arg>::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 Arg, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ typename enable_if< \ !is_same<typename decay<Arg>::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 <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ 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 <typename Handler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, redirect_error_handler<Handler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, redirect_error_handler<Handler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler> inline bool asio_handler_is_continuation( redirect_error_handler<Handler>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename Handler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, redirect_error_handler<Handler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename Handler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, redirect_error_handler<Handler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Signature> struct redirect_error_signature { typedef Signature type; }; #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename R, typename... Args> struct redirect_error_signature<R(boost::system::error_code, Args...)> { typedef R type(Args...); }; template <typename R, typename... Args> struct redirect_error_signature<R(const boost::system::error_code&, Args...)> { typedef R type(Args...); }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename R> struct redirect_error_signature<R(boost::system::error_code)> { typedef R type(); }; template <typename R> struct redirect_error_signature<R(const boost::system::error_code&)> { typedef R type(); }; #define BOOST_ASIO_PRIVATE_REDIRECT_ERROR_DEF(n) \ template <typename R, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ struct redirect_error_signature< \ R(boost::system::error_code, BOOST_ASIO_VARIADIC_TARGS(n))> \ { \ typedef R type(BOOST_ASIO_VARIADIC_TARGS(n)); \ }; \ \ template <typename R, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ 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 <typename CompletionToken, typename Signature> struct async_result<redirect_error_t<CompletionToken>, Signature> { typedef typename async_result<CompletionToken, typename detail::redirect_error_signature<Signature>::type> ::return_type return_type; template <typename Initiation> struct init_wrapper { template <typename Init> 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 <typename Handler, typename... Args> 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<Handler>::type>( ec_, BOOST_ASIO_MOVE_CAST(Handler)(handler)), BOOST_ASIO_MOVE_CAST(Args)(args)...); } #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename Handler> void operator()( BOOST_ASIO_MOVE_ARG(Handler) handler) { BOOST_ASIO_MOVE_CAST(Initiation)(initiation_)( detail::redirect_error_handler< typename decay<Handler>::type>( ec_, BOOST_ASIO_MOVE_CAST(Handler)(handler))); } #define BOOST_ASIO_PRIVATE_INIT_WRAPPER_DEF(n) \ template <typename Handler, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ 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<Handler>::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 <typename Initiation, typename RawCompletionToken, typename... Args> 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<CompletionToken, typename detail::redirect_error_signature<Signature>::type>( init_wrapper<typename decay<Initiation>::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 <typename Initiation, typename RawCompletionToken> static return_type initiate( BOOST_ASIO_MOVE_ARG(Initiation) initiation, BOOST_ASIO_MOVE_ARG(RawCompletionToken) token) { return async_initiate<CompletionToken, typename detail::redirect_error_signature<Signature>::type>( init_wrapper<typename decay<Initiation>::type>( token.ec_, BOOST_ASIO_MOVE_CAST(Initiation)(initiation)), token.token_); } #define BOOST_ASIO_PRIVATE_INITIATE_DEF(n) \ template <typename Initiation, typename RawCompletionToken, \ BOOST_ASIO_VARIADIC_TPARAMS(n)> \ 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<CompletionToken, \ typename detail::redirect_error_signature<Signature>::type>( \ init_wrapper<typename decay<Initiation>::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 <typename Handler, typename Executor> struct associated_executor<detail::redirect_error_handler<Handler>, Executor> : detail::associated_executor_forwarding_base<Handler, Executor> { typedef typename associated_executor<Handler, Executor>::type type; static type get( const detail::redirect_error_handler<Handler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<Handler, Executor>::get(h.handler_, ex); } }; template <typename Handler, typename Allocator> struct associated_allocator<detail::redirect_error_handler<Handler>, Allocator> { typedef typename associated_allocator<Handler, Allocator>::type type; static type get( const detail::redirect_error_handler<Handler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<Handler, Allocator>::get(h.handler_, a); } }; #endif // !defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_REDIRECT_ERROR_HPP impl/read_until.hpp 0000644 00000341207 15125530236 0010355 0 ustar 00 // // impl/read_until.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <algorithm> #include <string> #include <vector> #include <utility> #include <boost/asio/associated_allocator.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/buffers_iterator.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_tracking.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/limits.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Iterator1, typename Iterator2> std::pair<Iterator1, bool> 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 <typename SyncReadStream, typename DynamicBuffer_v1> inline std::size_t read_until(SyncReadStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, char delim, typename enable_if< is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncReadStream, typename DynamicBuffer_v1> 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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { typename decay<DynamicBuffer_v1>::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<buffers_type> 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::size_t>( std::max<std::size_t>(512, b.capacity() - b.size()), std::min<std::size_t>(65536, b.max_size() - b.size())); b.commit(s.read_some(b.prepare(bytes_to_read), ec)); if (ec) return 0; } } template <typename SyncReadStream, typename DynamicBuffer_v1> 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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncReadStream, typename DynamicBuffer_v1> 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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { typename decay<DynamicBuffer_v1>::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<buffers_type> 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<iterator, bool> 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::size_t>( std::max<std::size_t>(512, b.capacity() - b.size()), std::min<std::size_t>(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 <typename SyncReadStream, typename DynamicBuffer_v1> 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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncReadStream, typename DynamicBuffer_v1> 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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { typename decay<DynamicBuffer_v1>::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<buffers_type> 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<iterator, typename std::vector<boost::sub_match<iterator> >::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::size_t>( std::max<std::size_t>(512, b.capacity() - b.size()), std::min<std::size_t>(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 <typename SyncReadStream, typename DynamicBuffer_v1, typename MatchCondition> inline std::size_t read_until(SyncReadStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, MatchCondition match_condition, typename enable_if< is_match_condition<MatchCondition>::value && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncReadStream, typename DynamicBuffer_v1, typename MatchCondition> 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<MatchCondition>::value && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { typename decay<DynamicBuffer_v1>::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<buffers_type> 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<iterator, bool> 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::size_t>( std::max<std::size_t>(512, b.capacity() - b.size()), std::min<std::size_t>(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 <typename SyncReadStream, typename Allocator> inline std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, char delim) { return read_until(s, basic_streambuf_ref<Allocator>(b), delim); } template <typename SyncReadStream, typename Allocator> inline std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, char delim, boost::system::error_code& ec) { return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec); } template <typename SyncReadStream, typename Allocator> inline std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, BOOST_ASIO_STRING_VIEW_PARAM delim) { return read_until(s, basic_streambuf_ref<Allocator>(b), delim); } template <typename SyncReadStream, typename Allocator> inline std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, BOOST_ASIO_STRING_VIEW_PARAM delim, boost::system::error_code& ec) { return read_until(s, basic_streambuf_ref<Allocator>(b), delim, ec); } #if defined(BOOST_ASIO_HAS_BOOST_REGEX) template <typename SyncReadStream, typename Allocator> inline std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr) { return read_until(s, basic_streambuf_ref<Allocator>(b), expr); } template <typename SyncReadStream, typename Allocator> inline std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr, boost::system::error_code& ec) { return read_until(s, basic_streambuf_ref<Allocator>(b), expr, ec); } #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) template <typename SyncReadStream, typename Allocator, typename MatchCondition> inline std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, MatchCondition match_condition, typename enable_if<is_match_condition<MatchCondition>::value>::type*) { return read_until(s, basic_streambuf_ref<Allocator>(b), match_condition); } template <typename SyncReadStream, typename Allocator, typename MatchCondition> inline std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, MatchCondition match_condition, boost::system::error_code& ec, typename enable_if<is_match_condition<MatchCondition>::value>::type*) { return read_until(s, basic_streambuf_ref<Allocator>(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 <typename SyncReadStream, typename DynamicBuffer_v2> inline std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, char delim, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <typename SyncReadStream, typename DynamicBuffer_v2> std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, char delim, boost::system::error_code& ec, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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<buffers_type> iterator; buffers_type data_buffers = const_cast<const DynamicBuffer_v2&>(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::size_t>( std::max<std::size_t>(512, b.capacity() - b.size()), std::min<std::size_t>(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 <typename SyncReadStream, typename DynamicBuffer_v2> inline std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, BOOST_ASIO_STRING_VIEW_PARAM delim, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <typename SyncReadStream, typename DynamicBuffer_v2> 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<DynamicBuffer_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<buffers_type> iterator; buffers_type data_buffers = const_cast<const DynamicBuffer_v2&>(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<iterator, bool> 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::size_t>( std::max<std::size_t>(512, b.capacity() - b.size()), std::min<std::size_t>(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 <typename SyncReadStream, typename DynamicBuffer_v2> inline std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, const boost::regex& expr, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <typename SyncReadStream, typename DynamicBuffer_v2> 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<DynamicBuffer_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<buffers_type> iterator; buffers_type data_buffers = const_cast<const DynamicBuffer_v2&>(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<iterator, typename std::vector<boost::sub_match<iterator> >::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::size_t>( std::max<std::size_t>(512, b.capacity() - b.size()), std::min<std::size_t>(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 <typename SyncReadStream, typename DynamicBuffer_v2, typename MatchCondition> inline std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, MatchCondition match_condition, typename enable_if< is_match_condition<MatchCondition>::value && is_dynamic_buffer_v2<DynamicBuffer_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 <typename SyncReadStream, typename DynamicBuffer_v2, typename MatchCondition> std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, MatchCondition match_condition, boost::system::error_code& ec, typename enable_if< is_match_condition<MatchCondition>::value && is_dynamic_buffer_v2<DynamicBuffer_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<buffers_type> iterator; buffers_type data_buffers = const_cast<const DynamicBuffer_v2&>(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<iterator, bool> 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::size_t>( std::max<std::size_t>(512, b.capacity() - b.size()), std::min<std::size_t>(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 <typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler> class read_until_delim_op_v1 { public: template <typename BufferSequence> 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<std::size_t>::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<buffers_type> 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::size_t>( std::max<std::size_t>(512, buffers_.capacity() - buffers_.size()), std::min<std::size_t>(65536, buffers_.max_size() - buffers_.size())); } } // Check if we're done. if (!start && bytes_to_read == 0) break; // Start a new asynchronous read operation to obtain more data. { BOOST_ASIO_HANDLER_LOCATION(( __FILE__, __LINE__, "async_read_until")); 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 <typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, read_until_delim_op_v1<AsyncReadStream, DynamicBuffer_v1, ReadHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, read_until_delim_op_v1<AsyncReadStream, DynamicBuffer_v1, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler> inline bool asio_handler_is_continuation( read_until_delim_op_v1<AsyncReadStream, DynamicBuffer_v1, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, read_until_delim_op_v1<AsyncReadStream, DynamicBuffer_v1, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, read_until_delim_op_v1<AsyncReadStream, DynamicBuffer_v1, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream> class initiate_async_read_until_delim_v1 { public: typedef typename AsyncReadStream::executor_type executor_type; explicit initiate_async_read_until_delim_v1(AsyncReadStream& stream) : stream_(stream) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return stream_.get_executor(); } template <typename ReadHandler, typename DynamicBuffer_v1> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); read_until_delim_op_v1<AsyncReadStream, typename decay<DynamicBuffer_v1>::type, typename decay<ReadHandler>::type>( stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim, handler2.value)(boost::system::error_code(), 0, 1); } private: AsyncReadStream& stream_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler, typename Allocator> struct associated_allocator< detail::read_until_delim_op_v1<AsyncReadStream, DynamicBuffer_v1, ReadHandler>, Allocator> { typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( const detail::read_until_delim_op_v1<AsyncReadStream, DynamicBuffer_v1, ReadHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; template <typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler, typename Executor> struct associated_executor< detail::read_until_delim_op_v1<AsyncReadStream, DynamicBuffer_v1, ReadHandler>, Executor> : detail::associated_executor_forwarding_base<ReadHandler, Executor> { typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( const detail::read_until_delim_op_v1<AsyncReadStream, DynamicBuffer_v1, ReadHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v1, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> BOOST_ASIO_INITFN_AUTO_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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_read_until_delim_v1<AsyncReadStream>(s), handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim); } namespace detail { template <typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler> class read_until_delim_string_op_v1 { public: template <typename BufferSequence> 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<std::size_t>::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<buffers_type> 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<iterator, bool> 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::size_t>( std::max<std::size_t>(512, buffers_.capacity() - buffers_.size()), std::min<std::size_t>(65536, buffers_.max_size() - buffers_.size())); } } // Check if we're done. if (!start && bytes_to_read == 0) break; // Start a new asynchronous read operation to obtain more data. { BOOST_ASIO_HANDLER_LOCATION(( __FILE__, __LINE__, "async_read_until")); 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 <typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, read_until_delim_string_op_v1<AsyncReadStream, DynamicBuffer_v1, ReadHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, read_until_delim_string_op_v1<AsyncReadStream, DynamicBuffer_v1, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler> inline bool asio_handler_is_continuation( read_until_delim_string_op_v1<AsyncReadStream, DynamicBuffer_v1, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, read_until_delim_string_op_v1<AsyncReadStream, DynamicBuffer_v1, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, read_until_delim_string_op_v1<AsyncReadStream, DynamicBuffer_v1, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream> class initiate_async_read_until_delim_string_v1 { public: typedef typename AsyncReadStream::executor_type executor_type; explicit initiate_async_read_until_delim_string_v1(AsyncReadStream& stream) : stream_(stream) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return stream_.get_executor(); } template <typename ReadHandler, typename DynamicBuffer_v1> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); read_until_delim_string_op_v1<AsyncReadStream, typename decay<DynamicBuffer_v1>::type, typename decay<ReadHandler>::type>( stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), delim, handler2.value)(boost::system::error_code(), 0, 1); } private: AsyncReadStream& stream_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler, typename Allocator> struct associated_allocator< detail::read_until_delim_string_op_v1<AsyncReadStream, DynamicBuffer_v1, ReadHandler>, Allocator> { typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( const detail::read_until_delim_string_op_v1<AsyncReadStream, DynamicBuffer_v1, ReadHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; template <typename AsyncReadStream, typename DynamicBuffer_v1, typename ReadHandler, typename Executor> struct associated_executor< detail::read_until_delim_string_op_v1<AsyncReadStream, DynamicBuffer_v1, ReadHandler>, Executor> : detail::associated_executor_forwarding_base<ReadHandler, Executor> { typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( const detail::read_until_delim_string_op_v1<AsyncReadStream, DynamicBuffer_v1, ReadHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v1, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> BOOST_ASIO_INITFN_AUTO_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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_read_until_delim_string_v1<AsyncReadStream>(s), handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), static_cast<std::string>(delim)); } #if !defined(BOOST_ASIO_NO_EXTENSIONS) #if defined(BOOST_ASIO_HAS_BOOST_REGEX) namespace detail { template <typename AsyncReadStream, typename DynamicBuffer_v1, typename RegEx, typename ReadHandler> class read_until_expr_op_v1 { public: template <typename BufferSequence> 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<std::size_t>::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<buffers_type> 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<iterator, typename std::vector<boost::sub_match<iterator> >::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::size_t>( std::max<std::size_t>(512, buffers_.capacity() - buffers_.size()), std::min<std::size_t>(65536, buffers_.max_size() - buffers_.size())); } } // Check if we're done. if (!start && bytes_to_read == 0) break; // Start a new asynchronous read operation to obtain more data. { BOOST_ASIO_HANDLER_LOCATION(( __FILE__, __LINE__, "async_read_until")); 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 <typename AsyncReadStream, typename DynamicBuffer_v1, typename RegEx, typename ReadHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, read_until_expr_op_v1<AsyncReadStream, DynamicBuffer_v1, RegEx, ReadHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v1, typename RegEx, typename ReadHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, read_until_expr_op_v1<AsyncReadStream, DynamicBuffer_v1, RegEx, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v1, typename RegEx, typename ReadHandler> inline bool asio_handler_is_continuation( read_until_expr_op_v1<AsyncReadStream, DynamicBuffer_v1, RegEx, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v1, typename RegEx, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, read_until_expr_op_v1<AsyncReadStream, DynamicBuffer_v1, RegEx, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v1, typename RegEx, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, read_until_expr_op_v1<AsyncReadStream, DynamicBuffer_v1, RegEx, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream> class initiate_async_read_until_expr_v1 { public: typedef typename AsyncReadStream::executor_type executor_type; explicit initiate_async_read_until_expr_v1(AsyncReadStream& stream) : stream_(stream) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return stream_.get_executor(); } template <typename ReadHandler, typename DynamicBuffer_v1, typename RegEx> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); read_until_expr_op_v1<AsyncReadStream, typename decay<DynamicBuffer_v1>::type, RegEx, typename decay<ReadHandler>::type>( stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), expr, handler2.value)(boost::system::error_code(), 0, 1); } private: AsyncReadStream& stream_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v1, typename RegEx, typename ReadHandler, typename Allocator> struct associated_allocator< detail::read_until_expr_op_v1<AsyncReadStream, DynamicBuffer_v1, RegEx, ReadHandler>, Allocator> { typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( const detail::read_until_expr_op_v1<AsyncReadStream, DynamicBuffer_v1, RegEx, ReadHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; template <typename AsyncReadStream, typename DynamicBuffer_v1, typename RegEx, typename ReadHandler, typename Executor> struct associated_executor< detail::read_until_expr_op_v1<AsyncReadStream, DynamicBuffer_v1, RegEx, ReadHandler>, Executor> : detail::associated_executor_forwarding_base<ReadHandler, Executor> { typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( const detail::read_until_expr_op_v1<AsyncReadStream, DynamicBuffer_v1, RegEx, ReadHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v1, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> BOOST_ASIO_INITFN_AUTO_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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_read_until_expr_v1<AsyncReadStream>(s), handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), expr); } #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) namespace detail { template <typename AsyncReadStream, typename DynamicBuffer_v1, typename MatchCondition, typename ReadHandler> class read_until_match_op_v1 { public: template <typename BufferSequence> 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<std::size_t>::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<buffers_type> 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<iterator, bool> 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::size_t>( std::max<std::size_t>(512, buffers_.capacity() - buffers_.size()), std::min<std::size_t>(65536, buffers_.max_size() - buffers_.size())); } } // Check if we're done. if (!start && bytes_to_read == 0) break; // Start a new asynchronous read operation to obtain more data. { BOOST_ASIO_HANDLER_LOCATION(( __FILE__, __LINE__, "async_read_until")); 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 <typename AsyncReadStream, typename DynamicBuffer_v1, typename MatchCondition, typename ReadHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1, MatchCondition, ReadHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v1, typename MatchCondition, typename ReadHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1, MatchCondition, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v1, typename MatchCondition, typename ReadHandler> inline bool asio_handler_is_continuation( read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1, MatchCondition, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v1, typename MatchCondition, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1, MatchCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v1, typename MatchCondition, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1, MatchCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream> class initiate_async_read_until_match_v1 { public: typedef typename AsyncReadStream::executor_type executor_type; explicit initiate_async_read_until_match_v1(AsyncReadStream& stream) : stream_(stream) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return stream_.get_executor(); } template <typename ReadHandler, typename DynamicBuffer_v1, typename MatchCondition> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); read_until_match_op_v1<AsyncReadStream, typename decay<DynamicBuffer_v1>::type, MatchCondition, typename decay<ReadHandler>::type>( stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), match_condition, handler2.value)(boost::system::error_code(), 0, 1); } private: AsyncReadStream& stream_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v1, typename MatchCondition, typename ReadHandler, typename Allocator> struct associated_allocator< detail::read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1, MatchCondition, ReadHandler>, Allocator> { typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( const detail::read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1, MatchCondition, ReadHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; template <typename AsyncReadStream, typename DynamicBuffer_v1, typename MatchCondition, typename ReadHandler, typename Executor> struct associated_executor< detail::read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1, MatchCondition, ReadHandler>, Executor> : detail::associated_executor_forwarding_base<ReadHandler, Executor> { typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( const detail::read_until_match_op_v1<AsyncReadStream, DynamicBuffer_v1, MatchCondition, ReadHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v1, typename MatchCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> BOOST_ASIO_INITFN_AUTO_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<MatchCondition>::value && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_read_until_match_v1<AsyncReadStream>(s), handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), match_condition); } #if !defined(BOOST_ASIO_NO_IOSTREAM) template <typename AsyncReadStream, typename Allocator, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { return async_read_until(s, basic_streambuf_ref<Allocator>(b), delim, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); } template <typename AsyncReadStream, typename Allocator, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, BOOST_ASIO_STRING_VIEW_PARAM delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { return async_read_until(s, basic_streambuf_ref<Allocator>(b), delim, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); } #if defined(BOOST_ASIO_HAS_BOOST_REGEX) template <typename AsyncReadStream, typename Allocator, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { return async_read_until(s, basic_streambuf_ref<Allocator>(b), expr, BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); } #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) template <typename AsyncReadStream, typename Allocator, typename MatchCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler, typename enable_if<is_match_condition<MatchCondition>::value>::type*) { return async_read_until(s, basic_streambuf_ref<Allocator>(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 <typename AsyncReadStream, typename DynamicBuffer_v2, typename ReadHandler> class read_until_delim_op_v2 { public: template <typename BufferSequence> 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<std::size_t>::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<buffers_type> iterator; buffers_type data_buffers = const_cast<const DynamicBuffer_v2&>(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::size_t>( std::max<std::size_t>(512, buffers_.capacity() - buffers_.size()), std::min<std::size_t>(65536, buffers_.max_size() - buffers_.size())); } } // Check if we're done. if (!start && bytes_to_read_ == 0) break; // Start a new asynchronous read operation to obtain more data. pos = buffers_.size(); buffers_.grow(bytes_to_read_); { BOOST_ASIO_HANDLER_LOCATION(( __FILE__, __LINE__, "async_read_until")); 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 <typename AsyncReadStream, typename DynamicBuffer_v2, typename ReadHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, read_until_delim_op_v2<AsyncReadStream, DynamicBuffer_v2, ReadHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v2, typename ReadHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, read_until_delim_op_v2<AsyncReadStream, DynamicBuffer_v2, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v2, typename ReadHandler> inline bool asio_handler_is_continuation( read_until_delim_op_v2<AsyncReadStream, DynamicBuffer_v2, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v2, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, read_until_delim_op_v2<AsyncReadStream, DynamicBuffer_v2, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v2, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, read_until_delim_op_v2<AsyncReadStream, DynamicBuffer_v2, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream> class initiate_async_read_until_delim_v2 { public: typedef typename AsyncReadStream::executor_type executor_type; explicit initiate_async_read_until_delim_v2(AsyncReadStream& stream) : stream_(stream) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return stream_.get_executor(); } template <typename ReadHandler, typename DynamicBuffer_v2> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); read_until_delim_op_v2<AsyncReadStream, typename decay<DynamicBuffer_v2>::type, typename decay<ReadHandler>::type>( stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim, handler2.value)(boost::system::error_code(), 0, 1); } private: AsyncReadStream& stream_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v2, typename ReadHandler, typename Allocator> struct associated_allocator< detail::read_until_delim_op_v2<AsyncReadStream, DynamicBuffer_v2, ReadHandler>, Allocator> { typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( const detail::read_until_delim_op_v2<AsyncReadStream, DynamicBuffer_v2, ReadHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; template <typename AsyncReadStream, typename DynamicBuffer_v2, typename ReadHandler, typename Executor> struct associated_executor< detail::read_until_delim_op_v2<AsyncReadStream, DynamicBuffer_v2, ReadHandler>, Executor> : detail::associated_executor_forwarding_base<ReadHandler, Executor> { typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( const detail::read_until_delim_op_v2<AsyncReadStream, DynamicBuffer_v2, ReadHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v2, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> BOOST_ASIO_INITFN_AUTO_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<DynamicBuffer_v2>::value >::type*) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_read_until_delim_v2<AsyncReadStream>(s), handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim); } namespace detail { template <typename AsyncReadStream, typename DynamicBuffer_v2, typename ReadHandler> class read_until_delim_string_op_v2 { public: template <typename BufferSequence> 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<std::size_t>::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<buffers_type> iterator; buffers_type data_buffers = const_cast<const DynamicBuffer_v2&>(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<iterator, bool> 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::size_t>( std::max<std::size_t>(512, buffers_.capacity() - buffers_.size()), std::min<std::size_t>(65536, buffers_.max_size() - buffers_.size())); } } // Check if we're done. if (!start && bytes_to_read_ == 0) break; // Start a new asynchronous read operation to obtain more data. pos = buffers_.size(); buffers_.grow(bytes_to_read_); { BOOST_ASIO_HANDLER_LOCATION(( __FILE__, __LINE__, "async_read_until")); 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 <typename AsyncReadStream, typename DynamicBuffer_v2, typename ReadHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, read_until_delim_string_op_v2<AsyncReadStream, DynamicBuffer_v2, ReadHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v2, typename ReadHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, read_until_delim_string_op_v2<AsyncReadStream, DynamicBuffer_v2, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v2, typename ReadHandler> inline bool asio_handler_is_continuation( read_until_delim_string_op_v2<AsyncReadStream, DynamicBuffer_v2, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v2, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, read_until_delim_string_op_v2<AsyncReadStream, DynamicBuffer_v2, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v2, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, read_until_delim_string_op_v2<AsyncReadStream, DynamicBuffer_v2, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream> class initiate_async_read_until_delim_string_v2 { public: typedef typename AsyncReadStream::executor_type executor_type; explicit initiate_async_read_until_delim_string_v2(AsyncReadStream& stream) : stream_(stream) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return stream_.get_executor(); } template <typename ReadHandler, typename DynamicBuffer_v2> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); read_until_delim_string_op_v2<AsyncReadStream, typename decay<DynamicBuffer_v2>::type, typename decay<ReadHandler>::type>( stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), delim, handler2.value)(boost::system::error_code(), 0, 1); } private: AsyncReadStream& stream_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v2, typename ReadHandler, typename Allocator> struct associated_allocator< detail::read_until_delim_string_op_v2<AsyncReadStream, DynamicBuffer_v2, ReadHandler>, Allocator> { typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( const detail::read_until_delim_string_op_v2<AsyncReadStream, DynamicBuffer_v2, ReadHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; template <typename AsyncReadStream, typename DynamicBuffer_v2, typename ReadHandler, typename Executor> struct associated_executor< detail::read_until_delim_string_op_v2<AsyncReadStream, DynamicBuffer_v2, ReadHandler>, Executor> : detail::associated_executor_forwarding_base<ReadHandler, Executor> { typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( const detail::read_until_delim_string_op_v2<AsyncReadStream, DynamicBuffer_v2, ReadHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v2, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> BOOST_ASIO_INITFN_AUTO_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<DynamicBuffer_v2>::value >::type*) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_read_until_delim_string_v2<AsyncReadStream>(s), handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), static_cast<std::string>(delim)); } #if !defined(BOOST_ASIO_NO_EXTENSIONS) #if defined(BOOST_ASIO_HAS_BOOST_REGEX) namespace detail { template <typename AsyncReadStream, typename DynamicBuffer_v2, typename RegEx, typename ReadHandler> class read_until_expr_op_v2 { public: template <typename BufferSequence> 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<std::size_t>::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<buffers_type> iterator; buffers_type data_buffers = const_cast<const DynamicBuffer_v2&>(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<iterator, typename std::vector<boost::sub_match<iterator> >::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::size_t>( std::max<std::size_t>(512, buffers_.capacity() - buffers_.size()), std::min<std::size_t>(65536, buffers_.max_size() - buffers_.size())); } } // Check if we're done. if (!start && bytes_to_read_ == 0) break; // Start a new asynchronous read operation to obtain more data. pos = buffers_.size(); buffers_.grow(bytes_to_read_); { BOOST_ASIO_HANDLER_LOCATION(( __FILE__, __LINE__, "async_read_until")); 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 <typename AsyncReadStream, typename DynamicBuffer_v2, typename RegEx, typename ReadHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, read_until_expr_op_v2<AsyncReadStream, DynamicBuffer_v2, RegEx, ReadHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v2, typename RegEx, typename ReadHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, read_until_expr_op_v2<AsyncReadStream, DynamicBuffer_v2, RegEx, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v2, typename RegEx, typename ReadHandler> inline bool asio_handler_is_continuation( read_until_expr_op_v2<AsyncReadStream, DynamicBuffer_v2, RegEx, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v2, typename RegEx, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, read_until_expr_op_v2<AsyncReadStream, DynamicBuffer_v2, RegEx, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v2, typename RegEx, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, read_until_expr_op_v2<AsyncReadStream, DynamicBuffer_v2, RegEx, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream> class initiate_async_read_until_expr_v2 { public: typedef typename AsyncReadStream::executor_type executor_type; explicit initiate_async_read_until_expr_v2(AsyncReadStream& stream) : stream_(stream) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return stream_.get_executor(); } template <typename ReadHandler, typename DynamicBuffer_v2, typename RegEx> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); read_until_expr_op_v2<AsyncReadStream, typename decay<DynamicBuffer_v2>::type, RegEx, typename decay<ReadHandler>::type>( stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), expr, handler2.value)(boost::system::error_code(), 0, 1); } private: AsyncReadStream& stream_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v2, typename RegEx, typename ReadHandler, typename Allocator> struct associated_allocator< detail::read_until_expr_op_v2<AsyncReadStream, DynamicBuffer_v2, RegEx, ReadHandler>, Allocator> { typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( const detail::read_until_expr_op_v2<AsyncReadStream, DynamicBuffer_v2, RegEx, ReadHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; template <typename AsyncReadStream, typename DynamicBuffer_v2, typename RegEx, typename ReadHandler, typename Executor> struct associated_executor< detail::read_until_expr_op_v2<AsyncReadStream, DynamicBuffer_v2, RegEx, ReadHandler>, Executor> : detail::associated_executor_forwarding_base<ReadHandler, Executor> { typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( const detail::read_until_expr_op_v2<AsyncReadStream, DynamicBuffer_v2, RegEx, ReadHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v2, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> BOOST_ASIO_INITFN_AUTO_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<DynamicBuffer_v2>::value >::type*) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_read_until_expr_v2<AsyncReadStream>(s), handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), expr); } #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) namespace detail { template <typename AsyncReadStream, typename DynamicBuffer_v2, typename MatchCondition, typename ReadHandler> class read_until_match_op_v2 { public: template <typename BufferSequence> 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<std::size_t>::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<buffers_type> iterator; buffers_type data_buffers = const_cast<const DynamicBuffer_v2&>(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<iterator, bool> 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::size_t>( std::max<std::size_t>(512, buffers_.capacity() - buffers_.size()), std::min<std::size_t>(65536, buffers_.max_size() - buffers_.size())); } } // Check if we're done. if (!start && bytes_to_read_ == 0) break; // Start a new asynchronous read operation to obtain more data. pos = buffers_.size(); buffers_.grow(bytes_to_read_); { BOOST_ASIO_HANDLER_LOCATION(( __FILE__, __LINE__, "async_read_until")); 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 <typename AsyncReadStream, typename DynamicBuffer_v2, typename MatchCondition, typename ReadHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2, MatchCondition, ReadHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v2, typename MatchCondition, typename ReadHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2, MatchCondition, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v2, typename MatchCondition, typename ReadHandler> inline bool asio_handler_is_continuation( read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2, MatchCondition, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v2, typename MatchCondition, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2, MatchCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v2, typename MatchCondition, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2, MatchCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream> class initiate_async_read_until_match_v2 { public: typedef typename AsyncReadStream::executor_type executor_type; explicit initiate_async_read_until_match_v2(AsyncReadStream& stream) : stream_(stream) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return stream_.get_executor(); } template <typename ReadHandler, typename DynamicBuffer_v2, typename MatchCondition> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); read_until_match_op_v2<AsyncReadStream, typename decay<DynamicBuffer_v2>::type, MatchCondition, typename decay<ReadHandler>::type>( stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), match_condition, handler2.value)(boost::system::error_code(), 0, 1); } private: AsyncReadStream& stream_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v2, typename MatchCondition, typename ReadHandler, typename Allocator> struct associated_allocator< detail::read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2, MatchCondition, ReadHandler>, Allocator> { typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( const detail::read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2, MatchCondition, ReadHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; template <typename AsyncReadStream, typename DynamicBuffer_v2, typename MatchCondition, typename ReadHandler, typename Executor> struct associated_executor< detail::read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2, MatchCondition, ReadHandler>, Executor> : detail::associated_executor_forwarding_base<ReadHandler, Executor> { typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( const detail::read_until_match_op_v2<AsyncReadStream, DynamicBuffer_v2, MatchCondition, ReadHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v2, typename MatchCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> BOOST_ASIO_INITFN_AUTO_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<MatchCondition>::value && is_dynamic_buffer_v2<DynamicBuffer_v2>::value >::type*) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_read_until_match_v2<AsyncReadStream>(s), handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), match_condition); } #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_READ_UNTIL_HPP impl/co_spawn.hpp 0000644 00000021202 15125530236 0010026 0 ustar 00 // // impl/co_spawn.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/awaitable.hpp> #include <boost/asio/dispatch.hpp> #include <boost/asio/execution/outstanding_work.hpp> #include <boost/asio/post.hpp> #include <boost/asio/prefer.hpp> #include <boost/asio/use_awaitable.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Executor, typename = void> class co_spawn_work_guard { public: typedef typename decay< typename prefer_result<Executor, execution::outstanding_work_t::tracked_t >::type >::type executor_type; co_spawn_work_guard(const Executor& ex) : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return executor_; } private: executor_type executor_; }; #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) template <typename Executor> struct co_spawn_work_guard<Executor, typename enable_if< !execution::is_executor<Executor>::value >::type> : executor_work_guard<Executor> { co_spawn_work_guard(const Executor& ex) : executor_work_guard<Executor>(ex) { } }; #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) template <typename Executor> inline co_spawn_work_guard<Executor> make_co_spawn_work_guard(const Executor& ex) { return co_spawn_work_guard<Executor>(ex); } template <typename T, typename Executor, typename F, typename Handler> awaitable<void, Executor> co_spawn_entry_point( awaitable<T, Executor>*, Executor ex, F f, Handler handler) { auto spawn_work = make_co_spawn_work_guard(ex); auto handler_work = make_co_spawn_work_guard( boost::asio::get_associated_executor(handler, ex)); (void) co_await (post)(spawn_work.get_executor(), use_awaitable_t<Executor>{}); 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 <typename Executor, typename F, typename Handler> awaitable<void, Executor> co_spawn_entry_point( awaitable<void, Executor>*, Executor ex, F f, Handler handler) { auto spawn_work = make_co_spawn_work_guard(ex); auto handler_work = make_co_spawn_work_guard( boost::asio::get_associated_executor(handler, ex)); (void) co_await (post)(spawn_work.get_executor(), use_awaitable_t<Executor>{__FILE__, __LINE__, "co_spawn_entry_point"}); 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); }); } template <typename T, typename Executor> class awaitable_as_function { public: explicit awaitable_as_function(awaitable<T, Executor>&& a) : awaitable_(std::move(a)) { } awaitable<T, Executor> operator()() { return std::move(awaitable_); } private: awaitable<T, Executor> awaitable_; }; template <typename Executor> class initiate_co_spawn { public: typedef Executor executor_type; template <typename OtherExecutor> explicit initiate_co_spawn(const OtherExecutor& ex) : ex_(ex) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return ex_; } template <typename Handler, typename F> void operator()(Handler&& handler, F&& f) const { typedef typename result_of<F()>::type awaitable_type; auto a = (co_spawn_entry_point)(static_cast<awaitable_type*>(nullptr), ex_, std::forward<F>(f), std::forward<Handler>(handler)); awaitable_handler<executor_type, void>(std::move(a), ex_).launch(); } private: Executor ex_; }; } // namespace detail template <typename Executor, typename T, typename AwaitableExecutor, BOOST_ASIO_COMPLETION_TOKEN_FOR( void(std::exception_ptr, T)) CompletionToken> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( CompletionToken, void(std::exception_ptr, T)) co_spawn(const Executor& ex, awaitable<T, AwaitableExecutor> a, CompletionToken&& token, typename enable_if< (is_executor<Executor>::value || execution::is_executor<Executor>::value) && is_convertible<Executor, AwaitableExecutor>::value >::type*) { return async_initiate<CompletionToken, void(std::exception_ptr, T)>( detail::initiate_co_spawn<AwaitableExecutor>(AwaitableExecutor(ex)), token, detail::awaitable_as_function<T, AwaitableExecutor>(std::move(a))); } template <typename Executor, typename AwaitableExecutor, BOOST_ASIO_COMPLETION_TOKEN_FOR( void(std::exception_ptr)) CompletionToken> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( CompletionToken, void(std::exception_ptr)) co_spawn(const Executor& ex, awaitable<void, AwaitableExecutor> a, CompletionToken&& token, typename enable_if< (is_executor<Executor>::value || execution::is_executor<Executor>::value) && is_convertible<Executor, AwaitableExecutor>::value >::type*) { return async_initiate<CompletionToken, void(std::exception_ptr)>( detail::initiate_co_spawn<AwaitableExecutor>(AwaitableExecutor(ex)), token, detail::awaitable_as_function< void, AwaitableExecutor>(std::move(a))); } template <typename ExecutionContext, typename T, typename AwaitableExecutor, BOOST_ASIO_COMPLETION_TOKEN_FOR( void(std::exception_ptr, T)) CompletionToken> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( CompletionToken, void(std::exception_ptr, T)) co_spawn(ExecutionContext& ctx, awaitable<T, AwaitableExecutor> a, CompletionToken&& token, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value && is_convertible<typename ExecutionContext::executor_type, AwaitableExecutor>::value >::type*) { return (co_spawn)(ctx.get_executor(), std::move(a), std::forward<CompletionToken>(token)); } template <typename ExecutionContext, typename AwaitableExecutor, BOOST_ASIO_COMPLETION_TOKEN_FOR( void(std::exception_ptr)) CompletionToken> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( CompletionToken, void(std::exception_ptr)) co_spawn(ExecutionContext& ctx, awaitable<void, AwaitableExecutor> a, CompletionToken&& token, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value && is_convertible<typename ExecutionContext::executor_type, AwaitableExecutor>::value >::type*) { return (co_spawn)(ctx.get_executor(), std::move(a), std::forward<CompletionToken>(token)); } template <typename Executor, typename F, BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature< typename result_of<F()>::type>::type) CompletionToken> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, typename detail::awaitable_signature<typename result_of<F()>::type>::type) co_spawn(const Executor& ex, F&& f, CompletionToken&& token, typename enable_if< is_executor<Executor>::value || execution::is_executor<Executor>::value >::type*) { return async_initiate<CompletionToken, typename detail::awaitable_signature<typename result_of<F()>::type>::type>( detail::initiate_co_spawn< typename result_of<F()>::type::executor_type>(ex), token, std::forward<F>(f)); } template <typename ExecutionContext, typename F, BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature< typename result_of<F()>::type>::type) CompletionToken> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, typename detail::awaitable_signature<typename result_of<F()>::type>::type) co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type*) { return (co_spawn)(ctx.get_executor(), std::forward<F>(f), std::forward<CompletionToken>(token)); } } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_CO_SPAWN_HPP impl/use_awaitable.hpp 0000644 00000016054 15125530236 0011033 0 ustar 00 // // impl/use_awaitable.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Executor, typename T> class awaitable_handler_base : public awaitable_thread<Executor> { public: typedef void result_type; typedef awaitable<T, Executor> awaitable_type; // Construct from the entry point of a new thread of execution. awaitable_handler_base(awaitable<void, Executor> a, const Executor& ex) : awaitable_thread<Executor>(std::move(a), ex) { } // Transfer ownership from another awaitable_thread. explicit awaitable_handler_base(awaitable_thread<Executor>* h) : awaitable_thread<Executor>(std::move(*h)) { } protected: awaitable_frame<T, Executor>* frame() noexcept { return static_cast<awaitable_frame<T, Executor>*>(this->top_of_stack_); } }; template <typename, typename...> class awaitable_handler; template <typename Executor> class awaitable_handler<Executor> : public awaitable_handler_base<Executor, void> { public: using awaitable_handler_base<Executor, void>::awaitable_handler_base; void operator()() { this->frame()->attach_thread(this); this->frame()->return_void(); this->frame()->pop_frame(); this->pump(); } }; template <typename Executor> class awaitable_handler<Executor, boost::system::error_code> : public awaitable_handler_base<Executor, void> { public: using awaitable_handler_base<Executor, void>::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 <typename Executor> class awaitable_handler<Executor, std::exception_ptr> : public awaitable_handler_base<Executor, void> { public: using awaitable_handler_base<Executor, void>::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 <typename Executor, typename T> class awaitable_handler<Executor, T> : public awaitable_handler_base<Executor, T> { public: using awaitable_handler_base<Executor, T>::awaitable_handler_base; template <typename Arg> void operator()(Arg&& arg) { this->frame()->attach_thread(this); this->frame()->return_value(std::forward<Arg>(arg)); this->frame()->pop_frame(); this->pump(); } }; template <typename Executor, typename T> class awaitable_handler<Executor, boost::system::error_code, T> : public awaitable_handler_base<Executor, T> { public: using awaitable_handler_base<Executor, T>::awaitable_handler_base; template <typename Arg> 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>(arg)); this->frame()->pop_frame(); this->pump(); } }; template <typename Executor, typename T> class awaitable_handler<Executor, std::exception_ptr, T> : public awaitable_handler_base<Executor, T> { public: using awaitable_handler_base<Executor, T>::awaitable_handler_base; template <typename Arg> 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>(arg)); this->frame()->pop_frame(); this->pump(); } }; template <typename Executor, typename... Ts> class awaitable_handler : public awaitable_handler_base<Executor, std::tuple<Ts...>> { public: using awaitable_handler_base<Executor, std::tuple<Ts...>>::awaitable_handler_base; template <typename... Args> void operator()(Args&&... args) { this->frame()->attach_thread(this); this->frame()->return_values(std::forward<Args>(args)...); this->frame()->pop_frame(); this->pump(); } }; template <typename Executor, typename... Ts> class awaitable_handler<Executor, boost::system::error_code, Ts...> : public awaitable_handler_base<Executor, std::tuple<Ts...>> { public: using awaitable_handler_base<Executor, std::tuple<Ts...>>::awaitable_handler_base; template <typename... Args> 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>(args)...); this->frame()->pop_frame(); this->pump(); } }; template <typename Executor, typename... Ts> class awaitable_handler<Executor, std::exception_ptr, Ts...> : public awaitable_handler_base<Executor, std::tuple<Ts...>> { public: using awaitable_handler_base<Executor, std::tuple<Ts...>>::awaitable_handler_base; template <typename... Args> 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>(args)...); this->frame()->pop_frame(); this->pump(); } }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) #if defined(_MSC_VER) template <typename T> T dummy_return() { return std::move(*static_cast<T*>(nullptr)); } template <> void dummy_return() { } #endif // defined(_MSC_VER) template <typename Executor, typename R, typename... Args> class async_result<use_awaitable_t<Executor>, R(Args...)> { public: typedef typename detail::awaitable_handler< Executor, typename decay<Args>::type...> handler_type; typedef typename handler_type::awaitable_type return_type; template <typename Initiation, typename... InitArgs> static return_type initiate(Initiation initiation, use_awaitable_t<Executor> u, InitArgs... args) { (void)u; co_await [&](auto* frame) { BOOST_ASIO_HANDLER_LOCATION((u.file_name_, u.line_, u.function_name_)); handler_type handler(frame->detach_thread()); std::move(initiation)(std::move(handler), std::move(args)...); return static_cast<handler_type*>(nullptr); }; for (;;) {} // Never reached. #if defined(_MSC_VER) co_return dummy_return<typename return_type::value_type>(); #endif // defined(_MSC_VER) } }; #endif // !defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_USE_AWAITABLE_HPP impl/multiple_exceptions.ipp 0000644 00000002400 15125530236 0012311 0 ustar 00 // // impl/multiple_exceptions.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_MULTIPLE_EXCEPTIONS_IPP #define BOOST_ASIO_IMPL_MULTIPLE_EXCEPTIONS_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/multiple_exceptions.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) multiple_exceptions::multiple_exceptions( std::exception_ptr first) BOOST_ASIO_NOEXCEPT : first_(BOOST_ASIO_MOVE_CAST(std::exception_ptr)(first)) { } const char* multiple_exceptions::what() const BOOST_ASIO_NOEXCEPT_OR_NOTHROW { return "multiple exceptions"; } std::exception_ptr multiple_exceptions::first_exception() const { return first_; } #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_MULTIPLE_EXCEPTIONS_IPP impl/system_executor.hpp 0000644 00000014367 15125530236 0011475 0 ustar 00 // // impl/system_executor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/executor_op.hpp> #include <boost/asio/detail/global.hpp> #include <boost/asio/detail/recycling_allocator.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/system_context.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { template <typename Blocking, typename Relationship, typename Allocator> inline system_context& basic_system_executor<Blocking, Relationship, Allocator>::query( execution::context_t) BOOST_ASIO_NOEXCEPT { return detail::global<system_context>(); } template <typename Blocking, typename Relationship, typename Allocator> inline std::size_t basic_system_executor<Blocking, Relationship, Allocator>::query( execution::occupancy_t) const BOOST_ASIO_NOEXCEPT { return detail::global<system_context>().num_threads_; } template <typename Blocking, typename Relationship, typename Allocator> template <typename Function> inline void basic_system_executor<Blocking, Relationship, Allocator>::do_execute( BOOST_ASIO_MOVE_ARG(Function) f, execution::blocking_t::possibly_t) const { // Obtain a non-const instance of the function. detail::non_const_lvalue<Function> f2(f); #if !defined(BOOST_ASIO_NO_EXCEPTIONS) try { #endif// !defined(BOOST_ASIO_NO_EXCEPTIONS) detail::fenced_block b(detail::fenced_block::full); boost_asio_handler_invoke_helpers::invoke(f2.value, f2.value); #if !defined(BOOST_ASIO_NO_EXCEPTIONS) } catch (...) { std::terminate(); } #endif// !defined(BOOST_ASIO_NO_EXCEPTIONS) } template <typename Blocking, typename Relationship, typename Allocator> template <typename Function> inline void basic_system_executor<Blocking, Relationship, Allocator>::do_execute( BOOST_ASIO_MOVE_ARG(Function) f, execution::blocking_t::always_t) const { // Obtain a non-const instance of the function. detail::non_const_lvalue<Function> f2(f); #if !defined(BOOST_ASIO_NO_EXCEPTIONS) try { #endif// !defined(BOOST_ASIO_NO_EXCEPTIONS) detail::fenced_block b(detail::fenced_block::full); boost_asio_handler_invoke_helpers::invoke(f2.value, f2.value); #if !defined(BOOST_ASIO_NO_EXCEPTIONS) } catch (...) { std::terminate(); } #endif// !defined(BOOST_ASIO_NO_EXCEPTIONS) } template <typename Blocking, typename Relationship, typename Allocator> template <typename Function> void basic_system_executor<Blocking, Relationship, Allocator>::do_execute( BOOST_ASIO_MOVE_ARG(Function) f, execution::blocking_t::never_t) const { system_context& ctx = detail::global<system_context>(); // Allocate and construct an operation to wrap the function. typedef typename decay<Function>::type function_type; typedef detail::executor_op<function_type, Allocator> op; typename op::ptr p = { detail::addressof(allocator_), op::ptr::allocate(allocator_), 0 }; p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), allocator_); if (is_same<Relationship, execution::relationship_t::continuation_t>::value) { BOOST_ASIO_HANDLER_CREATION((ctx, *p.p, "system_executor", &ctx, 0, "execute(blk=never,rel=cont)")); } else { BOOST_ASIO_HANDLER_CREATION((ctx, *p.p, "system_executor", &ctx, 0, "execute(blk=never,rel=fork)")); } ctx.scheduler_.post_immediate_completion(p.p, is_same<Relationship, execution::relationship_t::continuation_t>::value); p.v = p.p = 0; } #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) template <typename Blocking, typename Relationship, typename Allocator> inline system_context& basic_system_executor< Blocking, Relationship, Allocator>::context() const BOOST_ASIO_NOEXCEPT { return detail::global<system_context>(); } template <typename Blocking, typename Relationship, typename Allocator> template <typename Function, typename OtherAllocator> void basic_system_executor<Blocking, Relationship, Allocator>::dispatch( BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator&) const { typename decay<Function>::type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); boost_asio_handler_invoke_helpers::invoke(tmp, tmp); } template <typename Blocking, typename Relationship, typename Allocator> template <typename Function, typename OtherAllocator> void basic_system_executor<Blocking, Relationship, Allocator>::post( BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const { typedef typename decay<Function>::type function_type; system_context& ctx = detail::global<system_context>(); // Allocate and construct an operation to wrap the function. typedef detail::executor_op<function_type, OtherAllocator> 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 <typename Blocking, typename Relationship, typename Allocator> template <typename Function, typename OtherAllocator> void basic_system_executor<Blocking, Relationship, Allocator>::defer( BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const { typedef typename decay<Function>::type function_type; system_context& ctx = detail::global<system_context>(); // Allocate and construct an operation to wrap the function. typedef detail::executor_op<function_type, OtherAllocator> 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; } #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_SYSTEM_EXECUTOR_HPP impl/read_at.hpp 0000644 00000067252 15125530236 0007633 0 ustar 00 // // impl/read_at.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <algorithm> #include <boost/asio/associated_allocator.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/completion_condition.hpp> #include <boost/asio/detail/array_fwd.hpp> #include <boost/asio/detail/base_from_completion_cond.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/consuming_buffers.hpp> #include <boost/asio/detail/dependent_type.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_tracking.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename SyncRandomAccessReadDevice, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition> 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<mutable_buffer, MutableBufferSequence, MutableBufferIterator> 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 <typename SyncRandomAccessReadDevice, typename MutableBufferSequence, typename CompletionCondition> 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 <typename SyncRandomAccessReadDevice, typename MutableBufferSequence> 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 <typename SyncRandomAccessReadDevice, typename MutableBufferSequence> 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 <typename SyncRandomAccessReadDevice, typename MutableBufferSequence, typename CompletionCondition> 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 <typename SyncRandomAccessReadDevice, typename Allocator, typename CompletionCondition> std::size_t read_at(SyncRandomAccessReadDevice& d, uint64_t offset, boost::asio::basic_streambuf<Allocator>& 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 <typename SyncRandomAccessReadDevice, typename Allocator> inline std::size_t read_at(SyncRandomAccessReadDevice& d, uint64_t offset, boost::asio::basic_streambuf<Allocator>& 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 <typename SyncRandomAccessReadDevice, typename Allocator> inline std::size_t read_at(SyncRandomAccessReadDevice& d, uint64_t offset, boost::asio::basic_streambuf<Allocator>& b, boost::system::error_code& ec) { return read_at(d, offset, b, transfer_all(), ec); } template <typename SyncRandomAccessReadDevice, typename Allocator, typename CompletionCondition> inline std::size_t read_at(SyncRandomAccessReadDevice& d, uint64_t offset, boost::asio::basic_streambuf<Allocator>& 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 <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> class read_at_op : detail::base_from_completion_cond<CompletionCondition> { 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<CompletionCondition>(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<CompletionCondition>( 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 { { BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read_at")); 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<mutable_buffer, MutableBufferSequence, MutableBufferIterator> buffers_type; AsyncRandomAccessReadDevice& device_; uint64_t offset_; buffers_type buffers_; int start_; ReadHandler handler_; }; template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> inline bool asio_handler_is_continuation( read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> 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<AsyncRandomAccessReadDevice, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>( d, offset, buffers, completion_condition, handler)( boost::system::error_code(), 0, 1); } template <typename AsyncRandomAccessReadDevice> class initiate_async_read_at_buffer_sequence { public: typedef typename AsyncRandomAccessReadDevice::executor_type executor_type; explicit initiate_async_read_at_buffer_sequence( AsyncRandomAccessReadDevice& device) : device_(device) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return device_.get_executor(); } template <typename ReadHandler, typename MutableBufferSequence, typename CompletionCondition> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); start_read_at_buffer_sequence_op(device_, offset, buffers, boost::asio::buffer_sequence_begin(buffers), completion_cond2.value, handler2.value); } private: AsyncRandomAccessReadDevice& device_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler, typename Allocator> struct associated_allocator< detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>, Allocator> { typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( const detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler, typename Executor> struct associated_executor< detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>, Executor> : detail::associated_executor_forwarding_base<ReadHandler, Executor> { typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( const detail::read_at_op<AsyncRandomAccessReadDevice, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> inline BOOST_ASIO_INITFN_AUTO_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<ReadHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_read_at_buffer_sequence< AsyncRandomAccessReadDevice>(d), handler, offset, buffers, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } template <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> inline BOOST_ASIO_INITFN_AUTO_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<ReadHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_read_at_buffer_sequence< AsyncRandomAccessReadDevice>(d), handler, offset, buffers, transfer_all()); } #if !defined(BOOST_ASIO_NO_EXTENSIONS) #if !defined(BOOST_ASIO_NO_IOSTREAM) namespace detail { template <typename AsyncRandomAccessReadDevice, typename Allocator, typename CompletionCondition, typename ReadHandler> class read_at_streambuf_op : detail::base_from_completion_cond<CompletionCondition> { public: read_at_streambuf_op(AsyncRandomAccessReadDevice& device, uint64_t offset, basic_streambuf<Allocator>& 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<CompletionCondition>(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<CompletionCondition>( 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 (;;) { { BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read_at")); 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<const std::size_t&>(total_transferred_)); } } //private: AsyncRandomAccessReadDevice& device_; uint64_t offset_; boost::asio::basic_streambuf<Allocator>& streambuf_; int start_; std::size_t total_transferred_; ReadHandler handler_; }; template <typename AsyncRandomAccessReadDevice, typename Allocator, typename CompletionCondition, typename ReadHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, CompletionCondition, ReadHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncRandomAccessReadDevice, typename Allocator, typename CompletionCondition, typename ReadHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncRandomAccessReadDevice, typename Allocator, typename CompletionCondition, typename ReadHandler> inline bool asio_handler_is_continuation( read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, CompletionCondition, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename AsyncRandomAccessReadDevice, typename Allocator, typename CompletionCondition, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename AsyncRandomAccessReadDevice, typename Allocator, typename CompletionCondition, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncRandomAccessReadDevice> class initiate_async_read_at_streambuf { public: typedef typename AsyncRandomAccessReadDevice::executor_type executor_type; explicit initiate_async_read_at_streambuf( AsyncRandomAccessReadDevice& device) : device_(device) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return device_.get_executor(); } template <typename ReadHandler, typename Allocator, typename CompletionCondition> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, uint64_t offset, basic_streambuf<Allocator>* 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<ReadHandler> handler2(handler); non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, CompletionCondition, typename decay<ReadHandler>::type>( device_, offset, *b, completion_cond2.value, handler2.value)( boost::system::error_code(), 0, 1); } private: AsyncRandomAccessReadDevice& device_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename AsyncRandomAccessReadDevice, typename Allocator, typename CompletionCondition, typename ReadHandler, typename Allocator1> struct associated_allocator< detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, CompletionCondition, ReadHandler>, Allocator1> { typedef typename associated_allocator<ReadHandler, Allocator1>::type type; static type get( const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, Allocator, CompletionCondition, ReadHandler>& h, const Allocator1& a = Allocator1()) BOOST_ASIO_NOEXCEPT { return associated_allocator<ReadHandler, Allocator1>::get(h.handler_, a); } }; template <typename AsyncRandomAccessReadDevice, typename Executor, typename CompletionCondition, typename ReadHandler, typename Executor1> struct associated_executor< detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, Executor, CompletionCondition, ReadHandler>, Executor1> : detail::associated_executor_forwarding_base<ReadHandler, Executor> { typedef typename associated_executor<ReadHandler, Executor1>::type type; static type get( const detail::read_at_streambuf_op<AsyncRandomAccessReadDevice, Executor, CompletionCondition, ReadHandler>& h, const Executor1& ex = Executor1()) BOOST_ASIO_NOEXCEPT { return associated_executor<ReadHandler, Executor1>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncRandomAccessReadDevice, typename Allocator, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, boost::asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_read_at_streambuf<AsyncRandomAccessReadDevice>(d), handler, offset, &b, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } template <typename AsyncRandomAccessReadDevice, typename Allocator, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, boost::asio::basic_streambuf<Allocator>& b, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_read_at_streambuf<AsyncRandomAccessReadDevice>(d), handler, offset, &b, transfer_all()); } #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_READ_AT_HPP impl/use_future.hpp 0000644 00000065732 15125530236 0010423 0 ustar 00 // // impl/use_future.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <tuple> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/dispatch.hpp> #include <boost/system/error_code.hpp> #include <boost/asio/execution.hpp> #include <boost/asio/packaged_task.hpp> #include <boost/system/system_error.hpp> #include <boost/asio/system_executor.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T, typename F, typename... Args> inline void promise_invoke_and_set(std::promise<T>& 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 <typename F, typename... Args> inline void promise_invoke_and_set(std::promise<void>& 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 <typename T, typename F> inline void promise_invoke_and_set(std::promise<T>& 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 <typename F, typename Args> inline void promise_invoke_and_set(std::promise<void>& 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 <typename T, typename F, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ inline void promise_invoke_and_set(std::promise<T>& p, \ F& f, BOOST_ASIO_VARIADIC_MOVE_PARAMS(n)) \ { \ p.set_value(f(BOOST_ASIO_VARIADIC_MOVE_ARGS(n))); \ } \ \ template <typename F, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ inline void promise_invoke_and_set(std::promise<void>& 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 <typename T, typename F, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ inline void promise_invoke_and_set(std::promise<T>& 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 <typename F, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ inline void promise_invoke_and_set(std::promise<void>& 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 <typename T, typename F> class promise_invoker { public: promise_invoker(const shared_ptr<std::promise<T> >& 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<std::promise<T> > p_; typename decay<F>::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 <typename T, typename Blocking = execution::blocking_t::possibly_t> class promise_executor { public: explicit promise_executor(const shared_ptr<std::promise<T> >& p) : p_(p) { } static BOOST_ASIO_CONSTEXPR Blocking query(execution::blocking_t) { return Blocking(); } promise_executor<T, execution::blocking_t::possibly_t> require(execution::blocking_t::possibly_t) const { return promise_executor<T, execution::blocking_t::possibly_t>(p_); } promise_executor<T, execution::blocking_t::never_t> require(execution::blocking_t::never_t) const { return promise_executor<T, execution::blocking_t::never_t>(p_); } template <typename F> void execute(BOOST_ASIO_MOVE_ARG(F) f) const { execution::execute( boost::asio::require(system_executor(), Blocking()), promise_invoker<T, F>(p_, BOOST_ASIO_MOVE_CAST(F)(f))); } #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) 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 <typename F, typename A> void dispatch(BOOST_ASIO_MOVE_ARG(F) f, const A&) const { promise_invoker<T, F>(p_, BOOST_ASIO_MOVE_CAST(F)(f))(); } template <typename F, typename A> void post(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const { system_executor().post( promise_invoker<T, F>(p_, BOOST_ASIO_MOVE_CAST(F)(f)), a); } template <typename F, typename A> void defer(BOOST_ASIO_MOVE_ARG(F) f, const A& a) const { system_executor().defer( promise_invoker<T, F>(p_, BOOST_ASIO_MOVE_CAST(F)(f)), a); } #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) 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<std::promise<T> > p_; }; // The base class for all completion handlers that create promises. template <typename T> class promise_creator { public: typedef promise_executor<T> executor_type; executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return executor_type(p_); } typedef std::future<T> future_type; future_type get_future() { return p_->get_future(); } protected: template <typename Allocator> void create_promise(const Allocator& a) { BOOST_ASIO_REBIND_ALLOC(Allocator, char) b(a); p_ = std::allocate_shared<std::promise<T>>(b, std::allocator_arg, b); } shared_ptr<std::promise<T> > p_; }; // For completion signature void(). class promise_handler_0 : public promise_creator<void> { public: void operator()() { this->p_->set_value(); } }; // For completion signature void(error_code). class promise_handler_ec_0 : public promise_creator<void> { 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<void> { 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 <typename T> class promise_handler_1 : public promise_creator<T> { public: template <typename Arg> 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 <typename T> class promise_handler_ec_1 : public promise_creator<T> { public: template <typename Arg> 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 <typename T> class promise_handler_ex_1 : public promise_creator<T> { public: template <typename Arg> 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 <typename T> class promise_handler_n : public promise_creator<T> { public: #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename... Args> 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 <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ 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 <typename T> class promise_handler_ec_n : public promise_creator<T> { public: #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename... Args> 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 <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ 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 <typename T> class promise_handler_ex_n : public promise_creator<T> { public: #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename... Args> 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 <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ 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 <typename> class promise_handler_selector; template <> class promise_handler_selector<void()> : public promise_handler_0 {}; template <> class promise_handler_selector<void(boost::system::error_code)> : public promise_handler_ec_0 {}; template <> class promise_handler_selector<void(std::exception_ptr)> : public promise_handler_ex_0 {}; template <typename Arg> class promise_handler_selector<void(Arg)> : public promise_handler_1<Arg> {}; template <typename Arg> class promise_handler_selector<void(boost::system::error_code, Arg)> : public promise_handler_ec_1<Arg> {}; template <typename Arg> class promise_handler_selector<void(std::exception_ptr, Arg)> : public promise_handler_ex_1<Arg> {}; #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename... Arg> class promise_handler_selector<void(Arg...)> : public promise_handler_n<std::tuple<Arg...> > {}; template <typename... Arg> class promise_handler_selector<void(boost::system::error_code, Arg...)> : public promise_handler_ec_n<std::tuple<Arg...> > {}; template <typename... Arg> class promise_handler_selector<void(std::exception_ptr, Arg...)> : public promise_handler_ex_n<std::tuple<Arg...> > {}; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #define BOOST_ASIO_PRIVATE_PROMISE_SELECTOR_DEF(n) \ template <typename Arg, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ class promise_handler_selector< \ void(Arg, BOOST_ASIO_VARIADIC_TARGS(n))> \ : public promise_handler_n< \ std::tuple<Arg, BOOST_ASIO_VARIADIC_TARGS(n)> > {}; \ \ template <typename Arg, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ class promise_handler_selector< \ void(boost::system::error_code, Arg, BOOST_ASIO_VARIADIC_TARGS(n))> \ : public promise_handler_ec_n< \ std::tuple<Arg, BOOST_ASIO_VARIADIC_TARGS(n)> > {}; \ \ template <typename Arg, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ class promise_handler_selector< \ void(std::exception_ptr, Arg, BOOST_ASIO_VARIADIC_TARGS(n))> \ : public promise_handler_ex_n< \ std::tuple<Arg, BOOST_ASIO_VARIADIC_TARGS(n)> > {}; \ /**/ BOOST_ASIO_VARIADIC_GENERATE_5(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 <typename Signature, typename Allocator> class promise_handler : public promise_handler_selector<Signature> { public: typedef Allocator allocator_type; typedef void result_type; promise_handler(use_future_t<Allocator> u) : allocator_(u.get_allocator()) { this->create_promise(allocator_); } allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT { return allocator_; } private: Allocator allocator_; }; template <typename Function> struct promise_function_wrapper { explicit promise_function_wrapper(Function& f) : function_(BOOST_ASIO_MOVE_CAST(Function)(f)) { } explicit promise_function_wrapper(const Function& f) : function_(f) { } void operator()() { function_(); } Function function_; }; #if !defined(BOOST_ASIO_NO_DEPRECATED) template <typename Function, typename Signature, typename Allocator> inline void asio_handler_invoke(Function& f, promise_handler<Signature, Allocator>* h) { typename promise_handler<Signature, Allocator>::executor_type ex(h->get_executor()); boost::asio::dispatch(ex, promise_function_wrapper<Function>(f)); } template <typename Function, typename Signature, typename Allocator> inline void asio_handler_invoke(const Function& f, promise_handler<Signature, Allocator>* h) { typename promise_handler<Signature, Allocator>::executor_type ex(h->get_executor()); boost::asio::dispatch(ex, promise_function_wrapper<Function>(f)); } #endif // !defined(BOOST_ASIO_NO_DEPRECATED) // Helper base class for async_result specialisation. template <typename Signature, typename Allocator> class promise_async_result { public: typedef promise_handler<Signature, Allocator> 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 <typename Function, typename Allocator> 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 <typename Function, typename Allocator, typename Result> class packaged_handler : public promise_creator<Result> { public: typedef Allocator allocator_type; typedef void result_type; packaged_handler(packaged_token<Function, Allocator> 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 <typename... Args> 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 <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ 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_; }; #if !defined(BOOST_ASIO_NO_DEPRECATED) template <typename Function, typename Function1, typename Allocator, typename Result> inline void asio_handler_invoke(Function& f, packaged_handler<Function1, Allocator, Result>* h) { typename packaged_handler<Function1, Allocator, Result>::executor_type ex(h->get_executor()); boost::asio::dispatch(ex, promise_function_wrapper<Function>(f)); } template <typename Function, typename Function1, typename Allocator, typename Result> inline void asio_handler_invoke(const Function& f, packaged_handler<Function1, Allocator, Result>* h) { typename packaged_handler<Function1, Allocator, Result>::executor_type ex(h->get_executor()); boost::asio::dispatch(ex, promise_function_wrapper<Function>(f)); } #endif // !defined(BOOST_ASIO_NO_DEPRECATED) // Helper base class for async_result specialisation. template <typename Function, typename Allocator, typename Result> class packaged_async_result { public: typedef packaged_handler<Function, Allocator, Result> 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 <typename Allocator> template <typename Function> inline detail::packaged_token<typename decay<Function>::type, Allocator> use_future_t<Allocator>::operator()(BOOST_ASIO_MOVE_ARG(Function) f) const { return detail::packaged_token<typename decay<Function>::type, Allocator>( BOOST_ASIO_MOVE_CAST(Function)(f), allocator_); } #if !defined(GENERATING_DOCUMENTATION) #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename Allocator, typename Result, typename... Args> class async_result<use_future_t<Allocator>, Result(Args...)> : public detail::promise_async_result< void(typename decay<Args>::type...), Allocator> { public: explicit async_result( typename detail::promise_async_result<void(typename decay<Args>::type...), Allocator>::completion_handler_type& h) : detail::promise_async_result< void(typename decay<Args>::type...), Allocator>(h) { } }; template <typename Function, typename Allocator, typename Result, typename... Args> class async_result<detail::packaged_token<Function, Allocator>, Result(Args...)> : public detail::packaged_async_result<Function, Allocator, typename result_of<Function(Args...)>::type> { public: explicit async_result( typename detail::packaged_async_result<Function, Allocator, typename result_of<Function(Args...)>::type>::completion_handler_type& h) : detail::packaged_async_result<Function, Allocator, typename result_of<Function(Args...)>::type>(h) { } }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename Allocator, typename Result> class async_result<use_future_t<Allocator>, Result()> : public detail::promise_async_result<void(), Allocator> { public: explicit async_result( typename detail::promise_async_result< void(), Allocator>::completion_handler_type& h) : detail::promise_async_result<void(), Allocator>(h) { } }; template <typename Function, typename Allocator, typename Result> class async_result<detail::packaged_token<Function, Allocator>, Result()> : public detail::packaged_async_result<Function, Allocator, typename result_of<Function()>::type> { public: explicit async_result( typename detail::packaged_async_result<Function, Allocator, typename result_of<Function()>::type>::completion_handler_type& h) : detail::packaged_async_result<Function, Allocator, typename result_of<Function()>::type>(h) { } }; #define BOOST_ASIO_PRIVATE_ASYNC_RESULT_DEF(n) \ template <typename Allocator, \ typename Result, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ class async_result<use_future_t<Allocator>, \ 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 <typename Function, typename Allocator, \ typename Result, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ class async_result<detail::packaged_token<Function, Allocator>, \ Result(BOOST_ASIO_VARIADIC_TARGS(n))> \ : public detail::packaged_async_result<Function, Allocator, \ typename result_of<Function(BOOST_ASIO_VARIADIC_TARGS(n))>::type> \ { \ public: \ explicit async_result( \ typename detail::packaged_async_result<Function, Allocator, \ typename result_of<Function(BOOST_ASIO_VARIADIC_TARGS(n))>::type \ >::completion_handler_type& h) \ : detail::packaged_async_result<Function, Allocator, \ typename result_of<Function(BOOST_ASIO_VARIADIC_TARGS(n))>::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) namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) template <typename T, typename Blocking> struct equality_comparable< boost::asio::detail::promise_executor<T, Blocking> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) template <typename T, typename Blocking, typename Function> struct execute_member< boost::asio::detail::promise_executor<T, Blocking>, Function> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_TRAIT) template <typename T, typename Blocking, typename Property> struct query_static_constexpr_member< boost::asio::detail::promise_executor<T, Blocking>, Property, typename boost::asio::enable_if< boost::asio::is_convertible< Property, boost::asio::execution::blocking_t >::value >::type > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef Blocking result_type; static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT { return Blocking(); } }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) template <typename T, typename Blocking> struct require_member< boost::asio::detail::promise_executor<T, Blocking>, execution::blocking_t::possibly_t > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef boost::asio::detail::promise_executor<T, execution::blocking_t::possibly_t> result_type; }; template <typename T, typename Blocking> struct require_member< boost::asio::detail::promise_executor<T, Blocking>, execution::blocking_t::never_t > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef boost::asio::detail::promise_executor<T, execution::blocking_t::never_t> result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) } // namespace traits #endif // !defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_USE_FUTURE_HPP impl/executor.hpp 0000644 00000015263 15125530236 0010065 0 ustar 00 // // impl/executor.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) #include <boost/asio/detail/atomic_count.hpp> #include <boost/asio/detail/global.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/recycling_allocator.hpp> #include <boost/asio/executor.hpp> #include <boost/asio/system_executor.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if !defined(GENERATING_DOCUMENTATION) // Default polymorphic executor implementation. template <typename Executor, typename Allocator> 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 { detail::ref_count_up(ref_count_); return const_cast<impl_base*>(static_cast<const impl_base*>(this)); } void destroy() BOOST_ASIO_NOEXCEPT { if (detail::ref_count_down(ref_count_)) { 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<Executor>(); } 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<const Executor*>(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 executor specialisation for system_executor. template <typename Allocator> class executor::impl<system_executor, Allocator> : public executor::impl_base { public: static impl_base* create(const system_executor&, const Allocator& = Allocator()) { return &detail::global<impl<system_executor, std::allocator<void> > >(); } impl() : impl_base(true) { } impl_base* clone() const BOOST_ASIO_NOEXCEPT { return const_cast<impl_base*>(static_cast<const impl_base*>(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), std::allocator<void>()); } void post(BOOST_ASIO_MOVE_ARG(function) f) { executor_.post(BOOST_ASIO_MOVE_CAST(function)(f), std::allocator<void>()); } void defer(BOOST_ASIO_MOVE_ARG(function) f) { executor_.defer(BOOST_ASIO_MOVE_CAST(function)(f), std::allocator<void>()); } type_id_result_type target_type() const BOOST_ASIO_NOEXCEPT { return type_id<system_executor>(); } 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_; }; template <typename Executor> executor::executor(Executor e) : impl_(impl<Executor, std::allocator<void> >::create(e)) { } template <typename Executor, typename Allocator> executor::executor(allocator_arg_t, const Allocator& a, Executor e) : impl_(impl<Executor, Allocator>::create(e, a)) { } template <typename Function, typename Allocator> 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 <typename Function, typename Allocator> 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 <typename Function, typename Allocator> 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 <typename Executor> Executor* executor::target() BOOST_ASIO_NOEXCEPT { return impl_ && impl_->target_type() == type_id<Executor>() ? static_cast<Executor*>(impl_->target()) : 0; } template <typename Executor> const Executor* executor::target() const BOOST_ASIO_NOEXCEPT { return impl_ && impl_->target_type() == type_id<Executor>() ? static_cast<Executor*>(impl_->target()) : 0; } #endif // !defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) #endif // BOOST_ASIO_IMPL_EXECUTOR_HPP impl/read.hpp 0000644 00000130171 15125530236 0007136 0 ustar 00 // // impl/read.hpp // ~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <algorithm> #include <boost/asio/associated_allocator.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/completion_condition.hpp> #include <boost/asio/detail/array_fwd.hpp> #include <boost/asio/detail/base_from_completion_cond.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/consuming_buffers.hpp> #include <boost/asio/detail/dependent_type.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_tracking.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename SyncReadStream, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition> 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<mutable_buffer, MutableBufferSequence, MutableBufferIterator> 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 <typename SyncReadStream, typename MutableBufferSequence, typename CompletionCondition> std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, boost::system::error_code& ec, typename enable_if< is_mutable_buffer_sequence<MutableBufferSequence>::value >::type*) { return detail::read_buffer_sequence(s, buffers, boost::asio::buffer_sequence_begin(buffers), BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); } template <typename SyncReadStream, typename MutableBufferSequence> inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, typename enable_if< is_mutable_buffer_sequence<MutableBufferSequence>::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 <typename SyncReadStream, typename MutableBufferSequence> inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, boost::system::error_code& ec, typename enable_if< is_mutable_buffer_sequence<MutableBufferSequence>::value >::type*) { return read(s, buffers, transfer_all(), ec); } template <typename SyncReadStream, typename MutableBufferSequence, typename CompletionCondition> inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, typename enable_if< is_mutable_buffer_sequence<MutableBufferSequence>::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 <typename SyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition> 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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { typename decay<DynamicBuffer_v1>::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::size_t>( std::max<std::size_t>(512, b.capacity() - b.size()), std::min<std::size_t>(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::size_t>( std::max<std::size_t>(512, b.capacity() - b.size()), std::min<std::size_t>(max_size, b.max_size() - b.size())); } return total_transferred; } template <typename SyncReadStream, typename DynamicBuffer_v1> inline std::size_t read(SyncReadStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, typename enable_if< is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncReadStream, typename DynamicBuffer_v1> 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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { return read(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), transfer_all(), ec); } template <typename SyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition> inline std::size_t read(SyncReadStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, CompletionCondition completion_condition, typename enable_if< is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncReadStream, typename Allocator, typename CompletionCondition> inline std::size_t read(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition, boost::system::error_code& ec) { return read(s, basic_streambuf_ref<Allocator>(b), BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), ec); } template <typename SyncReadStream, typename Allocator> inline std::size_t read(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b) { return read(s, basic_streambuf_ref<Allocator>(b)); } template <typename SyncReadStream, typename Allocator> inline std::size_t read(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, boost::system::error_code& ec) { return read(s, basic_streambuf_ref<Allocator>(b), ec); } template <typename SyncReadStream, typename Allocator, typename CompletionCondition> inline std::size_t read(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition) { return read(s, basic_streambuf_ref<Allocator>(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 <typename SyncReadStream, typename DynamicBuffer_v2, typename CompletionCondition> std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, CompletionCondition completion_condition, boost::system::error_code& ec, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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::size_t>( std::max<std::size_t>(512, b.capacity() - b.size()), std::min<std::size_t>(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::size_t>( std::max<std::size_t>(512, b.capacity() - b.size()), std::min<std::size_t>(max_size, b.max_size() - b.size())); } return total_transferred; } template <typename SyncReadStream, typename DynamicBuffer_v2> inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <typename SyncReadStream, typename DynamicBuffer_v2> inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, boost::system::error_code& ec, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_v2>::value >::type*) { return read(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), transfer_all(), ec); } template <typename SyncReadStream, typename DynamicBuffer_v2, typename CompletionCondition> inline std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, CompletionCondition completion_condition, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <typename AsyncReadStream, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> class read_op : detail::base_from_completion_cond<CompletionCondition> { 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<CompletionCondition>(other), stream_(other.stream_), buffers_(other.buffers_), start_(other.start_), handler_(other.handler_) { } read_op(read_op&& other) : detail::base_from_completion_cond<CompletionCondition>( 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 { { BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read")); 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<mutable_buffer, MutableBufferSequence, MutableBufferIterator> buffers_type; AsyncReadStream& stream_; buffers_type buffers_; int start_; ReadHandler handler_; }; template <typename AsyncReadStream, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> inline bool asio_handler_is_continuation( read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename AsyncReadStream, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename AsyncReadStream, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler> inline void start_read_buffer_sequence_op(AsyncReadStream& stream, const MutableBufferSequence& buffers, const MutableBufferIterator&, CompletionCondition& completion_condition, ReadHandler& handler) { detail::read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>( stream, buffers, completion_condition, handler)( boost::system::error_code(), 0, 1); } template <typename AsyncReadStream> class initiate_async_read_buffer_sequence { public: typedef typename AsyncReadStream::executor_type executor_type; explicit initiate_async_read_buffer_sequence(AsyncReadStream& stream) : stream_(stream) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return stream_.get_executor(); } template <typename ReadHandler, typename MutableBufferSequence, typename CompletionCondition> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); start_read_buffer_sequence_op(stream_, buffers, boost::asio::buffer_sequence_begin(buffers), completion_cond2.value, handler2.value); } private: AsyncReadStream& stream_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler, typename Allocator> struct associated_allocator< detail::read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>, Allocator> { typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( const detail::read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; template <typename AsyncReadStream, typename MutableBufferSequence, typename MutableBufferIterator, typename CompletionCondition, typename ReadHandler, typename Executor> struct associated_executor< detail::read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>, Executor> : detail::associated_executor_forwarding_base<ReadHandler, Executor> { typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( const detail::read_op<AsyncReadStream, MutableBufferSequence, MutableBufferIterator, CompletionCondition, ReadHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename MutableBufferSequence, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> inline BOOST_ASIO_INITFN_AUTO_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<MutableBufferSequence>::value >::type*) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_read_buffer_sequence<AsyncReadStream>(s), handler, buffers, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } template <typename AsyncReadStream, typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> inline BOOST_ASIO_INITFN_AUTO_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<MutableBufferSequence>::value >::type*) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_read_buffer_sequence<AsyncReadStream>(s), handler, buffers, transfer_all()); } #if !defined(BOOST_ASIO_NO_DYNAMIC_BUFFER_V1) namespace detail { template <typename AsyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition, typename ReadHandler> class read_dynbuf_v1_op : detail::base_from_completion_cond<CompletionCondition> { public: template <typename BufferSequence> 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<CompletionCondition>(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<CompletionCondition>( 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::size_t>( std::max<std::size_t>(512, buffers_.capacity() - buffers_.size()), std::min<std::size_t>(max_size, buffers_.max_size() - buffers_.size())); for (;;) { { BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read")); 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::size_t>( std::max<std::size_t>(512, buffers_.capacity() - buffers_.size()), std::min<std::size_t>(max_size, buffers_.max_size() - buffers_.size())); if ((!ec && bytes_transferred == 0) || bytes_available == 0) break; } handler_(ec, static_cast<const std::size_t&>(total_transferred_)); } } //private: AsyncReadStream& stream_; DynamicBuffer_v1 buffers_; int start_; std::size_t total_transferred_; ReadHandler handler_; }; template <typename AsyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition, typename ReadHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1, CompletionCondition, ReadHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition, typename ReadHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition, typename ReadHandler> inline bool asio_handler_is_continuation( read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1, CompletionCondition, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream> class initiate_async_read_dynbuf_v1 { public: typedef typename AsyncReadStream::executor_type executor_type; explicit initiate_async_read_dynbuf_v1(AsyncReadStream& stream) : stream_(stream) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return stream_.get_executor(); } template <typename ReadHandler, typename DynamicBuffer_v1, typename CompletionCondition> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); read_dynbuf_v1_op<AsyncReadStream, typename decay<DynamicBuffer_v1>::type, CompletionCondition, typename decay<ReadHandler>::type>( stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), completion_cond2.value, handler2.value)( boost::system::error_code(), 0, 1); } private: AsyncReadStream& stream_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition, typename ReadHandler, typename Allocator> struct associated_allocator< detail::read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1, CompletionCondition, ReadHandler>, Allocator> { typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( const detail::read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1, CompletionCondition, ReadHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; template <typename AsyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition, typename ReadHandler, typename Executor> struct associated_executor< detail::read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1, CompletionCondition, ReadHandler>, Executor> : detail::associated_executor_forwarding_base<ReadHandler, Executor> { typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( const detail::read_dynbuf_v1_op<AsyncReadStream, DynamicBuffer_v1, CompletionCondition, ReadHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v1, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> inline BOOST_ASIO_INITFN_AUTO_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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { return async_read(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v1)(buffers), transfer_all(), BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); } template <typename AsyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> inline BOOST_ASIO_INITFN_AUTO_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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::type>::value >::type*) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_read_dynbuf_v1<AsyncReadStream>(s), handler, 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 <typename AsyncReadStream, typename Allocator, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { return async_read(s, basic_streambuf_ref<Allocator>(b), BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); } template <typename AsyncReadStream, typename Allocator, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, CompletionCondition completion_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { return async_read(s, basic_streambuf_ref<Allocator>(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 <typename AsyncReadStream, typename DynamicBuffer_v2, typename CompletionCondition, typename ReadHandler> class read_dynbuf_v2_op : detail::base_from_completion_cond<CompletionCondition> { public: template <typename BufferSequence> 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<CompletionCondition>(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<CompletionCondition>( 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::size_t>( std::max<std::size_t>(512, buffers_.capacity() - buffers_.size()), std::min<std::size_t>(max_size, buffers_.max_size() - buffers_.size())); for (;;) { pos = buffers_.size(); buffers_.grow(bytes_available_); { BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_read")); 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::size_t>( std::max<std::size_t>(512, buffers_.capacity() - buffers_.size()), std::min<std::size_t>(max_size, buffers_.max_size() - buffers_.size())); if ((!ec && bytes_transferred == 0) || bytes_available_ == 0) break; } handler_(ec, static_cast<const std::size_t&>(total_transferred_)); } } //private: AsyncReadStream& stream_; DynamicBuffer_v2 buffers_; int start_; std::size_t total_transferred_; std::size_t bytes_available_; ReadHandler handler_; }; template <typename AsyncReadStream, typename DynamicBuffer_v2, typename CompletionCondition, typename ReadHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2, CompletionCondition, ReadHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v2, typename CompletionCondition, typename ReadHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream, typename DynamicBuffer_v2, typename CompletionCondition, typename ReadHandler> inline bool asio_handler_is_continuation( read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2, CompletionCondition, ReadHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v2, typename CompletionCondition, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename AsyncReadStream, typename DynamicBuffer_v2, typename CompletionCondition, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2, CompletionCondition, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncReadStream> class initiate_async_read_dynbuf_v2 { public: typedef typename AsyncReadStream::executor_type executor_type; explicit initiate_async_read_dynbuf_v2(AsyncReadStream& stream) : stream_(stream) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return stream_.get_executor(); } template <typename ReadHandler, typename DynamicBuffer_v2, typename CompletionCondition> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); read_dynbuf_v2_op<AsyncReadStream, typename decay<DynamicBuffer_v2>::type, CompletionCondition, typename decay<ReadHandler>::type>( stream_, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), completion_cond2.value, handler2.value)( boost::system::error_code(), 0, 1); } private: AsyncReadStream& stream_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v2, typename CompletionCondition, typename ReadHandler, typename Allocator> struct associated_allocator< detail::read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2, CompletionCondition, ReadHandler>, Allocator> { typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get( const detail::read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2, CompletionCondition, ReadHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; template <typename AsyncReadStream, typename DynamicBuffer_v2, typename CompletionCondition, typename ReadHandler, typename Executor> struct associated_executor< detail::read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2, CompletionCondition, ReadHandler>, Executor> : detail::associated_executor_forwarding_base<ReadHandler, Executor> { typedef typename associated_executor<ReadHandler, Executor>::type type; static type get( const detail::read_dynbuf_v2_op<AsyncReadStream, DynamicBuffer_v2, CompletionCondition, ReadHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncReadStream, typename DynamicBuffer_v2, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> inline BOOST_ASIO_INITFN_AUTO_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<DynamicBuffer_v2>::value >::type*) { return async_read(s, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), transfer_all(), BOOST_ASIO_MOVE_CAST(ReadHandler)(handler)); } template <typename AsyncReadStream, typename DynamicBuffer_v2, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> inline BOOST_ASIO_INITFN_AUTO_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<DynamicBuffer_v2>::value >::type*) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_read_dynbuf_v2<AsyncReadStream>(s), handler, BOOST_ASIO_MOVE_CAST(DynamicBuffer_v2)(buffers), BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_READ_HPP impl/src.hpp 0000644 00000007371 15125530236 0007017 0 ustar 00 // // impl/src.hpp // ~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_SRC_HPP #define BOOST_ASIO_IMPL_SRC_HPP #define BOOST_ASIO_SOURCE #include <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # error Do not compile Asio library source with BOOST_ASIO_HEADER_ONLY defined #endif #include <boost/asio/impl/error.ipp> #include <boost/asio/impl/execution_context.ipp> #include <boost/asio/impl/executor.ipp> #include <boost/asio/impl/handler_alloc_hook.ipp> #include <boost/asio/impl/io_context.ipp> #include <boost/asio/impl/multiple_exceptions.ipp> #include <boost/asio/impl/serial_port_base.ipp> #include <boost/asio/impl/system_context.ipp> #include <boost/asio/impl/thread_pool.ipp> #include <boost/asio/detail/impl/buffer_sequence_adapter.ipp> #include <boost/asio/detail/impl/descriptor_ops.ipp> #include <boost/asio/detail/impl/dev_poll_reactor.ipp> #include <boost/asio/detail/impl/epoll_reactor.ipp> #include <boost/asio/detail/impl/eventfd_select_interrupter.ipp> #include <boost/asio/detail/impl/handler_tracking.ipp> #include <boost/asio/detail/impl/kqueue_reactor.ipp> #include <boost/asio/detail/impl/null_event.ipp> #include <boost/asio/detail/impl/pipe_select_interrupter.ipp> #include <boost/asio/detail/impl/posix_event.ipp> #include <boost/asio/detail/impl/posix_mutex.ipp> #include <boost/asio/detail/impl/posix_thread.ipp> #include <boost/asio/detail/impl/posix_tss_ptr.ipp> #include <boost/asio/detail/impl/reactive_descriptor_service.ipp> #include <boost/asio/detail/impl/reactive_serial_port_service.ipp> #include <boost/asio/detail/impl/reactive_socket_service_base.ipp> #include <boost/asio/detail/impl/resolver_service_base.ipp> #include <boost/asio/detail/impl/scheduler.ipp> #include <boost/asio/detail/impl/select_reactor.ipp> #include <boost/asio/detail/impl/service_registry.ipp> #include <boost/asio/detail/impl/signal_set_service.ipp> #include <boost/asio/detail/impl/socket_ops.ipp> #include <boost/asio/detail/impl/socket_select_interrupter.ipp> #include <boost/asio/detail/impl/strand_executor_service.ipp> #include <boost/asio/detail/impl/strand_service.ipp> #include <boost/asio/detail/impl/throw_error.ipp> #include <boost/asio/detail/impl/timer_queue_ptime.ipp> #include <boost/asio/detail/impl/timer_queue_set.ipp> #include <boost/asio/detail/impl/win_iocp_handle_service.ipp> #include <boost/asio/detail/impl/win_iocp_io_context.ipp> #include <boost/asio/detail/impl/win_iocp_serial_port_service.ipp> #include <boost/asio/detail/impl/win_iocp_socket_service_base.ipp> #include <boost/asio/detail/impl/win_event.ipp> #include <boost/asio/detail/impl/win_mutex.ipp> #include <boost/asio/detail/impl/win_object_handle_service.ipp> #include <boost/asio/detail/impl/win_static_mutex.ipp> #include <boost/asio/detail/impl/win_thread.ipp> #include <boost/asio/detail/impl/win_tss_ptr.ipp> #include <boost/asio/detail/impl/winrt_ssocket_service_base.ipp> #include <boost/asio/detail/impl/winrt_timer_scheduler.ipp> #include <boost/asio/detail/impl/winsock_init.ipp> #include <boost/asio/execution/impl/bad_executor.ipp> #include <boost/asio/execution/impl/receiver_invocation_error.ipp> #include <boost/asio/generic/detail/impl/endpoint.ipp> #include <boost/asio/ip/impl/address.ipp> #include <boost/asio/ip/impl/address_v4.ipp> #include <boost/asio/ip/impl/address_v6.ipp> #include <boost/asio/ip/impl/host_name.ipp> #include <boost/asio/ip/impl/network_v4.ipp> #include <boost/asio/ip/impl/network_v6.ipp> #include <boost/asio/ip/detail/impl/endpoint.ipp> #include <boost/asio/local/detail/impl/endpoint.ipp> #endif // BOOST_ASIO_IMPL_SRC_HPP impl/buffered_read_stream.hpp 0000644 00000041253 15125530236 0012355 0 ustar 00 // // impl/buffered_read_stream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/associated_allocator.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { template <typename Stream> std::size_t buffered_read_stream<Stream>::fill() { detail::buffer_resize_guard<detail::buffered_stream_storage> 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 <typename Stream> std::size_t buffered_read_stream<Stream>::fill(boost::system::error_code& ec) { detail::buffer_resize_guard<detail::buffered_stream_storage> 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 <typename ReadHandler> 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 <typename ReadHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, buffered_fill_handler<ReadHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename ReadHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, buffered_fill_handler<ReadHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename ReadHandler> inline bool asio_handler_is_continuation( buffered_fill_handler<ReadHandler>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, buffered_fill_handler<ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, buffered_fill_handler<ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Stream> class initiate_async_buffered_fill { public: typedef typename remove_reference< Stream>::type::lowest_layer_type::executor_type executor_type; explicit initiate_async_buffered_fill( typename remove_reference<Stream>::type& next_layer) : next_layer_(next_layer) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return next_layer_.lowest_layer().get_executor(); } template <typename ReadHandler> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, buffered_stream_storage* storage) 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<ReadHandler> 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<typename decay<ReadHandler>::type>( *storage, previous_size, handler2.value)); } private: typename remove_reference<Stream>::type& next_layer_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename ReadHandler, typename Allocator> struct associated_allocator< detail::buffered_fill_handler<ReadHandler>, Allocator> { typedef typename associated_allocator<ReadHandler, Allocator>::type type; static type get(const detail::buffered_fill_handler<ReadHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<ReadHandler, Allocator>::get(h.handler_, a); } }; template <typename ReadHandler, typename Executor> struct associated_executor< detail::buffered_fill_handler<ReadHandler>, Executor> : detail::associated_executor_forwarding_base<ReadHandler, Executor> { typedef typename associated_executor<ReadHandler, Executor>::type type; static type get(const detail::buffered_fill_handler<ReadHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<ReadHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename Stream> template < BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) buffered_read_stream<Stream>::async_fill( BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_buffered_fill<Stream>(next_layer_), handler, &storage_); } template <typename Stream> template <typename MutableBufferSequence> std::size_t buffered_read_stream<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 <typename Stream> template <typename MutableBufferSequence> std::size_t buffered_read_stream<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 <typename MutableBufferSequence, typename ReadHandler> 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 <typename MutableBufferSequence, typename ReadHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, buffered_read_some_handler< MutableBufferSequence, ReadHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename MutableBufferSequence, typename ReadHandler> inline asio_handler_deallocate_is_deprecated 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_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename MutableBufferSequence, typename ReadHandler> 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 <typename Function, typename MutableBufferSequence, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, buffered_read_some_handler< MutableBufferSequence, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename MutableBufferSequence, typename ReadHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, buffered_read_some_handler< MutableBufferSequence, ReadHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Stream> class initiate_async_buffered_read_some { public: typedef typename remove_reference< Stream>::type::lowest_layer_type::executor_type executor_type; explicit initiate_async_buffered_read_some( typename remove_reference<Stream>::type& next_layer) : next_layer_(next_layer) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return next_layer_.lowest_layer().get_executor(); } template <typename ReadHandler, typename MutableBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, buffered_stream_storage* storage, 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<ReadHandler> handler2(handler); if (buffer_size(buffers) == 0 || !storage->empty()) { next_layer_.async_read_some(BOOST_ASIO_MUTABLE_BUFFER(0, 0), buffered_read_some_handler<MutableBufferSequence, typename decay<ReadHandler>::type>( *storage, buffers, handler2.value)); } else { initiate_async_buffered_fill<Stream>(this->next_layer_)( buffered_read_some_handler<MutableBufferSequence, typename decay<ReadHandler>::type>( *storage, buffers, handler2.value), storage); } } private: typename remove_reference<Stream>::type& next_layer_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename MutableBufferSequence, typename ReadHandler, typename Allocator> struct associated_allocator< detail::buffered_read_some_handler<MutableBufferSequence, ReadHandler>, Allocator> { typedef typename associated_allocator<ReadHandler, 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<ReadHandler, Allocator>::get(h.handler_, a); } }; template <typename MutableBufferSequence, typename ReadHandler, typename Executor> struct associated_executor< detail::buffered_read_some_handler<MutableBufferSequence, ReadHandler>, Executor> : detail::associated_executor_forwarding_base<ReadHandler, Executor> { typedef typename associated_executor<ReadHandler, 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<ReadHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename Stream> template <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) buffered_read_stream<Stream>::async_read_some( const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_buffered_read_some<Stream>(next_layer_), handler, &storage_, buffers); } template <typename Stream> template <typename MutableBufferSequence> std::size_t buffered_read_stream<Stream>::peek( const MutableBufferSequence& buffers) { if (storage_.empty()) this->fill(); return this->peek_copy(buffers); } template <typename Stream> template <typename MutableBufferSequence> std::size_t buffered_read_stream<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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_BUFFERED_READ_STREAM_HPP impl/io_context.ipp 0000644 00000010014 15125530236 0010370 0 ustar 00 // // impl/io_context.ipp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/io_context.hpp> #include <boost/asio/detail/concurrency_hint.hpp> #include <boost/asio/detail/limits.hpp> #include <boost/asio/detail/scoped_ptr.hpp> #include <boost/asio/detail/service_registry.hpp> #include <boost/asio/detail/throw_error.hpp> #if defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/win_iocp_io_context.hpp> #else # include <boost/asio/detail/scheduler.hpp> #endif #include <boost/asio/detail/push_options.hpp> 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<impl_type> scoped_impl(impl); boost::asio::add_service<impl_type>(*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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_IO_CONTEXT_IPP impl/dispatch.hpp 0000644 00000016617 15125530236 0010032 0 ustar 00 // // impl/dispatch.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/associated_allocator.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/detail/work_dispatcher.hpp> #include <boost/asio/execution/allocator.hpp> #include <boost/asio/execution/blocking.hpp> #include <boost/asio/prefer.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class initiate_dispatch { public: template <typename CompletionHandler> void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, typename enable_if< execution::is_executor< typename associated_executor< typename decay<CompletionHandler>::type >::type >::value >::type* = 0) const { typedef typename decay<CompletionHandler>::type handler_t; typename associated_executor<handler_t>::type ex( (get_associated_executor)(handler)); typename associated_allocator<handler_t>::type alloc( (get_associated_allocator)(handler)); execution::execute( boost::asio::prefer(ex, execution::blocking.possibly, execution::allocator(alloc)), BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); } template <typename CompletionHandler> void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, typename enable_if< !execution::is_executor< typename associated_executor< typename decay<CompletionHandler>::type >::type >::value >::type* = 0) const { typedef typename decay<CompletionHandler>::type handler_t; typename associated_executor<handler_t>::type ex( (get_associated_executor)(handler)); typename associated_allocator<handler_t>::type alloc( (get_associated_allocator)(handler)); ex.dispatch(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); } }; template <typename Executor> class initiate_dispatch_with_executor { public: typedef Executor executor_type; explicit initiate_dispatch_with_executor(const Executor& ex) : ex_(ex) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return ex_; } template <typename CompletionHandler> void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, typename enable_if< execution::is_executor< typename conditional<true, executor_type, CompletionHandler>::type >::value && !detail::is_work_dispatcher_required< typename decay<CompletionHandler>::type, Executor >::value >::type* = 0) const { typedef typename decay<CompletionHandler>::type handler_t; typename associated_allocator<handler_t>::type alloc( (get_associated_allocator)(handler)); execution::execute( boost::asio::prefer(ex_, execution::blocking.possibly, execution::allocator(alloc)), BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); } template <typename CompletionHandler> void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, typename enable_if< execution::is_executor< typename conditional<true, executor_type, CompletionHandler>::type >::value && detail::is_work_dispatcher_required< typename decay<CompletionHandler>::type, Executor >::value >::type* = 0) const { typedef typename decay<CompletionHandler>::type handler_t; typedef typename associated_executor< handler_t, Executor>::type handler_ex_t; handler_ex_t handler_ex((get_associated_executor)(handler, ex_)); typename associated_allocator<handler_t>::type alloc( (get_associated_allocator)(handler)); execution::execute( boost::asio::prefer(ex_, execution::blocking.possibly, execution::allocator(alloc)), detail::work_dispatcher<handler_t, handler_ex_t>( BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), handler_ex)); } template <typename CompletionHandler> void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, typename enable_if< !execution::is_executor< typename conditional<true, executor_type, CompletionHandler>::type >::value && !detail::is_work_dispatcher_required< typename decay<CompletionHandler>::type, Executor >::value >::type* = 0) const { typedef typename decay<CompletionHandler>::type handler_t; typename associated_allocator<handler_t>::type alloc( (get_associated_allocator)(handler)); ex_.dispatch(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); } template <typename CompletionHandler> void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, typename enable_if< !execution::is_executor< typename conditional<true, executor_type, CompletionHandler>::type >::value && detail::is_work_dispatcher_required< typename decay<CompletionHandler>::type, Executor >::value >::type* = 0) const { typedef typename decay<CompletionHandler>::type handler_t; typedef typename associated_executor< handler_t, Executor>::type handler_ex_t; handler_ex_t handler_ex((get_associated_executor)(handler, ex_)); typename associated_allocator<handler_t>::type alloc( (get_associated_allocator)(handler)); ex_.dispatch(detail::work_dispatcher<handler_t, handler_ex_t>( BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), handler_ex), alloc); } private: Executor ex_; }; } // namespace detail template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch( BOOST_ASIO_MOVE_ARG(CompletionToken) token) { return async_initiate<CompletionToken, void()>( detail::initiate_dispatch(), token); } template <typename Executor, BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch( const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, typename enable_if< execution::is_executor<Executor>::value || is_executor<Executor>::value >::type*) { return async_initiate<CompletionToken, void()>( detail::initiate_dispatch_with_executor<Executor>(ex), token); } template <typename ExecutionContext, BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch( ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, typename enable_if<is_convertible< ExecutionContext&, execution_context&>::value>::type*) { return async_initiate<CompletionToken, void()>( detail::initiate_dispatch_with_executor< typename ExecutionContext::executor_type>( ctx.get_executor()), token); } } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_DISPATCH_HPP impl/spawn.hpp 0000644 00000037061 15125530236 0007357 0 ustar 00 // // impl/spawn.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_SPAWN_HPP #define BOOST_ASIO_IMPL_SPAWN_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/associated_allocator.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/bind_executor.hpp> #include <boost/asio/detail/atomic_count.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/system/system_error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Handler, typename T> class coro_handler { public: coro_handler(basic_yield_context<Handler> ctx) : coro_(ctx.coro_.lock()), ca_(ctx.ca_), handler_(ctx.handler_), ready_(0), ec_(ctx.ec_), value_(0) { } void operator()(T value) { *ec_ = boost::system::error_code(); *value_ = BOOST_ASIO_MOVE_CAST(T)(value); if (--*ready_ == 0) (*coro_)(); } void operator()(boost::system::error_code ec, T value) { *ec_ = ec; *value_ = BOOST_ASIO_MOVE_CAST(T)(value); if (--*ready_ == 0) (*coro_)(); } //private: shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_; typename basic_yield_context<Handler>::caller_type& ca_; Handler handler_; atomic_count* ready_; boost::system::error_code* ec_; T* value_; }; template <typename Handler> class coro_handler<Handler, void> { public: coro_handler(basic_yield_context<Handler> ctx) : coro_(ctx.coro_.lock()), ca_(ctx.ca_), handler_(ctx.handler_), ready_(0), ec_(ctx.ec_) { } void operator()() { *ec_ = boost::system::error_code(); if (--*ready_ == 0) (*coro_)(); } void operator()(boost::system::error_code ec) { *ec_ = ec; if (--*ready_ == 0) (*coro_)(); } //private: shared_ptr<typename basic_yield_context<Handler>::callee_type> coro_; typename basic_yield_context<Handler>::caller_type& ca_; Handler handler_; atomic_count* ready_; boost::system::error_code* ec_; }; template <typename Handler, typename T> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, coro_handler<Handler, T>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename T> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, coro_handler<Handler, T>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename T> inline bool asio_handler_is_continuation(coro_handler<Handler, T>*) { return true; } template <typename Function, typename Handler, typename T> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, coro_handler<Handler, T>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename Handler, typename T> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, coro_handler<Handler, T>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename T> class coro_async_result { public: typedef coro_handler<Handler, T> completion_handler_type; typedef T return_type; explicit coro_async_result(completion_handler_type& h) : handler_(h), ca_(h.ca_), ready_(2) { h.ready_ = &ready_; out_ec_ = h.ec_; if (!out_ec_) h.ec_ = &ec_; h.value_ = &value_; } return_type get() { // Must not hold shared_ptr to coro while suspended. handler_.coro_.reset(); if (--ready_ != 0) ca_(); if (!out_ec_ && ec_) throw boost::system::system_error(ec_); return BOOST_ASIO_MOVE_CAST(return_type)(value_); } private: completion_handler_type& handler_; typename basic_yield_context<Handler>::caller_type& ca_; atomic_count ready_; boost::system::error_code* out_ec_; boost::system::error_code ec_; return_type value_; }; template <typename Handler> class coro_async_result<Handler, void> { public: typedef coro_handler<Handler, void> completion_handler_type; typedef void return_type; explicit coro_async_result(completion_handler_type& h) : handler_(h), ca_(h.ca_), ready_(2) { h.ready_ = &ready_; out_ec_ = h.ec_; if (!out_ec_) h.ec_ = &ec_; } void get() { // Must not hold shared_ptr to coro while suspended. handler_.coro_.reset(); if (--ready_ != 0) ca_(); if (!out_ec_ && ec_) throw boost::system::system_error(ec_); } private: completion_handler_type& handler_; typename basic_yield_context<Handler>::caller_type& ca_; atomic_count ready_; boost::system::error_code* out_ec_; boost::system::error_code ec_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename Handler, typename ReturnType> class async_result<basic_yield_context<Handler>, ReturnType()> : public detail::coro_async_result<Handler, void> { public: explicit async_result( typename detail::coro_async_result<Handler, void>::completion_handler_type& h) : detail::coro_async_result<Handler, void>(h) { } }; template <typename Handler, typename ReturnType, typename Arg1> class async_result<basic_yield_context<Handler>, ReturnType(Arg1)> : public detail::coro_async_result<Handler, typename decay<Arg1>::type> { public: explicit async_result( typename detail::coro_async_result<Handler, typename decay<Arg1>::type>::completion_handler_type& h) : detail::coro_async_result<Handler, typename decay<Arg1>::type>(h) { } }; template <typename Handler, typename ReturnType> class async_result<basic_yield_context<Handler>, ReturnType(boost::system::error_code)> : public detail::coro_async_result<Handler, void> { public: explicit async_result( typename detail::coro_async_result<Handler, void>::completion_handler_type& h) : detail::coro_async_result<Handler, void>(h) { } }; template <typename Handler, typename ReturnType, typename Arg2> class async_result<basic_yield_context<Handler>, ReturnType(boost::system::error_code, Arg2)> : public detail::coro_async_result<Handler, typename decay<Arg2>::type> { public: explicit async_result( typename detail::coro_async_result<Handler, typename decay<Arg2>::type>::completion_handler_type& h) : detail::coro_async_result<Handler, typename decay<Arg2>::type>(h) { } }; template <typename Handler, typename T, typename Allocator> struct associated_allocator<detail::coro_handler<Handler, T>, Allocator> { typedef typename associated_allocator<Handler, Allocator>::type type; static type get(const detail::coro_handler<Handler, T>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<Handler, Allocator>::get(h.handler_, a); } }; template <typename Handler, typename T, typename Executor> struct associated_executor<detail::coro_handler<Handler, T>, Executor> : detail::associated_executor_forwarding_base<Handler, Executor> { typedef typename associated_executor<Handler, Executor>::type type; static type get(const detail::coro_handler<Handler, T>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<Handler, Executor>::get(h.handler_, ex); } }; namespace detail { template <typename Handler, typename Function> struct spawn_data : private noncopyable { template <typename Hand, typename Func> spawn_data(BOOST_ASIO_MOVE_ARG(Hand) handler, bool call_handler, BOOST_ASIO_MOVE_ARG(Func) function) : handler_(BOOST_ASIO_MOVE_CAST(Hand)(handler)), call_handler_(call_handler), function_(BOOST_ASIO_MOVE_CAST(Func)(function)) { } weak_ptr<typename basic_yield_context<Handler>::callee_type> coro_; Handler handler_; bool call_handler_; Function function_; }; template <typename Handler, typename Function> struct coro_entry_point { void operator()(typename basic_yield_context<Handler>::caller_type& ca) { shared_ptr<spawn_data<Handler, Function> > data(data_); #if !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2) ca(); // Yield until coroutine pointer has been initialised. #endif // !defined(BOOST_COROUTINES_UNIDIRECT) && !defined(BOOST_COROUTINES_V2) const basic_yield_context<Handler> yield( data->coro_, ca, data->handler_); (data->function_)(yield); if (data->call_handler_) (data->handler_)(); } shared_ptr<spawn_data<Handler, Function> > data_; }; template <typename Handler, typename Function> struct spawn_helper { typedef typename associated_allocator<Handler>::type allocator_type; allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT { return (get_associated_allocator)(data_->handler_); } typedef typename associated_executor<Handler>::type executor_type; executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return (get_associated_executor)(data_->handler_); } void operator()() { typedef typename basic_yield_context<Handler>::callee_type callee_type; coro_entry_point<Handler, Function> entry_point = { data_ }; shared_ptr<callee_type> coro(new callee_type(entry_point, attributes_)); data_->coro_ = coro; (*coro)(); } shared_ptr<spawn_data<Handler, Function> > data_; boost::coroutines::attributes attributes_; }; template <typename Function, typename Handler, typename Function1> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, spawn_helper<Handler, Function1>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->data_->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename Handler, typename Function1> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, spawn_helper<Handler, Function1>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->data_->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } inline void default_spawn_handler() {} } // namespace detail template <typename Function> inline void spawn(BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes) { typedef typename decay<Function>::type function_type; typename associated_executor<function_type>::type ex( (get_associated_executor)(function)); boost::asio::spawn(ex, BOOST_ASIO_MOVE_CAST(Function)(function), attributes); } template <typename Handler, typename Function> void spawn(BOOST_ASIO_MOVE_ARG(Handler) handler, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes, typename enable_if< !is_executor<typename decay<Handler>::type>::value && !execution::is_executor<typename decay<Handler>::type>::value && !is_convertible<Handler&, execution_context&>::value>::type*) { typedef typename decay<Handler>::type handler_type; typedef typename decay<Function>::type function_type; detail::spawn_helper<handler_type, function_type> helper; helper.data_.reset( new detail::spawn_data<handler_type, function_type>( BOOST_ASIO_MOVE_CAST(Handler)(handler), true, BOOST_ASIO_MOVE_CAST(Function)(function))); helper.attributes_ = attributes; boost::asio::dispatch(helper); } template <typename Handler, typename Function> void spawn(basic_yield_context<Handler> ctx, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes) { typedef typename decay<Function>::type function_type; Handler handler(ctx.handler_); // Explicit copy that might be moved from. detail::spawn_helper<Handler, function_type> helper; helper.data_.reset( new detail::spawn_data<Handler, function_type>( BOOST_ASIO_MOVE_CAST(Handler)(handler), false, BOOST_ASIO_MOVE_CAST(Function)(function))); helper.attributes_ = attributes; boost::asio::dispatch(helper); } template <typename Function, typename Executor> inline void spawn(const Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes, typename enable_if< is_executor<Executor>::value || execution::is_executor<Executor>::value >::type*) { boost::asio::spawn(boost::asio::strand<Executor>(ex), BOOST_ASIO_MOVE_CAST(Function)(function), attributes); } template <typename Function, typename Executor> inline void spawn(const strand<Executor>& ex, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes) { boost::asio::spawn(boost::asio::bind_executor( ex, &detail::default_spawn_handler), BOOST_ASIO_MOVE_CAST(Function)(function), attributes); } #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) template <typename Function> inline void spawn(const boost::asio::io_context::strand& s, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes) { boost::asio::spawn(boost::asio::bind_executor( s, &detail::default_spawn_handler), BOOST_ASIO_MOVE_CAST(Function)(function), attributes); } #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) template <typename Function, typename ExecutionContext> inline void spawn(ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes, typename enable_if<is_convertible< ExecutionContext&, execution_context&>::value>::type*) { boost::asio::spawn(ctx.get_executor(), BOOST_ASIO_MOVE_CAST(Function)(function), attributes); } #endif // !defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_SPAWN_HPP impl/io_context.hpp 0000644 00000032640 15125530236 0010400 0 ustar 00 // // impl/io_context.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/completion_handler.hpp> #include <boost/asio/detail/executor_op.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/recycling_allocator.hpp> #include <boost/asio/detail/service_registry.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if !defined(GENERATING_DOCUMENTATION) template <typename Service> inline Service& use_service(io_context& ioc) { // Check that Service meets the necessary type requirements. (void)static_cast<execution_context::service*>(static_cast<Service*>(0)); (void)static_cast<const execution_context::id*>(&Service::id); return ioc.service_registry_->template use_service<Service>(ioc); } template <> inline detail::io_context_impl& use_service<detail::io_context_impl>( io_context& ioc) { return ioc.impl_; } #endif // !defined(GENERATING_DOCUMENTATION) inline io_context::executor_type io_context::get_executor() BOOST_ASIO_NOEXCEPT { return executor_type(*this); } #if defined(BOOST_ASIO_HAS_CHRONO) template <typename Rep, typename Period> std::size_t io_context::run_for( const chrono::duration<Rep, Period>& rel_time) { return this->run_until(chrono::steady_clock::now() + rel_time); } template <typename Clock, typename Duration> std::size_t io_context::run_until( const chrono::time_point<Clock, Duration>& abs_time) { std::size_t n = 0; while (this->run_one_until(abs_time)) if (n != (std::numeric_limits<std::size_t>::max)()) ++n; return n; } template <typename Rep, typename Period> std::size_t io_context::run_one_for( const chrono::duration<Rep, Period>& rel_time) { return this->run_one_until(chrono::steady_clock::now() + rel_time); } template <typename Clock, typename Duration> std::size_t io_context::run_one_until( const chrono::time_point<Clock, Duration>& 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<long>(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 <typename LegacyCompletionHandler> 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<LegacyCompletionHandler> 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<LegacyCompletionHandler>::type, executor_type> op; typename op::ptr p = { detail::addressof(handler2.value), op::ptr::allocate(handler2.value), 0 }; p.p = new (p.v) op(handler2.value, self->get_executor()); BOOST_ASIO_HANDLER_CREATION((*self, *p.p, "io_context", self, 0, "dispatch")); self->impl_.do_dispatch(p.p); p.v = p.p = 0; } } }; template <typename LegacyCompletionHandler> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ()) io_context::dispatch(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler) { return async_initiate<LegacyCompletionHandler, void ()>( initiate_dispatch(), handler, this); } struct io_context::initiate_post { template <typename LegacyCompletionHandler> 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<LegacyCompletionHandler> 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<LegacyCompletionHandler>::type, executor_type> op; typename op::ptr p = { detail::addressof(handler2.value), op::ptr::allocate(handler2.value), 0 }; p.p = new (p.v) op(handler2.value, self->get_executor()); 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 <typename LegacyCompletionHandler> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ()) io_context::post(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler) { return async_initiate<LegacyCompletionHandler, void ()>( initiate_post(), handler, this); } template <typename Handler> #if defined(GENERATING_DOCUMENTATION) unspecified #else inline detail::wrapped_handler<io_context&, Handler> #endif io_context::wrap(Handler handler) { return detail::wrapped_handler<io_context&, Handler>(*this, handler); } #endif // !defined(BOOST_ASIO_NO_DEPRECATED) template <typename Allocator, unsigned int Bits> io_context::basic_executor_type<Allocator, Bits>& io_context::basic_executor_type<Allocator, Bits>::operator=( const basic_executor_type& other) BOOST_ASIO_NOEXCEPT { if (this != &other) { io_context* old_io_context = io_context_; io_context_ = other.io_context_; allocator_ = other.allocator_; bits_ = other.bits_; if (Bits & outstanding_work_tracked) { if (io_context_) io_context_->impl_.work_started(); if (old_io_context) old_io_context->impl_.work_finished(); } } return *this; } #if defined(BOOST_ASIO_HAS_MOVE) template <typename Allocator, unsigned int Bits> io_context::basic_executor_type<Allocator, Bits>& io_context::basic_executor_type<Allocator, Bits>::operator=( basic_executor_type&& other) BOOST_ASIO_NOEXCEPT { if (this != &other) { io_context_ = other.io_context_; allocator_ = std::move(other.allocator_); bits_ = other.bits_; if (Bits & outstanding_work_tracked) other.io_context_ = 0; } return *this; } #endif // defined(BOOST_ASIO_HAS_MOVE) template <typename Allocator, unsigned int Bits> inline bool io_context::basic_executor_type<Allocator, Bits>::running_in_this_thread() const BOOST_ASIO_NOEXCEPT { return io_context_->impl_.can_dispatch(); } template <typename Allocator, unsigned int Bits> template <typename Function> void io_context::basic_executor_type<Allocator, Bits>::execute( BOOST_ASIO_MOVE_ARG(Function) f) const { typedef typename decay<Function>::type function_type; // Invoke immediately if the blocking.possibly property is enabled and we are // already inside the thread pool. if ((bits_ & blocking_never) == 0 && io_context_->impl_.can_dispatch()) { // Make a local, non-const copy of the function. function_type tmp(BOOST_ASIO_MOVE_CAST(Function)(f)); #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ && !defined(BOOST_ASIO_NO_EXCEPTIONS) try { #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) // && !defined(BOOST_ASIO_NO_EXCEPTIONS) detail::fenced_block b(detail::fenced_block::full); boost_asio_handler_invoke_helpers::invoke(tmp, tmp); return; #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ && !defined(BOOST_ASIO_NO_EXCEPTIONS) } catch (...) { io_context_->impl_.capture_current_exception(); return; } #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) // && !defined(BOOST_ASIO_NO_EXCEPTIONS) } // Allocate and construct an operation to wrap the function. typedef detail::executor_op<function_type, Allocator, detail::operation> op; typename op::ptr p = { detail::addressof(allocator_), op::ptr::allocate(allocator_), 0 }; p.p = new (p.v) op(BOOST_ASIO_MOVE_CAST(Function)(f), allocator_); BOOST_ASIO_HANDLER_CREATION((*io_context_, *p.p, "io_context", io_context_, 0, "execute")); io_context_->impl_.post_immediate_completion(p.p, (bits_ & relationship_continuation) != 0); p.v = p.p = 0; } #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) template <typename Allocator, unsigned int Bits> inline io_context& io_context::basic_executor_type< Allocator, Bits>::context() const BOOST_ASIO_NOEXCEPT { return *io_context_; } template <typename Allocator, unsigned int Bits> inline void io_context::basic_executor_type<Allocator, Bits>::on_work_started() const BOOST_ASIO_NOEXCEPT { io_context_->impl_.work_started(); } template <typename Allocator, unsigned int Bits> inline void io_context::basic_executor_type<Allocator, Bits>::on_work_finished() const BOOST_ASIO_NOEXCEPT { io_context_->impl_.work_finished(); } template <typename Allocator, unsigned int Bits> template <typename Function, typename OtherAllocator> void io_context::basic_executor_type<Allocator, Bits>::dispatch( BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const { typedef typename decay<Function>::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<function_type, OtherAllocator, detail::operation> 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((*io_context_, *p.p, "io_context", io_context_, 0, "dispatch")); io_context_->impl_.post_immediate_completion(p.p, false); p.v = p.p = 0; } template <typename Allocator, unsigned int Bits> template <typename Function, typename OtherAllocator> void io_context::basic_executor_type<Allocator, Bits>::post( BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const { typedef typename decay<Function>::type function_type; // Allocate and construct an operation to wrap the function. typedef detail::executor_op<function_type, OtherAllocator, detail::operation> 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((*io_context_, *p.p, "io_context", io_context_, 0, "post")); io_context_->impl_.post_immediate_completion(p.p, false); p.v = p.p = 0; } template <typename Allocator, unsigned int Bits> template <typename Function, typename OtherAllocator> void io_context::basic_executor_type<Allocator, Bits>::defer( BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const { typedef typename decay<Function>::type function_type; // Allocate and construct an operation to wrap the function. typedef detail::executor_op<function_type, OtherAllocator, detail::operation> 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((*io_context_, *p.p, "io_context", io_context_, 0, "defer")); io_context_->impl_.post_immediate_completion(p.p, true); p.v = p.p = 0; } #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) #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<boost::asio::io_context&>(io_context_impl_.context()); } #endif // !defined(BOOST_ASIO_NO_DEPRECATED) inline boost::asio::io_context& io_context::service::get_io_context() { return static_cast<boost::asio::io_context&>(context()); } } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_IO_CONTEXT_HPP impl/system_context.ipp 0000644 00000004075 15125530236 0011317 0 ustar 00 // // impl/system_context.ipp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/system_context.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { struct system_context::thread_function { detail::scheduler* scheduler_; void operator()() { #if !defined(BOOST_ASIO_NO_EXCEPTIONS) try { #endif// !defined(BOOST_ASIO_NO_EXCEPTIONS) boost::system::error_code ec; scheduler_->run(ec); #if !defined(BOOST_ASIO_NO_EXCEPTIONS) } catch (...) { std::terminate(); } #endif// !defined(BOOST_ASIO_NO_EXCEPTIONS) } }; system_context::system_context() : scheduler_(add_scheduler(new detail::scheduler(*this, 0, false))) { scheduler_.work_started(); thread_function f = { &scheduler_ }; num_threads_ = detail::thread::hardware_concurrency() * 2; num_threads_ = num_threads_ ? num_threads_ : 2; threads_.create_threads(f, num_threads_); } 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<detail::scheduler> scoped_impl(s); boost::asio::add_service<detail::scheduler>(*this, scoped_impl.get()); return *scoped_impl.release(); } } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_SYSTEM_CONTEXT_IPP impl/defer.hpp 0000644 00000017173 15125530236 0007316 0 ustar 00 // // impl/defer.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/associated_allocator.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/detail/work_dispatcher.hpp> #include <boost/asio/execution/allocator.hpp> #include <boost/asio/execution/blocking.hpp> #include <boost/asio/execution/relationship.hpp> #include <boost/asio/prefer.hpp> #include <boost/asio/require.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class initiate_defer { public: template <typename CompletionHandler> void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, typename enable_if< execution::is_executor< typename associated_executor< typename decay<CompletionHandler>::type >::type >::value >::type* = 0) const { typedef typename decay<CompletionHandler>::type handler_t; typename associated_executor<handler_t>::type ex( (get_associated_executor)(handler)); typename associated_allocator<handler_t>::type alloc( (get_associated_allocator)(handler)); execution::execute( boost::asio::prefer( boost::asio::require(ex, execution::blocking.never), execution::relationship.continuation, execution::allocator(alloc)), BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); } template <typename CompletionHandler> void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, typename enable_if< !execution::is_executor< typename associated_executor< typename decay<CompletionHandler>::type >::type >::value >::type* = 0) const { typedef typename decay<CompletionHandler>::type handler_t; typename associated_executor<handler_t>::type ex( (get_associated_executor)(handler)); typename associated_allocator<handler_t>::type alloc( (get_associated_allocator)(handler)); ex.defer(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); } }; template <typename Executor> class initiate_defer_with_executor { public: typedef Executor executor_type; explicit initiate_defer_with_executor(const Executor& ex) : ex_(ex) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return ex_; } template <typename CompletionHandler> void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, typename enable_if< execution::is_executor< typename conditional<true, executor_type, CompletionHandler>::type >::value && !detail::is_work_dispatcher_required< typename decay<CompletionHandler>::type, Executor >::value >::type* = 0) const { typedef typename decay<CompletionHandler>::type handler_t; typename associated_allocator<handler_t>::type alloc( (get_associated_allocator)(handler)); execution::execute( boost::asio::prefer( boost::asio::require(ex_, execution::blocking.never), execution::relationship.continuation, execution::allocator(alloc)), BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)); } template <typename CompletionHandler> void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, typename enable_if< execution::is_executor< typename conditional<true, executor_type, CompletionHandler>::type >::value && detail::is_work_dispatcher_required< typename decay<CompletionHandler>::type, Executor >::value >::type* = 0) const { typedef typename decay<CompletionHandler>::type handler_t; typedef typename associated_executor< handler_t, Executor>::type handler_ex_t; handler_ex_t handler_ex((get_associated_executor)(handler, ex_)); typename associated_allocator<handler_t>::type alloc( (get_associated_allocator)(handler)); execution::execute( boost::asio::prefer( boost::asio::require(ex_, execution::blocking.never), execution::relationship.continuation, execution::allocator(alloc)), detail::work_dispatcher<handler_t, handler_ex_t>( BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), handler_ex)); } template <typename CompletionHandler> void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, typename enable_if< !execution::is_executor< typename conditional<true, executor_type, CompletionHandler>::type >::value && !detail::is_work_dispatcher_required< typename decay<CompletionHandler>::type, Executor >::value >::type* = 0) const { typedef typename decay<CompletionHandler>::type handler_t; typename associated_allocator<handler_t>::type alloc( (get_associated_allocator)(handler)); ex_.defer(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), alloc); } template <typename CompletionHandler> void operator()(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, typename enable_if< !execution::is_executor< typename conditional<true, executor_type, CompletionHandler>::type >::value && detail::is_work_dispatcher_required< typename decay<CompletionHandler>::type, Executor >::value >::type* = 0) const { typedef typename decay<CompletionHandler>::type handler_t; typedef typename associated_executor< handler_t, Executor>::type handler_ex_t; handler_ex_t handler_ex((get_associated_executor)(handler, ex_)); typename associated_allocator<handler_t>::type alloc( (get_associated_allocator)(handler)); ex_.defer(detail::work_dispatcher<handler_t, handler_ex_t>( BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler), handler_ex), alloc); } private: Executor ex_; }; } // namespace detail template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer( BOOST_ASIO_MOVE_ARG(CompletionToken) token) { return async_initiate<CompletionToken, void()>( detail::initiate_defer(), token); } template <typename Executor, BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer( const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token, typename enable_if< execution::is_executor<Executor>::value || is_executor<Executor>::value >::type*) { return async_initiate<CompletionToken, void()>( detail::initiate_defer_with_executor<Executor>(ex), token); } template <typename ExecutionContext, BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer( ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token, typename enable_if<is_convertible< ExecutionContext&, execution_context&>::value>::type*) { return async_initiate<CompletionToken, void()>( detail::initiate_defer_with_executor< typename ExecutionContext::executor_type>( ctx.get_executor()), token); } } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_DEFER_HPP impl/write_at.hpp 0000644 00000060233 15125530236 0010042 0 ustar 00 // // impl/write_at.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/associated_allocator.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/completion_condition.hpp> #include <boost/asio/detail/array_fwd.hpp> #include <boost/asio/detail/base_from_completion_cond.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/consuming_buffers.hpp> #include <boost/asio/detail/dependent_type.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_tracking.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition> 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<const_buffer, ConstBufferSequence, ConstBufferIterator> 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 <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence, typename CompletionCondition> 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 <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence> 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 <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence> 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 <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence, typename CompletionCondition> 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 <typename SyncRandomAccessWriteDevice, typename Allocator, typename CompletionCondition> std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, boost::asio::basic_streambuf<Allocator>& 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 <typename SyncRandomAccessWriteDevice, typename Allocator> inline std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, boost::asio::basic_streambuf<Allocator>& 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 <typename SyncRandomAccessWriteDevice, typename Allocator> inline std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, boost::asio::basic_streambuf<Allocator>& b, boost::system::error_code& ec) { return write_at(d, offset, b, transfer_all(), ec); } template <typename SyncRandomAccessWriteDevice, typename Allocator, typename CompletionCondition> inline std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, boost::asio::basic_streambuf<Allocator>& 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 <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> class write_at_op : detail::base_from_completion_cond<CompletionCondition> { 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<CompletionCondition>(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<CompletionCondition>( 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 { { BOOST_ASIO_HANDLER_LOCATION((__FILE__, __LINE__, "async_write_at")); 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<const_buffer, ConstBufferSequence, ConstBufferIterator> buffers_type; AsyncRandomAccessWriteDevice& device_; uint64_t offset_; buffers_type buffers_; int start_; WriteHandler handler_; }; template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> inline bool asio_handler_is_continuation( write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { return this_handler->start_ == 0 ? true : boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler> 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<AsyncRandomAccessWriteDevice, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>( d, offset, buffers, completion_condition, handler)( boost::system::error_code(), 0, 1); } template <typename AsyncRandomAccessWriteDevice> class initiate_async_write_at_buffer_sequence { public: typedef typename AsyncRandomAccessWriteDevice::executor_type executor_type; explicit initiate_async_write_at_buffer_sequence( AsyncRandomAccessWriteDevice& device) : device_(device) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return device_.get_executor(); } template <typename WriteHandler, typename ConstBufferSequence, typename CompletionCondition> void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, 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<WriteHandler> handler2(handler); non_const_lvalue<CompletionCondition> completion_cond2(completion_cond); start_write_at_buffer_sequence_op(device_, offset, buffers, boost::asio::buffer_sequence_begin(buffers), completion_cond2.value, handler2.value); } private: AsyncRandomAccessWriteDevice& device_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler, typename Allocator> struct associated_allocator< detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>, Allocator> { typedef typename associated_allocator<WriteHandler, Allocator>::type type; static type get( const detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<WriteHandler, Allocator>::get(h.handler_, a); } }; template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, typename ConstBufferIterator, typename CompletionCondition, typename WriteHandler, typename Executor> struct associated_executor< detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>, Executor> : detail::associated_executor_forwarding_base<WriteHandler, Executor> { typedef typename associated_executor<WriteHandler, Executor>::type type; static type get( const detail::write_at_op<AsyncRandomAccessWriteDevice, ConstBufferSequence, ConstBufferIterator, CompletionCondition, WriteHandler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<WriteHandler, Executor>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler> inline BOOST_ASIO_INITFN_AUTO_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<WriteHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_write_at_buffer_sequence< AsyncRandomAccessWriteDevice>(d), handler, offset, buffers, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } template <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler> inline BOOST_ASIO_INITFN_AUTO_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<WriteHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_write_at_buffer_sequence< AsyncRandomAccessWriteDevice>(d), handler, offset, buffers, transfer_all()); } #if !defined(BOOST_ASIO_NO_EXTENSIONS) #if !defined(BOOST_ASIO_NO_IOSTREAM) namespace detail { template <typename Allocator, typename WriteHandler> class write_at_streambuf_op { public: write_at_streambuf_op( boost::asio::basic_streambuf<Allocator>& 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<Allocator>& streambuf_; WriteHandler handler_; }; template <typename Allocator, typename WriteHandler> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, write_at_streambuf_op<Allocator, WriteHandler>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Allocator, typename WriteHandler> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, write_at_streambuf_op<Allocator, WriteHandler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Allocator, typename WriteHandler> inline bool asio_handler_is_continuation( write_at_streambuf_op<Allocator, WriteHandler>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename Allocator, typename WriteHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, write_at_streambuf_op<Allocator, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename Allocator, typename WriteHandler> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, write_at_streambuf_op<Allocator, WriteHandler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename AsyncRandomAccessWriteDevice> class initiate_async_write_at_streambuf { public: typedef typename AsyncRandomAccessWriteDevice::executor_type executor_type; explicit initiate_async_write_at_streambuf( AsyncRandomAccessWriteDevice& device) : device_(device) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return device_.get_executor(); } template <typename WriteHandler, typename Allocator, typename CompletionCondition> void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, uint64_t offset, basic_streambuf<Allocator>* 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<WriteHandler> handler2(handler); async_write_at(device_, offset, b->data(), BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition), write_at_streambuf_op<Allocator, typename decay<WriteHandler>::type>( *b, handler2.value)); } private: AsyncRandomAccessWriteDevice& device_; }; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) template <typename Allocator, typename WriteHandler, typename Allocator1> struct associated_allocator< detail::write_at_streambuf_op<Allocator, WriteHandler>, Allocator1> { typedef typename associated_allocator<WriteHandler, Allocator1>::type type; static type get( const detail::write_at_streambuf_op<Allocator, WriteHandler>& h, const Allocator1& a = Allocator1()) BOOST_ASIO_NOEXCEPT { return associated_allocator<WriteHandler, Allocator1>::get(h.handler_, a); } }; template <typename Executor, typename WriteHandler, typename Executor1> struct associated_executor< detail::write_at_streambuf_op<Executor, WriteHandler>, Executor1> : detail::associated_executor_forwarding_base<WriteHandler, Executor> { typedef typename associated_executor<WriteHandler, Executor1>::type type; static type get( const detail::write_at_streambuf_op<Executor, WriteHandler>& h, const Executor1& ex = Executor1()) BOOST_ASIO_NOEXCEPT { return associated_executor<WriteHandler, Executor1>::get(h.handler_, ex); } }; #endif // !defined(GENERATING_DOCUMENTATION) template <typename AsyncRandomAccessWriteDevice, typename Allocator, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, boost::asio::basic_streambuf<Allocator>& b, CompletionCondition completion_condition, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_write_at_streambuf< AsyncRandomAccessWriteDevice>(d), handler, offset, &b, BOOST_ASIO_MOVE_CAST(CompletionCondition)(completion_condition)); } template <typename AsyncRandomAccessWriteDevice, typename Allocator, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, boost::asio::basic_streambuf<Allocator>& b, BOOST_ASIO_MOVE_ARG(WriteHandler) handler) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( detail::initiate_async_write_at_streambuf< AsyncRandomAccessWriteDevice>(d), handler, offset, &b, transfer_all()); } #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_WRITE_AT_HPP impl/detached.hpp 0000644 00000006456 15125530236 0007774 0 ustar 00 // // impl/detached.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/variadic_templates.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename... Args> void operator()(Args...) { } #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) void operator()() { } #define BOOST_ASIO_PRIVATE_DETACHED_DEF(n) \ template <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ 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 <typename Signature> struct async_result<detached_t, Signature> { 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 <typename Initiation, typename RawCompletionToken, typename... Args> 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 <typename Initiation, typename RawCompletionToken> 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 <typename Initiation, typename RawCompletionToken, \ BOOST_ASIO_VARIADIC_TPARAMS(n)> \ 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_DETACHED_HPP impl/thread_pool.ipp 0000644 00000006074 15125530236 0010530 0 ustar 00 // // impl/thread_pool.ipp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <stdexcept> #include <boost/asio/thread_pool.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { struct thread_pool::thread_function { detail::scheduler* scheduler_; void operator()() { #if !defined(BOOST_ASIO_NO_EXCEPTIONS) try { #endif// !defined(BOOST_ASIO_NO_EXCEPTIONS) boost::system::error_code ec; scheduler_->run(ec); #if !defined(BOOST_ASIO_NO_EXCEPTIONS) } catch (...) { std::terminate(); } #endif// !defined(BOOST_ASIO_NO_EXCEPTIONS) } }; #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) namespace detail { inline long default_thread_pool_size() { std::size_t num_threads = thread::hardware_concurrency() * 2; num_threads = num_threads == 0 ? 2 : num_threads; return static_cast<long>(num_threads); } } // namespace detail thread_pool::thread_pool() : scheduler_(add_scheduler(new detail::scheduler(*this, 0, false))), num_threads_(detail::default_thread_pool_size()) { scheduler_.work_started(); thread_function f = { &scheduler_ }; threads_.create_threads(f, static_cast<std::size_t>(num_threads_)); } #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) namespace detail { inline long clamp_thread_pool_size(std::size_t n) { if (n > 0x7FFFFFFF) { std::out_of_range ex("thread pool size"); boost::asio::detail::throw_exception(ex); } return static_cast<long>(n & 0x7FFFFFFF); } } // namespace detail thread_pool::thread_pool(std::size_t num_threads) : scheduler_(add_scheduler(new detail::scheduler( *this, num_threads == 1 ? 1 : 0, false))), num_threads_(detail::clamp_thread_pool_size(num_threads)) { scheduler_.work_started(); thread_function f = { &scheduler_ }; threads_.create_threads(f, static_cast<std::size_t>(num_threads_)); } thread_pool::~thread_pool() { stop(); join(); } void thread_pool::stop() { scheduler_.stop(); } void thread_pool::attach() { ++num_threads_; thread_function f = { &scheduler_ }; f(); } void thread_pool::join() { if (!threads_.empty()) { scheduler_.work_finished(); threads_.join(); } } detail::scheduler& thread_pool::add_scheduler(detail::scheduler* s) { detail::scoped_ptr<detail::scheduler> scoped_impl(s); boost::asio::add_service<detail::scheduler>(*this, scoped_impl.get()); return *scoped_impl.release(); } void thread_pool::wait() { scheduler_.work_finished(); threads_.join(); } } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_THREAD_POOL_IPP impl/system_context.hpp 0000644 00000001553 15125530236 0011314 0 ustar 00 // // impl/system_context.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/system_executor.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { inline system_context::executor_type system_context::get_executor() BOOST_ASIO_NOEXCEPT { return system_executor(); } } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_SYSTEM_CONTEXT_HPP socket_base.hpp 0000644 00000037103 15125530236 0007545 0 ustar 00 // // socket_base.hpp // ~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/io_control.hpp> #include <boost/asio/detail/socket_option.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_SOCKET_BASE_HPP basic_raw_socket.hpp 0000644 00000133624 15125530236 0010572 0 ustar 00 // // basic_raw_socket.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/basic_socket.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Protocol, typename Executor = any_io_executor> 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 <typename Protocol, typename Executor> class basic_raw_socket : public basic_socket<Protocol, Executor> { public: /// The type of the executor associated with the object. typedef Executor executor_type; /// Rebinds the socket type to another executor. template <typename Executor1> struct rebind_executor { /// The socket type when rebound to the specified executor. typedef basic_raw_socket<Protocol, Executor1> other; }; /// The native representation of a socket. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; #else typedef typename basic_socket<Protocol, Executor>::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<Protocol, Executor>(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 <typename ExecutionContext> explicit basic_raw_socket(ExecutionContext& context, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_socket<Protocol, Executor>(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<Protocol, Executor>(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 <typename ExecutionContext> basic_raw_socket(ExecutionContext& context, const protocol_type& protocol, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_socket<Protocol, Executor>(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<Protocol, Executor>(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 <typename ExecutionContext> basic_raw_socket(ExecutionContext& context, const endpoint_type& endpoint, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_socket<Protocol, Executor>(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<Protocol, Executor>(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 <typename ExecutionContext> basic_raw_socket(ExecutionContext& context, const protocol_type& protocol, const native_handle_type& native_socket, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_socket<Protocol, Executor>(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) BOOST_ASIO_NOEXCEPT : basic_socket<Protocol, Executor>(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<Protocol, Executor>::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 <typename Protocol1, typename Executor1> basic_raw_socket(basic_raw_socket<Protocol1, Executor1>&& other, typename enable_if< is_convertible<Protocol1, Protocol>::value && is_convertible<Executor1, Executor>::value >::type* = 0) : basic_socket<Protocol, Executor>(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 Protocol1, typename Executor1> typename enable_if< is_convertible<Protocol1, Protocol>::value && is_convertible<Executor1, Executor>::value, basic_raw_socket& >::type operator=(basic_raw_socket<Protocol1, Executor1>&& other) { basic_socket<Protocol, Executor>::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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_send(const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( initiate_async_send(this), handler, 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 <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( initiate_async_send(this), handler, 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( initiate_async_send_to(this), handler, 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 <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( initiate_async_send_to(this), handler, 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_receive(const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( initiate_async_receive(this), handler, 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( initiate_async_receive(this), handler, 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( initiate_async_receive_from(this), handler, 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( initiate_async_receive_from(this), handler, buffers, &sender_endpoint, flags); } private: // Disallow copying and assignment. basic_raw_socket(const basic_raw_socket&) BOOST_ASIO_DELETED; basic_raw_socket& operator=(const basic_raw_socket&) BOOST_ASIO_DELETED; class initiate_async_send { public: typedef Executor executor_type; explicit initiate_async_send(basic_raw_socket* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename WriteHandler, typename ConstBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, 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<WriteHandler> handler2(handler); self_->impl_.get_service().async_send( self_->impl_.get_implementation(), buffers, flags, handler2.value, self_->impl_.get_executor()); } private: basic_raw_socket* self_; }; class initiate_async_send_to { public: typedef Executor executor_type; explicit initiate_async_send_to(basic_raw_socket* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename WriteHandler, typename ConstBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, 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<WriteHandler> handler2(handler); self_->impl_.get_service().async_send_to( self_->impl_.get_implementation(), buffers, destination, flags, handler2.value, self_->impl_.get_executor()); } private: basic_raw_socket* self_; }; class initiate_async_receive { public: typedef Executor executor_type; explicit initiate_async_receive(basic_raw_socket* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename ReadHandler, typename MutableBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); self_->impl_.get_service().async_receive( self_->impl_.get_implementation(), buffers, flags, handler2.value, self_->impl_.get_executor()); } private: basic_raw_socket* self_; }; class initiate_async_receive_from { public: typedef Executor executor_type; explicit initiate_async_receive_from(basic_raw_socket* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename ReadHandler, typename MutableBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); self_->impl_.get_service().async_receive_from( self_->impl_.get_implementation(), buffers, *sender_endpoint, flags, handler2.value, self_->impl_.get_executor()); } private: basic_raw_socket* self_; }; }; } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_BASIC_RAW_SOCKET_HPP static_thread_pool.hpp 0000644 00000001472 15125530236 0011132 0 ustar 00 // // static_thread_pool.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_STATIC_THREAD_POOL_HPP #define BOOST_ASIO_STATIC_THREAD_POOL_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/thread_pool.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { typedef thread_pool static_thread_pool; } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_STATIC_THREAD_POOL_HPP write.hpp 0000644 00000147337 15125530236 0006430 0 ustar 00 // // write.hpp // ~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/async_result.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/error.hpp> #if !defined(BOOST_ASIO_NO_EXTENSIONS) # include <boost/asio/basic_streambuf_fwd.hpp> #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) #include <boost/asio/detail/push_options.hpp> 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 <typename SyncWriteStream, typename ConstBufferSequence> std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, typename enable_if< is_const_buffer_sequence<ConstBufferSequence>::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 <typename SyncWriteStream, typename ConstBufferSequence> std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, boost::system::error_code& ec, typename enable_if< is_const_buffer_sequence<ConstBufferSequence>::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 <typename SyncWriteStream, typename ConstBufferSequence, typename CompletionCondition> std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, typename enable_if< is_const_buffer_sequence<ConstBufferSequence>::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 <typename SyncWriteStream, typename ConstBufferSequence, typename CompletionCondition> std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, boost::system::error_code& ec, typename enable_if< is_const_buffer_sequence<ConstBufferSequence>::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 <typename SyncWriteStream, typename DynamicBuffer_v1> std::size_t write(SyncWriteStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, typename enable_if< is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncWriteStream, typename DynamicBuffer_v1> 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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition> std::size_t write(SyncWriteStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, CompletionCondition completion_condition, typename enable_if< is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition> 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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncWriteStream, typename Allocator> std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& 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 <typename SyncWriteStream, typename Allocator> std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& 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 <typename SyncWriteStream, typename Allocator, typename CompletionCondition> std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& 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 <typename SyncWriteStream, typename Allocator, typename CompletionCondition> std::size_t write(SyncWriteStream& s, basic_streambuf<Allocator>& 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 <typename SyncWriteStream, typename DynamicBuffer_v2> std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <typename SyncWriteStream, typename DynamicBuffer_v2> std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, boost::system::error_code& ec, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <typename SyncWriteStream, typename DynamicBuffer_v2, typename CompletionCondition> std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, CompletionCondition completion_condition, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <typename SyncWriteStream, typename DynamicBuffer_v2, typename CompletionCondition> std::size_t write(SyncWriteStream& s, DynamicBuffer_v2 buffers, CompletionCondition completion_condition, boost::system::error_code& ec, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <em>composed operation</em>. 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 <typename AsyncWriteStream, typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncWriteStream::executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncWriteStream::executor_type), typename enable_if< is_const_buffer_sequence<ConstBufferSequence>::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 <em>composed operation</em>. 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 <typename AsyncWriteStream, typename ConstBufferSequence, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler> BOOST_ASIO_INITFN_AUTO_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<ConstBufferSequence>::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 <em>composed operation</em>. 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 <typename AsyncWriteStream, typename DynamicBuffer_v1, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncWriteStream::executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncWriteStream::executor_type), typename enable_if< is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <em>composed operation</em>. 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 <typename AsyncWriteStream, typename DynamicBuffer_v1, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler> BOOST_ASIO_INITFN_AUTO_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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <em>composed operation</em>. 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 <typename AsyncWriteStream, typename Allocator, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncWriteStream::executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& b, BOOST_ASIO_MOVE_ARG(WriteHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncWriteStream::executor_type)); /// 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 <em>composed operation</em>. 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 <typename AsyncWriteStream, typename Allocator, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, basic_streambuf<Allocator>& 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 <em>composed operation</em>. 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 <typename AsyncWriteStream, typename DynamicBuffer_v2, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncWriteStream::executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write(AsyncWriteStream& s, DynamicBuffer_v2 buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncWriteStream::executor_type), typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <em>composed operation</em>. 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 <typename AsyncWriteStream, typename DynamicBuffer_v2, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler> BOOST_ASIO_INITFN_AUTO_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<DynamicBuffer_v2>::value >::type* = 0); /*@}*/ } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/write.hpp> #endif // BOOST_ASIO_WRITE_HPP executor_work_guard.hpp 0000644 00000017547 15125530236 0011357 0 ustar 00 // // executor_work_guard.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) #include <boost/asio/associated_executor.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution.hpp> #include <boost/asio/is_executor.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if !defined(BOOST_ASIO_EXECUTOR_WORK_GUARD_DECL) #define BOOST_ASIO_EXECUTOR_WORK_GUARD_DECL template <typename Executor, typename = void> class executor_work_guard; #endif // !defined(BOOST_ASIO_EXECUTOR_WORK_GUARD_DECL) /// An object of type @c executor_work_guard controls ownership of executor work /// within a scope. #if defined(GENERATING_DOCUMENTATION) template <typename Executor> #else // defined(GENERATING_DOCUMENTATION) template <typename Executor, typename> #endif // defined(GENERATING_DOCUMENTATION) 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 <tt>on_work_started()</tt> 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 <tt>on_work_finished()</tt> 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 <tt>on_work_finished()</tt> 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_; }; #if !defined(GENERATING_DOCUMENTATION) template <typename Executor> class executor_work_guard<Executor, typename enable_if< !is_executor<Executor>::value && execution::is_executor<Executor>::value >::type> { public: typedef Executor executor_type; explicit executor_work_guard(const executor_type& e) BOOST_ASIO_NOEXCEPT : executor_(e), owns_(true) { new (&work_) work_type(boost::asio::prefer(executor_, execution::outstanding_work.tracked)); } executor_work_guard(const executor_work_guard& other) BOOST_ASIO_NOEXCEPT : executor_(other.executor_), owns_(other.owns_) { if (owns_) { new (&work_) work_type(boost::asio::prefer(executor_, execution::outstanding_work.tracked)); } } #if defined(BOOST_ASIO_HAS_MOVE) executor_work_guard(executor_work_guard&& other) BOOST_ASIO_NOEXCEPT : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)), owns_(other.owns_) { if (owns_) { new (&work_) work_type( BOOST_ASIO_MOVE_CAST(work_type)( *static_cast<work_type*>( static_cast<void*>(&other.work_)))); other.owns_ = false; } } #endif // defined(BOOST_ASIO_HAS_MOVE) ~executor_work_guard() { if (owns_) static_cast<work_type*>(static_cast<void*>(&work_))->~work_type(); } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return executor_; } bool owns_work() const BOOST_ASIO_NOEXCEPT { return owns_; } void reset() BOOST_ASIO_NOEXCEPT { if (owns_) { static_cast<work_type*>(static_cast<void*>(&work_))->~work_type(); owns_ = false; } } private: // Disallow assignment. executor_work_guard& operator=(const executor_work_guard&); typedef typename decay< typename prefer_result< const executor_type&, execution::outstanding_work_t::tracked_t >::type >::type work_type; executor_type executor_; typename aligned_storage<sizeof(work_type), alignment_of<work_type>::value>::type work_; bool owns_; }; #endif // !defined(GENERATING_DOCUMENTATION) /// Create an @ref executor_work_guard object. template <typename Executor> inline executor_work_guard<Executor> make_work_guard(const Executor& ex, typename enable_if< is_executor<Executor>::value || execution::is_executor<Executor>::value >::type* = 0) { return executor_work_guard<Executor>(ex); } /// Create an @ref executor_work_guard object. template <typename ExecutionContext> inline executor_work_guard<typename ExecutionContext::executor_type> make_work_guard(ExecutionContext& ctx, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) { return executor_work_guard<typename ExecutionContext::executor_type>( ctx.get_executor()); } /// Create an @ref executor_work_guard object. template <typename T> inline executor_work_guard<typename associated_executor<T>::type> make_work_guard(const T& t, typename enable_if< !is_executor<T>::value && !execution::is_executor<T>::value && !is_convertible<T&, execution_context& >::value>::type* = 0) { return executor_work_guard<typename associated_executor<T>::type>( associated_executor<T>::get(t)); } /// Create an @ref executor_work_guard object. template <typename T, typename Executor> inline executor_work_guard<typename associated_executor<T, Executor>::type> make_work_guard(const T& t, const Executor& ex, typename enable_if< is_executor<Executor>::value || execution::is_executor<Executor>::value >::type* = 0) { return executor_work_guard<typename associated_executor<T, Executor>::type>( associated_executor<T, Executor>::get(t, ex)); } /// Create an @ref executor_work_guard object. template <typename T, typename ExecutionContext> inline executor_work_guard<typename associated_executor<T, typename ExecutionContext::executor_type>::type> make_work_guard(const T& t, ExecutionContext& ctx, typename enable_if< !is_executor<T>::value && !execution::is_executor<T>::value && !is_convertible<T&, execution_context&>::value && is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) { return executor_work_guard<typename associated_executor<T, typename ExecutionContext::executor_type>::type>( associated_executor<T, typename ExecutionContext::executor_type>::get( t, ctx.get_executor())); } } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) #endif // BOOST_ASIO_EXECUTOR_WORK_GUARD_HPP handler_continuation_hook.hpp 0000644 00000002702 15125530236 0012507 0 ustar 00 // // handler_continuation_hook.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/push_options.hpp> 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 <tt>false</tt>. * * @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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_HANDLER_CONTINUATION_HOOK_HPP buffered_read_stream_fwd.hpp 0000644 00000001273 15125530236 0012252 0 ustar 00 // // buffered_read_stream_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <typename Stream> class buffered_read_stream; } // namespace asio } // namespace boost #endif // BOOST_ASIO_BUFFERED_READ_STREAM_FWD_HPP handler_invoke_hook.hpp 0000644 00000007240 15125530236 0011272 0 ustar 00 // // handler_invoke_hook.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { /** @defgroup asio_handler_invoke boost::asio::asio_handler_invoke * * @brief (Deprecated: Use the associated_executor trait.) 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 <typename Function> * void asio_handler_invoke(Function function, my_handler* context) * { * context->strand_.dispatch(function); * } * @endcode */ /*@{*/ #if defined(BOOST_ASIO_NO_DEPRECATED) // Places in asio that would have previously called the invocation hook to // execute a handler, now call it only to check whether the result type is this // type. If the result is not this type, it indicates that the user code still // has the old hooks in place, and if so we want to trigger a compile error. enum asio_handler_invoke_is_no_longer_used {}; typedef asio_handler_invoke_is_no_longer_used asio_handler_invoke_is_deprecated; #else // defined(BOOST_ASIO_NO_DEPRECATED) typedef void asio_handler_invoke_is_deprecated; #endif // defined(BOOST_ASIO_NO_DEPRECATED) /// Default handler invocation hook used for non-const function objects. template <typename Function> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, ...) { function(); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } /// Default handler invocation hook used for const function objects. template <typename Function> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, ...) { Function tmp(function); tmp(); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } /*@}*/ } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_HANDLER_INVOKE_HOOK_HPP post.hpp 0000644 00000011230 15125530236 0006241 0 ustar 00 // // post.hpp // ~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/is_executor.hpp> #include <boost/asio/detail/push_options.hpp> 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 <tt>post()</tt>. * * 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 <tt>handler(forward<CompletionToken>(token))</tt>. * * @li Constructs an object @c result of type <tt>async_result<Handler></tt>, * initializing the object as <tt>result(handler)</tt>. * * @li Obtains the handler's associated executor object @c ex by performing * <tt>get_associated_executor(handler)</tt>. * * @li Obtains the handler's associated allocator object @c alloc by performing * <tt>get_associated_allocator(handler)</tt>. * * @li Performs <tt>ex.post(std::move(handler), alloc)</tt>. * * @li Returns <tt>result.get()</tt>. */ template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken> BOOST_ASIO_INITFN_AUTO_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 <tt>post()</tt>. * * 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 <tt>handler(forward<CompletionToken>(token))</tt>. * * @li Constructs an object @c result of type <tt>async_result<Handler></tt>, * initializing the object as <tt>result(handler)</tt>. * * @li Obtains the handler's associated executor object @c ex1 by performing * <tt>get_associated_executor(handler)</tt>. * * @li Creates a work object @c w by performing <tt>make_work(ex1)</tt>. * * @li Obtains the handler's associated allocator object @c alloc by performing * <tt>get_associated_allocator(handler)</tt>. * * @li Constructs a function object @c f with a function call operator that * performs <tt>ex1.dispatch(std::move(handler), alloc)</tt> followed by * <tt>w.reset()</tt>. * * @li Performs <tt>Executor(ex).post(std::move(f), alloc)</tt>. * * @li Returns <tt>result.get()</tt>. */ template <typename Executor, BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post( const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if< execution::is_executor<Executor>::value || is_executor<Executor>::value >::type* = 0); /// Submits a completion token or function object for execution. /** * @returns <tt>post(ctx.get_executor(), forward<CompletionToken>(token))</tt>. */ template <typename ExecutionContext, BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename ExecutionContext::executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) post( ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename ExecutionContext::executor_type), typename enable_if<is_convertible< ExecutionContext&, execution_context&>::value>::type* = 0); } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/post.hpp> #endif // BOOST_ASIO_POST_HPP experimental/impl/as_single.hpp 0000644 00000014126 15125530236 0012665 0 ustar 00 // // experimental/impl/as_single.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_EXPERIMENTAL_AS_SINGLE_HPP #define BOOST_ASIO_IMPL_EXPERIMENTAL_AS_SINGLE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <tuple> #include <boost/asio/associated_executor.hpp> #include <boost/asio/associated_allocator.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/variadic_templates.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace experimental { namespace detail { // Class to adapt a as_single_t as a completion handler. template <typename Handler> class as_single_handler { public: typedef void result_type; template <typename CompletionToken> as_single_handler(as_single_t<CompletionToken> e) : handler_(BOOST_ASIO_MOVE_CAST(CompletionToken)(e.token_)) { } template <typename RedirectedHandler> as_single_handler(BOOST_ASIO_MOVE_ARG(RedirectedHandler) h) : handler_(BOOST_ASIO_MOVE_CAST(RedirectedHandler)(h)) { } void operator()() { handler_(); } template <typename Arg> void operator()(BOOST_ASIO_MOVE_ARG(Arg) arg) { handler_(BOOST_ASIO_MOVE_CAST(Arg)(arg)); } template <typename... Args> void operator()(BOOST_ASIO_MOVE_ARG(Args)... args) { handler_(std::make_tuple(BOOST_ASIO_MOVE_CAST(Args)(args)...)); } //private: Handler handler_; }; template <typename Handler> inline void* asio_handler_allocate(std::size_t size, as_single_handler<Handler>* this_handler) { return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); } template <typename Handler> inline void asio_handler_deallocate(void* pointer, std::size_t size, as_single_handler<Handler>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); } template <typename Handler> inline bool asio_handler_is_continuation( as_single_handler<Handler>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename Handler> inline void asio_handler_invoke(Function& function, as_single_handler<Handler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } template <typename Function, typename Handler> inline void asio_handler_invoke(const Function& function, as_single_handler<Handler>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); } template <typename Signature> struct as_single_signature { typedef Signature type; }; template <typename R> struct as_single_signature<R()> { typedef R type(); }; template <typename R, typename Arg> struct as_single_signature<R(Arg)> { typedef R type(Arg); }; template <typename R, typename... Args> struct as_single_signature<R(Args...)> { typedef R type(std::tuple<typename decay<Args>::type...>); }; } // namespace detail } // namespace experimental #if !defined(GENERATING_DOCUMENTATION) template <typename CompletionToken, typename Signature> struct async_result<experimental::as_single_t<CompletionToken>, Signature> { typedef typename async_result<CompletionToken, typename experimental::detail::as_single_signature<Signature>::type> ::return_type return_type; template <typename Initiation> struct init_wrapper { init_wrapper(Initiation init) : initiation_(BOOST_ASIO_MOVE_CAST(Initiation)(init)) { } template <typename Handler, typename... Args> void operator()( BOOST_ASIO_MOVE_ARG(Handler) handler, BOOST_ASIO_MOVE_ARG(Args)... args) { BOOST_ASIO_MOVE_CAST(Initiation)(initiation_)( experimental::detail::as_single_handler< typename decay<Handler>::type>( BOOST_ASIO_MOVE_CAST(Handler)(handler)), BOOST_ASIO_MOVE_CAST(Args)(args)...); } Initiation initiation_; }; template <typename Initiation, typename RawCompletionToken, typename... Args> 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<CompletionToken, typename experimental::detail::as_single_signature<Signature>::type>( init_wrapper<typename decay<Initiation>::type>( BOOST_ASIO_MOVE_CAST(Initiation)(initiation)), token.token_, BOOST_ASIO_MOVE_CAST(Args)(args)...); } }; template <typename Handler, typename Executor> struct associated_executor< experimental::detail::as_single_handler<Handler>, Executor> : detail::associated_executor_forwarding_base<Handler, Executor> { typedef typename associated_executor<Handler, Executor>::type type; static type get( const experimental::detail::as_single_handler<Handler>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<Handler, Executor>::get(h.handler_, ex); } }; template <typename Handler, typename Allocator> struct associated_allocator< experimental::detail::as_single_handler<Handler>, Allocator> { typedef typename associated_allocator<Handler, Allocator>::type type; static type get( const experimental::detail::as_single_handler<Handler>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<Handler, Allocator>::get(h.handler_, a); } }; #endif // !defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IMPL_EXPERIMENTAL_AS_SINGLE_HPP experimental/as_single.hpp 0000644 00000011003 15125530236 0011713 0 ustar 00 // // experimental/as_single.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_EXPERIMENTAL_AS_SINGLE_HPP #define BOOST_ASIO_EXPERIMENTAL_AS_SINGLE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace experimental { /// Completion token type used to specify that the completion handler /// arguments should be combined into a single argument. /** * The as_single_t class is used to indicate that any arguments to the * completion handler should be combined and passed as a single argument. * If there is already one argument, that argument is passed as-is. If * there is more than argument, the arguments are first moved into a * @c std::tuple and that tuple is then passed to the completion handler. */ template <typename CompletionToken> class as_single_t { public: /// Tag type used to prevent the "default" constructor from being used for /// conversions. struct default_constructor_tag {}; /// Default constructor. /** * This constructor is only valid if the underlying completion token is * default constructible and move constructible. The underlying completion * token is itself defaulted as an argument to allow it to capture a source * location. */ BOOST_ASIO_CONSTEXPR as_single_t( default_constructor_tag = default_constructor_tag(), CompletionToken token = CompletionToken()) : token_(BOOST_ASIO_MOVE_CAST(CompletionToken)(token)) { } /// Constructor. template <typename T> BOOST_ASIO_CONSTEXPR explicit as_single_t( BOOST_ASIO_MOVE_ARG(T) completion_token) : token_(BOOST_ASIO_MOVE_CAST(T)(completion_token)) { } /// Adapts an executor to add the @c as_single_t completion token as the /// default. template <typename InnerExecutor> struct executor_with_default : InnerExecutor { /// Specify @c as_single_t as the default completion token type. typedef as_single_t default_completion_token_type; /// Construct the adapted executor from the inner executor type. executor_with_default(const InnerExecutor& ex) BOOST_ASIO_NOEXCEPT : InnerExecutor(ex) { } /// Convert the specified executor to the inner executor type, then use /// that to construct the adapted executor. template <typename OtherExecutor> executor_with_default(const OtherExecutor& ex, typename enable_if< is_convertible<OtherExecutor, InnerExecutor>::value >::type* = 0) BOOST_ASIO_NOEXCEPT : InnerExecutor(ex) { } }; /// Type alias to adapt an I/O object to use @c as_single_t as its /// default completion token type. #if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) \ || defined(GENERATING_DOCUMENTATION) template <typename T> using as_default_on_t = typename T::template rebind_executor< executor_with_default<typename T::executor_type> >::other; #endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) // || defined(GENERATING_DOCUMENTATION) /// Function helper to adapt an I/O object to use @c as_single_t as its /// default completion token type. template <typename T> static typename decay<T>::type::template rebind_executor< executor_with_default<typename decay<T>::type::executor_type> >::other as_default_on(BOOST_ASIO_MOVE_ARG(T) object) { return typename decay<T>::type::template rebind_executor< executor_with_default<typename decay<T>::type::executor_type> >::other(BOOST_ASIO_MOVE_CAST(T)(object)); } //private: CompletionToken token_; }; /// Create a completion token to specify that the completion handler arguments /// should be combined into a single argument. template <typename CompletionToken> inline BOOST_ASIO_CONSTEXPR as_single_t<typename decay<CompletionToken>::type> as_single(BOOST_ASIO_MOVE_ARG(CompletionToken) completion_token) { return as_single_t<typename decay<CompletionToken>::type>( BOOST_ASIO_MOVE_CAST(CompletionToken)(completion_token)); } } // namespace experimental } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/experimental/impl/as_single.hpp> #endif // BOOST_ASIO_EXPERIMENTAL_AS_SINGLE_HPP serial_port_base.hpp 0000644 00000011557 15125530236 0010605 0 ustar 00 // // serial_port_base.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) #if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) # include <termios.h> #endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) #include <boost/asio/detail/socket_types.hpp> #include <boost/system/error_code.hpp> #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 <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #undef BOOST_ASIO_OPTION_STORAGE #include <boost/asio/impl/serial_port_base.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/impl/serial_port_base.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) // || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_SERIAL_PORT_BASE_HPP buffered_stream.hpp 0000644 00000021562 15125530236 0010422 0 ustar 00 // // buffered_stream.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/async_result.hpp> #include <boost/asio/buffered_read_stream.hpp> #include <boost/asio/buffered_write_stream.hpp> #include <boost/asio/buffered_stream_fwd.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Stream> class buffered_stream : private noncopyable { public: /// The type of the next layer. typedef typename remove_reference<Stream>::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 <typename Arg> 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 <typename Arg> 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_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_flush( BOOST_ASIO_MOVE_ARG(WriteHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_some(const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { 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_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_fill( BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_some(const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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<Stream> write_stream_type; write_stream_type inner_stream_impl_; // The buffered read stream. typedef buffered_read_stream<write_stream_type&> read_stream_type; read_stream_type stream_impl_; }; } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_BUFFERED_STREAM_HPP buffered_write_stream.hpp 0000644 00000017552 15125530236 0011640 0 ustar 00 // // buffered_write_stream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/buffered_write_stream_fwd.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/completion_condition.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffered_stream_storage.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> #include <boost/asio/write.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Stream> class buffered_write_stream : private noncopyable { public: /// The type of the next layer. typedef typename remove_reference<Stream>::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 <typename Arg> explicit buffered_write_stream(Arg& a) : next_layer_(a), storage_(default_buffer_size) { } /// Construct, passing the specified argument to initialise the next layer. template <typename Arg> 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_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_flush( BOOST_ASIO_MOVE_ARG(WriteHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)); /// Write the given data to the stream. Returns the number of bytes written. /// Throws an exception on failure. template <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_some(const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)); /// Read some data from the stream. Returns the number of bytes read. Throws /// an exception on failure. template <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_some(const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename ConstBufferSequence> 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 <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/buffered_write_stream.hpp> #endif // BOOST_ASIO_BUFFERED_WRITE_STREAM_HPP serial_port.hpp 0000644 00000001762 15125530236 0007610 0 ustar 00 // // serial_port.hpp // ~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_SERIAL_PORT) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/basic_serial_port.hpp> 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 io_service.hpp 0000644 00000001535 15125530236 0007412 0 ustar 00 // // io_service.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/io_context.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IO_SERVICE_HPP this_coro.hpp 0000644 00000002175 15125530236 0007255 0 ustar 00 // // this_coro.hpp // ~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_THIS_CORO_HPP any_io_executor.hpp 0000644 00000005101 15125530236 0010450 0 ustar 00 // // any_io_executor.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_ANY_IO_EXECUTOR_HPP #define BOOST_ASIO_ANY_IO_EXECUTOR_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) # include <boost/asio/executor.hpp> #else // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) # include <boost/asio/execution.hpp> # include <boost/asio/execution_context.hpp> #endif // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) typedef executor any_io_executor; #else // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) /// Polymorphic executor type for use with I/O objects. /** * The @c any_io_executor type is a polymorphic executor that supports the set * of properties required by I/O objects. It is defined as the * execution::any_executor class template parameterised as follows: * @code execution::any_executor< * execution::context_as_t<execution_context&>, * execution::blocking_t::never_t, * execution::prefer_only<execution::blocking_t::possibly_t>, * execution::prefer_only<execution::outstanding_work_t::tracked_t>, * execution::prefer_only<execution::outstanding_work_t::untracked_t>, * execution::prefer_only<execution::relationship_t::fork_t>, * execution::prefer_only<execution::relationship_t::continuation_t> * > @endcode */ #if defined(GENERATING_DOCUMENTATION) typedef execution::any_executor<...> any_io_executor; #else // defined(GENERATING_DOCUMENTATION) typedef execution::any_executor< execution::context_as_t<execution_context&>, execution::blocking_t::never_t, execution::prefer_only<execution::blocking_t::possibly_t>, execution::prefer_only<execution::outstanding_work_t::tracked_t>, execution::prefer_only<execution::outstanding_work_t::untracked_t>, execution::prefer_only<execution::relationship_t::fork_t>, execution::prefer_only<execution::relationship_t::continuation_t> > any_io_executor; #endif // defined(GENERATING_DOCUMENTATION) #endif // defined(BOOST_ASIO_USE_TS_EXECUTOR_AS_DEFAULT) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_ANY_IO_EXECUTOR_HPP thread_pool.hpp 0000644 00000111277 15125530236 0007570 0 ustar 00 // // thread_pool.hpp // ~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/atomic_count.hpp> #include <boost/asio/detail/scheduler.hpp> #include <boost/asio/detail/thread_group.hpp> #include <boost/asio/execution.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { struct thread_pool_bits { BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, blocking_never = 1); BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, blocking_always = 2); BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, blocking_mask = 3); BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, relationship_continuation = 4); BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, outstanding_work_tracked = 8); }; } // namespace detail /// 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: template <typename Allocator, unsigned int Bits> class basic_executor_type; template <typename Allocator, unsigned int Bits> friend class basic_executor_type; /// Executor used to submit functions to a thread pool. typedef basic_executor_type<std::allocator<void>, 0> executor_type; /// Scheduler used to schedule receivers on a thread pool. typedef basic_executor_type<std::allocator<void>, 0> scheduler_type; #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// Constructs a pool with an automatically determined number of threads. BOOST_ASIO_DECL thread_pool(); #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// 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; /// Obtains the executor associated with the pool. executor_type executor() BOOST_ASIO_NOEXCEPT; /// Obtains the scheduler associated with the pool. scheduler_type scheduler() 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(); /// Attaches the current thread to the pool. /** * This function attaches the current thread to the pool so that it may be * used for executing submitted function objects. Blocks the calling thread * until the pool is stopped or joined and has no outstanding work. */ BOOST_ASIO_DECL void attach(); /// 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(); /// Waits for threads to complete. /** * This function blocks until the threads in the pool have completed. If @c * stop() is not called prior to @c wait(), the @c wait() call will wait * until the pool has no more outstanding work. */ BOOST_ASIO_DECL void wait(); private: thread_pool(const thread_pool&) BOOST_ASIO_DELETED; thread_pool& operator=(const thread_pool&) BOOST_ASIO_DELETED; 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_; // The current number of threads in the pool. detail::atomic_count num_threads_; }; /// Executor implementation type used to submit functions to a thread pool. template <typename Allocator, unsigned int Bits> class thread_pool::basic_executor_type : detail::thread_pool_bits { public: /// The sender type, when this type is used as a scheduler. typedef basic_executor_type sender_type; /// The bulk execution shape type. typedef std::size_t shape_type; /// The bulk execution index type. typedef std::size_t index_type; #if defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT) \ && defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) template < template <typename...> class Tuple, template <typename...> class Variant> using value_types = Variant<Tuple<>>; template <template <typename...> class Variant> using error_types = Variant<std::exception_ptr>; BOOST_ASIO_STATIC_CONSTEXPR(bool, sends_done = true); #endif // defined(BOOST_ASIO_HAS_DEDUCED_EXECUTION_IS_TYPED_SENDER_TRAIT) // && defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) /// Copy constructor. basic_executor_type( const basic_executor_type& other) BOOST_ASIO_NOEXCEPT : pool_(other.pool_), allocator_(other.allocator_), bits_(other.bits_) { if (Bits & outstanding_work_tracked) if (pool_) pool_->scheduler_.work_started(); } #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move constructor. basic_executor_type(basic_executor_type&& other) BOOST_ASIO_NOEXCEPT : pool_(other.pool_), allocator_(BOOST_ASIO_MOVE_CAST(Allocator)(other.allocator_)), bits_(other.bits_) { if (Bits & outstanding_work_tracked) other.pool_ = 0; } #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Destructor. ~basic_executor_type() BOOST_ASIO_NOEXCEPT { if (Bits & outstanding_work_tracked) if (pool_) pool_->scheduler_.work_finished(); } /// Assignment operator. basic_executor_type& operator=( const basic_executor_type& other) BOOST_ASIO_NOEXCEPT; #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move assignment operator. basic_executor_type& operator=( basic_executor_type&& other) BOOST_ASIO_NOEXCEPT; #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Obtain an executor with the @c blocking.possibly property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code auto ex1 = my_thread_pool.executor(); * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::blocking.possibly); @endcode */ BOOST_ASIO_CONSTEXPR basic_executor_type<Allocator, BOOST_ASIO_UNSPECIFIED(Bits & ~blocking_mask)> require(execution::blocking_t::possibly_t) const { return basic_executor_type<Allocator, Bits & ~blocking_mask>( pool_, allocator_, bits_ & ~blocking_mask); } /// Obtain an executor with the @c blocking.always property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code auto ex1 = my_thread_pool.executor(); * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::blocking.always); @endcode */ BOOST_ASIO_CONSTEXPR basic_executor_type<Allocator, BOOST_ASIO_UNSPECIFIED((Bits & ~blocking_mask) | blocking_always)> require(execution::blocking_t::always_t) const { return basic_executor_type<Allocator, BOOST_ASIO_UNSPECIFIED((Bits & ~blocking_mask) | blocking_always)>( pool_, allocator_, bits_ & ~blocking_mask); } /// Obtain an executor with the @c blocking.never property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code auto ex1 = my_thread_pool.executor(); * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::blocking.never); @endcode */ BOOST_ASIO_CONSTEXPR basic_executor_type<Allocator, BOOST_ASIO_UNSPECIFIED(Bits & ~blocking_mask)> require(execution::blocking_t::never_t) const { return basic_executor_type<Allocator, Bits & ~blocking_mask>( pool_, allocator_, (bits_ & ~blocking_mask) | blocking_never); } /// Obtain an executor with the @c relationship.fork property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code auto ex1 = my_thread_pool.executor(); * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::relationship.fork); @endcode */ BOOST_ASIO_CONSTEXPR basic_executor_type require( execution::relationship_t::fork_t) const { return basic_executor_type(pool_, allocator_, bits_ & ~relationship_continuation); } /// Obtain an executor with the @c relationship.continuation property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code auto ex1 = my_thread_pool.executor(); * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::relationship.continuation); @endcode */ BOOST_ASIO_CONSTEXPR basic_executor_type require( execution::relationship_t::continuation_t) const { return basic_executor_type(pool_, allocator_, bits_ | relationship_continuation); } /// Obtain an executor with the @c outstanding_work.tracked property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code auto ex1 = my_thread_pool.executor(); * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::outstanding_work.tracked); @endcode */ BOOST_ASIO_CONSTEXPR basic_executor_type<Allocator, BOOST_ASIO_UNSPECIFIED(Bits | outstanding_work_tracked)> require(execution::outstanding_work_t::tracked_t) const { return basic_executor_type<Allocator, Bits | outstanding_work_tracked>( pool_, allocator_, bits_); } /// Obtain an executor with the @c outstanding_work.untracked property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code auto ex1 = my_thread_pool.executor(); * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::outstanding_work.untracked); @endcode */ BOOST_ASIO_CONSTEXPR basic_executor_type<Allocator, BOOST_ASIO_UNSPECIFIED(Bits & ~outstanding_work_tracked)> require(execution::outstanding_work_t::untracked_t) const { return basic_executor_type<Allocator, Bits & ~outstanding_work_tracked>( pool_, allocator_, bits_); } /// Obtain an executor with the specified @c allocator property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code auto ex1 = my_thread_pool.executor(); * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::allocator(my_allocator)); @endcode */ template <typename OtherAllocator> BOOST_ASIO_CONSTEXPR basic_executor_type<OtherAllocator, Bits> require(execution::allocator_t<OtherAllocator> a) const { return basic_executor_type<OtherAllocator, Bits>( pool_, a.value(), bits_); } /// Obtain an executor with the default @c allocator property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code auto ex1 = my_thread_pool.executor(); * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::allocator); @endcode */ BOOST_ASIO_CONSTEXPR basic_executor_type<std::allocator<void>, Bits> require(execution::allocator_t<void>) const { return basic_executor_type<std::allocator<void>, Bits>( pool_, std::allocator<void>(), bits_); } /// Query the current value of the @c bulk_guarantee property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code auto ex = my_thread_pool.executor(); * if (boost::asio::query(ex, boost::asio::execution::bulk_guarantee) * == boost::asio::execution::bulk_guarantee.parallel) * ... @endcode */ static BOOST_ASIO_CONSTEXPR execution::bulk_guarantee_t query( execution::bulk_guarantee_t) BOOST_ASIO_NOEXCEPT { return execution::bulk_guarantee.parallel; } /// Query the current value of the @c mapping property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code auto ex = my_thread_pool.executor(); * if (boost::asio::query(ex, boost::asio::execution::mapping) * == boost::asio::execution::mapping.thread) * ... @endcode */ static BOOST_ASIO_CONSTEXPR execution::mapping_t query( execution::mapping_t) BOOST_ASIO_NOEXCEPT { return execution::mapping.thread; } /// Query the current value of the @c context property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code auto ex = my_thread_pool.executor(); * boost::asio::thread_pool& pool = boost::asio::query( * ex, boost::asio::execution::context); @endcode */ thread_pool& query(execution::context_t) const BOOST_ASIO_NOEXCEPT { return *pool_; } /// Query the current value of the @c blocking property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code auto ex = my_thread_pool.executor(); * if (boost::asio::query(ex, boost::asio::execution::blocking) * == boost::asio::execution::blocking.always) * ... @endcode */ BOOST_ASIO_CONSTEXPR execution::blocking_t query( execution::blocking_t) const BOOST_ASIO_NOEXCEPT { return (bits_ & blocking_never) ? execution::blocking_t(execution::blocking.never) : ((Bits & blocking_always) ? execution::blocking_t(execution::blocking.always) : execution::blocking_t(execution::blocking.possibly)); } /// Query the current value of the @c relationship property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code auto ex = my_thread_pool.executor(); * if (boost::asio::query(ex, boost::asio::execution::relationship) * == boost::asio::execution::relationship.continuation) * ... @endcode */ BOOST_ASIO_CONSTEXPR execution::relationship_t query( execution::relationship_t) const BOOST_ASIO_NOEXCEPT { return (bits_ & relationship_continuation) ? execution::relationship_t(execution::relationship.continuation) : execution::relationship_t(execution::relationship.fork); } /// Query the current value of the @c outstanding_work property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code auto ex = my_thread_pool.executor(); * if (boost::asio::query(ex, boost::asio::execution::outstanding_work) * == boost::asio::execution::outstanding_work.tracked) * ... @endcode */ static BOOST_ASIO_CONSTEXPR execution::outstanding_work_t query( execution::outstanding_work_t) BOOST_ASIO_NOEXCEPT { return (Bits & outstanding_work_tracked) ? execution::outstanding_work_t(execution::outstanding_work.tracked) : execution::outstanding_work_t(execution::outstanding_work.untracked); } /// Query the current value of the @c allocator property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code auto ex = my_thread_pool.executor(); * auto alloc = boost::asio::query(ex, * boost::asio::execution::allocator); @endcode */ template <typename OtherAllocator> BOOST_ASIO_CONSTEXPR Allocator query( execution::allocator_t<OtherAllocator>) const BOOST_ASIO_NOEXCEPT { return allocator_; } /// Query the current value of the @c allocator property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code auto ex = my_thread_pool.executor(); * auto alloc = boost::asio::query(ex, * boost::asio::execution::allocator); @endcode */ BOOST_ASIO_CONSTEXPR Allocator query( execution::allocator_t<void>) const BOOST_ASIO_NOEXCEPT { return allocator_; } /// Query the occupancy (recommended number of work items) for the pool. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code auto ex = my_thread_pool.executor(); * std::size_t occupancy = boost::asio::query( * ex, boost::asio::execution::occupancy); @endcode */ std::size_t query(execution::occupancy_t) const BOOST_ASIO_NOEXCEPT { return static_cast<std::size_t>(pool_->num_threads_); } /// Determine whether the thread pool is running in the current thread. /** * @return @c true if the current thread is running the thread 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 basic_executor_type& a, const basic_executor_type& b) BOOST_ASIO_NOEXCEPT { return a.pool_ == b.pool_ && a.allocator_ == b.allocator_ && a.bits_ == b.bits_; } /// Compare two executors for inequality. /** * Two executors are equal if they refer to the same underlying thread pool. */ friend bool operator!=(const basic_executor_type& a, const basic_executor_type& b) BOOST_ASIO_NOEXCEPT { return a.pool_ != b.pool_ || a.allocator_ != b.allocator_ || a.bits_ != b.bits_; } /// Execution function. /** * Do not call this function directly. It is intended for use with the * execution::execute customisation point. * * For example: * @code auto ex = my_thread_pool.executor(); * execution::execute(ex, my_function_object); @endcode */ template <typename Function> void execute(BOOST_ASIO_MOVE_ARG(Function) f) const { this->do_execute(BOOST_ASIO_MOVE_CAST(Function)(f), integral_constant<bool, (Bits & blocking_always) != 0>()); } /// Bulk execution function. template <typename Function> void bulk_execute(BOOST_ASIO_MOVE_ARG(Function) f, std::size_t n) const { this->do_bulk_execute(BOOST_ASIO_MOVE_CAST(Function)(f), n, integral_constant<bool, (Bits & blocking_always) != 0>()); } /// Schedule function. /** * Do not call this function directly. It is intended for use with the * execution::schedule customisation point. * * @return An object that satisfies the sender concept. */ sender_type schedule() const BOOST_ASIO_NOEXCEPT { return *this; } /// Connect function. /** * Do not call this function directly. It is intended for use with the * execution::connect customisation point. * * @return An object of an unspecified type that satisfies the @c * operation_state concept. */ template <BOOST_ASIO_EXECUTION_RECEIVER_OF_0 Receiver> #if defined(GENERATING_DOCUMENTATION) unspecified #else // defined(GENERATING_DOCUMENTATION) execution::detail::as_operation<basic_executor_type, Receiver> #endif // defined(GENERATING_DOCUMENTATION) connect(BOOST_ASIO_MOVE_ARG(Receiver) r) const { return execution::detail::as_operation<basic_executor_type, Receiver>( *this, BOOST_ASIO_MOVE_CAST(Receiver)(r)); } #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// 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 <typename Function, typename OtherAllocator> void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& 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 <typename Function, typename OtherAllocator> void post(BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& 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 <typename Function, typename OtherAllocator> void defer(BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const; #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) private: friend class thread_pool; template <typename, unsigned int> friend class basic_executor_type; // Constructor used by thread_pool::get_executor(). explicit basic_executor_type(thread_pool& p) BOOST_ASIO_NOEXCEPT : pool_(&p), allocator_(), bits_(0) { if (Bits & outstanding_work_tracked) pool_->scheduler_.work_started(); } // Constructor used by require(). basic_executor_type(thread_pool* p, const Allocator& a, unsigned int bits) BOOST_ASIO_NOEXCEPT : pool_(p), allocator_(a), bits_(bits) { if (Bits & outstanding_work_tracked) if (pool_) pool_->scheduler_.work_started(); } /// Execution helper implementation for possibly and never blocking. template <typename Function> void do_execute(BOOST_ASIO_MOVE_ARG(Function) f, false_type) const; /// Execution helper implementation for always blocking. template <typename Function> void do_execute(BOOST_ASIO_MOVE_ARG(Function) f, true_type) const; /// Bulk execution helper implementation for possibly and never blocking. template <typename Function> void do_bulk_execute(BOOST_ASIO_MOVE_ARG(Function) f, std::size_t n, false_type) const; /// Bulk execution helper implementation for always blocking. template <typename Function> void do_bulk_execute(BOOST_ASIO_MOVE_ARG(Function) f, std::size_t n, true_type) const; // The underlying thread pool. thread_pool* pool_; // The allocator used for execution functions. Allocator allocator_; // The runtime-switched properties of the thread pool executor. unsigned int bits_; }; #if !defined(GENERATING_DOCUMENTATION) namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) template <typename Allocator, unsigned int Bits> struct equality_comparable< boost::asio::thread_pool::basic_executor_type<Allocator, Bits> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) template <typename Allocator, unsigned int Bits, typename Function> struct execute_member< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, Function > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT) template <typename Allocator, unsigned int Bits> struct schedule_member< const boost::asio::thread_pool::basic_executor_type<Allocator, Bits> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::thread_pool::basic_executor_type< Allocator, Bits> result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT) template <typename Allocator, unsigned int Bits, typename Receiver> struct connect_member< const boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, Receiver > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::execution::detail::as_operation< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, Receiver> result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) template <typename Allocator, unsigned int Bits> struct require_member< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, boost::asio::execution::blocking_t::possibly_t > : boost::asio::detail::thread_pool_bits { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef boost::asio::thread_pool::basic_executor_type< Allocator, Bits & ~blocking_mask> result_type; }; template <typename Allocator, unsigned int Bits> struct require_member< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, boost::asio::execution::blocking_t::always_t > : boost::asio::detail::thread_pool_bits { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::thread_pool::basic_executor_type<Allocator, (Bits & ~blocking_mask) | blocking_always> result_type; }; template <typename Allocator, unsigned int Bits> struct require_member< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, boost::asio::execution::blocking_t::never_t > : boost::asio::detail::thread_pool_bits { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::thread_pool::basic_executor_type< Allocator, Bits & ~blocking_mask> result_type; }; template <typename Allocator, unsigned int Bits> struct require_member< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, boost::asio::execution::relationship_t::fork_t > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::thread_pool::basic_executor_type< Allocator, Bits> result_type; }; template <typename Allocator, unsigned int Bits> struct require_member< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, boost::asio::execution::relationship_t::continuation_t > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::thread_pool::basic_executor_type< Allocator, Bits> result_type; }; template <typename Allocator, unsigned int Bits> struct require_member< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, boost::asio::execution::outstanding_work_t::tracked_t > : boost::asio::detail::thread_pool_bits { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::thread_pool::basic_executor_type< Allocator, Bits | outstanding_work_tracked> result_type; }; template <typename Allocator, unsigned int Bits> struct require_member< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, boost::asio::execution::outstanding_work_t::untracked_t > : boost::asio::detail::thread_pool_bits { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::thread_pool::basic_executor_type< Allocator, Bits & ~outstanding_work_tracked> result_type; }; template <typename Allocator, unsigned int Bits> struct require_member< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, boost::asio::execution::allocator_t<void> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::thread_pool::basic_executor_type< std::allocator<void>, Bits> result_type; }; template <unsigned int Bits, typename Allocator, typename OtherAllocator> struct require_member< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, boost::asio::execution::allocator_t<OtherAllocator> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::thread_pool::basic_executor_type< OtherAllocator, Bits> result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) template <typename Allocator, unsigned int Bits, typename Property> struct query_static_constexpr_member< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, Property, typename boost::asio::enable_if< boost::asio::is_convertible< Property, boost::asio::execution::bulk_guarantee_t >::value >::type > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef boost::asio::execution::bulk_guarantee_t::parallel_t result_type; static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT { return result_type(); } }; template <typename Allocator, unsigned int Bits, typename Property> struct query_static_constexpr_member< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, Property, typename boost::asio::enable_if< boost::asio::is_convertible< Property, boost::asio::execution::outstanding_work_t >::value >::type > : boost::asio::detail::thread_pool_bits { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef boost::asio::execution::outstanding_work_t result_type; static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT { return (Bits & outstanding_work_tracked) ? execution::outstanding_work_t(execution::outstanding_work.tracked) : execution::outstanding_work_t(execution::outstanding_work.untracked); } }; template <typename Allocator, unsigned int Bits, typename Property> struct query_static_constexpr_member< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, Property, typename boost::asio::enable_if< boost::asio::is_convertible< Property, boost::asio::execution::mapping_t >::value >::type > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef boost::asio::execution::mapping_t::thread_t result_type; static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT { return result_type(); } }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) template <typename Allocator, unsigned int Bits, typename Property> struct query_member< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, Property, typename boost::asio::enable_if< boost::asio::is_convertible< Property, boost::asio::execution::blocking_t >::value >::type > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef boost::asio::execution::blocking_t result_type; }; template <typename Allocator, unsigned int Bits, typename Property> struct query_member< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, Property, typename boost::asio::enable_if< boost::asio::is_convertible< Property, boost::asio::execution::relationship_t >::value >::type > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef boost::asio::execution::relationship_t result_type; }; template <typename Allocator, unsigned int Bits> struct query_member< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, boost::asio::execution::occupancy_t > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef std::size_t result_type; }; template <typename Allocator, unsigned int Bits> struct query_member< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, boost::asio::execution::context_t > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef boost::asio::thread_pool& result_type; }; template <typename Allocator, unsigned int Bits> struct query_member< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, boost::asio::execution::allocator_t<void> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef Allocator result_type; }; template <typename Allocator, unsigned int Bits, typename OtherAllocator> struct query_member< boost::asio::thread_pool::basic_executor_type<Allocator, Bits>, boost::asio::execution::allocator_t<OtherAllocator> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef Allocator result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) } // namespace traits #endif // !defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/thread_pool.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/impl/thread_pool.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_THREAD_POOL_HPP redirect_error.hpp 0000644 00000003622 15125530236 0010274 0 ustar 00 // // redirect_error.hpp // ~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/system/error_code.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename CompletionToken> class redirect_error_t { public: /// Constructor. template <typename T> 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 <typename CompletionToken> inline redirect_error_t<typename decay<CompletionToken>::type> redirect_error( BOOST_ASIO_MOVE_ARG(CompletionToken) completion_token, boost::system::error_code& ec) { return redirect_error_t<typename decay<CompletionToken>::type>( BOOST_ASIO_MOVE_CAST(CompletionToken)(completion_token), ec); } } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/redirect_error.hpp> #endif // BOOST_ASIO_REDIRECT_ERROR_HPP basic_streambuf.hpp 0000644 00000032622 15125530236 0010415 0 ustar 00 // // basic_streambuf.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_NO_IOSTREAM) #include <algorithm> #include <cstring> #include <stdexcept> #include <streambuf> #include <vector> #include <boost/asio/basic_streambuf_fwd.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/detail/limits.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Allocator = std::allocator<char> > #else template <typename Allocator> #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<std::size_t>::max)(), const Allocator& allocator = Allocator()) : max_size_(maximum_size), buffer_(allocator) { std::size_t pend = (std::min<std::size_t>)(max_size_, buffer_delta); buffer_.resize((std::max<std::size_t>)(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 <tt>size() + n > max_size()</tt>. * * @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 <tt>prepare(x)</tt> where <tt>x >= n</tt>, 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<std::size_t>(n, epptr() - pptr()); pbump(static_cast<int>(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<int>(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 * <tt>size() > max_size()</tt> 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<std::size_t>)(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<char_type, Allocator> 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::size_t>( std::max<std::size_t>(512, sb.buffer_.capacity() - sb.size()), std::min<std::size_t>(max_size, sb.max_size() - sb.size())); } }; /// Adapts basic_streambuf to the dynamic buffer sequence type requirements. #if defined(GENERATING_DOCUMENTATION) template <typename Allocator = std::allocator<char> > #else template <typename Allocator> #endif class basic_streambuf_ref { public: /// The type used to represent the input sequence as a list of buffers. typedef typename basic_streambuf<Allocator>::const_buffers_type const_buffers_type; /// The type used to represent the output sequence as a list of buffers. typedef typename basic_streambuf<Allocator>::mutable_buffers_type mutable_buffers_type; /// Construct a basic_streambuf_ref for the given basic_streambuf object. explicit basic_streambuf_ref(basic_streambuf<Allocator>& 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<Allocator>& sb_; }; } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // BOOST_ASIO_BASIC_STREAMBUF_HPP basic_deadline_timer.hpp 0000644 00000057136 15125530236 0011401 0 ustar 00 // // basic_deadline_timer.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ || defined(GENERATING_DOCUMENTATION) #include <cstddef> #include <boost/asio/any_io_executor.hpp> #include <boost/asio/detail/deadline_timer_service.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/io_object_impl.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/time_traits.hpp> #include <boost/asio/detail/push_options.hpp> 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 Time, typename TimeTraits = boost::asio::time_traits<Time>, typename Executor = any_io_executor> class basic_deadline_timer { public: /// The type of the executor associated with the object. typedef Executor executor_type; /// Rebinds the timer type to another executor. template <typename Executor1> struct rebind_executor { /// The timer type when rebound to the specified executor. typedef basic_deadline_timer<Time, TimeTraits, Executor1> other; }; /// 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 <typename ExecutionContext> explicit basic_deadline_timer(ExecutionContext& context, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename ExecutionContext> basic_deadline_timer(ExecutionContext& context, const time_type& expiry_time, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename ExecutionContext> basic_deadline_timer(ExecutionContext& context, const duration_type& expiry_time, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) WaitHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (boost::system::error_code)) async_wait( BOOST_ASIO_MOVE_ARG(WaitHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WaitHandler, void (boost::system::error_code)>( initiate_async_wait(this), handler); } 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; class initiate_async_wait { public: typedef Executor executor_type; explicit initiate_async_wait(basic_deadline_timer* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename WaitHandler> void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler) 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<WaitHandler> handler2(handler); self_->impl_.get_service().async_wait( self_->impl_.get_implementation(), handler2.value, self_->impl_.get_executor()); } private: basic_deadline_timer* self_; }; detail::io_object_impl< detail::deadline_timer_service<TimeTraits>, Executor> impl_; }; } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) // || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_BASIC_DEADLINE_TIMER_HPP read_until.hpp 0000644 00000351265 15125530236 0007421 0 ustar 00 // // read_until.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <string> #include <boost/asio/async_result.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/detail/regex_fwd.hpp> #include <boost/asio/detail/string_view.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> #if !defined(BOOST_ASIO_NO_EXTENSIONS) # include <boost/asio/basic_streambuf_fwd.hpp> #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { char (&has_result_type_helper(...))[2]; template <typename T> char has_result_type_helper(T*, typename T::result_type* = 0); template <typename T> 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 <typename T> 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<T>::type>::value || detail::has_result_type<T>::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::size_t 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 <typename SyncReadStream, typename DynamicBuffer_v1> std::size_t read_until(SyncReadStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, char delim, typename enable_if< is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncReadStream, typename DynamicBuffer_v1> 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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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::size_t 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 <typename SyncReadStream, typename DynamicBuffer_v1> 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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncReadStream, typename DynamicBuffer_v1> 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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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::size_t 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 <typename SyncReadStream, typename DynamicBuffer_v1> 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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncReadStream, typename DynamicBuffer_v1> 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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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<iterator, bool> match_condition(iterator begin, iterator end); * @endcode * where @c iterator represents the type: * @code buffers_iterator<typename DynamicBuffer_v1::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 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<iterator, bool> * 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 <typename Iterator> * std::pair<Iterator, bool> 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<match_char> * : public boost::true_type {}; * } // namespace asio * ... * std::string data; * boost::asio::read_until(s, data, match_char('a')); * @endcode */ template <typename SyncReadStream, typename DynamicBuffer_v1, typename MatchCondition> std::size_t read_until(SyncReadStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, MatchCondition match_condition, typename enable_if< is_match_condition<MatchCondition>::value && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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<iterator, bool> match_condition(iterator begin, iterator end); * @endcode * where @c iterator represents the type: * @code buffers_iterator<DynamicBuffer_v1::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 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 <typename SyncReadStream, typename DynamicBuffer_v1, typename MatchCondition> 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<MatchCondition>::value && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncReadStream, typename Allocator> std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& 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 <typename SyncReadStream, typename Allocator> std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& 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 <typename SyncReadStream, typename Allocator> std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& 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 <typename SyncReadStream, typename Allocator> std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& 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 <typename SyncReadStream, typename Allocator> std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& 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 <typename SyncReadStream, typename Allocator> std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& 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<iterator, bool> match_condition(iterator begin, iterator end); * @endcode * where @c iterator represents the type: * @code buffers_iterator<basic_streambuf<Allocator>::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<iterator, bool> * 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 <typename Iterator> * std::pair<Iterator, bool> 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<match_char> * : public boost::true_type {}; * } // namespace asio * ... * boost::asio::streambuf b; * boost::asio::read_until(s, b, match_char('a')); * @endcode */ template <typename SyncReadStream, typename Allocator, typename MatchCondition> std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, MatchCondition match_condition, typename enable_if<is_match_condition<MatchCondition>::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<iterator, bool> match_condition(iterator begin, iterator end); * @endcode * where @c iterator represents the type: * @code buffers_iterator<basic_streambuf<Allocator>::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 <typename SyncReadStream, typename Allocator, typename MatchCondition> std::size_t read_until(SyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, MatchCondition match_condition, boost::system::error_code& ec, typename enable_if<is_match_condition<MatchCondition>::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::size_t 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 <typename SyncReadStream, typename DynamicBuffer_v2> std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, char delim, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <typename SyncReadStream, typename DynamicBuffer_v2> std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, char delim, boost::system::error_code& ec, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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::size_t 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 <typename SyncReadStream, typename DynamicBuffer_v2> std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, BOOST_ASIO_STRING_VIEW_PARAM delim, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <typename SyncReadStream, typename DynamicBuffer_v2> 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<DynamicBuffer_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::size_t 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 <typename SyncReadStream, typename DynamicBuffer_v2> std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, const boost::regex& expr, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <typename SyncReadStream, typename DynamicBuffer_v2> 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<DynamicBuffer_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<iterator, bool> match_condition(iterator begin, iterator end); * @endcode * where @c iterator represents the type: * @code buffers_iterator<typename DynamicBuffer_v2::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 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<iterator, bool> * 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 <typename Iterator> * std::pair<Iterator, bool> 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<match_char> * : public boost::true_type {}; * } // namespace asio * ... * std::string data; * boost::asio::read_until(s, data, match_char('a')); * @endcode */ template <typename SyncReadStream, typename DynamicBuffer_v2, typename MatchCondition> std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, MatchCondition match_condition, typename enable_if< is_match_condition<MatchCondition>::value && is_dynamic_buffer_v2<DynamicBuffer_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<iterator, bool> match_condition(iterator begin, iterator end); * @endcode * where @c iterator represents the type: * @code buffers_iterator<DynamicBuffer_v2::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 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 <typename SyncReadStream, typename DynamicBuffer_v2, typename MatchCondition> std::size_t read_until(SyncReadStream& s, DynamicBuffer_v2 buffers, MatchCondition match_condition, boost::system::error_code& ec, typename enable_if< is_match_condition<MatchCondition>::value && is_dynamic_buffer_v2<DynamicBuffer_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 <em>composed operation</em>. 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 <typename AsyncReadStream, typename DynamicBuffer_v1, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <em>composed operation</em>. 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 <typename AsyncReadStream, typename DynamicBuffer_v1, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <em>composed operation</em>. 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 <typename AsyncReadStream, typename DynamicBuffer_v1, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <em>composed operation</em>. 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<iterator, bool> match_condition(iterator begin, iterator end); * @endcode * where @c iterator represents the type: * @code buffers_iterator<typename DynamicBuffer_v1::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 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<iterator, bool> * 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 <typename Iterator> * std::pair<Iterator, bool> 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<match_char> * : 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 <typename AsyncReadStream, typename DynamicBuffer_v1, typename MatchCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type), typename enable_if< is_match_condition<MatchCondition>::value && is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <em>composed operation</em>. 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 <typename AsyncReadStream, typename Allocator, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, char delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type)); /// 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 <em>composed operation</em>. 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 <typename AsyncReadStream, typename Allocator, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, BOOST_ASIO_STRING_VIEW_PARAM delim, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type)); #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 <em>composed operation</em>. 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 <typename AsyncReadStream, typename Allocator, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, const boost::regex& expr, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type)); #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 <em>composed operation</em>. 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<iterator, bool> match_condition(iterator begin, iterator end); * @endcode * where @c iterator represents the type: * @code buffers_iterator<basic_streambuf<Allocator>::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<iterator, bool> * 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 <typename Iterator> * std::pair<Iterator, bool> 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<match_char> * : 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 <typename AsyncReadStream, typename Allocator, typename MatchCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_until(AsyncReadStream& s, boost::asio::basic_streambuf<Allocator>& b, MatchCondition match_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type), typename enable_if<is_match_condition<MatchCondition>::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 <em>composed operation</em>. 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 <typename AsyncReadStream, typename DynamicBuffer_v2, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <em>composed operation</em>. 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 <typename AsyncReadStream, typename DynamicBuffer_v2, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <em>composed operation</em>. 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 <typename AsyncReadStream, typename DynamicBuffer_v2, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <em>composed operation</em>. 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<iterator, bool> match_condition(iterator begin, iterator end); * @endcode * where @c iterator represents the type: * @code buffers_iterator<typename DynamicBuffer_v2::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 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<iterator, bool> * 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 <typename Iterator> * std::pair<Iterator, bool> 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<match_char> * : 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 <typename AsyncReadStream, typename DynamicBuffer_v2, typename MatchCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type), typename enable_if< is_match_condition<MatchCondition>::value && is_dynamic_buffer_v2<DynamicBuffer_v2>::value >::type* = 0); #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) /*@}*/ } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/read_until.hpp> #endif // BOOST_ASIO_READ_UNTIL_HPP query.hpp 0000644 00000020203 15125530236 0006421 0 ustar 00 // // query.hpp // ~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_QUERY_HPP #define BOOST_ASIO_QUERY_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/is_applicable_property.hpp> #include <boost/asio/traits/query_member.hpp> #include <boost/asio/traits/query_free.hpp> #include <boost/asio/traits/static_query.hpp> #include <boost/asio/detail/push_options.hpp> #if defined(GENERATING_DOCUMENTATION) namespace boost { namespace asio { /// A customisation point that queries the value of a property. /** * The name <tt>query</tt> denotes a customization point object. The * expression <tt>boost::asio::query(E, P)</tt> for some * subexpressions <tt>E</tt> and <tt>P</tt> (with types <tt>T = * decay_t<decltype(E)></tt> and <tt>Prop = decay_t<decltype(P)></tt>) is * expression-equivalent to: * * @li If <tt>is_applicable_property_v<T, Prop></tt> is not a well-formed * constant expression with value <tt>true</tt>, <tt>boost::asio::query(E, * P)</tt> is ill-formed. * * @li Otherwise, <tt>Prop::template static_query_v<T></tt> if the expression * <tt>Prop::template static_query_v<T></tt> is a well-formed constant * expression. * * @li Otherwise, <tt>(E).query(P)</tt> if the expression * <tt>(E).query(P)</tt> is well-formed. * * @li Otherwise, <tt>query(E, P)</tt> if the expression * <tt>query(E, P)</tt> is a valid expression with overload * resolution performed in a context that does not include the declaration * of the <tt>query</tt> customization point object. * * @li Otherwise, <tt>boost::asio::query(E, P)</tt> is ill-formed. */ inline constexpr unspecified query = unspecified; /// A type trait that determines whether a @c query expression is well-formed. /** * Class template @c can_query is a trait that is derived from * @c true_type if the expression <tt>boost::asio::query(std::declval<T>(), * std::declval<Property>())</tt> is well formed; otherwise @c false_type. */ template <typename T, typename Property> struct can_query : integral_constant<bool, automatically_determined> { }; /// A type trait that determines whether a @c query expression will /// not throw. /** * Class template @c is_nothrow_query is a trait that is derived from * @c true_type if the expression <tt>boost::asio::query(std::declval<T>(), * std::declval<Property>())</tt> is @c noexcept; otherwise @c false_type. */ template <typename T, typename Property> struct is_nothrow_query : integral_constant<bool, automatically_determined> { }; /// A type trait that determines the result type of a @c query expression. /** * Class template @c query_result is a trait that determines the result * type of the expression <tt>boost::asio::query(std::declval<T>(), * std::declval<Property>())</tt>. */ template <typename T, typename Property> struct query_result { /// The result of the @c query expression. typedef automatically_determined type; }; } // namespace asio } // namespace boost #else // defined(GENERATING_DOCUMENTATION) namespace asio_query_fn { using boost::asio::decay; using boost::asio::declval; using boost::asio::enable_if; using boost::asio::is_applicable_property; using boost::asio::traits::query_free; using boost::asio::traits::query_member; using boost::asio::traits::static_query; void query(); enum overload_type { static_value, call_member, call_free, ill_formed }; template <typename T, typename Properties, typename = void> struct call_traits { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; template <typename T, typename Property> struct call_traits<T, void(Property), typename enable_if< ( is_applicable_property< typename decay<T>::type, typename decay<Property>::type >::value && static_query<T, Property>::is_valid ) >::type> : static_query<T, Property> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = static_value); }; template <typename T, typename Property> struct call_traits<T, void(Property), typename enable_if< ( is_applicable_property< typename decay<T>::type, typename decay<Property>::type >::value && !static_query<T, Property>::is_valid && query_member<T, Property>::is_valid ) >::type> : query_member<T, Property> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); }; template <typename T, typename Property> struct call_traits<T, void(Property), typename enable_if< ( is_applicable_property< typename decay<T>::type, typename decay<Property>::type >::value && !static_query<T, Property>::is_valid && !query_member<T, Property>::is_valid && query_free<T, Property>::is_valid ) >::type> : query_free<T, Property> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); }; struct impl { template <typename T, typename Property> BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(Property)>::overload == static_value, typename call_traits<T, void(Property)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T), BOOST_ASIO_MOVE_ARG(Property)) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(Property)>::is_noexcept)) { return static_query< typename decay<T>::type, typename decay<Property>::type >::value(); } template <typename T, typename Property> BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(Property)>::overload == call_member, typename call_traits<T, void(Property)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(Property) p) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(Property)>::is_noexcept)) { return BOOST_ASIO_MOVE_CAST(T)(t).query(BOOST_ASIO_MOVE_CAST(Property)(p)); } template <typename T, typename Property> BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(Property)>::overload == call_free, typename call_traits<T, void(Property)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(Property) p) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(Property)>::is_noexcept)) { return query(BOOST_ASIO_MOVE_CAST(T)(t), BOOST_ASIO_MOVE_CAST(Property)(p)); } }; template <typename T = impl> struct static_instance { static const T instance; }; template <typename T> const T static_instance<T>::instance = {}; } // namespace asio_query_fn namespace boost { namespace asio { namespace { static BOOST_ASIO_CONSTEXPR const asio_query_fn::impl& query = asio_query_fn::static_instance<>::instance; } // namespace template <typename T, typename Property> struct can_query : integral_constant<bool, asio_query_fn::call_traits<T, void(Property)>::overload != asio_query_fn::ill_formed> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename Property> constexpr bool can_query_v = can_query<T, Property>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename Property> struct is_nothrow_query : integral_constant<bool, asio_query_fn::call_traits<T, void(Property)>::is_noexcept> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename Property> constexpr bool is_nothrow_query_v = is_nothrow_query<T, Property>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename Property> struct query_result { typedef typename asio_query_fn::call_traits< T, void(Property)>::result_type type; }; } // namespace asio } // namespace boost #endif // defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_QUERY_HPP deadline_timer.hpp 0000644 00000002162 15125530236 0010225 0 ustar 00 // // deadline_timer.hpp // ~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/socket_types.hpp> // Must come before posix_time. #include <boost/asio/basic_deadline_timer.hpp> #include <boost/date_time/posix_time/posix_time_types.hpp> namespace boost { namespace asio { /// Typedef for the typical usage of timer. Uses a UTC clock. typedef basic_deadline_timer<boost::posix_time::ptime> deadline_timer; } // namespace asio } // namespace boost #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) // || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_DEADLINE_TIMER_HPP co_spawn.hpp 0000644 00000034255 15125530236 0007101 0 ustar 00 // // co_spawn.hpp // ~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) #include <boost/asio/awaitable.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/is_executor.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename T> struct awaitable_signature; template <typename T, typename Executor> struct awaitable_signature<awaitable<T, Executor>> { typedef void type(std::exception_ptr, T); }; template <typename Executor> struct awaitable_signature<awaitable<void, Executor>> { typedef void type(std::exception_ptr); }; } // namespace detail /// Spawn a new coroutined-based thread of execution. /** * @param ex The executor that will be used to schedule the new thread of * execution. * * @param a The boost::asio::awaitable object that is the result of calling the * coroutine's entry point function. * * @param token The completion token that will handle the notification that * the thread of execution has completed. The function signature of the * completion handler must be: * @code void handler(std::exception_ptr, T); @endcode * * @par Example * @code * boost::asio::awaitable<std::size_t> echo(tcp::socket socket) * { * std::size_t bytes_transferred = 0; * * try * { * char data[1024]; * for (;;) * { * std::size_t n = co_await socket.async_read_some( * boost::asio::buffer(data), boost::asio::use_awaitable); * * co_await boost::asio::async_write(socket, * boost::asio::buffer(data, n), boost::asio::use_awaitable); * * bytes_transferred += n; * } * } * catch (const std::exception&) * { * } * * co_return bytes_transferred; * } * * // ... * * boost::asio::co_spawn(my_executor, * echo(std::move(my_tcp_socket)), * [](std::exception_ptr e, std::size_t n) * { * std::cout << "transferred " << n << "\n"; * }); * @endcode */ template <typename Executor, typename T, typename AwaitableExecutor, BOOST_ASIO_COMPLETION_TOKEN_FOR( void(std::exception_ptr, T)) CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( CompletionToken, void(std::exception_ptr, T)) co_spawn(const Executor& ex, awaitable<T, AwaitableExecutor> a, CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if< (is_executor<Executor>::value || execution::is_executor<Executor>::value) && is_convertible<Executor, AwaitableExecutor>::value >::type* = 0); /// Spawn a new coroutined-based thread of execution. /** * @param ex The executor that will be used to schedule the new thread of * execution. * * @param a The boost::asio::awaitable object that is the result of calling the * coroutine's entry point function. * * @param token The completion token that will handle the notification that * the thread of execution has completed. The function signature of the * completion handler must be: * @code void handler(std::exception_ptr); @endcode * * @par Example * @code * boost::asio::awaitable<void> echo(tcp::socket socket) * { * try * { * char data[1024]; * for (;;) * { * std::size_t n = co_await socket.async_read_some( * boost::asio::buffer(data), boost::asio::use_awaitable); * * co_await boost::asio::async_write(socket, * boost::asio::buffer(data, n), boost::asio::use_awaitable); * } * } * catch (const std::exception& e) * { * std::cerr << "Exception: " << e.what() << "\n"; * } * } * * // ... * * boost::asio::co_spawn(my_executor, * echo(std::move(my_tcp_socket)), * boost::asio::detached); * @endcode */ template <typename Executor, typename AwaitableExecutor, BOOST_ASIO_COMPLETION_TOKEN_FOR( void(std::exception_ptr)) CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( CompletionToken, void(std::exception_ptr)) co_spawn(const Executor& ex, awaitable<void, AwaitableExecutor> a, CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if< (is_executor<Executor>::value || execution::is_executor<Executor>::value) && is_convertible<Executor, AwaitableExecutor>::value >::type* = 0); /// Spawn a new coroutined-based thread of execution. /** * @param ctx An execution context that will provide the executor to be used to * schedule the new thread of execution. * * @param a The boost::asio::awaitable object that is the result of calling the * coroutine's entry point function. * * @param token The completion token that will handle the notification that * the thread of execution has completed. The function signature of the * completion handler must be: * @code void handler(std::exception_ptr); @endcode * * @par Example * @code * boost::asio::awaitable<std::size_t> echo(tcp::socket socket) * { * std::size_t bytes_transferred = 0; * * try * { * char data[1024]; * for (;;) * { * std::size_t n = co_await socket.async_read_some( * boost::asio::buffer(data), boost::asio::use_awaitable); * * co_await boost::asio::async_write(socket, * boost::asio::buffer(data, n), boost::asio::use_awaitable); * * bytes_transferred += n; * } * } * catch (const std::exception&) * { * } * * co_return bytes_transferred; * } * * // ... * * boost::asio::co_spawn(my_io_context, * echo(std::move(my_tcp_socket)), * [](std::exception_ptr e, std::size_t n) * { * std::cout << "transferred " << n << "\n"; * }); * @endcode */ template <typename ExecutionContext, typename T, typename AwaitableExecutor, BOOST_ASIO_COMPLETION_TOKEN_FOR( void(std::exception_ptr, T)) CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename ExecutionContext::executor_type)> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( CompletionToken, void(std::exception_ptr, T)) co_spawn(ExecutionContext& ctx, awaitable<T, AwaitableExecutor> a, CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename ExecutionContext::executor_type), typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value && is_convertible<typename ExecutionContext::executor_type, AwaitableExecutor>::value >::type* = 0); /// Spawn a new coroutined-based thread of execution. /** * @param ctx An execution context that will provide the executor to be used to * schedule the new thread of execution. * * @param a The boost::asio::awaitable object that is the result of calling the * coroutine's entry point function. * * @param token The completion token that will handle the notification that * the thread of execution has completed. The function signature of the * completion handler must be: * @code void handler(std::exception_ptr); @endcode * * @par Example * @code * boost::asio::awaitable<void> echo(tcp::socket socket) * { * try * { * char data[1024]; * for (;;) * { * std::size_t n = co_await socket.async_read_some( * boost::asio::buffer(data), boost::asio::use_awaitable); * * co_await boost::asio::async_write(socket, * boost::asio::buffer(data, n), boost::asio::use_awaitable); * } * } * catch (const std::exception& e) * { * std::cerr << "Exception: " << e.what() << "\n"; * } * } * * // ... * * boost::asio::co_spawn(my_io_context, * echo(std::move(my_tcp_socket)), * boost::asio::detached); * @endcode */ template <typename ExecutionContext, typename AwaitableExecutor, BOOST_ASIO_COMPLETION_TOKEN_FOR( void(std::exception_ptr)) CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename ExecutionContext::executor_type)> inline BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( CompletionToken, void(std::exception_ptr)) co_spawn(ExecutionContext& ctx, awaitable<void, AwaitableExecutor> a, CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename ExecutionContext::executor_type), typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value && is_convertible<typename ExecutionContext::executor_type, AwaitableExecutor>::value >::type* = 0); /// Spawn a new coroutined-based thread of execution. /** * @param ex The executor that will be used to schedule the new thread of * execution. * * @param f A nullary function object with a return type of the form * @c boost::asio::awaitable<R,E> that will be used as the coroutine's entry * point. * * @param token The completion token that will handle the notification that the * thread of execution has completed. If @c R is @c void, the function * signature of the completion handler must be: * * @code void handler(std::exception_ptr); @endcode * Otherwise, the function signature of the completion handler must be: * @code void handler(std::exception_ptr, R); @endcode * * * @par Example * @code * boost::asio::awaitable<std::size_t> echo(tcp::socket socket) * { * std::size_t bytes_transferred = 0; * * try * { * char data[1024]; * for (;;) * { * std::size_t n = co_await socket.async_read_some( * boost::asio::buffer(data), boost::asio::use_awaitable); * * co_await boost::asio::async_write(socket, * boost::asio::buffer(data, n), boost::asio::use_awaitable); * * bytes_transferred += n; * } * } * catch (const std::exception&) * { * } * * co_return bytes_transferred; * } * * // ... * * boost::asio::co_spawn(my_executor, * [socket = std::move(my_tcp_socket)]() mutable * -> boost::asio::awaitable<void> * { * try * { * char data[1024]; * for (;;) * { * std::size_t n = co_await socket.async_read_some( * boost::asio::buffer(data), boost::asio::use_awaitable); * * co_await boost::asio::async_write(socket, * boost::asio::buffer(data, n), boost::asio::use_awaitable); * } * } * catch (const std::exception& e) * { * std::cerr << "Exception: " << e.what() << "\n"; * } * }, boost::asio::detached); * @endcode */ template <typename Executor, typename F, BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature< typename result_of<F()>::type>::type) CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, typename detail::awaitable_signature<typename result_of<F()>::type>::type) co_spawn(const Executor& ex, F&& f, CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if< is_executor<Executor>::value || execution::is_executor<Executor>::value >::type* = 0); /// Spawn a new coroutined-based thread of execution. /** * @param ctx An execution context that will provide the executor to be used to * schedule the new thread of execution. * * @param f A nullary function object with a return type of the form * @c boost::asio::awaitable<R,E> that will be used as the coroutine's entry * point. * * @param token The completion token that will handle the notification that the * thread of execution has completed. If @c R is @c void, the function * signature of the completion handler must be: * * @code void handler(std::exception_ptr); @endcode * Otherwise, the function signature of the completion handler must be: * @code void handler(std::exception_ptr, R); @endcode * * * @par Example * @code * boost::asio::awaitable<std::size_t> echo(tcp::socket socket) * { * std::size_t bytes_transferred = 0; * * try * { * char data[1024]; * for (;;) * { * std::size_t n = co_await socket.async_read_some( * boost::asio::buffer(data), boost::asio::use_awaitable); * * co_await boost::asio::async_write(socket, * boost::asio::buffer(data, n), boost::asio::use_awaitable); * * bytes_transferred += n; * } * } * catch (const std::exception&) * { * } * * co_return bytes_transferred; * } * * // ... * * boost::asio::co_spawn(my_io_context, * [socket = std::move(my_tcp_socket)]() mutable * -> boost::asio::awaitable<void> * { * try * { * char data[1024]; * for (;;) * { * std::size_t n = co_await socket.async_read_some( * boost::asio::buffer(data), boost::asio::use_awaitable); * * co_await boost::asio::async_write(socket, * boost::asio::buffer(data, n), boost::asio::use_awaitable); * } * } * catch (const std::exception& e) * { * std::cerr << "Exception: " << e.what() << "\n"; * } * }, boost::asio::detached); * @endcode */ template <typename ExecutionContext, typename F, BOOST_ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature< typename result_of<F()>::type>::type) CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename ExecutionContext::executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, typename detail::awaitable_signature<typename result_of<F()>::type>::type) co_spawn(ExecutionContext& ctx, F&& f, CompletionToken&& token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename ExecutionContext::executor_type), typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0); } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/co_spawn.hpp> #endif // defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_CO_SPAWN_HPP is_read_buffered.hpp 0000644 00000003156 15125530236 0010534 0 ustar 00 // // is_read_buffered.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/buffered_read_stream_fwd.hpp> #include <boost/asio/buffered_stream_fwd.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Stream> char is_read_buffered_helper(buffered_stream<Stream>* s); template <typename Stream> char is_read_buffered_helper(buffered_read_stream<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 <typename Stream> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IS_READ_BUFFERED_HPP error.hpp 0000644 00000024157 15125530236 0006421 0 ustar 00 // // error.hpp // ~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/cerrno.hpp> #include <boost/system/error_code.hpp> #include <boost/system/system_error.hpp> #if defined(BOOST_ASIO_WINDOWS) \ || defined(__CYGWIN__) \ || defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <winerror.h> #else # include <cerrno> # include <netdb.h> #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 <boost/asio/detail/push_options.hpp> 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<boost::asio::error::basic_errors> { static const bool value = true; }; template<> struct is_error_code_enum<boost::asio::error::netdb_errors> { static const bool value = true; }; template<> struct is_error_code_enum<boost::asio::error::addrinfo_errors> { static const bool value = true; }; template<> struct is_error_code_enum<boost::asio::error::misc_errors> { 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<int>(e), get_system_category()); } inline boost::system::error_code make_error_code(netdb_errors e) { return boost::system::error_code( static_cast<int>(e), get_netdb_category()); } inline boost::system::error_code make_error_code(addrinfo_errors e) { return boost::system::error_code( static_cast<int>(e), get_addrinfo_category()); } inline boost::system::error_code make_error_code(misc_errors e) { return boost::system::error_code( static_cast<int>(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 <boost/asio/detail/pop_options.hpp> #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 <boost/asio/impl/error.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_ERROR_HPP traits/static_query.hpp 0000644 00000005773 15125530236 0011315 0 ustar 00 // // traits/static_query.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_STATIC_QUERY_HPP #define BOOST_ASIO_TRAITS_STATIC_QUERY_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_CONSTEXPR) \ && defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_CONSTEXPR) // && defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename Property, typename = void> struct static_query_default; template <typename T, typename Property, typename = void> struct static_query; } // namespace traits namespace detail { struct no_static_query { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; template <typename T, typename Property, typename = void> struct static_query_trait : conditional< is_same<T, typename decay<T>::type>::value && is_same<Property, typename decay<Property>::type>::value, no_static_query, traits::static_query< typename decay<T>::type, typename decay<Property>::type> >::type { }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) template <typename T, typename Property> struct static_query_trait<T, Property, typename void_type< decltype(decay<Property>::type::template static_query_v<T>) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( decay<Property>::type::template static_query_v<T>); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(decay<Property>::type::template static_query_v<T>)); static BOOST_ASIO_CONSTEXPR result_type value() noexcept(is_noexcept) { return decay<Property>::type::template static_query_v<T>; } }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_QUERY_TRAIT) } // namespace detail namespace traits { template <typename T, typename Property, typename> struct static_query_default : detail::static_query_trait<T, Property> { }; template <typename T, typename Property, typename> struct static_query : static_query_default<T, Property> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_STATIC_QUERY_HPP traits/require_concept_member.hpp 0000644 00000006056 15125530236 0013312 0 ustar 00 // // traits/require_concept_member.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_REQUIRE_CONCEPT_MEMBER_HPP #define BOOST_ASIO_TRAITS_REQUIRE_CONCEPT_MEMBER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename Property, typename = void> struct require_concept_member_default; template <typename T, typename Property, typename = void> struct require_concept_member; } // namespace traits namespace detail { struct no_require_concept_member { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT) template <typename T, typename Property, typename = void> struct require_concept_member_trait : no_require_concept_member { }; template <typename T, typename Property> struct require_concept_member_trait<T, Property, typename void_type< decltype(declval<T>().require_concept(declval<Property>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( declval<T>().require_concept(declval<Property>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( declval<T>().require_concept(declval<Property>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT) template <typename T, typename Property, typename = void> struct require_concept_member_trait : conditional< is_same<T, typename decay<T>::type>::value && is_same<Property, typename decay<Property>::type>::value, no_require_concept_member, traits::require_concept_member< typename decay<T>::type, typename decay<Property>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_MEMBER_TRAIT) } // namespace detail namespace traits { template <typename T, typename Property, typename> struct require_concept_member_default : detail::require_concept_member_trait<T, Property> { }; template <typename T, typename Property, typename> struct require_concept_member : require_concept_member_default<T, Property> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_REQUIRE_CONCEPT_MEMBER_HPP traits/start_member.hpp 0000644 00000005220 15125530236 0011250 0 ustar 00 // // traits/start_member.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_START_MEMBER_HPP #define BOOST_ASIO_TRAITS_START_MEMBER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_START_MEMBER_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename = void> struct start_member_default; template <typename T, typename = void> struct start_member; } // namespace traits namespace detail { struct no_start_member { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_START_MEMBER_TRAIT) template <typename T, typename = void> struct start_member_trait : no_start_member { }; template <typename T> struct start_member_trait<T, typename void_type< decltype(declval<T>().start()) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype(declval<T>().start()); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(declval<T>().start())); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_START_MEMBER_TRAIT) template <typename T, typename = void> struct start_member_trait : conditional< is_same<T, typename remove_reference<T>::type>::value, typename conditional< is_same<T, typename add_const<T>::type>::value, no_start_member, traits::start_member<typename add_const<T>::type> >::type, traits::start_member<typename remove_reference<T>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_START_MEMBER_TRAIT) } // namespace detail namespace traits { template <typename T, typename> struct start_member_default : detail::start_member_trait<T> { }; template <typename T, typename> struct start_member : start_member_default<T> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_START_MEMBER_HPP traits/query_static_constexpr_member.hpp 0000644 00000006256 15125530236 0014746 0 ustar 00 // // traits/query_static_constexpr_member.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_QUERY_STATIC_CONSTEXPR_MEMBER_HPP #define BOOST_ASIO_TRAITS_QUERY_STATIC_CONSTEXPR_MEMBER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_CONSTEXPR) \ && defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_CONSTEXPR) // && defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename Property, typename = void> struct query_static_constexpr_member_default; template <typename T, typename Property, typename = void> struct query_static_constexpr_member; } // namespace traits namespace detail { struct no_query_static_constexpr_member { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); }; template <typename T, typename Property, typename = void> struct query_static_constexpr_member_trait : conditional< is_same<T, typename decay<T>::type>::value && is_same<Property, typename decay<Property>::type>::value, no_query_static_constexpr_member, traits::query_static_constexpr_member< typename decay<T>::type, typename decay<Property>::type> >::type { }; #if defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) template <typename T, typename Property> struct query_static_constexpr_member_trait<T, Property, typename enable_if< (static_cast<void>(T::query(Property{})), true) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype(T::query(Property{})); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(T::query(Property{}))); static BOOST_ASIO_CONSTEXPR result_type value() noexcept(is_noexcept) { return T::query(Property{}); } }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) } // namespace detail namespace traits { template <typename T, typename Property, typename> struct query_static_constexpr_member_default : detail::query_static_constexpr_member_trait<T, Property> { }; template <typename T, typename Property, typename> struct query_static_constexpr_member : query_static_constexpr_member_default<T, Property> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_QUERY_STATIC_CONSTEXPR_MEMBER_HPP traits/submit_free.hpp 0000644 00000005543 15125530236 0011100 0 ustar 00 // // traits/submit_free.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_SUBMIT_FREE_HPP #define BOOST_ASIO_TRAITS_SUBMIT_FREE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename S, typename R, typename = void> struct submit_free_default; template <typename S, typename R, typename = void> struct submit_free; } // namespace traits namespace detail { struct no_submit_free { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT) template <typename S, typename R, typename = void> struct submit_free_trait : no_submit_free { }; template <typename S, typename R> struct submit_free_trait<S, R, typename void_type< decltype(submit(declval<S>(), declval<R>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( submit(declval<S>(), declval<R>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( submit(declval<S>(), declval<R>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT) template <typename S, typename R, typename = void> struct submit_free_trait : conditional< is_same<S, typename remove_reference<S>::type>::value && is_same<R, typename decay<R>::type>::value, typename conditional< is_same<S, typename add_const<S>::type>::value, no_submit_free, traits::submit_free<typename add_const<S>::type, R> >::type, traits::submit_free< typename remove_reference<S>::type, typename decay<R>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_SUBMIT_FREE_TRAIT) } // namespace detail namespace traits { template <typename S, typename R, typename> struct submit_free_default : detail::submit_free_trait<S, R> { }; template <typename S, typename R, typename> struct submit_free : submit_free_default<S, R> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_SUBMIT_FREE_HPP traits/require_free.hpp 0000644 00000005475 15125530236 0011255 0 ustar 00 // // traits/require_free.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_REQUIRE_FREE_HPP #define BOOST_ASIO_TRAITS_REQUIRE_FREE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename Property, typename = void> struct require_free_default; template <typename T, typename Property, typename = void> struct require_free; } // namespace traits namespace detail { struct no_require_free { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) template <typename T, typename Property, typename = void> struct require_free_trait : no_require_free { }; template <typename T, typename Property> struct require_free_trait<T, Property, typename void_type< decltype(require(declval<T>(), declval<Property>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( require(declval<T>(), declval<Property>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( require(declval<T>(), declval<Property>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) template <typename T, typename Property, typename = void> struct require_free_trait : conditional< is_same<T, typename decay<T>::type>::value && is_same<Property, typename decay<Property>::type>::value, no_require_free, traits::require_free< typename decay<T>::type, typename decay<Property>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_FREE_TRAIT) } // namespace detail namespace traits { template <typename T, typename Property, typename> struct require_free_default : detail::require_free_trait<T, Property> { }; template <typename T, typename Property, typename> struct require_free : require_free_default<T, Property> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_REQUIRE_FREE_HPP traits/start_free.hpp 0000644 00000005137 15125530236 0010731 0 ustar 00 // // traits/start_free.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_START_FREE_HPP #define BOOST_ASIO_TRAITS_START_FREE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_START_FREE_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename = void> struct start_free_default; template <typename T, typename = void> struct start_free; } // namespace traits namespace detail { struct no_start_free { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_START_FREE_TRAIT) template <typename T, typename = void> struct start_free_trait : no_start_free { }; template <typename T> struct start_free_trait<T, typename void_type< decltype(start(declval<T>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype(start(declval<T>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(start(declval<T>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_START_FREE_TRAIT) template <typename T, typename = void> struct start_free_trait : conditional< is_same<T, typename remove_reference<T>::type>::value, typename conditional< is_same<T, typename add_const<T>::type>::value, no_start_free, traits::start_free<typename add_const<T>::type> >::type, traits::start_free<typename remove_reference<T>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_START_FREE_TRAIT) } // namespace detail namespace traits { template <typename T, typename> struct start_free_default : detail::start_free_trait<T> { }; template <typename T, typename> struct start_free : start_free_default<T> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_START_FREE_HPP traits/require_concept_free.hpp 0000644 00000006005 15125530236 0012756 0 ustar 00 // // traits/require_concept_free.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_REQUIRE_CONCEPT_FREE_HPP #define BOOST_ASIO_TRAITS_REQUIRE_CONCEPT_FREE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename Property, typename = void> struct require_concept_free_default; template <typename T, typename Property, typename = void> struct require_concept_free; } // namespace traits namespace detail { struct no_require_concept_free { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT) template <typename T, typename Property, typename = void> struct require_concept_free_trait : no_require_concept_free { }; template <typename T, typename Property> struct require_concept_free_trait<T, Property, typename void_type< decltype(require_concept(declval<T>(), declval<Property>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( require_concept(declval<T>(), declval<Property>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( require_concept(declval<T>(), declval<Property>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT) template <typename T, typename Property, typename = void> struct require_concept_free_trait : conditional< is_same<T, typename decay<T>::type>::value && is_same<Property, typename decay<Property>::type>::value, no_require_concept_free, traits::require_concept_free< typename decay<T>::type, typename decay<Property>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_CONCEPT_FREE_TRAIT) } // namespace detail namespace traits { template <typename T, typename Property, typename> struct require_concept_free_default : detail::require_concept_free_trait<T, Property> { }; template <typename T, typename Property, typename> struct require_concept_free : require_concept_free_default<T, Property> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_REQUIRE_CONCEPT_FREE_HPP traits/query_free.hpp 0000644 00000005413 15125530236 0010736 0 ustar 00 // // traits/query_free.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_QUERY_FREE_HPP #define BOOST_ASIO_TRAITS_QUERY_FREE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename Property, typename = void> struct query_free_default; template <typename T, typename Property, typename = void> struct query_free; } // namespace traits namespace detail { struct no_query_free { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) template <typename T, typename Property, typename = void> struct query_free_trait : no_query_free { }; template <typename T, typename Property> struct query_free_trait<T, Property, typename void_type< decltype(query(declval<T>(), declval<Property>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( query(declval<T>(), declval<Property>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( query(declval<T>(), declval<Property>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) template <typename T, typename Property, typename = void> struct query_free_trait : conditional< is_same<T, typename decay<T>::type>::value && is_same<Property, typename decay<Property>::type>::value, no_query_free, traits::query_free< typename decay<T>::type, typename decay<Property>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_FREE_TRAIT) } // namespace detail namespace traits { template <typename T, typename Property, typename> struct query_free_default : detail::query_free_trait<T, Property> { }; template <typename T, typename Property, typename> struct query_free : query_free_default<T, Property> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_QUERY_FREE_HPP traits/set_done_member.hpp 0000644 00000005336 15125530236 0011723 0 ustar 00 // // traits/set_done_member.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_SET_DONE_MEMBER_HPP #define BOOST_ASIO_TRAITS_SET_DONE_MEMBER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename = void> struct set_done_member_default; template <typename T, typename = void> struct set_done_member; } // namespace traits namespace detail { struct no_set_done_member { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) template <typename T, typename = void> struct set_done_member_trait : no_set_done_member { }; template <typename T> struct set_done_member_trait<T, typename void_type< decltype(declval<T>().set_done()) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype(declval<T>().set_done()); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(declval<T>().set_done())); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) template <typename T, typename = void> struct set_done_member_trait : conditional< is_same<T, typename remove_reference<T>::type>::value, typename conditional< is_same<T, typename add_const<T>::type>::value, no_set_done_member, traits::set_done_member<typename add_const<T>::type> >::type, traits::set_done_member<typename remove_reference<T>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_SET_DONE_MEMBER_TRAIT) } // namespace detail namespace traits { template <typename T, typename> struct set_done_member_default : detail::set_done_member_trait<T> { }; template <typename T, typename> struct set_done_member : set_done_member_default<T> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_SET_DONE_MEMBER_HPP traits/static_require_concept.hpp 0000644 00000006723 15125530236 0013333 0 ustar 00 // // traits/static_require_concept.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_STATIC_REQUIRE_CONCEPT_HPP #define BOOST_ASIO_TRAITS_STATIC_REQUIRE_CONCEPT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/traits/static_query.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) # define BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_CONCEPT_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename Property, typename = void> struct static_require_concept_default; template <typename T, typename Property, typename = void> struct static_require_concept; } // namespace traits namespace detail { struct no_static_require_concept { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); }; template <typename T, typename Property, typename = void> struct static_require_concept_trait : conditional< is_same<T, typename decay<T>::type>::value && is_same<Property, typename decay<Property>::type>::value, no_static_require_concept, traits::static_require_concept< typename decay<T>::type, typename decay<Property>::type> >::type { }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_CONCEPT_TRAIT) #if defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) template <typename T, typename Property> struct static_require_concept_trait<T, Property, typename enable_if< decay<Property>::type::value() == traits::static_query<T, Property>::value() >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); }; #else // defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) false_type static_require_concept_test(...); template <typename T, typename Property> true_type static_require_concept_test(T*, Property*, typename enable_if< Property::value() == traits::static_query<T, Property>::value() >::type* = 0); template <typename T, typename Property> struct has_static_require_concept { BOOST_ASIO_STATIC_CONSTEXPR(bool, value = decltype((static_require_concept_test)( static_cast<T*>(0), static_cast<Property*>(0)))::value); }; template <typename T, typename Property> struct static_require_concept_trait<T, Property, typename enable_if< has_static_require_concept<typename decay<T>::type, typename decay<Property>::type>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); }; #endif // defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_CONCEPT_TRAIT) } // namespace detail namespace traits { template <typename T, typename Property, typename> struct static_require_concept_default : detail::static_require_concept_trait<T, Property> { }; template <typename T, typename Property, typename> struct static_require_concept : static_require_concept_default<T, Property> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_STATIC_REQUIRE_CONCEPT_HPP traits/prefer_free.hpp 0000644 00000005444 15125530236 0011060 0 ustar 00 // // traits/prefer_free.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_PREFER_FREE_HPP #define BOOST_ASIO_TRAITS_PREFER_FREE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename Property, typename = void> struct prefer_free_default; template <typename T, typename Property, typename = void> struct prefer_free; } // namespace traits namespace detail { struct no_prefer_free { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) template <typename T, typename Property, typename = void> struct prefer_free_trait : no_prefer_free { }; template <typename T, typename Property> struct prefer_free_trait<T, Property, typename void_type< decltype(prefer(declval<T>(), declval<Property>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( prefer(declval<T>(), declval<Property>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( prefer(declval<T>(), declval<Property>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) template <typename T, typename Property, typename = void> struct prefer_free_trait : conditional< is_same<T, typename decay<T>::type>::value && is_same<Property, typename decay<Property>::type>::value, no_prefer_free, traits::prefer_free< typename decay<T>::type, typename decay<Property>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_PREFER_FREE_TRAIT) } // namespace detail namespace traits { template <typename T, typename Property, typename> struct prefer_free_default : detail::prefer_free_trait<T, Property> { }; template <typename T, typename Property, typename> struct prefer_free : prefer_free_default<T, Property> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_PREFER_FREE_HPP traits/schedule_free.hpp 0000644 00000005255 15125530236 0011371 0 ustar 00 // // traits/schedule_free.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_SCHEDULE_FREE_HPP #define BOOST_ASIO_TRAITS_SCHEDULE_FREE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_SCHEDULE_FREE_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename = void> struct schedule_free_default; template <typename T, typename = void> struct schedule_free; } // namespace traits namespace detail { struct no_schedule_free { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_SCHEDULE_FREE_TRAIT) template <typename T, typename = void> struct schedule_free_trait : no_schedule_free { }; template <typename T> struct schedule_free_trait<T, typename void_type< decltype(schedule(declval<T>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype(schedule(declval<T>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(schedule(declval<T>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_SCHEDULE_FREE_TRAIT) template <typename T, typename = void> struct schedule_free_trait : conditional< is_same<T, typename remove_reference<T>::type>::value, typename conditional< is_same<T, typename add_const<T>::type>::value, no_schedule_free, traits::schedule_free<typename add_const<T>::type> >::type, traits::schedule_free<typename remove_reference<T>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_SCHEDULE_FREE_TRAIT) } // namespace detail namespace traits { template <typename T, typename> struct schedule_free_default : detail::schedule_free_trait<T> { }; template <typename T, typename> struct schedule_free : schedule_free_default<T> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_SCHEDULE_FREE_HPP traits/static_require.hpp 0000644 00000006411 15125530236 0011612 0 ustar 00 // // traits/static_require.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_STATIC_REQUIRE_HPP #define BOOST_ASIO_TRAITS_STATIC_REQUIRE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/traits/static_query.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) # define BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename Property, typename = void> struct static_require_default; template <typename T, typename Property, typename = void> struct static_require; } // namespace traits namespace detail { struct no_static_require { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); }; template <typename T, typename Property, typename = void> struct static_require_trait : conditional< is_same<T, typename decay<T>::type>::value && is_same<Property, typename decay<Property>::type>::value, no_static_require, traits::static_require< typename decay<T>::type, typename decay<Property>::type> >::type { }; #if defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) #if defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) template <typename T, typename Property> struct static_require_trait<T, Property, typename enable_if< decay<Property>::type::value() == traits::static_query<T, Property>::value() >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); }; #else // defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) false_type static_require_test(...); template <typename T, typename Property> true_type static_require_test(T*, Property*, typename enable_if< Property::value() == traits::static_query<T, Property>::value() >::type* = 0); template <typename T, typename Property> struct has_static_require { BOOST_ASIO_STATIC_CONSTEXPR(bool, value = decltype((static_require_test)( static_cast<T*>(0), static_cast<Property*>(0)))::value); }; template <typename T, typename Property> struct static_require_trait<T, Property, typename enable_if< has_static_require<typename decay<T>::type, typename decay<Property>::type>::value >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); }; #endif // defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #endif // defined(BOOST_ASIO_HAS_DEDUCED_STATIC_REQUIRE_TRAIT) } // namespace detail namespace traits { template <typename T, typename Property, typename> struct static_require_default : detail::static_require_trait<T, Property> { }; template <typename T, typename Property, typename> struct static_require : static_require_default<T, Property> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_STATIC_REQUIRE_HPP traits/connect_free.hpp 0000644 00000005575 15125530236 0011233 0 ustar 00 // // traits/connect_free.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_CONNECT_FREE_HPP #define BOOST_ASIO_TRAITS_CONNECT_FREE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_CONNECT_FREE_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename S, typename R, typename = void> struct connect_free_default; template <typename S, typename R, typename = void> struct connect_free; } // namespace traits namespace detail { struct no_connect_free { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_CONNECT_FREE_TRAIT) template <typename S, typename R, typename = void> struct connect_free_trait : no_connect_free { }; template <typename S, typename R> struct connect_free_trait<S, R, typename void_type< decltype(connect(declval<S>(), declval<R>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( connect(declval<S>(), declval<R>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( connect(declval<S>(), declval<R>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_CONNECT_FREE_TRAIT) template <typename S, typename R, typename = void> struct connect_free_trait : conditional< is_same<S, typename remove_reference<S>::type>::value && is_same<R, typename decay<R>::type>::value, typename conditional< is_same<S, typename add_const<S>::type>::value, no_connect_free, traits::connect_free<typename add_const<S>::type, R> >::type, traits::connect_free< typename remove_reference<S>::type, typename decay<R>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_CONNECT_FREE_TRAIT) } // namespace detail namespace traits { template <typename S, typename R, typename> struct connect_free_default : detail::connect_free_trait<S, R> { }; template <typename S, typename R, typename> struct connect_free : connect_free_default<S, R> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_CONNECT_FREE_HPP traits/set_done_free.hpp 0000644 00000005255 15125530236 0011375 0 ustar 00 // // traits/set_done_free.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_SET_DONE_FREE_HPP #define BOOST_ASIO_TRAITS_SET_DONE_FREE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename = void> struct set_done_free_default; template <typename T, typename = void> struct set_done_free; } // namespace traits namespace detail { struct no_set_done_free { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT) template <typename T, typename = void> struct set_done_free_trait : no_set_done_free { }; template <typename T> struct set_done_free_trait<T, typename void_type< decltype(set_done(declval<T>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype(set_done(declval<T>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(set_done(declval<T>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT) template <typename T, typename = void> struct set_done_free_trait : conditional< is_same<T, typename remove_reference<T>::type>::value, typename conditional< is_same<T, typename add_const<T>::type>::value, no_set_done_free, traits::set_done_free<typename add_const<T>::type> >::type, traits::set_done_free<typename remove_reference<T>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_SET_DONE_FREE_TRAIT) } // namespace detail namespace traits { template <typename T, typename> struct set_done_free_default : detail::set_done_free_trait<T> { }; template <typename T, typename> struct set_done_free : set_done_free_default<T> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_SET_DONE_FREE_HPP traits/connect_member.hpp 0000644 00000005650 15125530236 0011553 0 ustar 00 // // traits/connect_member.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_CONNECT_MEMBER_HPP #define BOOST_ASIO_TRAITS_CONNECT_MEMBER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename S, typename R, typename = void> struct connect_member_default; template <typename S, typename R, typename = void> struct connect_member; } // namespace traits namespace detail { struct no_connect_member { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT) template <typename S, typename R, typename = void> struct connect_member_trait : no_connect_member { }; template <typename S, typename R> struct connect_member_trait<S, R, typename void_type< decltype(declval<S>().connect(declval<R>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( declval<S>().connect(declval<R>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( declval<S>().connect(declval<R>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT) template <typename S, typename R, typename = void> struct connect_member_trait : conditional< is_same<S, typename remove_reference<S>::type>::value && is_same<R, typename decay<R>::type>::value, typename conditional< is_same<S, typename add_const<S>::type>::value, no_connect_member, traits::connect_member<typename add_const<S>::type, R> >::type, traits::connect_member< typename remove_reference<S>::type, typename decay<R>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_CONNECT_MEMBER_TRAIT) } // namespace detail namespace traits { template <typename S, typename R, typename> struct connect_member_default : detail::connect_member_trait<S, R> { }; template <typename S, typename R, typename> struct connect_member : connect_member_default<S, R> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_CONNECT_MEMBER_HPP traits/set_error_free.hpp 0000644 00000005661 15125530236 0011602 0 ustar 00 // // traits/set_error_free.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_SET_ERROR_FREE_HPP #define BOOST_ASIO_TRAITS_SET_ERROR_FREE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename E, typename = void> struct set_error_free_default; template <typename T, typename E, typename = void> struct set_error_free; } // namespace traits namespace detail { struct no_set_error_free { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT) template <typename T, typename E, typename = void> struct set_error_free_trait : no_set_error_free { }; template <typename T, typename E> struct set_error_free_trait<T, E, typename void_type< decltype(set_error(declval<T>(), declval<E>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( set_error(declval<T>(), declval<E>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( set_error(declval<T>(), declval<E>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT) template <typename T, typename E, typename = void> struct set_error_free_trait : conditional< is_same<T, typename remove_reference<T>::type>::value && is_same<E, typename decay<E>::type>::value, typename conditional< is_same<T, typename add_const<T>::type>::value, no_set_error_free, traits::set_error_free<typename add_const<T>::type, E> >::type, traits::set_error_free< typename remove_reference<T>::type, typename decay<E>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_SET_ERROR_FREE_TRAIT) } // namespace detail namespace traits { template <typename T, typename E, typename> struct set_error_free_default : detail::set_error_free_trait<T, E> { }; template <typename T, typename E, typename> struct set_error_free : set_error_free_default<T, E> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_SET_ERROR_FREE_HPP traits/prefer_member.hpp 0000644 00000005515 15125530236 0011405 0 ustar 00 // // traits/prefer_member.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_PREFER_MEMBER_HPP #define BOOST_ASIO_TRAITS_PREFER_MEMBER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename Property, typename = void> struct prefer_member_default; template <typename T, typename Property, typename = void> struct prefer_member; } // namespace traits namespace detail { struct no_prefer_member { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) template <typename T, typename Property, typename = void> struct prefer_member_trait : no_prefer_member { }; template <typename T, typename Property> struct prefer_member_trait<T, Property, typename void_type< decltype(declval<T>().prefer(declval<Property>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( declval<T>().prefer(declval<Property>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( declval<T>().prefer(declval<Property>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) template <typename T, typename Property, typename = void> struct prefer_member_trait : conditional< is_same<T, typename decay<T>::type>::value && is_same<Property, typename decay<Property>::type>::value, no_prefer_member, traits::prefer_member< typename decay<T>::type, typename decay<Property>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT) } // namespace detail namespace traits { template <typename T, typename Property, typename> struct prefer_member_default : detail::prefer_member_trait<T, Property> { }; template <typename T, typename Property, typename> struct prefer_member : prefer_member_default<T, Property> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_PREFER_MEMBER_HPP traits/set_value_free.hpp 0000644 00000016756 15125530236 0011574 0 ustar 00 // // traits/set_value_free.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_SET_VALUE_FREE_HPP #define BOOST_ASIO_TRAITS_SET_VALUE_FREE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/variadic_templates.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename Vs, typename = void> struct set_value_free_default; template <typename T, typename Vs, typename = void> struct set_value_free; } // namespace traits namespace detail { struct no_set_value_free { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT) template <typename T, typename Vs, typename = void> struct set_value_free_trait : no_set_value_free { }; #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T, typename... Vs> struct set_value_free_trait<T, void(Vs...), typename void_type< decltype(set_value(declval<T>(), declval<Vs>()...)) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( set_value(declval<T>(), declval<Vs>()...)); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( set_value(declval<T>(), declval<Vs>()...))); }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T> struct set_value_free_trait<T, void(), typename void_type< decltype(set_value(declval<T>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype(set_value(declval<T>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(set_value(declval<T>()))); }; #define BOOST_ASIO_PRIVATE_SET_VALUE_FREE_TRAIT_DEF(n) \ template <typename T, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ struct set_value_free_trait<T, void(BOOST_ASIO_VARIADIC_TARGS(n)), \ typename void_type< \ decltype(set_value(declval<T>(), BOOST_ASIO_VARIADIC_DECLVAL(n))) \ >::type> \ { \ BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); \ \ using result_type = decltype( \ set_value(declval<T>(), BOOST_ASIO_VARIADIC_DECLVAL(n))); \ \ BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( \ set_value(declval<T>(), BOOST_ASIO_VARIADIC_DECLVAL(n)))); \ }; \ /**/ BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_SET_VALUE_FREE_TRAIT_DEF) #undef BOOST_ASIO_PRIVATE_SET_VALUE_FREE_TRAIT_DEF #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #else // defined(BOOST_ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT) template <typename T, typename Vs, typename = void> struct set_value_free_trait; #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T, typename... Vs> struct set_value_free_trait<T, void(Vs...)> : conditional< is_same<T, typename remove_reference<T>::type>::value && conjunction<is_same<Vs, typename decay<Vs>::type>...>::value, typename conditional< is_same<T, typename add_const<T>::type>::value, no_set_value_free, traits::set_value_free<typename add_const<T>::type, void(Vs...)> >::type, traits::set_value_free< typename remove_reference<T>::type, void(typename decay<Vs>::type...)> >::type { }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T> struct set_value_free_trait<T, void()> : conditional< is_same<T, typename remove_reference<T>::type>::value, typename conditional< is_same<T, typename add_const<T>::type>::value, no_set_value_free, traits::set_value_free<typename add_const<T>::type, void()> >::type, traits::set_value_free<typename remove_reference<T>::type, void()> >::type { }; #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME(n) \ BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_##n #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_1 \ && is_same<T1, typename decay<T1>::type>::value #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_2 \ BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_1 \ && is_same<T2, typename decay<T2>::type>::value #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_3 \ BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_2 \ && is_same<T3, typename decay<T3>::type>::value #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_4 \ BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_3 \ && is_same<T4, typename decay<T4>::type>::value #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_5 \ BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_4 \ && is_same<T5, typename decay<T5>::type>::value #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_6 \ BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_5 \ && is_same<T6, typename decay<T6>::type>::value #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_7 \ BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_6 \ && is_same<T7, typename decay<T7>::type>::value #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_8 \ BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_7 \ && is_same<T8, typename decay<T8>::type>::value #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF(n) \ template <typename T, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ struct set_value_free_trait<T, void(BOOST_ASIO_VARIADIC_TARGS(n))> : \ conditional< \ is_same<T, typename remove_reference<T>::type>::value \ BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME(n), \ typename conditional< \ is_same<T, typename add_const<T>::type>::value, \ no_set_value_free, \ traits::set_value_free< \ typename add_const<T>::type, \ void(BOOST_ASIO_VARIADIC_TARGS(n))> \ >::type, \ traits::set_value_free< \ typename remove_reference<T>::type, \ void(BOOST_ASIO_VARIADIC_DECAY(n))> \ >::type \ { \ }; \ /**/ BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF) #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_1 #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_2 #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_3 #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_4 #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_5 #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_6 #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_7 #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_8 #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #endif // defined(BOOST_ASIO_HAS_DEDUCED_SET_VALUE_FREE_TRAIT) } // namespace detail namespace traits { template <typename T, typename Vs, typename> struct set_value_free_default : detail::set_value_free_trait<T, Vs> { }; template <typename T, typename Vs, typename> struct set_value_free : set_value_free_default<T, Vs> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_SET_VALUE_FREE_HPP traits/execute_member.hpp 0000644 00000005366 15125530236 0011570 0 ustar 00 // // traits/execute_member.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_EXECUTE_MEMBER_HPP #define BOOST_ASIO_TRAITS_EXECUTE_MEMBER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename F, typename = void> struct execute_member_default; template <typename T, typename F, typename = void> struct execute_member; } // namespace traits namespace detail { struct no_execute_member { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) template <typename T, typename F, typename = void> struct execute_member_trait : no_execute_member { }; template <typename T, typename F> struct execute_member_trait<T, F, typename void_type< decltype(declval<T>().execute(declval<F>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( declval<T>().execute(declval<F>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( declval<T>().execute(declval<F>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) template <typename T, typename F, typename = void> struct execute_member_trait : conditional< is_same<T, typename decay<T>::type>::value && is_same<F, typename decay<F>::type>::value, no_execute_member, traits::execute_member< typename decay<T>::type, typename decay<F>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) } // namespace detail namespace traits { template <typename T, typename F, typename> struct execute_member_default : detail::execute_member_trait<T, F> { }; template <typename T, typename F, typename> struct execute_member : execute_member_default<T, F> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_EXECUTE_MEMBER_HPP traits/submit_member.hpp 0000644 00000005616 15125530236 0011427 0 ustar 00 // // traits/submit_member.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_SUBMIT_MEMBER_HPP #define BOOST_ASIO_TRAITS_SUBMIT_MEMBER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename S, typename R, typename = void> struct submit_member_default; template <typename S, typename R, typename = void> struct submit_member; } // namespace traits namespace detail { struct no_submit_member { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT) template <typename S, typename R, typename = void> struct submit_member_trait : no_submit_member { }; template <typename S, typename R> struct submit_member_trait<S, R, typename void_type< decltype(declval<S>().submit(declval<R>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( declval<S>().submit(declval<R>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( declval<S>().submit(declval<R>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT) template <typename S, typename R, typename = void> struct submit_member_trait : conditional< is_same<S, typename remove_reference<S>::type>::value && is_same<R, typename decay<R>::type>::value, typename conditional< is_same<S, typename add_const<S>::type>::value, no_submit_member, traits::submit_member<typename add_const<S>::type, R> >::type, traits::submit_member< typename remove_reference<S>::type, typename decay<R>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_SUBMIT_MEMBER_TRAIT) } // namespace detail namespace traits { template <typename S, typename R, typename> struct submit_member_default : detail::submit_member_trait<S, R> { }; template <typename S, typename R, typename> struct submit_member : submit_member_default<S, R> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_SUBMIT_MEMBER_HPP traits/equality_comparable.hpp 0000644 00000005361 15125530236 0012614 0 ustar 00 // // traits/equality_comparable.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_EQUALITY_COMPARABLE_HPP #define BOOST_ASIO_TRAITS_EQUALITY_COMPARABLE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) namespace boost { namespace asio { namespace traits { template <typename T, typename = void> struct equality_comparable_default; template <typename T, typename = void> struct equality_comparable; } // namespace traits namespace detail { struct no_equality_comparable { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) template <typename T, typename = void> struct equality_comparable_trait : no_equality_comparable { }; template <typename T> struct equality_comparable_trait<T, typename void_type< decltype( static_cast<void>( static_cast<bool>(declval<const T>() == declval<const T>()) ), static_cast<void>( static_cast<bool>(declval<const T>() != declval<const T>()) ) ) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(declval<const T>() == declval<const T>()) && noexcept(declval<const T>() != declval<const T>())); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) template <typename T, typename = void> struct equality_comparable_trait : conditional< is_same<T, typename decay<T>::type>::value, no_equality_comparable, traits::equality_comparable<typename decay<T>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) } // namespace detail namespace traits { template <typename T, typename> struct equality_comparable_default : detail::equality_comparable_trait<T> { }; template <typename T, typename> struct equality_comparable : equality_comparable_default<T> { }; } // namespace traits } // namespace asio } // namespace boost #endif // BOOST_ASIO_TRAITS_EQUALITY_COMPARABLE_HPP traits/schedule_member.hpp 0000644 00000005336 15125530236 0011717 0 ustar 00 // // traits/schedule_member.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_SCHEDULE_MEMBER_HPP #define BOOST_ASIO_TRAITS_SCHEDULE_MEMBER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename = void> struct schedule_member_default; template <typename T, typename = void> struct schedule_member; } // namespace traits namespace detail { struct no_schedule_member { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT) template <typename T, typename = void> struct schedule_member_trait : no_schedule_member { }; template <typename T> struct schedule_member_trait<T, typename void_type< decltype(declval<T>().schedule()) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype(declval<T>().schedule()); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(declval<T>().schedule())); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT) template <typename T, typename = void> struct schedule_member_trait : conditional< is_same<T, typename remove_reference<T>::type>::value, typename conditional< is_same<T, typename add_const<T>::type>::value, no_schedule_member, traits::schedule_member<typename add_const<T>::type> >::type, traits::schedule_member<typename remove_reference<T>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_SCHEDULE_MEMBER_TRAIT) } // namespace detail namespace traits { template <typename T, typename> struct schedule_member_default : detail::schedule_member_trait<T> { }; template <typename T, typename> struct schedule_member : schedule_member_default<T> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_SCHEDULE_MEMBER_HPP traits/set_error_member.hpp 0000644 00000005734 15125530236 0012131 0 ustar 00 // // traits/set_error_member.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_SET_ERROR_MEMBER_HPP #define BOOST_ASIO_TRAITS_SET_ERROR_MEMBER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename E, typename = void> struct set_error_member_default; template <typename T, typename E, typename = void> struct set_error_member; } // namespace traits namespace detail { struct no_set_error_member { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) template <typename T, typename E, typename = void> struct set_error_member_trait : no_set_error_member { }; template <typename T, typename E> struct set_error_member_trait<T, E, typename void_type< decltype(declval<T>().set_error(declval<E>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( declval<T>().set_error(declval<E>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( declval<T>().set_error(declval<E>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) template <typename T, typename E, typename = void> struct set_error_member_trait : conditional< is_same<T, typename remove_reference<T>::type>::value && is_same<E, typename decay<E>::type>::value, typename conditional< is_same<T, typename add_const<T>::type>::value, no_set_error_member, traits::set_error_member<typename add_const<T>::type, E> >::type, traits::set_error_member< typename remove_reference<T>::type, typename decay<E>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_SET_ERROR_MEMBER_TRAIT) } // namespace detail namespace traits { template <typename T, typename E, typename> struct set_error_member_default : detail::set_error_member_trait<T, E> { }; template <typename T, typename E, typename> struct set_error_member : set_error_member_default<T, E> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_SET_ERROR_MEMBER_HPP traits/set_value_member.hpp 0000644 00000017063 15125530236 0012112 0 ustar 00 // // traits/set_value_member.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_SET_VALUE_MEMBER_HPP #define BOOST_ASIO_TRAITS_SET_VALUE_MEMBER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/variadic_templates.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename Vs, typename = void> struct set_value_member_default; template <typename T, typename Vs, typename = void> struct set_value_member; } // namespace traits namespace detail { struct no_set_value_member { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) template <typename T, typename Vs, typename = void> struct set_value_member_trait : no_set_value_member { }; #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T, typename... Vs> struct set_value_member_trait<T, void(Vs...), typename void_type< decltype(declval<T>().set_value(declval<Vs>()...)) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( declval<T>().set_value(declval<Vs>()...)); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( declval<T>().set_value(declval<Vs>()...))); }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T> struct set_value_member_trait<T, void(), typename void_type< decltype(declval<T>().set_value()) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype(declval<T>().set_value()); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept(declval<T>().set_value())); }; #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF(n) \ template <typename T, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ struct set_value_member_trait<T, void(BOOST_ASIO_VARIADIC_TARGS(n)), \ typename void_type< \ decltype(declval<T>().set_value(BOOST_ASIO_VARIADIC_DECLVAL(n))) \ >::type> \ { \ BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); \ \ using result_type = decltype( \ declval<T>().set_value(BOOST_ASIO_VARIADIC_DECLVAL(n))); \ \ BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( \ declval<T>().set_value(BOOST_ASIO_VARIADIC_DECLVAL(n)))); \ }; \ /**/ BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF) #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #else // defined(BOOST_ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) template <typename T, typename Vs, typename = void> struct set_value_member_trait; #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T, typename... Vs> struct set_value_member_trait<T, void(Vs...)> : conditional< is_same<T, typename remove_reference<T>::type>::value && conjunction<is_same<Vs, typename decay<Vs>::type>...>::value, typename conditional< is_same<T, typename add_const<T>::type>::value, no_set_value_member, traits::set_value_member<typename add_const<T>::type, void(Vs...)> >::type, traits::set_value_member< typename remove_reference<T>::type, void(typename decay<Vs>::type...)> >::type { }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T> struct set_value_member_trait<T, void()> : conditional< is_same<T, typename remove_reference<T>::type>::value, typename conditional< is_same<T, typename add_const<T>::type>::value, no_set_value_member, traits::set_value_member<typename add_const<T>::type, void()> >::type, traits::set_value_member<typename remove_reference<T>::type, void()> >::type { }; #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME(n) \ BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_##n #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_1 \ && is_same<T1, typename decay<T1>::type>::value #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_2 \ BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_1 \ && is_same<T2, typename decay<T2>::type>::value #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_3 \ BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_2 \ && is_same<T3, typename decay<T3>::type>::value #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_4 \ BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_3 \ && is_same<T4, typename decay<T4>::type>::value #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_5 \ BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_4 \ && is_same<T5, typename decay<T5>::type>::value #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_6 \ BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_5 \ && is_same<T6, typename decay<T6>::type>::value #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_7 \ BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_6 \ && is_same<T7, typename decay<T7>::type>::value #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_8 \ BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_7 \ && is_same<T8, typename decay<T8>::type>::value #define BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF(n) \ template <typename T, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ struct set_value_member_trait<T, void(BOOST_ASIO_VARIADIC_TARGS(n))> : \ conditional< \ is_same<T, typename remove_reference<T>::type>::value \ BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME(n), \ typename conditional< \ is_same<T, typename add_const<T>::type>::value, \ no_set_value_member, \ traits::set_value_member< \ typename add_const<T>::type, \ void(BOOST_ASIO_VARIADIC_TARGS(n))> \ >::type, \ traits::set_value_member< \ typename remove_reference<T>::type, \ void(BOOST_ASIO_VARIADIC_DECAY(n))> \ >::type \ { \ }; \ /**/ BOOST_ASIO_VARIADIC_GENERATE(BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF) #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_TRAIT_DEF #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_1 #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_2 #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_3 #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_4 #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_5 #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_6 #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_7 #undef BOOST_ASIO_PRIVATE_SET_VALUE_MEMBER_IS_SAME_8 #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #endif // defined(BOOST_ASIO_HAS_DEDUCED_SET_VALUE_MEMBER_TRAIT) } // namespace detail namespace traits { template <typename T, typename Vs, typename> struct set_value_member_default : detail::set_value_member_trait<T, Vs> { }; template <typename T, typename Vs, typename> struct set_value_member : set_value_member_default<T, Vs> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_SET_VALUE_MEMBER_HPP traits/bulk_execute_member.hpp 0000644 00000006407 15125530236 0012602 0 ustar 00 // // traits/bulk_execute_member.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_BULK_EXECUTE_MEMBER_HPP #define BOOST_ASIO_TRAITS_BULK_EXECUTE_MEMBER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_BULK_EXECUTE_MEMBER_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename F, typename N, typename = void> struct bulk_execute_member_default; template <typename T, typename F, typename N, typename = void> struct bulk_execute_member; } // namespace traits namespace detail { struct no_bulk_execute_member { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_BULK_EXECUTE_MEMBER_TRAIT) template <typename T, typename F, typename N, typename = void> struct bulk_execute_member_trait : no_bulk_execute_member { }; template <typename T, typename F, typename N> struct bulk_execute_member_trait<T, F, N, typename void_type< decltype(declval<T>().bulk_execute(declval<F>(), declval<N>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( declval<T>().bulk_execute(declval<F>(), declval<N>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( declval<T>().bulk_execute(declval<F>(), declval<N>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_BULK_EXECUTE_MEMBER_TRAIT) template <typename T, typename F, typename N, typename = void> struct bulk_execute_member_trait : conditional< is_same<T, typename remove_reference<T>::type>::value && is_same<F, typename decay<F>::type>::value && is_same<N, typename decay<N>::type>::value, typename conditional< is_same<T, typename add_const<T>::type>::value, no_bulk_execute_member, traits::bulk_execute_member<typename add_const<T>::type, F, N> >::type, traits::bulk_execute_member< typename remove_reference<T>::type, typename decay<F>::type, typename decay<N>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_BULK_EXECUTE_MEMBER_TRAIT) } // namespace detail namespace traits { template <typename T, typename F, typename N, typename> struct bulk_execute_member_default : detail::bulk_execute_member_trait<T, F, N> { }; template <typename T, typename F, typename N, typename> struct bulk_execute_member : bulk_execute_member_default<T, F, N> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_BULK_EXECUTE_MEMBER_HPP traits/require_member.hpp 0000644 00000005546 15125530236 0011602 0 ustar 00 // // traits/require_member.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_REQUIRE_MEMBER_HPP #define BOOST_ASIO_TRAITS_REQUIRE_MEMBER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename Property, typename = void> struct require_member_default; template <typename T, typename Property, typename = void> struct require_member; } // namespace traits namespace detail { struct no_require_member { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) template <typename T, typename Property, typename = void> struct require_member_trait : no_require_member { }; template <typename T, typename Property> struct require_member_trait<T, Property, typename void_type< decltype(declval<T>().require(declval<Property>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( declval<T>().require(declval<Property>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( declval<T>().require(declval<Property>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) template <typename T, typename Property, typename = void> struct require_member_trait : conditional< is_same<T, typename decay<T>::type>::value && is_same<Property, typename decay<Property>::type>::value, no_require_member, traits::require_member< typename decay<T>::type, typename decay<Property>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) } // namespace detail namespace traits { template <typename T, typename Property, typename> struct require_member_default : detail::require_member_trait<T, Property> { }; template <typename T, typename Property, typename> struct require_member : require_member_default<T, Property> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_REQUIRE_MEMBER_HPP traits/bulk_execute_free.hpp 0000644 00000006334 15125530236 0012253 0 ustar 00 // // traits/bulk_execute_free.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_BULK_EXECUTE_FREE_HPP #define BOOST_ASIO_TRAITS_BULK_EXECUTE_FREE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_BULK_EXECUTE_FREE_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename F, typename N, typename = void> struct bulk_execute_free_default; template <typename T, typename F, typename N, typename = void> struct bulk_execute_free; } // namespace traits namespace detail { struct no_bulk_execute_free { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_BULK_EXECUTE_FREE_TRAIT) template <typename T, typename F, typename N, typename = void> struct bulk_execute_free_trait : no_bulk_execute_free { }; template <typename T, typename F, typename N> struct bulk_execute_free_trait<T, F, N, typename void_type< decltype(bulk_execute(declval<T>(), declval<F>(), declval<N>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( bulk_execute(declval<T>(), declval<F>(), declval<N>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( bulk_execute(declval<T>(), declval<F>(), declval<N>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_BULK_EXECUTE_FREE_TRAIT) template <typename T, typename F, typename N, typename = void> struct bulk_execute_free_trait : conditional< is_same<T, typename remove_reference<T>::type>::value && is_same<F, typename decay<F>::type>::value && is_same<N, typename decay<N>::type>::value, typename conditional< is_same<T, typename add_const<T>::type>::value, no_bulk_execute_free, traits::bulk_execute_free<typename add_const<T>::type, F, N> >::type, traits::bulk_execute_free< typename remove_reference<T>::type, typename decay<F>::type, typename decay<N>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_BULK_EXECUTE_FREE_TRAIT) } // namespace detail namespace traits { template <typename T, typename F, typename N, typename> struct bulk_execute_free_default : detail::bulk_execute_free_trait<T, F, N> { }; template <typename T, typename F, typename N, typename> struct bulk_execute_free : bulk_execute_free_default<T, F, N> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_BULK_EXECUTE_FREE_HPP traits/query_member.hpp 0000644 00000005464 15125530236 0011272 0 ustar 00 // // traits/query_member.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_QUERY_MEMBER_HPP #define BOOST_ASIO_TRAITS_QUERY_MEMBER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename Property, typename = void> struct query_member_default; template <typename T, typename Property, typename = void> struct query_member; } // namespace traits namespace detail { struct no_query_member { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) template <typename T, typename Property, typename = void> struct query_member_trait : no_query_member { }; template <typename T, typename Property> struct query_member_trait<T, Property, typename void_type< decltype(declval<T>().query(declval<Property>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( declval<T>().query(declval<Property>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( declval<T>().query(declval<Property>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) template <typename T, typename Property, typename = void> struct query_member_trait : conditional< is_same<T, typename decay<T>::type>::value && is_same<Property, typename decay<Property>::type>::value, no_query_member, traits::query_member< typename decay<T>::type, typename decay<Property>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) } // namespace detail namespace traits { template <typename T, typename Property, typename> struct query_member_default : detail::query_member_trait<T, Property> { }; template <typename T, typename Property, typename> struct query_member : query_member_default<T, Property> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_QUERY_MEMBER_HPP traits/execute_free.hpp 0000644 00000005315 15125530236 0011234 0 ustar 00 // // traits/execute_free.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_TRAITS_EXECUTE_FREE_HPP #define BOOST_ASIO_TRAITS_EXECUTE_FREE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #if defined(BOOST_ASIO_HAS_DECLTYPE) \ && defined(BOOST_ASIO_HAS_NOEXCEPT) \ && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # define BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT 1 #endif // defined(BOOST_ASIO_HAS_DECLTYPE) // && defined(BOOST_ASIO_HAS_NOEXCEPT) // && defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace traits { template <typename T, typename F, typename = void> struct execute_free_default; template <typename T, typename F, typename = void> struct execute_free; } // namespace traits namespace detail { struct no_execute_free { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = false); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); }; #if defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT) template <typename T, typename F, typename = void> struct execute_free_trait : no_execute_free { }; template <typename T, typename F> struct execute_free_trait<T, F, typename void_type< decltype(execute(declval<T>(), declval<F>())) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); using result_type = decltype( execute(declval<T>(), declval<F>())); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = noexcept( execute(declval<T>(), declval<F>()))); }; #else // defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT) template <typename T, typename F, typename = void> struct execute_free_trait : conditional< is_same<T, typename decay<T>::type>::value && is_same<F, typename decay<F>::type>::value, no_execute_free, traits::execute_free< typename decay<T>::type, typename decay<F>::type> >::type { }; #endif // defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_FREE_TRAIT) } // namespace detail namespace traits { template <typename T, typename F, typename> struct execute_free_default : detail::execute_free_trait<T, F> { }; template <typename T, typename F, typename> struct execute_free : execute_free_default<T, F> { }; } // namespace traits } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_TRAITS_EXECUTE_FREE_HPP use_awaitable.hpp 0000644 00000013275 15125530236 0010074 0 ustar 00 // // use_awaitable.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) #include <boost/asio/awaitable.hpp> #include <boost/asio/detail/handler_tracking.hpp> #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION) # include <boost/asio/detail/source_location.hpp> # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION) #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) #include <boost/asio/detail/push_options.hpp> 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<void> 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 <typename Executor = any_io_executor> struct use_awaitable_t { /// Default constructor. BOOST_ASIO_CONSTEXPR use_awaitable_t( #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION) detail::source_location location = detail::source_location::current() # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION) #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) ) #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) # if defined(BOOST_ASIO_HAS_SOURCE_LOCATION) : file_name_(location.file_name()), line_(location.line()), function_name_(location.function_name()) # else // defined(BOOST_ASIO_HAS_SOURCE_LOCATION) : file_name_(0), line_(0), function_name_(0) # endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION) #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) { } /// Constructor used to specify file name, line, and function name. BOOST_ASIO_CONSTEXPR use_awaitable_t(const char* file_name, int line, const char* function_name) #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) : file_name_(file_name), line_(line), function_name_(function_name) #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) { #if !defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) (void)file_name; (void)line; (void)function_name; #endif // !defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) } /// Adapts an executor to add the @c use_awaitable_t completion token as the /// default. template <typename InnerExecutor> struct executor_with_default : InnerExecutor { /// Specify @c use_awaitable_t as the default completion token type. typedef use_awaitable_t default_completion_token_type; /// Construct the adapted executor from the inner executor type. executor_with_default(const InnerExecutor& ex) BOOST_ASIO_NOEXCEPT : InnerExecutor(ex) { } /// Convert the specified executor to the inner executor type, then use /// that to construct the adapted executor. template <typename OtherExecutor> executor_with_default(const OtherExecutor& ex, typename enable_if< is_convertible<OtherExecutor, InnerExecutor>::value >::type* = 0) BOOST_ASIO_NOEXCEPT : InnerExecutor(ex) { } }; /// Type alias to adapt an I/O object to use @c use_awaitable_t as its /// default completion token type. #if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) \ || defined(GENERATING_DOCUMENTATION) template <typename T> using as_default_on_t = typename T::template rebind_executor< executor_with_default<typename T::executor_type> >::other; #endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) // || defined(GENERATING_DOCUMENTATION) /// Function helper to adapt an I/O object to use @c use_awaitable_t as its /// default completion token type. template <typename T> static typename decay<T>::type::template rebind_executor< executor_with_default<typename decay<T>::type::executor_type> >::other as_default_on(BOOST_ASIO_MOVE_ARG(T) object) { return typename decay<T>::type::template rebind_executor< executor_with_default<typename decay<T>::type::executor_type> >::other(BOOST_ASIO_MOVE_CAST(T)(object)); } #if defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) const char* file_name_; int line_; const char* function_name_; #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) }; /// 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(GENERATING_DOCUMENTATION) constexpr use_awaitable_t<> use_awaitable; #elif defined(BOOST_ASIO_HAS_CONSTEXPR) constexpr use_awaitable_t<> use_awaitable(0, 0, 0); #elif defined(BOOST_ASIO_MSVC) __declspec(selectany) use_awaitable_t<> use_awaitable(0, 0, 0); #endif } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/use_awaitable.hpp> #endif // defined(BOOST_ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_USE_AWAITABLE_HPP streambuf.hpp 0000644 00000001472 15125530236 0007253 0 ustar 00 // // streambuf.hpp // ~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_NO_IOSTREAM) #include <boost/asio/basic_streambuf.hpp> 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 unyield.hpp 0000644 00000000575 15125530236 0006737 0 ustar 00 // // unyield.hpp // ~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifdef reenter # undef reenter #endif #ifdef yield # undef yield #endif #ifdef fork # undef fork #endif execution.hpp 0000644 00000003517 15125530236 0007270 0 ustar 00 // // execution.hpp // ~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_HPP #define BOOST_ASIO_EXECUTION_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/execution/allocator.hpp> #include <boost/asio/execution/any_executor.hpp> #include <boost/asio/execution/bad_executor.hpp> #include <boost/asio/execution/blocking.hpp> #include <boost/asio/execution/blocking_adaptation.hpp> #include <boost/asio/execution/bulk_execute.hpp> #include <boost/asio/execution/bulk_guarantee.hpp> #include <boost/asio/execution/connect.hpp> #include <boost/asio/execution/context.hpp> #include <boost/asio/execution/context_as.hpp> #include <boost/asio/execution/execute.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/invocable_archetype.hpp> #include <boost/asio/execution/mapping.hpp> #include <boost/asio/execution/occupancy.hpp> #include <boost/asio/execution/operation_state.hpp> #include <boost/asio/execution/outstanding_work.hpp> #include <boost/asio/execution/prefer_only.hpp> #include <boost/asio/execution/receiver.hpp> #include <boost/asio/execution/receiver_invocation_error.hpp> #include <boost/asio/execution/relationship.hpp> #include <boost/asio/execution/schedule.hpp> #include <boost/asio/execution/scheduler.hpp> #include <boost/asio/execution/sender.hpp> #include <boost/asio/execution/set_done.hpp> #include <boost/asio/execution/set_error.hpp> #include <boost/asio/execution/set_value.hpp> #include <boost/asio/execution/start.hpp> #include <boost/asio/execution/submit.hpp> #endif // BOOST_ASIO_EXECUTION_HPP posix/descriptor.hpp 0000644 00000002004 15125530236 0010573 0 ustar 00 // // posix/descriptor.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/posix/basic_descriptor.hpp> 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 posix/basic_stream_descriptor.hpp 0000644 00000042546 15125530236 0013326 0 ustar 00 // // posix/basic_stream_descriptor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/posix/descriptor.hpp> #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/push_options.hpp> 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 <typename Executor = any_io_executor> class basic_stream_descriptor : public basic_descriptor<Executor> { public: /// The type of the executor associated with the object. typedef Executor executor_type; /// Rebinds the descriptor type to another executor. template <typename Executor1> struct rebind_executor { /// The descriptor type when rebound to the specified executor. typedef basic_stream_descriptor<Executor1> other; }; /// The native representation of a descriptor. typedef typename basic_descriptor<Executor>::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<Executor>(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 <typename ExecutionContext> explicit basic_stream_descriptor(ExecutionContext& context, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_descriptor<Executor>(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<Executor>(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 <typename ExecutionContext> basic_stream_descriptor(ExecutionContext& context, const native_handle_type& native_descriptor, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_descriptor<Executor>(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) BOOST_ASIO_NOEXCEPT : 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_some(const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( initiate_async_write_some(this), handler, 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_some(const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( initiate_async_read_some(this), handler, buffers); } private: class initiate_async_write_some { public: typedef Executor executor_type; explicit initiate_async_write_some(basic_stream_descriptor* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename WriteHandler, typename ConstBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, 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<WriteHandler> handler2(handler); self_->impl_.get_service().async_write_some( self_->impl_.get_implementation(), buffers, handler2.value, self_->impl_.get_executor()); } private: basic_stream_descriptor* self_; }; class initiate_async_read_some { public: typedef Executor executor_type; explicit initiate_async_read_some(basic_stream_descriptor* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename ReadHandler, typename MutableBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); self_->impl_.get_service().async_read_some( self_->impl_.get_implementation(), buffers, handler2.value, self_->impl_.get_executor()); } private: basic_stream_descriptor* self_; }; }; } // namespace posix } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP posix/basic_descriptor.hpp 0000644 00000056564 15125530236 0011760 0 ustar 00 // // posix/basic_descriptor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/any_io_executor.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/io_object_impl.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/reactive_descriptor_service.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/posix/descriptor_base.hpp> #if defined(BOOST_ASIO_HAS_MOVE) # include <utility> #endif // defined(BOOST_ASIO_HAS_MOVE) #include <boost/asio/detail/push_options.hpp> 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 <typename Executor = any_io_executor> class basic_descriptor : public descriptor_base { public: /// The type of the executor associated with the object. typedef Executor executor_type; /// Rebinds the descriptor type to another executor. template <typename Executor1> struct rebind_executor { /// The descriptor type when rebound to the specified executor. typedef basic_descriptor<Executor1> other; }; /// 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 <typename ExecutionContext> explicit basic_descriptor(ExecutionContext& context, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename ExecutionContext> basic_descriptor(ExecutionContext& context, const native_handle_type& native_descriptor, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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) BOOST_ASIO_NOEXCEPT : 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 <typename IoControlCommand> 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 <typename IoControlCommand> 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_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) WaitHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (boost::system::error_code)) async_wait(wait_type w, BOOST_ASIO_MOVE_ARG(WaitHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WaitHandler, void (boost::system::error_code)>( initiate_async_wait(this), handler, 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<detail::reactive_descriptor_service, Executor> impl_; private: // Disallow copying and assignment. basic_descriptor(const basic_descriptor&) BOOST_ASIO_DELETED; basic_descriptor& operator=(const basic_descriptor&) BOOST_ASIO_DELETED; class initiate_async_wait { public: typedef Executor executor_type; explicit initiate_async_wait(basic_descriptor* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename WaitHandler> void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler, 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<WaitHandler> handler2(handler); self_->impl_.get_service().async_wait( self_->impl_.get_implementation(), w, handler2.value, self_->impl_.get_executor()); } private: basic_descriptor* self_; }; }; } // namespace posix } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_POSIX_BASIC_DESCRIPTOR_HPP posix/descriptor_base.hpp 0000644 00000004501 15125530236 0011571 0 ustar 00 // // posix/descriptor_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/io_control.hpp> #include <boost/asio/detail/socket_option.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) // || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_POSIX_DESCRIPTOR_BASE_HPP posix/stream_descriptor.hpp 0000644 00000002112 15125530236 0012146 0 ustar 00 // // posix/stream_descriptor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/posix/basic_stream_descriptor.hpp> 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 buffered_write_stream_fwd.hpp 0000644 00000001301 15125530236 0012461 0 ustar 00 // // buffered_write_stream_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <typename Stream> class buffered_write_stream; } // namespace asio } // namespace boost #endif // BOOST_ASIO_BUFFERED_WRITE_STREAM_FWD_HPP system_executor.hpp 0000644 00000054001 15125530236 0010521 0 ustar 00 // // system_executor.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/execution.hpp> #include <boost/asio/detail/push_options.hpp> 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. When the blocking.never property is * established, the system executor will schedule the function to run on an * unspecified system thread pool. When either blocking.possibly or * blocking.always is established, the executor invokes the function * immediately. */ template <typename Blocking, typename Relationship, typename Allocator> class basic_system_executor { public: /// Default constructor. basic_system_executor() BOOST_ASIO_NOEXCEPT : allocator_(Allocator()) { } /// Obtain an executor with the @c blocking.possibly property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code boost::asio::system_executor ex1; * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::blocking.possibly); @endcode */ basic_system_executor<execution::blocking_t::possibly_t, Relationship, Allocator> require(execution::blocking_t::possibly_t) const { return basic_system_executor<execution::blocking_t::possibly_t, Relationship, Allocator>(allocator_); } /// Obtain an executor with the @c blocking.always property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code boost::asio::system_executor ex1; * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::blocking.always); @endcode */ basic_system_executor<execution::blocking_t::always_t, Relationship, Allocator> require(execution::blocking_t::always_t) const { return basic_system_executor<execution::blocking_t::always_t, Relationship, Allocator>(allocator_); } /// Obtain an executor with the @c blocking.never property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code boost::asio::system_executor ex1; * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::blocking.never); @endcode */ basic_system_executor<execution::blocking_t::never_t, Relationship, Allocator> require(execution::blocking_t::never_t) const { return basic_system_executor<execution::blocking_t::never_t, Relationship, Allocator>(allocator_); } /// Obtain an executor with the @c relationship.continuation property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code boost::asio::system_executor ex1; * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::relationship.continuation); @endcode */ basic_system_executor<Blocking, execution::relationship_t::continuation_t, Allocator> require(execution::relationship_t::continuation_t) const { return basic_system_executor<Blocking, execution::relationship_t::continuation_t, Allocator>(allocator_); } /// Obtain an executor with the @c relationship.fork property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code boost::asio::system_executor ex1; * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::relationship.fork); @endcode */ basic_system_executor<Blocking, execution::relationship_t::fork_t, Allocator> require(execution::relationship_t::fork_t) const { return basic_system_executor<Blocking, execution::relationship_t::fork_t, Allocator>(allocator_); } /// Obtain an executor with the specified @c allocator property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code boost::asio::system_executor ex1; * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::allocator(my_allocator)); @endcode */ template <typename OtherAllocator> basic_system_executor<Blocking, Relationship, OtherAllocator> require(execution::allocator_t<OtherAllocator> a) const { return basic_system_executor<Blocking, Relationship, OtherAllocator>(a.value()); } /// Obtain an executor with the default @c allocator property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code boost::asio::system_executor ex1; * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::allocator); @endcode */ basic_system_executor<Blocking, Relationship, std::allocator<void> > require(execution::allocator_t<void>) const { return basic_system_executor<Blocking, Relationship, std::allocator<void> >(); } /// Query the current value of the @c mapping property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code boost::asio::system_executor ex; * if (boost::asio::query(ex, boost::asio::execution::mapping) * == boost::asio::execution::mapping.thread) * ... @endcode */ static BOOST_ASIO_CONSTEXPR execution::mapping_t query( execution::mapping_t) BOOST_ASIO_NOEXCEPT { return execution::mapping.thread; } /// Query the current value of the @c context property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code boost::asio::system_executor ex; * boost::asio::system_context& pool = boost::asio::query( * ex, boost::asio::execution::context); @endcode */ static system_context& query(execution::context_t) BOOST_ASIO_NOEXCEPT; /// Query the current value of the @c blocking property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code boost::asio::system_executor ex; * if (boost::asio::query(ex, boost::asio::execution::blocking) * == boost::asio::execution::blocking.always) * ... @endcode */ static BOOST_ASIO_CONSTEXPR execution::blocking_t query( execution::blocking_t) BOOST_ASIO_NOEXCEPT { return Blocking(); } /// Query the current value of the @c relationship property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code boost::asio::system_executor ex; * if (boost::asio::query(ex, boost::asio::execution::relationship) * == boost::asio::execution::relationship.continuation) * ... @endcode */ static BOOST_ASIO_CONSTEXPR execution::relationship_t query( execution::relationship_t) BOOST_ASIO_NOEXCEPT { return Relationship(); } /// Query the current value of the @c allocator property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code boost::asio::system_executor ex; * auto alloc = boost::asio::query(ex, * boost::asio::execution::allocator); @endcode */ template <typename OtherAllocator> BOOST_ASIO_CONSTEXPR Allocator query( execution::allocator_t<OtherAllocator>) const BOOST_ASIO_NOEXCEPT { return allocator_; } /// Query the current value of the @c allocator property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code boost::asio::system_executor ex; * auto alloc = boost::asio::query(ex, * boost::asio::execution::allocator); @endcode */ BOOST_ASIO_CONSTEXPR Allocator query( execution::allocator_t<void>) const BOOST_ASIO_NOEXCEPT { return allocator_; } /// Query the occupancy (recommended number of work items) for the system /// context. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code boost::asio::system_executor ex; * std::size_t occupancy = boost::asio::query( * ex, boost::asio::execution::occupancy); @endcode */ std::size_t query(execution::occupancy_t) 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 basic_system_executor&, const basic_system_executor&) BOOST_ASIO_NOEXCEPT { return true; } /// Compare two executors for inequality. /** * Two executors are equal if they refer to the same underlying io_context. */ friend bool operator!=(const basic_system_executor&, const basic_system_executor&) BOOST_ASIO_NOEXCEPT { return false; } /// Execution function. /** * Do not call this function directly. It is intended for use with the * execution::execute customisation point. * * For example: * @code boost::asio::system_executor ex; * execution::execute(ex, my_function_object); @endcode */ template <typename Function> void execute(BOOST_ASIO_MOVE_ARG(Function) f) const { this->do_execute(BOOST_ASIO_MOVE_CAST(Function)(f), Blocking()); } #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// 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 <typename Function, typename OtherAllocator> void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& 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 <typename Function, typename OtherAllocator> void post(BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& 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 <typename Function, typename OtherAllocator> void defer(BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const; #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) private: template <typename, typename, typename> friend class basic_system_executor; // Constructor used by require(). basic_system_executor(const Allocator& a) : allocator_(a) { } /// Execution helper implementation for the possibly blocking property. template <typename Function> void do_execute(BOOST_ASIO_MOVE_ARG(Function) f, execution::blocking_t::possibly_t) const; /// Execution helper implementation for the always blocking property. template <typename Function> void do_execute(BOOST_ASIO_MOVE_ARG(Function) f, execution::blocking_t::always_t) const; /// Execution helper implementation for the never blocking property. template <typename Function> void do_execute(BOOST_ASIO_MOVE_ARG(Function) f, execution::blocking_t::never_t) const; // The allocator used for execution functions. Allocator allocator_; }; /// An executor that uses arbitrary threads. /** * The system executor represents an execution context where functions are * permitted to run on arbitrary threads. When the blocking.never property is * established, the system executor will schedule the function to run on an * unspecified system thread pool. When either blocking.possibly or * blocking.always is established, the executor invokes the function * immediately. */ typedef basic_system_executor<execution::blocking_t::possibly_t, execution::relationship_t::fork_t, std::allocator<void> > system_executor; #if !defined(GENERATING_DOCUMENTATION) namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) template <typename Blocking, typename Relationship, typename Allocator> struct equality_comparable< boost::asio::basic_system_executor<Blocking, Relationship, Allocator> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) template <typename Blocking, typename Relationship, typename Allocator, typename Function> struct execute_member< boost::asio::basic_system_executor<Blocking, Relationship, Allocator>, Function > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) template <typename Blocking, typename Relationship, typename Allocator> struct require_member< boost::asio::basic_system_executor<Blocking, Relationship, Allocator>, boost::asio::execution::blocking_t::possibly_t > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::basic_system_executor< boost::asio::execution::blocking_t::possibly_t, Relationship, Allocator> result_type; }; template <typename Blocking, typename Relationship, typename Allocator> struct require_member< boost::asio::basic_system_executor<Blocking, Relationship, Allocator>, boost::asio::execution::blocking_t::always_t > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::basic_system_executor< boost::asio::execution::blocking_t::always_t, Relationship, Allocator> result_type; }; template <typename Blocking, typename Relationship, typename Allocator> struct require_member< boost::asio::basic_system_executor<Blocking, Relationship, Allocator>, boost::asio::execution::blocking_t::never_t > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::basic_system_executor< boost::asio::execution::blocking_t::never_t, Relationship, Allocator> result_type; }; template <typename Blocking, typename Relationship, typename Allocator> struct require_member< boost::asio::basic_system_executor<Blocking, Relationship, Allocator>, boost::asio::execution::relationship_t::fork_t > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::basic_system_executor<Blocking, boost::asio::execution::relationship_t::fork_t, Allocator> result_type; }; template <typename Blocking, typename Relationship, typename Allocator> struct require_member< boost::asio::basic_system_executor<Blocking, Relationship, Allocator>, boost::asio::execution::relationship_t::continuation_t > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::basic_system_executor<Blocking, boost::asio::execution::relationship_t::continuation_t, Allocator> result_type; }; template <typename Blocking, typename Relationship, typename Allocator> struct require_member< boost::asio::basic_system_executor<Blocking, Relationship, Allocator>, boost::asio::execution::allocator_t<void> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::basic_system_executor<Blocking, Relationship, std::allocator<void> > result_type; }; template <typename Blocking, typename Relationship, typename Allocator, typename OtherAllocator> struct require_member< boost::asio::basic_system_executor<Blocking, Relationship, Allocator>, boost::asio::execution::allocator_t<OtherAllocator> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::basic_system_executor<Blocking, Relationship, OtherAllocator> result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) template <typename Blocking, typename Relationship, typename Allocator, typename Property> struct query_static_constexpr_member< boost::asio::basic_system_executor<Blocking, Relationship, Allocator>, Property, typename boost::asio::enable_if< boost::asio::is_convertible< Property, boost::asio::execution::mapping_t >::value >::type > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef boost::asio::execution::mapping_t::thread_t result_type; static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT { return result_type(); } }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) template <typename Blocking, typename Relationship, typename Allocator, typename Property> struct query_member< boost::asio::basic_system_executor<Blocking, Relationship, Allocator>, Property, typename boost::asio::enable_if< boost::asio::is_convertible< Property, boost::asio::execution::blocking_t >::value >::type > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef boost::asio::execution::blocking_t result_type; }; template <typename Blocking, typename Relationship, typename Allocator, typename Property> struct query_member< boost::asio::basic_system_executor<Blocking, Relationship, Allocator>, Property, typename boost::asio::enable_if< boost::asio::is_convertible< Property, boost::asio::execution::relationship_t >::value >::type > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef boost::asio::execution::relationship_t result_type; }; template <typename Blocking, typename Relationship, typename Allocator> struct query_member< boost::asio::basic_system_executor<Blocking, Relationship, Allocator>, boost::asio::execution::context_t > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef boost::asio::system_context& result_type; }; template <typename Blocking, typename Relationship, typename Allocator> struct query_member< boost::asio::basic_system_executor<Blocking, Relationship, Allocator>, boost::asio::execution::allocator_t<void> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef Allocator result_type; }; template <typename Blocking, typename Relationship, typename Allocator> struct query_member< boost::asio::basic_system_executor<Blocking, Relationship, Allocator>, boost::asio::execution::allocator_t<Allocator> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef Allocator result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) } // namespace traits #endif // !defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/system_executor.hpp> #endif // BOOST_ASIO_SYSTEM_EXECUTOR_HPP version.hpp 0000644 00000001256 15125530236 0006750 0 ustar 00 // // version.hpp // ~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 101801 // 1.18.1 #endif // BOOST_ASIO_VERSION_HPP steady_timer.hpp 0000644 00000002432 15125530236 0007751 0 ustar 00 // // steady_timer.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) #include <boost/asio/basic_waitable_timer.hpp> #include <boost/asio/detail/chrono.hpp> 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<boost::chrono::steady_clock> timer; * @endcode */ typedef basic_waitable_timer<chrono::steady_clock> steady_timer; } // namespace asio } // namespace boost #endif // defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_STEADY_TIMER_HPP handler_alloc_hook.hpp 0000644 00000006617 15125530236 0011100 0 ustar 00 // // handler_alloc_hook.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if defined(BOOST_ASIO_NO_DEPRECATED) // Places in asio that would have previously called the allocate or deallocate // hooks to manage memory, now call them only to check whether the result types // are these types. If the result is not the correct type, it indicates that // the user code still has the old hooks in place, and if so we want to trigger // a compile error. enum asio_handler_allocate_is_no_longer_used {}; enum asio_handler_deallocate_is_no_longer_used {}; typedef asio_handler_allocate_is_no_longer_used asio_handler_allocate_is_deprecated; typedef asio_handler_deallocate_is_no_longer_used asio_handler_deallocate_is_deprecated; #else // defined(BOOST_ASIO_NO_DEPRECATED) typedef void* asio_handler_allocate_is_deprecated; typedef void asio_handler_deallocate_is_deprecated; #endif // defined(BOOST_ASIO_NO_DEPRECATED) /// (Deprecated: Use the associated_allocator trait.) 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 <tt>::operator * new</tt> and <tt>::operator delete</tt>. * * @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 asio_handler_allocate_is_deprecated 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 <tt>::operator * new</tt> and <tt>::operator delete</tt>. * * @sa asio_handler_allocate. */ BOOST_ASIO_DECL asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, ...); } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/impl/handler_alloc_hook.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_HANDLER_ALLOC_HOOK_HPP time_traits.hpp 0000644 00000004351 15125530236 0007606 0 ustar 00 // // time_traits.hpp // ~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/socket_types.hpp> // Must come before posix_time. #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ || defined(GENERATING_DOCUMENTATION) #include <boost/date_time/posix_time/posix_time_types.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { /// Time traits suitable for use with the deadline timer. template <typename Time> struct time_traits; /// Time traits specialised for posix_time. template <> struct time_traits<boost::posix_time::ptime> { /// 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) // || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_TIME_TRAITS_HPP ip/network_v4.hpp 0000644 00000016163 15125530236 0010000 0 ustar 00 // // ip/network_v4.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #include <string> #include <boost/asio/detail/string_view.hpp> #include <boost/system/error_code.hpp> #include <boost/asio/ip/address_v4_range.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, const network_v4& net); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/ip/impl/network_v4.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/ip/impl/network_v4.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_IP_NETWORK_V4_HPP ip/bad_address_cast.hpp 0000644 00000002445 15125530236 0011141 0 ustar 00 // // ip/bad_address_cast.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <typeinfo> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_ADDRESS_HPP ip/address_v4.hpp 0000644 00000023556 15125530236 0007740 0 ustar 00 // // ip/address_v4.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <string> #include <boost/asio/detail/array.hpp> #include <boost/asio/detail/cstdint.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/string_view.hpp> #include <boost/asio/detail/winsock_init.hpp> #include <boost/system/error_code.hpp> #if !defined(BOOST_ASIO_NO_IOSTREAM) # include <iosfwd> #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #include <boost/asio/detail/push_options.hpp> 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<unsigned char, 4> bytes_type; #else typedef boost::asio::detail::array<unsigned char, 4> 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 <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, const address_v4& addr); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/ip/impl/address_v4.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/ip/impl/address_v4.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_IP_ADDRESS_V4_HPP ip/v6_only.hpp 0000644 00000003421 15125530236 0007263 0 ustar 00 // // ip/v6_only.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/socket_option.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_V6_ONLY_HPP ip/basic_resolver_iterator.hpp 0000644 00000012042 15125530236 0012601 0 ustar 00 // // ip/basic_resolver_iterator.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <cstring> #include <iterator> #include <string> #include <vector> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/ip/basic_resolver_entry.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <boost/asio/detail/winrt_utils.hpp> #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <boost/asio/detail/push_options.hpp> 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<InternetProtocol> @endcode * * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ template <typename InternetProtocol> 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<InternetProtocol> value_type; /// The type of the result of applying operator->() to the iterator. typedef const basic_resolver_entry<InternetProtocol>* pointer; /// The type of the result of applying operator*() to the iterator. typedef const basic_resolver_entry<InternetProtocol>& 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<InternetProtocol>& operator*() const { return dereference(); } /// Dereference an iterator. const basic_resolver_entry<InternetProtocol>* 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<InternetProtocol>& dereference() const { return (*values_)[index_]; } typedef std::vector<basic_resolver_entry<InternetProtocol> > values_type; typedef boost::asio::detail::shared_ptr<values_type> values_ptr_type; values_ptr_type values_; std::size_t index_; }; } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_BASIC_RESOLVER_ITERATOR_HPP ip/address_v6_range.hpp 0000644 00000006407 15125530236 0011112 0 ustar 00 // // ip/address_v6_range.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #include <boost/asio/ip/address_v6_iterator.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ip { template <typename> 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<address_v6> { public: /// The type of an iterator that points into the range. typedef basic_address_iterator<address_v6> 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> address_v6_range; } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_ADDRESS_V6_RANGE_HPP ip/resolver_base.hpp 0000644 00000007274 15125530236 0010534 0 ustar 00 // // ip/resolver_base.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/push_options.hpp> 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<flags>( static_cast<unsigned int>(x) & static_cast<unsigned int>(y)); } friend flags operator|(flags x, flags y) { return static_cast<flags>( static_cast<unsigned int>(x) | static_cast<unsigned int>(y)); } friend flags operator^(flags x, flags y) { return static_cast<flags>( static_cast<unsigned int>(x) ^ static_cast<unsigned int>(y)); } friend flags operator~(flags x) { return static_cast<flags>(~static_cast<unsigned int>(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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_RESOLVER_BASE_HPP ip/impl/address_v4.ipp 0000644 00000013005 15125530236 0010666 0 ustar 00 // // ip/impl/address_v4.ipp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <climits> #include <limits> #include <stdexcept> #include <boost/asio/error.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/ip/address_v4.hpp> #include <boost/asio/detail/push_options.hpp> 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<uint_type>::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<boost::asio::detail::u_long_type>(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<std::string>(str)); } address_v4 make_address_v4(string_view str, boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT { return make_address_v4(static_cast<std::string>(str), ec); } #endif // defined(BOOST_ASIO_HAS_STRING_VIEW) } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_IMPL_ADDRESS_V4_IPP ip/impl/network_v4.hpp 0000644 00000002714 15125530236 0010736 0 ustar 00 // // ip/impl/network_v4.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ip { template <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& 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<Elem, Traits>::failbit) boost::asio::detail::throw_error(ec); else os.setstate(std::basic_ostream<Elem, Traits>::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 <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // BOOST_ASIO_IP_IMPL_NETWORK_V4_HPP ip/impl/host_name.ipp 0000644 00000002622 15125530236 0010610 0 ustar 00 // // ip/impl/host_name.ipp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/winsock_init.hpp> #include <boost/asio/ip/host_name.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_IMPL_HOST_NAME_IPP ip/impl/address_v4.hpp 0000644 00000003237 15125530236 0010673 0 ustar 00 // // ip/impl/address_v4.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, const address_v4& addr) { return os << addr.to_string().c_str(); } } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // BOOST_ASIO_IP_IMPL_ADDRESS_V4_HPP ip/impl/network_v6.hpp 0000644 00000002601 15125530236 0010733 0 ustar 00 // // ip/impl/network_v6.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ip { template <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& 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<Elem, Traits>::failbit) boost::asio::detail::throw_error(ec); else os.setstate(std::basic_ostream<Elem, Traits>::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 <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // BOOST_ASIO_IP_IMPL_NETWORK_V6_HPP ip/impl/network_v6.ipp 0000644 00000011541 15125530236 0010737 0 ustar 00 // // ip/impl/network_v6.ipp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #include <climits> #include <cstdio> #include <cstdlib> #include <stdexcept> #include <boost/asio/error.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/ip/network_v6.hpp> #include <boost/asio/detail/push_options.hpp> 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<unsigned short>(prefix_len)); } #if defined(BOOST_ASIO_HAS_STRING_VIEW) network_v6 make_network_v6(string_view str) { return make_network_v6(static_cast<std::string>(str)); } network_v6 make_network_v6(string_view str, boost::system::error_code& ec) { return make_network_v6(static_cast<std::string>(str), ec); } #endif // defined(BOOST_ASIO_HAS_STRING_VIEW) } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_IMPL_NETWORK_V6_IPP ip/impl/basic_endpoint.hpp 0000644 00000002313 15125530236 0011610 0 ustar 00 // // ip/impl/basic_endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ip { template <typename Elem, typename Traits, typename InternetProtocol> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, const basic_endpoint<InternetProtocol>& 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 <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // BOOST_ASIO_IP_IMPL_BASIC_ENDPOINT_HPP ip/impl/address.ipp 0000644 00000013047 15125530236 0010263 0 ustar 00 // // ip/impl/address.ipp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <typeinfo> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/error.hpp> #include <boost/asio/ip/address.hpp> #include <boost/asio/ip/bad_address_cast.hpp> #include <boost/system/system_error.hpp> #include <boost/asio/detail/push_options.hpp> 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<std::string>(str)); } address make_address(string_view str, boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT { return make_address(static_cast<std::string>(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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_IMPL_ADDRESS_IPP ip/impl/address_v6.ipp 0000644 00000024237 15125530236 0010701 0 ustar 00 // // ip/impl/address_v6.ipp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstring> #include <stdexcept> #include <typeinfo> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/error.hpp> #include <boost/asio/ip/address_v6.hpp> #include <boost/asio/ip/bad_address_cast.hpp> #include <boost/asio/detail/push_options.hpp> 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<std::string>(str)); } address_v6 make_address_v6(string_view str, boost::system::error_code& ec) BOOST_ASIO_NOEXCEPT { return make_address_v6(static_cast<std::string>(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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_IMPL_ADDRESS_V6_IPP ip/impl/address.hpp 0000644 00000003151 15125530236 0010255 0 ustar 00 // // ip/impl/address.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, const address& addr) { return os << addr.to_string().c_str(); } } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // BOOST_ASIO_IP_IMPL_ADDRESS_HPP ip/impl/address_v6.hpp 0000644 00000003237 15125530236 0010675 0 ustar 00 // // ip/impl/address_v6.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, const address_v6& addr) { return os << addr.to_string().c_str(); } } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // BOOST_ASIO_IP_IMPL_ADDRESS_V6_HPP ip/impl/network_v4.ipp 0000644 00000012763 15125530236 0010744 0 ustar 00 // // ip/impl/network_v4.ipp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #include <climits> #include <cstdio> #include <cstdlib> #include <stdexcept> #include <boost/asio/error.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/ip/network_v4.hpp> #include <boost/asio/detail/push_options.hpp> 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<unsigned short>(prefix_len)); } #if defined(BOOST_ASIO_HAS_STRING_VIEW) network_v4 make_network_v4(string_view str) { return make_network_v4(static_cast<std::string>(str)); } network_v4 make_network_v4(string_view str, boost::system::error_code& ec) { return make_network_v4(static_cast<std::string>(str), ec); } #endif // defined(BOOST_ASIO_HAS_STRING_VIEW) } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_IMPL_NETWORK_V4_IPP ip/host_name.hpp 0000644 00000002122 15125530236 0007641 0 ustar 00 // // ip/host_name.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <string> #include <boost/system/error_code.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/ip/impl/host_name.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_IP_HOST_NAME_HPP ip/multicast.hpp 0000644 00000012570 15125530236 0007701 0 ustar 00 // // ip/multicast.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/ip/detail/socket_option.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_MULTICAST_HPP ip/basic_resolver_query.hpp 0000644 00000022214 15125530236 0012117 0 ustar 00 // // ip/basic_resolver_query.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <string> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/ip/resolver_query_base.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename InternetProtocol> 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 * <tt>/etc/services</tt>. On Windows, service names may be found in the file * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. 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<int>(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 * <tt>/etc/services</tt>. On Windows, service names may be found in the file * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. 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<int>(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 * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. 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 * <tt>/etc/services</tt>. On Windows, service names may be found in the file * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. 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<int>(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 * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. 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 * <tt>/etc/services</tt>. On Windows, service names may be found in the file * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. 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<int>(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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_BASIC_RESOLVER_QUERY_HPP ip/unicast.hpp 0000644 00000003371 15125530236 0007341 0 ustar 00 // // ip/unicast.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/ip/detail/socket_option.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_UNICAST_HPP ip/tcp.hpp 0000644 00000007530 15125530236 0006462 0 ustar 00 // // ip/tcp.hpp // ~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/basic_socket_acceptor.hpp> #include <boost/asio/basic_socket_iostream.hpp> #include <boost/asio/basic_stream_socket.hpp> #include <boost/asio/detail/socket_option.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/ip/basic_endpoint.hpp> #include <boost/asio/ip/basic_resolver.hpp> #include <boost/asio/ip/basic_resolver_iterator.hpp> #include <boost/asio/ip/basic_resolver_query.hpp> #include <boost/asio/detail/push_options.hpp> 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<tcp> endpoint; /// Construct to represent the IPv4 TCP protocol. static tcp v4() BOOST_ASIO_NOEXCEPT { return tcp(BOOST_ASIO_OS_DEF(AF_INET)); } /// Construct to represent the IPv6 TCP protocol. static tcp v6() BOOST_ASIO_NOEXCEPT { return tcp(BOOST_ASIO_OS_DEF(AF_INET6)); } /// Obtain an identifier for the type of the protocol. int type() const BOOST_ASIO_NOEXCEPT { return BOOST_ASIO_OS_DEF(SOCK_STREAM); } /// Obtain an identifier for the protocol. int protocol() const BOOST_ASIO_NOEXCEPT { return BOOST_ASIO_OS_DEF(IPPROTO_TCP); } /// Obtain an identifier for the protocol family. int family() const BOOST_ASIO_NOEXCEPT { return family_; } /// The TCP socket type. typedef basic_stream_socket<tcp> socket; /// The TCP acceptor type. typedef basic_socket_acceptor<tcp> acceptor; /// The TCP resolver type. typedef basic_resolver<tcp> resolver; #if !defined(BOOST_ASIO_NO_IOSTREAM) /// The TCP iostream type. typedef basic_socket_iostream<tcp> 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) BOOST_ASIO_NOEXCEPT : family_(protocol_family) { } int family_; }; } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_TCP_HPP ip/network_v6.hpp 0000644 00000014544 15125530236 0010003 0 ustar 00 // // ip/network_v6.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #include <string> #include <boost/asio/detail/string_view.hpp> #include <boost/system/error_code.hpp> #include <boost/asio/ip/address_v6_range.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, const network_v6& net); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/ip/impl/network_v6.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/ip/impl/network_v6.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_IP_NETWORK_V6_HPP ip/basic_endpoint.hpp 0000644 00000016436 15125530236 0010662 0 ustar 00 // // ip/basic_endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/ip/address.hpp> #include <boost/asio/ip/detail/endpoint.hpp> #if !defined(BOOST_ASIO_NO_IOSTREAM) # include <iosfwd> #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #include <boost/asio/detail/push_options.hpp> 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 <typename InternetProtocol> 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<InternetProtocol>& e1, const basic_endpoint<InternetProtocol>& e2) BOOST_ASIO_NOEXCEPT { return e1.impl_ == e2.impl_; } /// Compare two endpoints for inequality. friend bool operator!=(const basic_endpoint<InternetProtocol>& e1, const basic_endpoint<InternetProtocol>& e2) BOOST_ASIO_NOEXCEPT { return !(e1 == e2); } /// Compare endpoints for ordering. friend bool operator<(const basic_endpoint<InternetProtocol>& e1, const basic_endpoint<InternetProtocol>& e2) BOOST_ASIO_NOEXCEPT { return e1.impl_ < e2.impl_; } /// Compare endpoints for ordering. friend bool operator>(const basic_endpoint<InternetProtocol>& e1, const basic_endpoint<InternetProtocol>& e2) BOOST_ASIO_NOEXCEPT { return e2.impl_ < e1.impl_; } /// Compare endpoints for ordering. friend bool operator<=(const basic_endpoint<InternetProtocol>& e1, const basic_endpoint<InternetProtocol>& e2) BOOST_ASIO_NOEXCEPT { return !(e2 < e1); } /// Compare endpoints for ordering. friend bool operator>=(const basic_endpoint<InternetProtocol>& e1, const basic_endpoint<InternetProtocol>& 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 <typename Elem, typename Traits, typename InternetProtocol> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, const basic_endpoint<InternetProtocol>& endpoint); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/ip/impl/basic_endpoint.hpp> #endif // BOOST_ASIO_IP_BASIC_ENDPOINT_HPP ip/address_v4_range.hpp 0000644 00000006500 15125530236 0011102 0 ustar 00 // // ip/address_v4_range.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/ip/address_v4_iterator.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ip { template <typename> 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<address_v4> { public: /// The type of an iterator that points into the range. typedef basic_address_iterator<address_v4> 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> address_v4_range; } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_ADDRESS_V4_RANGE_HPP ip/basic_resolver.hpp 0000644 00000132673 15125530236 0010705 0 ustar 00 // // ip/basic_resolver.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <string> #include <boost/asio/any_io_executor.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/io_object_impl.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/string_view.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/ip/basic_resolver_iterator.hpp> #include <boost/asio/ip/basic_resolver_query.hpp> #include <boost/asio/ip/basic_resolver_results.hpp> #include <boost/asio/ip/resolver_base.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <boost/asio/detail/winrt_resolver_service.hpp> #else # include <boost/asio/detail/resolver_service.hpp> #endif #if defined(BOOST_ASIO_HAS_MOVE) # include <utility> #endif // defined(BOOST_ASIO_HAS_MOVE) #include <boost/asio/detail/push_options.hpp> 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 <typename InternetProtocol, typename Executor = any_io_executor> 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 <typename InternetProtocol, typename Executor> class basic_resolver : public resolver_base { public: /// The type of the executor associated with the object. typedef Executor executor_type; /// Rebinds the resolver type to another executor. template <typename Executor1> struct rebind_executor { /// The resolver type when rebound to the specified executor. typedef basic_resolver<InternetProtocol, Executor1> other; }; /// 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<InternetProtocol> query; /// (Deprecated.) The iterator type. typedef basic_resolver_iterator<InternetProtocol> iterator; #endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// The results type. typedef basic_resolver_results<InternetProtocol> 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 <typename ExecutionContext> explicit basic_resolver(ExecutionContext& context, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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_)) { } // All resolvers have access to each other's implementations. template <typename InternetProtocol1, typename Executor1> friend class basic_resolver; /// 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. */ template <typename Executor1> basic_resolver(basic_resolver<InternetProtocol, Executor1>&& other, typename enable_if< is_convertible<Executor1, Executor>::value >::type* = 0) : 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; } /// 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. */ template <typename Executor1> typename enable_if< is_convertible<Executor1, Executor>::value, basic_resolver& >::type operator=(basic_resolver<InternetProtocol, Executor1>&& other) { basic_resolver tmp(std::move(other)); impl_ = std::move(tmp.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 * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. 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 * <tt>/etc/services</tt>. On Windows, service names may be found in the file * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. 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 * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. 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 * <tt>/etc/services</tt>. On Windows, service names may be found in the file * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. 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 * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. 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 * <tt>/etc/services</tt>. On Windows, service names may be found in the file * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. 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<protocol_type> q(static_cast<std::string>(host), static_cast<std::string>(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 * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. 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 * <tt>/etc/services</tt>. On Windows, service names may be found in the file * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. 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<protocol_type> q(static_cast<std::string>(host), static_cast<std::string>(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 * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. 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 * <tt>/etc/services</tt>. On Windows, service names may be found in the file * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. 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 * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. 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 * <tt>/etc/services</tt>. On Windows, service names may be found in the file * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. 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 * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. 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 * <tt>/etc/services</tt>. On Windows, service names may be found in the file * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. 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<protocol_type> q( protocol, static_cast<std::string>(host), static_cast<std::string>(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 * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. 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 * <tt>/etc/services</tt>. On Windows, service names may be found in the file * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. 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<protocol_type> q( protocol, static_cast<std::string>(host), static_cast<std::string>(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_COMPLETION_TOKEN_FOR(void (boost::system::error_code, results_type)) ResolveHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler, void (boost::system::error_code, results_type)) async_resolve(const query& q, BOOST_ASIO_MOVE_ARG(ResolveHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return boost::asio::async_initiate<ResolveHandler, void (boost::system::error_code, results_type)>( initiate_async_resolve(this), handler, 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 * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. 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 * <tt>/etc/services</tt>. On Windows, service names may be found in the file * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems * may use additional locations when resolving service names. */ template < BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, results_type)) ResolveHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { 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 * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. 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 * <tt>/etc/services</tt>. On Windows, service names may be found in the file * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems * may use additional locations when resolving service names. */ template < BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, results_type)) ResolveHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { basic_resolver_query<protocol_type> q(static_cast<std::string>(host), static_cast<std::string>(service), resolve_flags); return boost::asio::async_initiate<ResolveHandler, void (boost::system::error_code, results_type)>( initiate_async_resolve(this), handler, 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 * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. 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 * <tt>/etc/services</tt>. On Windows, service names may be found in the file * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems * may use additional locations when resolving service names. */ template < BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, results_type)) ResolveHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { 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 * <tt>/etc/hosts</tt>. On Windows, host names may be defined in the file * <tt>c:\\windows\\system32\\drivers\\etc\\hosts</tt>. 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 * <tt>/etc/services</tt>. On Windows, service names may be found in the file * <tt>c:\\windows\\system32\\drivers\\etc\\services</tt>. Operating systems * may use additional locations when resolving service names. */ template < BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, results_type)) ResolveHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { basic_resolver_query<protocol_type> q( protocol, static_cast<std::string>(host), static_cast<std::string>(service), resolve_flags); return boost::asio::async_initiate<ResolveHandler, void (boost::system::error_code, results_type)>( initiate_async_resolve(this), handler, 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_COMPLETION_TOKEN_FOR(void (boost::system::error_code, results_type)) ResolveHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ResolveHandler, void (boost::system::error_code, results_type)) async_resolve(const endpoint_type& e, BOOST_ASIO_MOVE_ARG(ResolveHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return boost::asio::async_initiate<ResolveHandler, void (boost::system::error_code, results_type)>( initiate_async_resolve(this), handler, e); } private: // Disallow copying and assignment. basic_resolver(const basic_resolver&) BOOST_ASIO_DELETED; basic_resolver& operator=(const basic_resolver&) BOOST_ASIO_DELETED; class initiate_async_resolve { public: typedef Executor executor_type; explicit initiate_async_resolve(basic_resolver* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename ResolveHandler, typename Query> void operator()(BOOST_ASIO_MOVE_ARG(ResolveHandler) handler, 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<ResolveHandler> handler2(handler); self_->impl_.get_service().async_resolve( self_->impl_.get_implementation(), q, handler2.value, self_->impl_.get_executor()); } private: basic_resolver* self_; }; # if defined(BOOST_ASIO_WINDOWS_RUNTIME) boost::asio::detail::io_object_impl< boost::asio::detail::winrt_resolver_service<InternetProtocol>, Executor> impl_; # else boost::asio::detail::io_object_impl< boost::asio::detail::resolver_service<InternetProtocol>, Executor> impl_; # endif }; } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_BASIC_RESOLVER_HPP ip/basic_resolver_results.hpp 0000644 00000023025 15125530236 0012454 0 ustar 00 // // ip/basic_resolver_results.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <cstring> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/ip/basic_resolver_iterator.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <boost/asio/detail/winrt_utils.hpp> #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <boost/asio/detail/push_options.hpp> 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<InternetProtocol> @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 <typename InternetProtocol> class basic_resolver_results #if !defined(BOOST_ASIO_NO_DEPRECATED) : public basic_resolver_iterator<InternetProtocol> #else // !defined(BOOST_ASIO_NO_DEPRECATED) : private basic_resolver_iterator<InternetProtocol> #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<protocol_type> 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<protocol_type> 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<InternetProtocol>(other) { } #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move constructor. basic_resolver_results(basic_resolver_results&& other) : basic_resolver_iterator<InternetProtocol>( 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<InternetProtocol>::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<InternetProtocol>::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<std::size_t>(address_info->ai_addrlen)); memcpy(endpoint.data(), address_info->ai_addr, address_info->ai_addrlen); results.values_->push_back( basic_resolver_entry<InternetProtocol>(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<InternetProtocol>( endpoint, host_name, service_name)); return results; } // Create results from a sequence of endpoints, host and service name. template <typename EndpointIterator> 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<InternetProtocol>( *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<InternetProtocol>( 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<basic_resolver_entry<InternetProtocol> > values_type; }; } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_BASIC_RESOLVER_RESULTS_HPP ip/detail/impl/endpoint.ipp 0000644 00000013332 15125530236 0011715 0 ustar 00 // // ip/detail/impl/endpoint.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstring> #if !defined(BOOST_ASIO_NO_IOSTREAM) # include <sstream> #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/ip/detail/endpoint.hpp> #include <boost/asio/detail/push_options.hpp> 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<boost::asio::detail::u_long_type>( 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_DETAIL_IMPL_ENDPOINT_IPP ip/detail/endpoint.hpp 0000644 00000010002 15125530236 0010742 0 ustar 00 // // ip/detail/endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <string> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/winsock_init.hpp> #include <boost/system/error_code.hpp> #include <boost/asio/ip/address.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/ip/detail/impl/endpoint.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_IP_DETAIL_ENDPOINT_HPP ip/detail/socket_option.hpp 0000644 00000033576 15125530236 0012027 0 ustar 00 // // detail/socket_option.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <cstring> #include <stdexcept> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/ip/address.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ip { namespace detail { namespace socket_option { // Helper template for implementing multicast enable loopback options. template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name> 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 <typename Protocol> 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 <typename Protocol> 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 <typename Protocol> void* data(const Protocol& protocol) { if (protocol.family() == PF_INET6) return &ipv6_value_; return &ipv4_value_; } // Get the address of the boolean data. template <typename Protocol> 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 <typename Protocol> 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 <typename Protocol> 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 <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name> 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 <typename Protocol> 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 <typename Protocol> int name(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return IPv6_Name; return IPv4_Name; } // Get the address of the data. template <typename Protocol> int* data(const Protocol&) { return &value_; } // Get the address of the data. template <typename Protocol> const int* data(const Protocol&) const { return &value_; } // Get the size of the data. template <typename Protocol> std::size_t size(const Protocol&) const { return sizeof(value_); } // Set the size of the data. template <typename Protocol> 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 <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name> 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 <typename Protocol> 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 <typename Protocol> int name(const Protocol& protocol) const { if (protocol.family() == PF_INET6) return IPv6_Name; return IPv4_Name; } // Get the address of the data. template <typename Protocol> void* data(const Protocol& protocol) { if (protocol.family() == PF_INET6) return &ipv6_value_; return &ipv4_value_; } // Get the address of the data. template <typename Protocol> 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 <typename Protocol> 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 <typename Protocol> 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 <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name> 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 <typename Protocol> 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 <typename Protocol> 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 <typename Protocol> 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 <typename Protocol> 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 <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name> 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 <typename Protocol> 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 <typename Protocol> 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 <typename Protocol> 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 <typename Protocol> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_DETAIL_SOCKET_OPTION_HPP ip/basic_resolver_entry.hpp 0000644 00000005714 15125530236 0012121 0 ustar 00 // // ip/basic_resolver_entry.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <string> #include <boost/asio/detail/string_view.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename InternetProtocol> 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<std::string>(host)), service_name_(static_cast<std::string>(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 <class Allocator> std::basic_string<char, std::char_traits<char>, Allocator> host_name( const Allocator& alloc = Allocator()) const { return std::basic_string<char, std::char_traits<char>, 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 <class Allocator> std::basic_string<char, std::char_traits<char>, Allocator> service_name( const Allocator& alloc = Allocator()) const { return std::basic_string<char, std::char_traits<char>, 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_BASIC_RESOLVER_ENTRY_HPP ip/udp.hpp 0000644 00000005144 15125530236 0006463 0 ustar 00 // // ip/udp.hpp // ~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/basic_datagram_socket.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/ip/basic_endpoint.hpp> #include <boost/asio/ip/basic_resolver.hpp> #include <boost/asio/ip/basic_resolver_iterator.hpp> #include <boost/asio/ip/basic_resolver_query.hpp> #include <boost/asio/detail/push_options.hpp> 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<udp> endpoint; /// Construct to represent the IPv4 UDP protocol. static udp v4() BOOST_ASIO_NOEXCEPT { return udp(BOOST_ASIO_OS_DEF(AF_INET)); } /// Construct to represent the IPv6 UDP protocol. static udp v6() BOOST_ASIO_NOEXCEPT { return udp(BOOST_ASIO_OS_DEF(AF_INET6)); } /// Obtain an identifier for the type of the protocol. int type() const BOOST_ASIO_NOEXCEPT { return BOOST_ASIO_OS_DEF(SOCK_DGRAM); } /// Obtain an identifier for the protocol. int protocol() const BOOST_ASIO_NOEXCEPT { return BOOST_ASIO_OS_DEF(IPPROTO_UDP); } /// Obtain an identifier for the protocol family. int family() const BOOST_ASIO_NOEXCEPT { return family_; } /// The UDP socket type. typedef basic_datagram_socket<udp> socket; /// The UDP resolver type. typedef basic_resolver<udp> 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) BOOST_ASIO_NOEXCEPT : family_(protocol_family) { } int family_; }; } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_UDP_HPP ip/address.hpp 0000644 00000020171 15125530236 0007315 0 ustar 00 // // ip/address.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <string> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/detail/string_view.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/system/error_code.hpp> #include <boost/asio/ip/address_v4.hpp> #include <boost/asio/ip/address_v6.hpp> #include <boost/asio/ip/bad_address_cast.hpp> #if !defined(BOOST_ASIO_NO_IOSTREAM) # include <iosfwd> #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #include <boost/asio/detail/push_options.hpp> 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 <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, const address& addr); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/ip/impl/address.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/ip/impl/address.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_IP_ADDRESS_HPP ip/address_v6.hpp 0000644 00000024511 15125530236 0007732 0 ustar 00 // // ip/address_v6.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <string> #include <boost/asio/detail/array.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/string_view.hpp> #include <boost/asio/detail/winsock_init.hpp> #include <boost/system/error_code.hpp> #include <boost/asio/ip/address_v4.hpp> #if !defined(BOOST_ASIO_NO_IOSTREAM) # include <iosfwd> #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ip { template <typename> 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<unsigned char, 16> bytes_type; #else typedef boost::asio::detail::array<unsigned char, 16> 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<address_v6>; // 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 <typename Elem, typename Traits> std::basic_ostream<Elem, Traits>& operator<<( std::basic_ostream<Elem, Traits>& os, const address_v6& addr); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/ip/impl/address_v6.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/ip/impl/address_v6.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_IP_ADDRESS_V6_HPP ip/resolver_query_base.hpp 0000644 00000002221 15125530236 0011744 0 ustar 00 // // ip/resolver_query_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/ip/resolver_base.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_RESOLVER_QUERY_BASE_HPP ip/address_v4_iterator.hpp 0000644 00000010244 15125530236 0011637 0 ustar 00 // // ip/address_v4_iterator.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/ip/address_v4.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ip { template <typename> 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<address_v4> { 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> address_v4_iterator; } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_ADDRESS_V4_ITERATOR_HPP ip/address_v6_iterator.hpp 0000644 00000010772 15125530236 0011647 0 ustar 00 // // ip/address_v6_iterator.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #include <boost/asio/ip/address_v6.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace ip { template <typename> 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<address_v6> { 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> address_v6_iterator; } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_ADDRESS_V6_ITERATOR_HPP ip/icmp.hpp 0000644 00000005461 15125530236 0006625 0 ustar 00 // // ip/icmp.hpp // ~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/basic_raw_socket.hpp> #include <boost/asio/ip/basic_endpoint.hpp> #include <boost/asio/ip/basic_resolver.hpp> #include <boost/asio/ip/basic_resolver_iterator.hpp> #include <boost/asio/ip/basic_resolver_query.hpp> #include <boost/asio/detail/push_options.hpp> 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<icmp> endpoint; /// Construct to represent the IPv4 ICMP protocol. static icmp v4() BOOST_ASIO_NOEXCEPT { return icmp(BOOST_ASIO_OS_DEF(IPPROTO_ICMP), BOOST_ASIO_OS_DEF(AF_INET)); } /// Construct to represent the IPv6 ICMP protocol. static icmp v6() BOOST_ASIO_NOEXCEPT { 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 BOOST_ASIO_NOEXCEPT { return BOOST_ASIO_OS_DEF(SOCK_RAW); } /// Obtain an identifier for the protocol. int protocol() const BOOST_ASIO_NOEXCEPT { return protocol_; } /// Obtain an identifier for the protocol family. int family() const BOOST_ASIO_NOEXCEPT { return family_; } /// The ICMP socket type. typedef basic_raw_socket<icmp> socket; /// The ICMP resolver type. typedef basic_resolver<icmp> 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) BOOST_ASIO_NOEXCEPT : protocol_(protocol_id), family_(protocol_family) { } int protocol_; int family_; }; } // namespace ip } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IP_ICMP_HPP high_resolution_timer.hpp 0000644 00000002562 15125530236 0011666 0 ustar 00 // // high_resolution_timer.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) #include <boost/asio/basic_waitable_timer.hpp> #include <boost/asio/detail/chrono.hpp> 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<boost::chrono::high_resolution_clock> 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 detail/atomic_count.hpp 0000644 00000003643 15125530236 0011213 0 ustar 00 // // detail/atomic_count.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_HAS_THREADS) // Nothing to include. #elif defined(BOOST_ASIO_HAS_STD_ATOMIC) # include <atomic> #else // defined(BOOST_ASIO_HAS_STD_ATOMIC) # include <boost/detail/atomic_count.hpp> #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; } inline void ref_count_up(atomic_count& a) { ++a; } inline bool ref_count_down(atomic_count& a) { return --a == 0; } #elif defined(BOOST_ASIO_HAS_STD_ATOMIC) typedef std::atomic<long> atomic_count; inline void increment(atomic_count& a, long b) { a += b; } inline void ref_count_up(atomic_count& a) { a.fetch_add(1, std::memory_order_relaxed); } inline bool ref_count_down(atomic_count& a) { if (a.fetch_sub(1, std::memory_order_release) == 1) { std::atomic_thread_fence(std::memory_order_acquire); return true; } return false; } #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; } inline void ref_count_up(atomic_count& a) { ++a; } inline bool ref_count_down(atomic_count& a) { return --a == 0; } #endif // defined(BOOST_ASIO_HAS_STD_ATOMIC) } // namespace detail } // namespace asio } // namespace boost #endif // BOOST_ASIO_DETAIL_ATOMIC_COUNT_HPP detail/gcc_x86_fenced_block.hpp 0000644 00000004634 15125530236 0012447 0 ustar 00 // // detail/gcc_x86_fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) #endif // BOOST_ASIO_DETAIL_GCC_X86_FENCED_BLOCK_HPP detail/wrapped_handler.hpp 0000644 00000023232 15125530236 0011662 0 ustar 00 // // detail/wrapped_handler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { struct is_continuation_delegated { template <typename Dispatcher, typename Handler> bool operator()(Dispatcher&, Handler& handler) const { return boost_asio_handler_cont_helpers::is_continuation(handler); } }; struct is_continuation_if_running { template <typename Dispatcher, typename Handler> bool operator()(Dispatcher& dispatcher, Handler&) const { return dispatcher.running_in_this_thread(); } }; template <typename Dispatcher, typename Handler, typename IsContinuation = is_continuation_delegated> 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 <typename Arg1> void operator()(const Arg1& arg1) { dispatcher_.dispatch(detail::bind_handler(handler_, arg1)); } template <typename Arg1> void operator()(const Arg1& arg1) const { dispatcher_.dispatch(detail::bind_handler(handler_, arg1)); } template <typename Arg1, typename Arg2> void operator()(const Arg1& arg1, const Arg2& arg2) { dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2)); } template <typename Arg1, typename Arg2> void operator()(const Arg1& arg1, const Arg2& arg2) const { dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2)); } template <typename Arg1, typename Arg2, typename Arg3> void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) { dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3)); } template <typename Arg1, typename Arg2, typename Arg3> void operator()(const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) const { dispatcher_.dispatch(detail::bind_handler(handler_, arg1, arg2, arg3)); } template <typename Arg1, typename Arg2, typename Arg3, typename Arg4> 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 <typename Arg1, typename Arg2, typename Arg3, typename Arg4> 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 <typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> 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 <typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> 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 <typename Handler, typename Context> 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 <typename Dispatcher, typename Handler, typename IsContinuation> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Dispatcher, typename Handler, typename IsContinuation> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Dispatcher, typename Handler, typename IsContinuation> inline bool asio_handler_is_continuation( wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler) { return IsContinuation()(this_handler->dispatcher_, this_handler->handler_); } template <typename Function, typename Dispatcher, typename Handler, typename IsContinuation> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler) { this_handler->dispatcher_.dispatch( rewrapped_handler<Function, Handler>( function, this_handler->handler_)); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename Dispatcher, typename Handler, typename IsContinuation> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, wrapped_handler<Dispatcher, Handler, IsContinuation>* this_handler) { this_handler->dispatcher_.dispatch( rewrapped_handler<Function, Handler>( function, this_handler->handler_)); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Context> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, rewrapped_handler<Handler, Context>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Context> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, rewrapped_handler<Handler, Context>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->context_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Dispatcher, typename Context> inline bool asio_handler_is_continuation( rewrapped_handler<Dispatcher, Context>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->context_); } template <typename Function, typename Handler, typename Context> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, rewrapped_handler<Handler, Context>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->context_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename Handler, typename Context> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, rewrapped_handler<Handler, Context>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->context_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_WRAPPED_HANDLER_HPP detail/base_from_completion_cond.hpp 0000644 00000003403 15125530236 0013712 0 ustar 00 // // detail/base_from_completion_cond.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/completion_condition.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename CompletionCondition> 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<transfer_all_t> { 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_BASE_FROM_COMPLETION_COND_HPP detail/epoll_reactor.hpp 0000644 00000022373 15125530236 0011362 0 ustar 00 // // detail/epoll_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_EPOLL) #include <boost/asio/detail/atomic_count.hpp> #include <boost/asio/detail/conditionally_enabled_mutex.hpp> #include <boost/asio/detail/limits.hpp> #include <boost/asio/detail/object_pool.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/select_interrupter.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/timer_queue_base.hpp> #include <boost/asio/detail/timer_queue_set.hpp> #include <boost/asio/detail/wait_op.hpp> #include <boost/asio/execution_context.hpp> #if defined(BOOST_ASIO_HAS_TIMERFD) # include <sys/timerfd.h> #endif // defined(BOOST_ASIO_HAS_TIMERFD) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class epoll_reactor : public execution_context_service_base<epoll_reactor> { 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<reactor_op> 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 <typename Time_Traits> void add_timer_queue(timer_queue<Time_Traits>& timer_queue); // Remove a timer queue from the reactor. template <typename Time_Traits> void remove_timer_queue(timer_queue<Time_Traits>& timer_queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template <typename Time_Traits> void schedule_timer(timer_queue<Time_Traits>& queue, const typename Time_Traits::time_type& time, typename timer_queue<Time_Traits>::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 <typename Time_Traits> std::size_t cancel_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); // Move the timer operations associated with the given timer. template <typename Time_Traits> void move_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& target, typename timer_queue<Time_Traits>::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<operation>& 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<descriptor_state> 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 <boost/asio/detail/pop_options.hpp> #include <boost/asio/detail/impl/epoll_reactor.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/epoll_reactor.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_HAS_EPOLL) #endif // BOOST_ASIO_DETAIL_EPOLL_REACTOR_HPP detail/type_traits.hpp 0000644 00000011716 15125530236 0011076 0 ustar 00 // // detail/type_traits.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) # include <type_traits> #else // defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) # include <boost/type_traits/add_const.hpp> # include <boost/type_traits/add_lvalue_reference.hpp> # include <boost/type_traits/aligned_storage.hpp> # include <boost/type_traits/alignment_of.hpp> # include <boost/type_traits/conditional.hpp> # include <boost/type_traits/decay.hpp> # include <boost/type_traits/has_nothrow_copy.hpp> # include <boost/type_traits/has_nothrow_destructor.hpp> # include <boost/type_traits/integral_constant.hpp> # include <boost/type_traits/is_base_of.hpp> # include <boost/type_traits/is_class.hpp> # include <boost/type_traits/is_const.hpp> # include <boost/type_traits/is_convertible.hpp> # include <boost/type_traits/is_constructible.hpp> # include <boost/type_traits/is_copy_constructible.hpp> # include <boost/type_traits/is_destructible.hpp> # include <boost/type_traits/is_function.hpp> # include <boost/type_traits/is_object.hpp> # include <boost/type_traits/is_same.hpp> # include <boost/type_traits/remove_cv.hpp> # include <boost/type_traits/remove_pointer.hpp> # include <boost/type_traits/remove_reference.hpp> # include <boost/utility/declval.hpp> # include <boost/utility/enable_if.hpp> # include <boost/utility/result_of.hpp> #endif // defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) namespace boost { namespace asio { #if defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) using std::add_const; using std::add_lvalue_reference; using std::aligned_storage; using std::alignment_of; using std::conditional; using std::decay; using std::declval; 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_constructible; using std::is_convertible; using std::is_copy_constructible; using std::is_destructible; using std::is_function; using std::is_move_constructible; using std::is_nothrow_copy_constructible; using std::is_nothrow_destructible; using std::is_object; using std::is_reference; using std::is_same; using std::is_scalar; using std::remove_cv; template <typename T> struct remove_cvref : remove_cv<typename std::remove_reference<T>::type> {}; using std::remove_pointer; using std::remove_reference; #if defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT) template <typename> struct result_of; template <typename F, typename... Args> struct result_of<F(Args...)> : std::invoke_result<F, Args...> {}; #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; using boost::add_lvalue_reference; using boost::aligned_storage; using boost::alignment_of; template <bool Condition, typename Type = void> struct enable_if : boost::enable_if_c<Condition, Type> {}; using boost::conditional; using boost::decay; using boost::declval; using boost::false_type; using boost::integral_constant; using boost::is_base_of; using boost::is_class; using boost::is_const; using boost::is_constructible; using boost::is_convertible; using boost::is_copy_constructible; using boost::is_destructible; using boost::is_function; #if defined(BOOST_ASIO_HAS_MOVE) template <typename T> struct is_move_constructible : false_type {}; #else // defined(BOOST_ASIO_HAS_MOVE) template <typename T> struct is_move_constructible : is_copy_constructible<T> {}; #endif // defined(BOOST_ASIO_HAS_MOVE) template <typename T> struct is_nothrow_copy_constructible : boost::has_nothrow_copy<T> {}; template <typename T> struct is_nothrow_destructible : boost::has_nothrow_destructor<T> {}; using boost::is_object; using boost::is_reference; using boost::is_same; using boost::is_scalar; using boost::remove_cv; template <typename T> struct remove_cvref : remove_cv<typename boost::remove_reference<T>::type> {}; using boost::remove_pointer; using boost::remove_reference; using boost::result_of; using boost::true_type; #endif // defined(BOOST_ASIO_HAS_STD_TYPE_TRAITS) template <typename> struct void_type { typedef void type; }; #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename...> struct conjunction : true_type {}; template <typename T> struct conjunction<T> : T {}; template <typename Head, typename... Tail> struct conjunction<Head, Tail...> : conditional<Head::value, conjunction<Tail...>, Head>::type {}; #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) } // namespace asio } // namespace boost #endif // BOOST_ASIO_DETAIL_TYPE_TRAITS_HPP detail/posix_fd_set_adapter.hpp 0000644 00000005660 15125530236 0012716 0 ustar 00 // // detail/posix_fd_set_adapter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_WINDOWS) \ && !defined(__CYGWIN__) \ && !defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <cstring> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/reactor_op_queue.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/push_options.hpp> 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<socket_type>& operations, op_queue<operation>& ops) { reactor_op_queue<socket_type>::iterator i = operations.begin(); while (i != operations.end()) { reactor_op_queue<socket_type>::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<socket_type>& operations, op_queue<operation>& ops) const { reactor_op_queue<socket_type>::iterator i = operations.begin(); while (i != operations.end()) { reactor_op_queue<socket_type>::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 <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_WINDOWS) // && !defined(__CYGWIN__) // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_POSIX_FD_SET_ADAPTER_HPP detail/win_mutex.hpp 0000644 00000003450 15125530236 0010542 0 ustar 00 // // detail/win_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS) #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/scoped_lock.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class win_mutex : private noncopyable { public: typedef boost::asio::detail::scoped_lock<win_mutex> 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/win_mutex.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_WINDOWS) #endif // BOOST_ASIO_DETAIL_WIN_MUTEX_HPP detail/null_socket_service.hpp 0000644 00000041603 15125530236 0012567 0 ustar 00 // // detail/null_socket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <boost/asio/buffer.hpp> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/post.hpp> #include <boost/asio/socket_base.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Protocol> class null_socket_service : public execution_context_service_base<null_socket_service<Protocol> > { 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<null_socket_service<Protocol> >(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 <typename Protocol1> void converting_move_construct(implementation_type&, null_socket_service<Protocol1>&, typename null_socket_service<Protocol1>::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 <typename IO_Control_Command> 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 <typename Option> 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 <typename Option> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence, typename Handler, typename IoExecutor> 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 <typename Handler, typename IoExecutor> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence, typename Handler, typename IoExecutor> 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 <typename Handler, typename IoExecutor> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence, typename Handler, typename IoExecutor> 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 <typename Handler, typename IoExecutor> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence, typename Handler, typename IoExecutor> 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 <typename Handler, typename IoExecutor> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence, typename Handler, typename IoExecutor> 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 <typename Handler, typename IoExecutor> 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 <typename Socket> 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 <typename Socket, typename Handler, typename IoExecutor> 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 <typename Handler, typename IoExecutor> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_NULL_SOCKET_SERVICE_HPP detail/posix_static_mutex.hpp 0000644 00000002673 15125530236 0012464 0 ustar 00 // // detail/posix_static_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_PTHREADS) #include <pthread.h> #include <boost/asio/detail/scoped_lock.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { struct posix_static_mutex { typedef boost::asio::detail::scoped_lock<posix_static_mutex> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_PTHREADS) #endif // BOOST_ASIO_DETAIL_POSIX_STATIC_MUTEX_HPP detail/winrt_resolve_op.hpp 0000644 00000007736 15125530236 0012136 0 ustar 00 // // detail/winrt_resolve_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/winrt_async_op.hpp> #include <boost/asio/ip/basic_resolver_results.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Protocol, typename Handler, typename IoExecutor> 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<Protocol> query_type; typedef boost::asio::ip::basic_resolver_results<Protocol> 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)), work_(handler_, io_ex) { } 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<winrt_resolve_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); 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, boost::system::error_code, results_type> 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_; handler_work<Handler, IoExecutor> executor_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_WINRT_RESOLVE_OP_HPP detail/winrt_resolver_service.hpp 0000644 00000014236 15125530236 0013333 0 ustar 00 // // detail/winrt_resolver_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <boost/asio/ip/basic_resolver_query.hpp> #include <boost/asio/ip/basic_resolver_results.hpp> #include <boost/asio/post.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/winrt_async_manager.hpp> #include <boost/asio/detail/winrt_resolve_op.hpp> #include <boost/asio/detail/winrt_utils.hpp> #if defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/win_iocp_io_context.hpp> #else // defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/scheduler.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Protocol> class winrt_resolver_service : public execution_context_service_base<winrt_resolver_service<Protocol> > { 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<Protocol> query_type; // The results type. typedef boost::asio::ip::basic_resolver_results<Protocol> results_type; // Constructor. winrt_resolver_service(execution_context& context) : execution_context_service_base< winrt_resolver_service<Protocol> >(context), scheduler_(use_service<scheduler_impl>(context)), async_manager_(use_service<winrt_async_manager>(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 <typename Handler, typename IoExecutor> 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<Protocol, Handler, IoExecutor> 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 <typename Handler, typename IoExecutor> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_WINRT_RESOLVER_SERVICE_HPP detail/wait_op.hpp 0000644 00000001775 15125530236 0010175 0 ustar 00 // // detail/wait_op.hpp // ~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_WAIT_OP_HPP detail/null_signal_blocker.hpp 0000644 00000003133 15125530236 0012531 0 ustar 00 // // detail/null_signal_blocker.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_HAS_THREADS) \ || defined(BOOST_ASIO_WINDOWS) \ || defined(BOOST_ASIO_WINDOWS_RUNTIME) \ || defined(__CYGWIN__) \ || defined(__SYMBIAN32__) #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #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 detail/timer_scheduler.hpp 0000644 00000002205 15125530236 0011676 0 ustar 00 // // detail/timer_scheduler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/timer_scheduler_fwd.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <boost/asio/detail/winrt_timer_scheduler.hpp> #elif defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/win_iocp_io_context.hpp> #elif defined(BOOST_ASIO_HAS_EPOLL) # include <boost/asio/detail/epoll_reactor.hpp> #elif defined(BOOST_ASIO_HAS_KQUEUE) # include <boost/asio/detail/kqueue_reactor.hpp> #elif defined(BOOST_ASIO_HAS_DEV_POLL) # include <boost/asio/detail/dev_poll_reactor.hpp> #else # include <boost/asio/detail/select_reactor.hpp> #endif #endif // BOOST_ASIO_DETAIL_TIMER_SCHEDULER_HPP detail/bind_handler.hpp 0000644 00000071024 15125530236 0011136 0 ustar 00 // // detail/bind_handler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/associated_allocator.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_cont_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Handler, typename Arg1> class binder1 { public: template <typename T> 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<const Arg1&>(arg1_)); } void operator()() const { handler_(arg1_); } //private: Handler handler_; Arg1 arg1_; }; template <typename Handler, typename Arg1> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, binder1<Handler, Arg1>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, binder1<Handler, Arg1>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1> inline bool asio_handler_is_continuation( binder1<Handler, Arg1>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename Handler, typename Arg1> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, binder1<Handler, Arg1>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename Handler, typename Arg1> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, binder1<Handler, Arg1>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1> inline binder1<typename decay<Handler>::type, Arg1> bind_handler( BOOST_ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1) { return binder1<typename decay<Handler>::type, Arg1>(0, BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1); } template <typename Handler, typename Arg1, typename Arg2> class binder2 { public: template <typename T> 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<const Arg1&>(arg1_), static_cast<const Arg2&>(arg2_)); } void operator()() const { handler_(arg1_, arg2_); } //private: Handler handler_; Arg1 arg1_; Arg2 arg2_; }; template <typename Handler, typename Arg1, typename Arg2> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, binder2<Handler, Arg1, Arg2>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1, typename Arg2> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, binder2<Handler, Arg1, Arg2>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1, typename Arg2> inline bool asio_handler_is_continuation( binder2<Handler, Arg1, Arg2>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename Handler, typename Arg1, typename Arg2> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, binder2<Handler, Arg1, Arg2>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename Handler, typename Arg1, typename Arg2> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, binder2<Handler, Arg1, Arg2>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1, typename Arg2> inline binder2<typename decay<Handler>::type, Arg1, Arg2> bind_handler( BOOST_ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2) { return binder2<typename decay<Handler>::type, Arg1, Arg2>(0, BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1, arg2); } template <typename Handler, typename Arg1, typename Arg2, typename Arg3> class binder3 { public: template <typename T> 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<const Arg1&>(arg1_), static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_)); } void operator()() const { handler_(arg1_, arg2_, arg3_); } //private: Handler handler_; Arg1 arg1_; Arg2 arg2_; Arg3 arg3_; }; template <typename Handler, typename Arg1, typename Arg2, typename Arg3> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, binder3<Handler, Arg1, Arg2, Arg3>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1, typename Arg2, typename Arg3> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, binder3<Handler, Arg1, Arg2, Arg3>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1, typename Arg2, typename Arg3> inline bool asio_handler_is_continuation( binder3<Handler, Arg1, Arg2, Arg3>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename Handler, typename Arg1, typename Arg2, typename Arg3> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, binder3<Handler, Arg1, Arg2, Arg3>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename Handler, typename Arg1, typename Arg2, typename Arg3> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, binder3<Handler, Arg1, Arg2, Arg3>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1, typename Arg2, typename Arg3> inline binder3<typename decay<Handler>::type, Arg1, Arg2, Arg3> bind_handler( BOOST_ASIO_MOVE_ARG(Handler) handler, const Arg1& arg1, const Arg2& arg2, const Arg3& arg3) { return binder3<typename decay<Handler>::type, Arg1, Arg2, Arg3>(0, BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3); } template <typename Handler, typename Arg1, typename Arg2, typename Arg3, typename Arg4> class binder4 { public: template <typename T> 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<const Arg1&>(arg1_), static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_), static_cast<const Arg4&>(arg4_)); } void operator()() const { handler_(arg1_, arg2_, arg3_, arg4_); } //private: Handler handler_; Arg1 arg1_; Arg2 arg2_; Arg3 arg3_; Arg4 arg4_; }; template <typename Handler, typename Arg1, typename Arg2, typename Arg3, typename Arg4> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1, typename Arg2, typename Arg3, typename Arg4> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1, typename Arg2, typename Arg3, typename Arg4> inline bool asio_handler_is_continuation( binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename Handler, typename Arg1, typename Arg2, typename Arg3, typename Arg4> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename Handler, typename Arg1, typename Arg2, typename Arg3, typename Arg4> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, binder4<Handler, Arg1, Arg2, Arg3, Arg4>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1, typename Arg2, typename Arg3, typename Arg4> inline binder4<typename decay<Handler>::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<typename decay<Handler>::type, Arg1, Arg2, Arg3, Arg4>(0, BOOST_ASIO_MOVE_CAST(Handler)(handler), arg1, arg2, arg3, arg4); } template <typename Handler, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> class binder5 { public: template <typename T> 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<const Arg1&>(arg1_), static_cast<const Arg2&>(arg2_), static_cast<const Arg3&>(arg3_), static_cast<const Arg4&>(arg4_), static_cast<const Arg5&>(arg5_)); } void operator()() const { handler_(arg1_, arg2_, arg3_, arg4_, arg5_); } //private: Handler handler_; Arg1 arg1_; Arg2 arg2_; Arg3 arg3_; Arg4 arg4_; Arg5 arg5_; }; template <typename Handler, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> inline bool asio_handler_is_continuation( binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename Handler, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> inline asio_handler_invoke_is_deprecated asio_handler_invoke(Function& function, binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Function, typename Handler, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> inline asio_handler_invoke_is_deprecated asio_handler_invoke(const Function& function, binder5<Handler, Arg1, Arg2, Arg3, Arg4, Arg5>* this_handler) { boost_asio_handler_invoke_helpers::invoke( function, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5> inline binder5<typename decay<Handler>::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<typename decay<Handler>::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 <typename Handler, typename Arg1> 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 <typename Handler, typename Arg1> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, move_binder1<Handler, Arg1>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, move_binder1<Handler, Arg1>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1> inline bool asio_handler_is_continuation( move_binder1<Handler, Arg1>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename Handler, typename Arg1> inline asio_handler_invoke_is_deprecated asio_handler_invoke(BOOST_ASIO_MOVE_ARG(Function) function, move_binder1<Handler, Arg1>* this_handler) { boost_asio_handler_invoke_helpers::invoke( BOOST_ASIO_MOVE_CAST(Function)(function), this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1, typename Arg2> 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<const Arg1&>(arg1_), BOOST_ASIO_MOVE_CAST(Arg2)(arg2_)); } //private: Handler handler_; Arg1 arg1_; Arg2 arg2_; }; template <typename Handler, typename Arg1, typename Arg2> inline asio_handler_allocate_is_deprecated asio_handler_allocate(std::size_t size, move_binder2<Handler, Arg1, Arg2>* this_handler) { #if defined(BOOST_ASIO_NO_DEPRECATED) boost_asio_handler_alloc_helpers::allocate(size, this_handler->handler_); return asio_handler_allocate_is_no_longer_used(); #else // defined(BOOST_ASIO_NO_DEPRECATED) return boost_asio_handler_alloc_helpers::allocate( size, this_handler->handler_); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1, typename Arg2> inline asio_handler_deallocate_is_deprecated asio_handler_deallocate(void* pointer, std::size_t size, move_binder2<Handler, Arg1, Arg2>* this_handler) { boost_asio_handler_alloc_helpers::deallocate( pointer, size, this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_deallocate_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } template <typename Handler, typename Arg1, typename Arg2> inline bool asio_handler_is_continuation( move_binder2<Handler, Arg1, Arg2>* this_handler) { return boost_asio_handler_cont_helpers::is_continuation( this_handler->handler_); } template <typename Function, typename Handler, typename Arg1, typename Arg2> inline asio_handler_invoke_is_deprecated asio_handler_invoke(BOOST_ASIO_MOVE_ARG(Function) function, move_binder2<Handler, Arg1, Arg2>* this_handler) { boost_asio_handler_invoke_helpers::invoke( BOOST_ASIO_MOVE_CAST(Function)(function), this_handler->handler_); #if defined(BOOST_ASIO_NO_DEPRECATED) return asio_handler_invoke_is_no_longer_used(); #endif // defined(BOOST_ASIO_NO_DEPRECATED) } #endif // defined(BOOST_ASIO_HAS_MOVE) } // namespace detail template <typename Handler, typename Arg1, typename Allocator> struct associated_allocator<detail::binder1<Handler, Arg1>, Allocator> { typedef typename associated_allocator<Handler, Allocator>::type type; static type get(const detail::binder1<Handler, Arg1>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<Handler, Allocator>::get(h.handler_, a); } }; template <typename Handler, typename Arg1, typename Arg2, typename Allocator> struct associated_allocator<detail::binder2<Handler, Arg1, Arg2>, Allocator> { typedef typename associated_allocator<Handler, Allocator>::type type; static type get(const detail::binder2<Handler, Arg1, Arg2>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<Handler, Allocator>::get(h.handler_, a); } }; template <typename Handler, typename Arg1, typename Executor> struct associated_executor<detail::binder1<Handler, Arg1>, Executor> : detail::associated_executor_forwarding_base<Handler, Executor> { typedef typename associated_executor<Handler, Executor>::type type; static type get(const detail::binder1<Handler, Arg1>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<Handler, Executor>::get(h.handler_, ex); } }; template <typename Handler, typename Arg1, typename Arg2, typename Executor> struct associated_executor<detail::binder2<Handler, Arg1, Arg2>, Executor> : detail::associated_executor_forwarding_base<Handler, Executor> { typedef typename associated_executor<Handler, Executor>::type type; static type get(const detail::binder2<Handler, Arg1, Arg2>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<Handler, Executor>::get(h.handler_, ex); } }; #if defined(BOOST_ASIO_HAS_MOVE) template <typename Handler, typename Arg1, typename Allocator> struct associated_allocator<detail::move_binder1<Handler, Arg1>, Allocator> { typedef typename associated_allocator<Handler, Allocator>::type type; static type get(const detail::move_binder1<Handler, Arg1>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<Handler, Allocator>::get(h.handler_, a); } }; template <typename Handler, typename Arg1, typename Arg2, typename Allocator> struct associated_allocator< detail::move_binder2<Handler, Arg1, Arg2>, Allocator> { typedef typename associated_allocator<Handler, Allocator>::type type; static type get(const detail::move_binder2<Handler, Arg1, Arg2>& h, const Allocator& a = Allocator()) BOOST_ASIO_NOEXCEPT { return associated_allocator<Handler, Allocator>::get(h.handler_, a); } }; template <typename Handler, typename Arg1, typename Executor> struct associated_executor<detail::move_binder1<Handler, Arg1>, Executor> : detail::associated_executor_forwarding_base<Handler, Executor> { typedef typename associated_executor<Handler, Executor>::type type; static type get(const detail::move_binder1<Handler, Arg1>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<Handler, Executor>::get(h.handler_, ex); } }; template <typename Handler, typename Arg1, typename Arg2, typename Executor> struct associated_executor<detail::move_binder2<Handler, Arg1, Arg2>, Executor> : detail::associated_executor_forwarding_base<Handler, Executor> { typedef typename associated_executor<Handler, Executor>::type type; static type get(const detail::move_binder2<Handler, Arg1, Arg2>& h, const Executor& ex = Executor()) BOOST_ASIO_NOEXCEPT { return associated_executor<Handler, Executor>::get(h.handler_, ex); } }; #endif // defined(BOOST_ASIO_HAS_MOVE) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_BIND_HANDLER_HPP detail/scoped_lock.hpp 0000644 00000003626 15125530236 0011015 0 ustar 00 // // detail/scoped_lock.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { // Helper class to lock and unlock a mutex automatically. template <typename Mutex> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_SCOPED_LOCK_HPP detail/string_view.hpp 0000644 00000003046 15125530236 0011064 0 ustar 00 // // detail/string_view.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_STRING_VIEW) #if defined(BOOST_ASIO_HAS_STD_STRING_VIEW) # include <string_view> #elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW) # include <experimental/string_view> #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 detail/win_iocp_socket_recvfrom_op.hpp 0000644 00000010452 15125530236 0014303 0 ustar 00 // // detail/win_iocp_socket_recvfrom_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename MutableBufferSequence, typename Endpoint, typename Handler, typename IoExecutor> 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<int>(endpoint.capacity())), cancel_token_(cancel_token), buffers_(buffers), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), work_(handler_, io_ex) { } 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<win_iocp_socket_recvfrom_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) { buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence>::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, boost::system::error_code, std::size_t> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECVFROM_OP_HPP detail/call_stack.hpp 0000644 00000005673 15125530236 0010634 0 ustar 00 // // detail/call_stack.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/tss_ptr.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Key, typename Value = unsigned char> 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<Key, Value>::top_) { value_ = reinterpret_cast<unsigned char*>(this); call_stack<Key, Value>::top_ = this; } // Push the key/value pair on to the stack. context(Key* k, Value& v) : key_(k), value_(&v), next_(call_stack<Key, Value>::top_) { call_stack<Key, Value>::top_ = this; } // Pop the key/value pair from the stack. ~context() { call_stack<Key, Value>::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<Key, Value>; // 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<context> top_; }; template <typename Key, typename Value> tss_ptr<typename call_stack<Key, Value>::context> call_stack<Key, Value>::top_; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_CALL_STACK_HPP detail/op_queue.hpp 0000644 00000006361 15125530236 0010351 0 ustar 00 // // detail/op_queue.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Operation> class op_queue; class op_queue_access { public: template <typename Operation> static Operation* next(Operation* o) { return static_cast<Operation*>(o->next_); } template <typename Operation1, typename Operation2> static void next(Operation1*& o1, Operation2* o2) { o1->next_ = o2; } template <typename Operation> static void destroy(Operation* o) { o->destroy(); } template <typename Operation> static Operation*& front(op_queue<Operation>& q) { return q.front_; } template <typename Operation> static Operation*& back(op_queue<Operation>& q) { return q.back_; } }; template <typename Operation> 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<Operation*>(0)); } } // Push an operation on to the back of the queue. void push(Operation* h) { op_queue_access::next(h, static_cast<Operation*>(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 <typename OtherOperation> void push(op_queue<OtherOperation>& 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_OP_QUEUE_HPP detail/strand_executor_service.hpp 0000644 00000013736 15125530236 0013464 0 ustar 00 // // detail/strand_executor_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/atomic_count.hpp> #include <boost/asio/detail/executor_op.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/scheduler_operation.hpp> #include <boost/asio/detail/scoped_ptr.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { // Default service implementation for a strand. class strand_executor_service : public execution_context_service_base<strand_executor_service> { 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<scheduler_operation> 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<scheduler_operation> 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<strand_impl> 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 <typename Executor, typename Function> static void execute(const implementation_type& impl, Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, typename enable_if< can_query<Executor, execution::allocator_t<void> >::value >::type* = 0); // Request invocation of the given function. template <typename Executor, typename Function> static void execute(const implementation_type& impl, Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, typename enable_if< !can_query<Executor, execution::allocator_t<void> >::value >::type* = 0); // Request invocation of the given function. template <typename Executor, typename Function, typename Allocator> 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 <typename Executor, typename Function, typename Allocator> 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 <typename Executor, typename Function, typename Allocator> 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 <typename F, typename Allocator> class allocator_binder; template <typename Executor, typename = void> 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); // Helper function to request invocation of the given function. template <typename Executor, typename Function, typename Allocator> static void do_execute(const implementation_type& impl, Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a); // 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<mutex> 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 <boost/asio/detail/pop_options.hpp> #include <boost/asio/detail/impl/strand_executor_service.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/strand_executor_service.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_DETAIL_STRAND_EXECUTOR_SERVICE_HPP detail/win_iocp_handle_read_op.hpp 0000644 00000007564 15125530236 0013350 0 ustar 00 // // detail/win_iocp_handle_read_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename MutableBufferSequence, typename Handler, typename IoExecutor> 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)), work_(handler_, io_ex) { } 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<win_iocp_handle_read_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) if (owner) { // Check whether buffers are still valid. buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence>::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, boost::system::error_code, std::size_t> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_READ_OP_HPP detail/win_iocp_socket_accept_op.hpp 0000644 00000023742 15125530236 0013725 0 ustar 00 // // detail/win_iocp_socket_accept_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/win_iocp_socket_service_base.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Socket, typename Protocol, typename Handler, typename IoExecutor> 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)), work_(handler_, io_ex) { } 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<win_iocp_socket_accept_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; 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)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code> 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_; handler_work<Handler, IoExecutor> work_; }; #if defined(BOOST_ASIO_HAS_MOVE) template <typename Protocol, typename PeerIoExecutor, typename Handler, typename IoExecutor> 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)), work_(handler_, io_ex) { } 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<win_iocp_socket_move_accept_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; 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)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code, peer_socket_type> 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<PeerIoExecutor>::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_; handler_work<Handler, IoExecutor> work_; }; #endif // defined(BOOST_ASIO_HAS_MOVE) } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_ACCEPT_OP_HPP detail/functional.hpp 0000644 00000001766 15125530236 0010675 0 ustar 00 // // detail/functional.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <functional> #if !defined(BOOST_ASIO_HAS_STD_FUNCTION) # include <boost/function.hpp> #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 detail/signal_init.hpp 0000644 00000002056 15125530236 0011024 0 ustar 00 // // detail/signal_init.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) #include <csignal> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <int Signal = SIGPIPE> class signal_init { public: // Constructor. signal_init() { std::signal(Signal, SIG_IGN); } }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) #endif // BOOST_ASIO_DETAIL_SIGNAL_INIT_HPP detail/resolver_service.hpp 0000644 00000011266 15125530236 0012110 0 ustar 00 // // detail/resolver_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <boost/asio/ip/basic_resolver_query.hpp> #include <boost/asio/ip/basic_resolver_results.hpp> #include <boost/asio/detail/concurrency_hint.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/resolve_endpoint_op.hpp> #include <boost/asio/detail/resolve_query_op.hpp> #include <boost/asio/detail/resolver_service_base.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Protocol> class resolver_service : public execution_context_service_base<resolver_service<Protocol> >, 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<Protocol> query_type; // The results type. typedef boost::asio::ip::basic_resolver_results<Protocol> results_type; // Constructor. resolver_service(execution_context& context) : execution_context_service_base<resolver_service<Protocol> >(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& qry, boost::system::error_code& ec) { boost::asio::detail::addrinfo_type* address_info = 0; socket_ops::getaddrinfo(qry.host_name().c_str(), qry.service_name().c_str(), qry.hints(), &address_info, ec); auto_addrinfo auto_address_info(address_info); return ec ? results_type() : results_type::create( address_info, qry.host_name(), qry.service_name()); } // Asynchronously resolve a query to a list of entries. template <typename Handler, typename IoExecutor> void async_resolve(implementation_type& impl, const query_type& qry, Handler& handler, const IoExecutor& io_ex) { // Allocate and construct an operation to wrap the handler. typedef resolve_query_op<Protocol, Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl, qry, 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 <typename Handler, typename IoExecutor> 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<Protocol, Handler, IoExecutor> 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 <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_RESOLVER_SERVICE_HPP detail/std_event.hpp 0000644 00000007715 15125530236 0010526 0 ustar 00 // // detail/std_event.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) #include <chrono> #include <condition_variable> #include <boost/asio/detail/assert.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Lock> void signal(Lock& lock) { this->signal_all(lock); } // Signal all waiters. template <typename Lock> 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 <typename Lock> 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(); } // Unlock the mutex and signal one waiter who may destroy us. template <typename Lock> void unlock_and_signal_one_for_destruction(Lock& lock) { BOOST_ASIO_ASSERT(lock.locked()); state_ |= 1; bool have_waiters = (state_ > 1); if (have_waiters) cond_.notify_one(); lock.unlock(); } // If there's a waiter, unlock the mutex and signal it. template <typename Lock> 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 <typename Lock> void clear(Lock& lock) { BOOST_ASIO_ASSERT(lock.locked()); (void)lock; state_ &= ~std::size_t(1); } // Wait for the event to become signalled. template <typename Lock> 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 <typename Lock> 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 <typename Lock> explicit unique_lock_adapter(Lock& lock) : unique_lock_(lock.mutex().mutex_, std::adopt_lock) { } ~unique_lock_adapter() { unique_lock_.release(); } std::unique_lock<std::mutex> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) #endif // BOOST_ASIO_DETAIL_STD_EVENT_HPP detail/win_iocp_thread_info.hpp 0000644 00000001607 15125530236 0012676 0 ustar 00 // // detail/win_iocp_thread_info.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/thread_info_base.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { struct win_iocp_thread_info : public thread_info_base { }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_WIN_IOCP_THREAD_INFO_HPP detail/noncopyable.hpp 0000644 00000001750 15125530236 0011035 0 ustar 00 // // detail/noncopyable.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_NONCOPYABLE_HPP detail/mutex.hpp 0000644 00000002507 15125530236 0007667 0 ustar 00 // // detail/mutex.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_HAS_THREADS) # include <boost/asio/detail/null_mutex.hpp> #elif defined(BOOST_ASIO_WINDOWS) # include <boost/asio/detail/win_mutex.hpp> #elif defined(BOOST_ASIO_HAS_PTHREADS) # include <boost/asio/detail/posix_mutex.hpp> #elif defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) # include <boost/asio/detail/std_mutex.hpp> #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 detail/winrt_timer_scheduler.hpp 0000644 00000011347 15125530236 0013130 0 ustar 00 // // detail/winrt_timer_scheduler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <cstddef> #include <boost/asio/detail/event.hpp> #include <boost/asio/detail/limits.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/thread.hpp> #include <boost/asio/detail/timer_queue_base.hpp> #include <boost/asio/detail/timer_queue_set.hpp> #include <boost/asio/detail/wait_op.hpp> #include <boost/asio/execution_context.hpp> #if defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/win_iocp_io_context.hpp> #else // defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/scheduler.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #if defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/thread.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class winrt_timer_scheduler : public execution_context_service_base<winrt_timer_scheduler> { 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 <typename Time_Traits> void add_timer_queue(timer_queue<Time_Traits>& queue); // Remove a timer queue from the reactor. template <typename Time_Traits> void remove_timer_queue(timer_queue<Time_Traits>& queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template <typename Time_Traits> void schedule_timer(timer_queue<Time_Traits>& queue, const typename Time_Traits::time_type& time, typename timer_queue<Time_Traits>::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 <typename Time_Traits> std::size_t cancel_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); // Move the timer operations associated with the given timer. template <typename Time_Traits> void move_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& to, typename timer_queue<Time_Traits>::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 <boost/asio/detail/pop_options.hpp> #include <boost/asio/detail/impl/winrt_timer_scheduler.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/winrt_timer_scheduler.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_WINRT_TIMER_SCHEDULER_HPP detail/null_mutex.hpp 0000644 00000002347 15125530236 0010723 0 ustar 00 // // detail/null_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_HAS_THREADS) #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/scoped_lock.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class null_mutex : private noncopyable { public: typedef boost::asio::detail::scoped_lock<null_mutex> 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 <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_HAS_THREADS) #endif // BOOST_ASIO_DETAIL_NULL_MUTEX_HPP detail/hash_map.hpp 0000644 00000020227 15125530236 0010304 0 ustar 00 // // detail/hash_map.hpp // ~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <list> #include <utility> #include <boost/asio/detail/assert.hpp> #include <boost/asio/detail/noncopyable.hpp> #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) # include <boost/asio/detail/socket_types.hpp> #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { inline std::size_t calculate_hash_value(int i) { return static_cast<std::size_t>(i); } inline std::size_t calculate_hash_value(void* p) { return reinterpret_cast<std::size_t>(p) + (reinterpret_cast<std::size_t>(p) >> 3); } #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) inline std::size_t calculate_hash_value(SOCKET s) { return static_cast<std::size_t>(s); } #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) // Note: assumes K and V are POD types. template <typename K, typename V> class hash_map : private noncopyable { public: // The type of a value in the map. typedef std::pair<K, V> value_type; // The type of a non-const iterator over the hash map. typedef typename std::list<value_type>::iterator iterator; // The type of a const iterator over the hash map. typedef typename std::list<value_type>::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<iterator, bool> 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<iterator, bool>(buckets_[bucket].last, true); } iterator end_it = buckets_[bucket].last; ++end_it; while (it != end_it) { if (it->first == v.first) return std::pair<iterator, bool>(it, false); ++it; } buckets_[bucket].last = values_insert(end_it, v); ++size_; return std::pair<iterator, bool>(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<value_type> values_; // The list of spare nodes waiting to be recycled. Assumes that POD types only // are stored in the hash map. std::list<value_type> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_HASH_MAP_HPP detail/executor_op.hpp 0000644 00000005055 15125530236 0011062 0 ustar 00 // // detail/executor_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/scheduler_operation.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Handler, typename Alloc, typename Operation = scheduler_operation> class executor_op : public Operation { public: BOOST_ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(executor_op); template <typename H> 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<executor_op*>(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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_EXECUTOR_OP_HPP detail/win_thread.hpp 0000644 00000006241 15125530236 0010650 0 ustar 00 // // detail/win_thread.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS) \ && !defined(BOOST_ASIO_WINDOWS_APP) \ && !defined(UNDER_CE) #include <cstddef> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename T> 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 <typename T> long win_thread_base<T>::terminate_threads_ = 0; class win_thread : private noncopyable, public win_thread_base<win_thread> { public: // Constructor. template <typename Function> win_thread(Function f, unsigned int stack_size = 0) : thread_(0), exit_event_(0) { start_thread(new func<Function>(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 <typename Function> 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/win_thread.ipp> #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 detail/gcc_arm_fenced_block.hpp 0000644 00000004276 15125530236 0012603 0 ustar 00 // // detail/gcc_arm_fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(__GNUC__) && defined(__arm__) #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(__GNUC__) && defined(__arm__) #endif // BOOST_ASIO_DETAIL_GCC_ARM_FENCED_BLOCK_HPP detail/impl/select_reactor.ipp 0000644 00000022210 15125530236 0012456 0 ustar 00 // // detail/impl/select_reactor.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #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 <boost/asio/detail/fd_set_adapter.hpp> #include <boost/asio/detail/select_reactor.hpp> #include <boost/asio/detail/signal_blocker.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/push_options.hpp> 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<select_reactor>(ctx), scheduler_(use_service<scheduler_type>(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; if (thread_) interrupter_.interrupt(); #endif // defined(BOOST_ASIO_HAS_IOCP) lock.unlock(); #if defined(BOOST_ASIO_HAS_IOCP) if (thread_) { thread_->join(); delete thread_; thread_ = 0; } #endif // defined(BOOST_ASIO_HAS_IOCP) op_queue<operation> 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<operation> 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<operation>& 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<int>(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())) { if (!interrupter_.reset()) { lock.lock(); interrupter_.recreate(); } --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<operation> 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<operation> 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 <boost/asio/detail/pop_options.hpp> #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 detail/impl/resolver_service_base.ipp 0000644 00000007463 15125530236 0014050 0 ustar 00 // // detail/impl/resolver_service_base.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/resolver_service_base.hpp> #include <boost/asio/detail/push_options.hpp> 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<scheduler_impl>(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 if (fork_ev != execution_context::fork_prepare) { work_scheduler_->restart(); } } void resolver_service_base::construct( resolver_service_base::implementation_type& impl) { impl.reset(static_cast<void*>(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<void*>(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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_IMPL_RESOLVER_SERVICE_BASE_IPP detail/impl/epoll_reactor.hpp 0000644 00000004607 15125530236 0012323 0 ustar 00 // // detail/impl/epoll_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Time_Traits> void epoll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue) { do_add_timer_queue(queue); } template <typename Time_Traits> void epoll_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue) { do_remove_timer_queue(queue); } template <typename Time_Traits> void epoll_reactor::schedule_timer(timer_queue<Time_Traits>& queue, const typename Time_Traits::time_type& time, typename timer_queue<Time_Traits>::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 <typename Time_Traits> std::size_t epoll_reactor::cancel_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled) { mutex::scoped_lock lock(mutex_); op_queue<operation> ops; std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); lock.unlock(); scheduler_.post_deferred_completions(ops); return n; } template <typename Time_Traits> void epoll_reactor::move_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& target, typename timer_queue<Time_Traits>::per_timer_data& source) { mutex::scoped_lock lock(mutex_); op_queue<operation> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_EPOLL) #endif // BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_HPP detail/impl/descriptor_ops.ipp 0000644 00000035363 15125530236 0012534 0 ustar 00 // // detail/impl/descriptor_ops.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cerrno> #include <boost/asio/detail/descriptor_ops.hpp> #include <boost/asio/error.hpp> #if !defined(BOOST_ASIO_WINDOWS) \ && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ && !defined(__CYGWIN__) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { namespace descriptor_ops { int open(const char* path, int flags, boost::system::error_code& ec) { int result = ::open(path, flags); get_last_error(ec, result < 0); return result; } int close(int d, state_type& state, boost::system::error_code& ec) { int result = 0; if (d != -1) { result = ::close(d); get_last_error(ec, result < 0); 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__) || defined(__EMSCRIPTEN__) int flags = ::fcntl(d, F_GETFL, 0); if (flags >= 0) ::fcntl(d, F_SETFL, flags & ~O_NONBLOCK); #else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) ioctl_arg_type arg = 0; ::ioctl(d, FIONBIO, &arg); #endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) state &= ~non_blocking; result = ::close(d); get_last_error(ec, result < 0); } } 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; } #if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) int result = ::fcntl(d, F_GETFL, 0); get_last_error(ec, result < 0); if (result >= 0) { int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); result = ::fcntl(d, F_SETFL, flag); get_last_error(ec, result < 0); } #else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) ioctl_arg_type arg = (value ? 1 : 0); int result = ::ioctl(d, FIONBIO, &arg); get_last_error(ec, result < 0); #endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) if (result >= 0) { 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; } #if defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) int result = ::fcntl(d, F_GETFL, 0); get_last_error(ec, result < 0); if (result >= 0) { int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); result = ::fcntl(d, F_SETFL, flag); get_last_error(ec, result < 0); } #else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) ioctl_arg_type arg = (value ? 1 : 0); int result = ::ioctl(d, FIONBIO, &arg); get_last_error(ec, result < 0); #endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) if (result >= 0) { 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.assign(0, ec.category()); return 0; } // Read some data. for (;;) { // Try to complete the operation without blocking. signed_size_type bytes = ::readv(d, bufs, static_cast<int>(count)); get_last_error(ec, bytes < 0); // 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; } } std::size_t sync_read1(int d, state_type state, void* data, std::size_t size, 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 (size == 0) { ec.assign(0, ec.category()); return 0; } // Read some data. for (;;) { // Try to complete the operation without blocking. signed_size_type bytes = ::read(d, data, size); get_last_error(ec, bytes < 0); // 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. signed_size_type bytes = ::readv(d, bufs, static_cast<int>(count)); get_last_error(ec, bytes < 0); // Check for end of stream. if (bytes == 0) { ec = boost::asio::error::eof; return true; } // Check if operation succeeded. if (bytes > 0) { bytes_transferred = bytes; 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 failed. bytes_transferred = 0; return true; } } bool non_blocking_read1(int d, void* data, std::size_t size, boost::system::error_code& ec, std::size_t& bytes_transferred) { for (;;) { // Read some data. signed_size_type bytes = ::read(d, data, size); get_last_error(ec, bytes < 0); // Check for end of stream. if (bytes == 0) { ec = boost::asio::error::eof; return true; } // Check if operation succeeded. if (bytes > 0) { bytes_transferred = bytes; 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 failed. 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.assign(0, ec.category()); return 0; } // Write some data. for (;;) { // Try to complete the operation without blocking. signed_size_type bytes = ::writev(d, bufs, static_cast<int>(count)); get_last_error(ec, bytes < 0); // 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; } } std::size_t sync_write1(int d, state_type state, const void* data, std::size_t size, 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 (size == 0) { ec.assign(0, ec.category()); return 0; } // Write some data. for (;;) { // Try to complete the operation without blocking. signed_size_type bytes = ::write(d, data, size); get_last_error(ec, bytes < 0); // 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. signed_size_type bytes = ::writev(d, bufs, static_cast<int>(count)); get_last_error(ec, bytes < 0); // Check if operation succeeded. if (bytes >= 0) { bytes_transferred = bytes; 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 failed. bytes_transferred = 0; return true; } } bool non_blocking_write1(int d, const void* data, std::size_t size, boost::system::error_code& ec, std::size_t& bytes_transferred) { for (;;) { // Write some data. signed_size_type bytes = ::write(d, data, size); get_last_error(ec, bytes < 0); // Check if operation succeeded. if (bytes >= 0) { bytes_transferred = bytes; 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 failed. 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; } int result = ::ioctl(d, cmd, arg); get_last_error(ec, result < 0); if (result >= 0) { // 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<long>(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; } int result = ::fcntl(d, cmd); get_last_error(ec, result < 0); 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; } int result = ::fcntl(d, cmd, arg); get_last_error(ec, result < 0); 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; int result = ::poll(&fds, 1, timeout); get_last_error(ec, result < 0); if (result == 0) if (state & user_set_non_blocking) ec = boost::asio::error::would_block; 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; int result = ::poll(&fds, 1, timeout); get_last_error(ec, result < 0); if (result == 0) if (state & user_set_non_blocking) ec = boost::asio::error::would_block; 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; int result = ::poll(&fds, 1, timeout); get_last_error(ec, result < 0); if (result == 0) if (state & user_set_non_blocking) ec = boost::asio::error::would_block; return result; } } // namespace descriptor_ops } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_WINDOWS) // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) // && !defined(__CYGWIN__) #endif // BOOST_ASIO_DETAIL_IMPL_DESCRIPTOR_OPS_IPP detail/impl/timer_queue_ptime.ipp 0000644 00000004552 15125530236 0013213 0 ustar 00 // // detail/impl/timer_queue_ptime.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) #include <boost/asio/detail/timer_queue_ptime.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { timer_queue<time_traits<boost::posix_time::ptime> >::timer_queue() { } timer_queue<time_traits<boost::posix_time::ptime> >::~timer_queue() { } bool timer_queue<time_traits<boost::posix_time::ptime> >::enqueue_timer( const time_type& time, per_timer_data& timer, wait_op* op) { return impl_.enqueue_timer(time, timer, op); } bool timer_queue<time_traits<boost::posix_time::ptime> >::empty() const { return impl_.empty(); } long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_msec( long max_duration) const { return impl_.wait_duration_msec(max_duration); } long timer_queue<time_traits<boost::posix_time::ptime> >::wait_duration_usec( long max_duration) const { return impl_.wait_duration_usec(max_duration); } void timer_queue<time_traits<boost::posix_time::ptime> >::get_ready_timers( op_queue<operation>& ops) { impl_.get_ready_timers(ops); } void timer_queue<time_traits<boost::posix_time::ptime> >::get_all_timers( op_queue<operation>& ops) { impl_.get_all_timers(ops); } std::size_t timer_queue<time_traits<boost::posix_time::ptime> >::cancel_timer( per_timer_data& timer, op_queue<operation>& ops, std::size_t max_cancelled) { return impl_.cancel_timer(timer, ops, max_cancelled); } void timer_queue<time_traits<boost::posix_time::ptime> >::move_timer( per_timer_data& target, per_timer_data& source) { impl_.move_timer(target, source); } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) #endif // BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_PTIME_IPP detail/impl/win_iocp_io_context.ipp 0000644 00000040372 15125530236 0013533 0 ustar 00 // // detail/impl/win_iocp_io_context.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/error.hpp> #include <boost/asio/detail/cstdint.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/limits.hpp> #include <boost/asio/detail/thread.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/win_iocp_io_context.hpp> #include <boost/asio/detail/push_options.hpp> 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<win_iocp_io_context>(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<DWORD>(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()) { stop(); 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()) { stop(); thread_->join(); thread_.reset(); ::InterlockedDecrement(&outstanding_work_); } while (::InterlockedExchangeAdd(&outstanding_work_, 0) > 0) { op_queue<win_iocp_operation> 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<win_iocp_operation*>(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, this_thread, ec)) if (n != (std::numeric_limits<size_t>::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, this_thread, 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), this_thread, 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, this_thread, ec)) if (n != (std::numeric_limits<size_t>::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, this_thread, 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::capture_current_exception() { if (thread_info_base* this_thread = thread_call_stack::contains(this)) this_thread->capture_current_exception(); } 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<win_iocp_operation>& 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<win_iocp_operation>& 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<ulong_ptr_t>( &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<ulong_ptr_t>(&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, win_iocp_thread_info& this_thread, 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<win_iocp_operation> 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<win_iocp_operation*>(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<int>(op->Offset), *reinterpret_cast<boost::system::error_category*>(op->Internal)); bytes_transferred = op->OffsetHigh; } // Otherwise ensure any result has been saved into the OVERLAPPED // structure. else { op->Internal = reinterpret_cast<ulong_ptr_t>(&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); this_thread.rethrow_pending_exception(); 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_IPP detail/impl/strand_executor_service.hpp 0000644 00000026462 15125530236 0014425 0 ustar 00 // // detail/impl/strand_executor_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/call_stack.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/recycling_allocator.hpp> #include <boost/asio/executor_work_guard.hpp> #include <boost/asio/defer.hpp> #include <boost/asio/dispatch.hpp> #include <boost/asio/post.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename F, typename Allocator> class strand_executor_service::allocator_binder { public: typedef Allocator allocator_type; allocator_binder(BOOST_ASIO_MOVE_ARG(F) f, const Allocator& a) : f_(BOOST_ASIO_MOVE_CAST(F)(f)), allocator_(a) { } allocator_binder(const allocator_binder& other) : f_(other.f_), allocator_(other.allocator_) { } #if defined(BOOST_ASIO_HAS_MOVE) allocator_binder(allocator_binder&& other) : f_(BOOST_ASIO_MOVE_CAST(F)(other.f_)), allocator_(BOOST_ASIO_MOVE_CAST(allocator_type)(other.allocator_)) { } #endif // defined(BOOST_ASIO_HAS_MOVE) allocator_type get_allocator() const BOOST_ASIO_NOEXCEPT { return allocator_; } void operator()() { f_(); } private: F f_; allocator_type allocator_; }; template <typename Executor> class strand_executor_service::invoker<Executor, typename enable_if< execution::is_executor<Executor>::value >::type> { public: invoker(const implementation_type& impl, Executor& ex) : impl_(impl), executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) { } invoker(const invoker& other) : impl_(other.impl_), executor_(other.executor_) { } #if defined(BOOST_ASIO_HAS_MOVE) invoker(invoker&& other) : impl_(BOOST_ASIO_MOVE_CAST(implementation_type)(other.impl_)), executor_(BOOST_ASIO_MOVE_CAST(executor_type)(other.executor_)) { } #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) { recycling_allocator<void> allocator; execution::execute( boost::asio::prefer( boost::asio::require(this_->executor_, execution::blocking.never), execution::allocator(allocator)), BOOST_ASIO_MOVE_CAST(invoker)(*this_)); } } }; void operator()() { // Indicate that this strand is executing on the current thread. call_stack<strand_impl>::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: typedef typename decay< typename prefer_result< Executor, execution::outstanding_work_t::tracked_t >::type >::type executor_type; implementation_type impl_; executor_type executor_; }; #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) template <typename Executor> class strand_executor_service::invoker<Executor, typename enable_if< !execution::is_executor<Executor>::value >::type> { 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<Executor>)(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<void> allocator; ex.post(BOOST_ASIO_MOVE_CAST(invoker)(*this_), allocator); } } }; void operator()() { // Indicate that this strand is executing on the current thread. call_stack<strand_impl>::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<Executor> work_; }; #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) template <typename Executor, typename Function> inline void strand_executor_service::execute(const implementation_type& impl, Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, typename enable_if< can_query<Executor, execution::allocator_t<void> >::value >::type*) { return strand_executor_service::do_execute(impl, ex, BOOST_ASIO_MOVE_CAST(Function)(function), boost::asio::query(ex, execution::allocator)); } template <typename Executor, typename Function> inline void strand_executor_service::execute(const implementation_type& impl, Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, typename enable_if< !can_query<Executor, execution::allocator_t<void> >::value >::type*) { return strand_executor_service::do_execute(impl, ex, BOOST_ASIO_MOVE_CAST(Function)(function), std::allocator<void>()); } template <typename Executor, typename Function, typename Allocator> void strand_executor_service::do_execute(const implementation_type& impl, Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a) { typedef typename decay<Function>::type function_type; // If the executor is not never-blocking, and we are already in the strand, // then the function can run immediately. if (boost::asio::query(ex, execution::blocking) != execution::blocking.never && call_stack<strand_impl>::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<function_type, Allocator> 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, "execute")); // 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) { execution::execute(ex, invoker<Executor>(impl, ex)); } } template <typename Executor, typename Function, typename Allocator> void strand_executor_service::dispatch(const implementation_type& impl, Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a) { typedef typename decay<Function>::type function_type; // If we are already in the strand then the function can run immediately. if (call_stack<strand_impl>::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<function_type, Allocator> 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) { boost::asio::dispatch(ex, allocator_binder<invoker<Executor>, Allocator>( invoker<Executor>(impl, ex), a)); } } // Request invocation of the given function and return immediately. template <typename Executor, typename Function, typename Allocator> void strand_executor_service::post(const implementation_type& impl, Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a) { typedef typename decay<Function>::type function_type; // Allocate and construct an operation to wrap the function. typedef executor_op<function_type, Allocator> 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) { boost::asio::post(ex, allocator_binder<invoker<Executor>, Allocator>( invoker<Executor>(impl, ex), a)); } } // Request invocation of the given function and return immediately. template <typename Executor, typename Function, typename Allocator> void strand_executor_service::defer(const implementation_type& impl, Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const Allocator& a) { typedef typename decay<Function>::type function_type; // Allocate and construct an operation to wrap the function. typedef executor_op<function_type, Allocator> 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) { boost::asio::defer(ex, allocator_binder<invoker<Executor>, Allocator>( invoker<Executor>(impl, ex), a)); } } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_HPP detail/impl/eventfd_select_interrupter.ipp 0000644 00000011243 15125530236 0015121 0 ustar 00 // // detail/impl/eventfd_select_interrupter.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_EVENTFD) #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__) # include <asm/unistd.h> #else // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__) # include <sys/eventfd.h> #endif // __GLIBC__ == 2 && __GLIBC_MINOR__ < 8 && !defined(__UCLIBC__) #include <boost/asio/detail/cstdint.hpp> #include <boost/asio/detail/eventfd_select_interrupter.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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 && !defined(__UCLIBC__) 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 && !defined(__UCLIBC__) # 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 && !defined(__UCLIBC__) 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; return true; } } else { for (;;) { // Clear all data from the pipe. char data[1024]; int bytes_read = ::read(read_descriptor_, data, sizeof(data)); if (bytes_read == sizeof(data)) continue; if (bytes_read > 0) return true; if (bytes_read == 0) return false; if (errno == EINTR) continue; if (errno == EWOULDBLOCK) return true; if (errno == EAGAIN) return true; return false; } } } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_EVENTFD) #endif // BOOST_ASIO_DETAIL_IMPL_EVENTFD_SELECT_INTERRUPTER_IPP detail/impl/strand_executor_service.ipp 0000644 00000007065 15125530236 0014424 0 ustar 00 // // detail/impl/strand_executor_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/strand_executor_service.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { strand_executor_service::strand_executor_service(execution_context& ctx) : execution_context_service_base<strand_executor_service>(ctx), mutex_(), salt_(0), impl_list_(0) { } void strand_executor_service::shutdown() { op_queue<scheduler_operation> 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<std::size_t>(new_impl.get()); mutex_index += (reinterpret_cast<std::size_t>(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<strand_impl>::contains(impl.get()); } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_IMPL_STRAND_EXECUTOR_SERVICE_IPP detail/impl/winrt_timer_scheduler.hpp 0000644 00000005150 15125530236 0014064 0 ustar 00 // // detail/impl/winrt_timer_scheduler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Time_Traits> void winrt_timer_scheduler::add_timer_queue(timer_queue<Time_Traits>& queue) { do_add_timer_queue(queue); } // Remove a timer queue from the reactor. template <typename Time_Traits> void winrt_timer_scheduler::remove_timer_queue(timer_queue<Time_Traits>& queue) { do_remove_timer_queue(queue); } template <typename Time_Traits> void winrt_timer_scheduler::schedule_timer(timer_queue<Time_Traits>& queue, const typename Time_Traits::time_type& time, typename timer_queue<Time_Traits>::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 <typename Time_Traits> std::size_t winrt_timer_scheduler::cancel_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled) { boost::asio::detail::mutex::scoped_lock lock(mutex_); op_queue<operation> ops; std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); lock.unlock(); scheduler_.post_deferred_completions(ops); return n; } template <typename Time_Traits> void winrt_timer_scheduler::move_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& to, typename timer_queue<Time_Traits>::per_timer_data& from) { boost::asio::detail::mutex::scoped_lock lock(mutex_); op_queue<operation> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_HPP detail/impl/reactive_serial_port_service.ipp 0000644 00000010266 15125530236 0015415 0 ustar 00 // // detail/impl/reactive_serial_port_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_SERIAL_PORT) #if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) #include <cstring> #include <boost/asio/detail/reactive_serial_port_service.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { reactive_serial_port_service::reactive_serial_port_service( execution_context& context) : execution_context_service_base<reactive_serial_port_service>(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; s = ::tcgetattr(fd, &ios); descriptor_ops::get_last_error(ec, s < 0); 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; s = ::tcsetattr(fd, TCSANOW, &ios); descriptor_ops::get_last_error(ec, s < 0); } 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; int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios); descriptor_ops::get_last_error(ec, s < 0); if (s < 0) return ec; if (store(option, ios, ec)) return ec; s = ::tcsetattr(descriptor_service_.native_handle(impl), TCSANOW, &ios); descriptor_ops::get_last_error(ec, s < 0); 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; int s = ::tcgetattr(descriptor_service_.native_handle(impl), &ios); descriptor_ops::get_last_error(ec, s < 0); if (s < 0) return ec; return load(option, ios, ec); } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) #endif // defined(BOOST_ASIO_HAS_SERIAL_PORT) #endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SERIAL_PORT_SERVICE_IPP detail/impl/posix_thread.ipp 0000644 00000003654 15125530236 0012164 0 ustar 00 // // detail/impl/posix_thread.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_PTHREADS) #include <boost/asio/detail/posix_thread.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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<posix_thread::func_base*>(arg) }; func.ptr->run(); return 0; } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_PTHREADS) #endif // BOOST_ASIO_DETAIL_IMPL_POSIX_THREAD_IPP detail/impl/epoll_reactor.ipp 0000644 00000053544 15125530236 0012330 0 ustar 00 // // detail/impl/epoll_reactor.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_EPOLL) #include <cstddef> #include <sys/epoll.h> #include <boost/asio/detail/epoll_reactor.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #if defined(BOOST_ASIO_HAS_TIMERFD) # include <sys/timerfd.h> #endif // defined(BOOST_ASIO_HAS_TIMERFD) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { epoll_reactor::epoll_reactor(boost::asio::execution_context& ctx) : execution_context_service_base<epoll_reactor>(ctx), scheduler_(use_service<scheduler>(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<operation> 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<uintmax_t>(descriptor), reinterpret_cast<uintmax_t>(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<uintmax_t>(descriptor), reinterpret_cast<uintmax_t>(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<operation> 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<operation> 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<uintmax_t>(descriptor), reinterpret_cast<uintmax_t>(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<operation> 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<uintmax_t>(descriptor), reinterpret_cast<uintmax_t>(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<operation>& 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<uintmax_t>(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<descriptor_state*>(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<operation> 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<descriptor_state*>(base); uint32_t events = static_cast<uint32_t>(bytes_transferred); if (operation* op = descriptor_data->perform_io(events)) { op->complete(owner, ec, 0); } } } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_EPOLL) #endif // BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP detail/impl/service_registry.hpp 0000644 00000005134 15125530236 0013055 0 ustar 00 // // detail/impl/service_registry.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Service> Service& service_registry::use_service() { execution_context::service::key key; init_key<Service>(key, 0); factory_type factory = &service_registry::create<Service, execution_context>; return *static_cast<Service*>(do_use_service(key, factory, &owner_)); } template <typename Service> Service& service_registry::use_service(io_context& owner) { execution_context::service::key key; init_key<Service>(key, 0); factory_type factory = &service_registry::create<Service, io_context>; return *static_cast<Service*>(do_use_service(key, factory, &owner)); } template <typename Service> void service_registry::add_service(Service* new_service) { execution_context::service::key key; init_key<Service>(key, 0); return do_add_service(key, new_service); } template <typename Service> bool service_registry::has_service() const { execution_context::service::key key; init_key<Service>(key, 0); return do_has_service(key); } template <typename Service> 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 <typename Service> void service_registry::init_key(execution_context::service::key& key, typename enable_if< is_base_of<typename Service::key_type, Service>::value>::type*) { key.type_info_ = &typeid(typeid_wrapper<Service>); key.id_ = 0; } template <typename Service> void service_registry::init_key_from_id(execution_context::service::key& key, const service_id<Service>& /*id*/) { key.type_info_ = &typeid(typeid_wrapper<Service>); key.id_ = 0; } #endif // !defined(BOOST_ASIO_NO_TYPEID) template <typename Service, typename Owner> execution_context::service* service_registry::create(void* owner) { return new Service(*static_cast<Owner*>(owner)); } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_HPP detail/impl/scheduler.ipp 0000644 00000037024 15125530236 0011447 0 ustar 00 // // detail/impl/scheduler.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/concurrency_hint.hpp> #include <boost/asio/detail/event.hpp> #include <boost/asio/detail/limits.hpp> #include <boost/asio/detail/reactor.hpp> #include <boost/asio/detail/scheduler.hpp> #include <boost/asio/detail/scheduler_thread_info.hpp> #include <boost/asio/detail/signal_blocker.hpp> #include <boost/asio/detail/push_options.hpp> 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<scheduler>(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_) { mutex::scoped_lock lock(mutex_); shutdown_ = true; stop_all_threads(lock); lock.unlock(); 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<reactor>(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<std::size_t>::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<thread_info*>(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<std::size_t>::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<thread_info*>(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<thread_info*>(this_thread)->private_outstanding_work; } void scheduler::capture_current_exception() { if (thread_info_base* this_thread = thread_call_stack::contains(this)) this_thread->capture_current_exception(); } 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<thread_info*>(this_thread)->private_outstanding_work; static_cast<thread_info*>(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_immediate_completions(std::size_t n, op_queue<scheduler::operation>& ops, 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<thread_info*>(this_thread)->private_outstanding_work += static_cast<long>(n); static_cast<thread_info*>(this_thread)->private_op_queue.push(ops); return; } } #else // defined(BOOST_ASIO_HAS_THREADS) (void)is_continuation; #endif // defined(BOOST_ASIO_HAS_THREADS) increment(outstanding_work_, static_cast<long>(n)); mutex::scoped_lock lock(mutex_); op_queue_.push(ops); 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<thread_info*>(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<scheduler::operation>& 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<thread_info*>(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<scheduler::operation>& ops) { op_queue<scheduler::operation> 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); this_thread.rethrow_pending_exception(); 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); this_thread.rethrow_pending_exception(); 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); this_thread.rethrow_pending_exception(); 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_IMPL_SCHEDULER_IPP detail/impl/winsock_init.ipp 0000644 00000004002 15125530236 0012157 0 ustar 00 // // detail/impl/winsock_init.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/winsock_init.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) #endif // BOOST_ASIO_DETAIL_IMPL_WINSOCK_INIT_IPP detail/impl/win_iocp_io_context.hpp 0000644 00000005743 15125530236 0013535 0 ustar 00 // // detail/impl/win_iocp_io_context.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/completion_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Time_Traits> void win_iocp_io_context::add_timer_queue( timer_queue<Time_Traits>& queue) { do_add_timer_queue(queue); } template <typename Time_Traits> void win_iocp_io_context::remove_timer_queue( timer_queue<Time_Traits>& queue) { do_remove_timer_queue(queue); } template <typename Time_Traits> void win_iocp_io_context::schedule_timer(timer_queue<Time_Traits>& queue, const typename Time_Traits::time_type& time, typename timer_queue<Time_Traits>::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 <typename Time_Traits> std::size_t win_iocp_io_context::cancel_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::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<win_iocp_operation> ops; std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); lock.unlock(); post_deferred_completions(ops); return n; } template <typename Time_Traits> void win_iocp_io_context::move_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& to, typename timer_queue<Time_Traits>::per_timer_data& from) { boost::asio::detail::mutex::scoped_lock lock(dispatch_mutex_); op_queue<operation> ops; queue.cancel_timer(to, ops); queue.move_timer(to, from); lock.unlock(); post_deferred_completions(ops); } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_IO_CONTEXT_HPP detail/impl/reactive_socket_service_base.ipp 0000644 00000021142 15125530236 0015347 0 ustar 00 // // detail/reactive_socket_service_base.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_HAS_IOCP) \ && !defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <boost/asio/detail/reactive_socket_service_base.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { reactive_socket_service_base::reactive_socket_service_base( execution_context& context) : reactor_(use_service<reactor>(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) BOOST_ASIO_NOEXCEPT { 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 <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_HAS_IOCP) // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_SOCKET_SERVICE_BASE_IPP detail/impl/signal_set_service.ipp 0000644 00000047630 15125530236 0013345 0 ustar 00 // // detail/impl/signal_set_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstring> #include <stdexcept> #include <boost/asio/detail/reactor.hpp> #include <boost/asio/detail/signal_blocker.hpp> #include <boost/asio/detail/signal_set_service.hpp> #include <boost/asio/detail/static_mutex.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/detail/push_options.hpp> 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(boost::system::error_code(), &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<pipe_read_op*>(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<signal_set_service>(context), scheduler_(boost::asio::use_service<scheduler_impl>(context)), #if !defined(BOOST_ASIO_WINDOWS) \ && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ && !defined(__CYGWIN__) reactor_(boost::asio::use_service<reactor>(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<operation> 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<operation> 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<operation> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_IMPL_SIGNAL_SET_SERVICE_IPP detail/impl/handler_tracking.ipp 0000644 00000027006 15125530236 0012767 0 ustar 00 // // detail/impl/handler_tracking.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #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 <cstdarg> #include <cstdio> #include <boost/asio/detail/handler_tracking.hpp> #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) # include <boost/asio/time_traits.hpp> #elif defined(BOOST_ASIO_HAS_CHRONO) # include <boost/asio/detail/chrono.hpp> # include <boost/asio/detail/chrono_time_traits.hpp> # include <boost/asio/wait_traits.hpp> #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) #if defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <boost/asio/detail/socket_types.hpp> #elif !defined(BOOST_ASIO_WINDOWS) # include <unistd.h> #endif // !defined(BOOST_ASIO_WINDOWS) #include <boost/asio/detail/push_options.hpp> 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<chrono::system_clock, boost::asio::wait_traits<chrono::system_clock> > traits_helper; traits_helper::posix_time_duration now( chrono::system_clock::now().time_since_epoch()); #endif seconds = static_cast<uint64_t>(now.total_seconds()); microseconds = static_cast<uint64_t>(now.total_microseconds() % 1000000); } }; struct handler_tracking::tracking_state { static_mutex mutex_; uint64_t next_id_; tss_ptr<completion>* current_completion_; tss_ptr<location>* current_location_; }; handler_tracking::tracking_state* handler_tracking::get_state() { static tracking_state state = { BOOST_ASIO_STATIC_MUTEX_INIT, 1, 0, 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<completion>; if (state->current_location_ == 0) state->current_location_ = new tss_ptr<location>; } handler_tracking::location::location( const char* file, int line, const char* func) : file_(file), line_(line), func_(func), next_(*get_state()->current_location_) { if (file_) *get_state()->current_location_ = this; } handler_tracking::location::~location() { if (file_) *get_state()->current_location_ = next_; } 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_; for (location* current_location = *state->current_location_; current_location; current_location = current_location->next_) { write_line( #if defined(BOOST_ASIO_WINDOWS) "@asio|%I64u.%06I64u|%I64u^%I64u|%s%s%.80s%s(%.80s:%d)\n", #else // defined(BOOST_ASIO_WINDOWS) "@asio|%llu.%06llu|%llu^%llu|%s%s%.80s%s(%.80s:%d)\n", #endif // defined(BOOST_ASIO_WINDOWS) timestamp.seconds, timestamp.microseconds, current_id, h.id_, current_location == *state->current_location_ ? "in " : "called from ", current_location->func_ ? "'" : "", current_location->func_ ? current_location->func_ : "", current_location->func_ ? "' " : "", current_location->file_, current_location->line_); } 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<uint64_t>(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<uint64_t>(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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) #endif // BOOST_ASIO_DETAIL_IMPL_HANDLER_TRACKING_IPP detail/impl/strand_service.hpp 0000644 00000006766 15125530236 0012514 0 ustar 00 // // detail/impl/strand_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/call_stack.hpp> #include <boost/asio/detail/completion_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/push_options.hpp> 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_impl_; 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_impl_->post_immediate_completion(impl_, false); } }; template <typename Handler> 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<strand_impl>::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<Handler, io_context::executor_type> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler, io_context_.get_executor()); 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<strand_impl>::context ctx(impl); // Ensure the next handler, if any, is scheduled on block exit. on_dispatch_exit on_exit = { &io_context_impl_, impl }; (void)on_exit; op::do_complete(&io_context_impl_, o, boost::system::error_code(), 0); } } // Request the io_context to invoke the given handler and return immediately. template <typename Handler> 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<Handler, io_context::executor_type> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler, io_context_.get_executor()); 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_HPP detail/impl/winrt_ssocket_service_base.ipp 0000644 00000042151 15125530236 0015076 0 ustar 00 // // detail/impl/winrt_ssocket_service_base.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_SSOCKET_SERVICE_BASE_IPP #define BOOST_ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <cstring> #include <boost/asio/detail/winrt_ssocket_service_base.hpp> #include <boost/asio/detail/winrt_async_op.hpp> #include <boost/asio/detail/winrt_utils.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { winrt_ssocket_service_base::winrt_ssocket_service_base( execution_context& context) : scheduler_(use_service<scheduler_impl>(context)), async_manager_(use_service<winrt_async_manager>(context)), mutex_(), impl_list_(0) { } void winrt_ssocket_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) { boost::system::error_code ignored_ec; close(*impl, ignored_ec); impl = impl->next_; } } void winrt_ssocket_service_base::construct( winrt_ssocket_service_base::base_implementation_type& impl) { // 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 winrt_ssocket_service_base::base_move_construct( winrt_ssocket_service_base::base_implementation_type& impl, winrt_ssocket_service_base::base_implementation_type& other_impl) BOOST_ASIO_NOEXCEPT { impl.socket_ = other_impl.socket_; other_impl.socket_ = nullptr; // 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 winrt_ssocket_service_base::base_move_assign( winrt_ssocket_service_base::base_implementation_type& impl, winrt_ssocket_service_base& other_service, winrt_ssocket_service_base::base_implementation_type& other_impl) { boost::system::error_code ignored_ec; close(impl, ignored_ec); 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_ = nullptr; 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 winrt_ssocket_service_base::destroy( winrt_ssocket_service_base::base_implementation_type& impl) { boost::system::error_code ignored_ec; close(impl, ignored_ec); // 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 winrt_ssocket_service_base::close( winrt_ssocket_service_base::base_implementation_type& impl, boost::system::error_code& ec) { delete impl.socket_; impl.socket_ = nullptr; ec = boost::system::error_code(); return ec; } winrt_ssocket_service_base::native_handle_type winrt_ssocket_service_base::release( winrt_ssocket_service_base::base_implementation_type& impl, boost::system::error_code& ec) { if (!is_open(impl)) return nullptr; cancel(impl, ec); if (ec) return nullptr; native_handle_type tmp = impl.socket_; impl.socket_ = nullptr; return tmp; } std::size_t winrt_ssocket_service_base::do_get_endpoint( const base_implementation_type& impl, bool local, void* addr, std::size_t addr_len, boost::system::error_code& ec) const { if (!is_open(impl)) { ec = boost::asio::error::bad_descriptor; return addr_len; } try { std::string addr_string = winrt_utils::string(local ? impl.socket_->Information->LocalAddress->CanonicalName : impl.socket_->Information->RemoteAddress->CanonicalName); unsigned short port = winrt_utils::integer(local ? impl.socket_->Information->LocalPort : impl.socket_->Information->RemotePort); unsigned long scope = 0; switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family) { case BOOST_ASIO_OS_DEF(AF_INET): if (addr_len < sizeof(sockaddr_in4_type)) { ec = boost::asio::error::invalid_argument; return addr_len; } else { socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET), addr_string.c_str(), &reinterpret_cast<sockaddr_in4_type*>(addr)->sin_addr, &scope, ec); reinterpret_cast<sockaddr_in4_type*>(addr)->sin_port = socket_ops::host_to_network_short(port); ec = boost::system::error_code(); return sizeof(sockaddr_in4_type); } case BOOST_ASIO_OS_DEF(AF_INET6): if (addr_len < sizeof(sockaddr_in6_type)) { ec = boost::asio::error::invalid_argument; return addr_len; } else { socket_ops::inet_pton(BOOST_ASIO_OS_DEF(AF_INET6), addr_string.c_str(), &reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_addr, &scope, ec); reinterpret_cast<sockaddr_in6_type*>(addr)->sin6_port = socket_ops::host_to_network_short(port); ec = boost::system::error_code(); return sizeof(sockaddr_in6_type); } default: ec = boost::asio::error::address_family_not_supported; return addr_len; } } catch (Platform::Exception^ e) { ec = boost::system::error_code(e->HResult, boost::system::system_category()); return addr_len; } } boost::system::error_code winrt_ssocket_service_base::do_set_option( winrt_ssocket_service_base::base_implementation_type& impl, int level, int optname, const void* optval, std::size_t optlen, boost::system::error_code& ec) { if (!is_open(impl)) { ec = boost::asio::error::bad_descriptor; return ec; } try { if (level == BOOST_ASIO_OS_DEF(SOL_SOCKET) && optname == BOOST_ASIO_OS_DEF(SO_KEEPALIVE)) { if (optlen == sizeof(int)) { int value = 0; std::memcpy(&value, optval, optlen); impl.socket_->Control->KeepAlive = !!value; ec = boost::system::error_code(); } else { ec = boost::asio::error::invalid_argument; } } else if (level == BOOST_ASIO_OS_DEF(IPPROTO_TCP) && optname == BOOST_ASIO_OS_DEF(TCP_NODELAY)) { if (optlen == sizeof(int)) { int value = 0; std::memcpy(&value, optval, optlen); impl.socket_->Control->NoDelay = !!value; ec = boost::system::error_code(); } else { ec = boost::asio::error::invalid_argument; } } else { ec = boost::asio::error::invalid_argument; } } catch (Platform::Exception^ e) { ec = boost::system::error_code(e->HResult, boost::system::system_category()); } return ec; } void winrt_ssocket_service_base::do_get_option( const winrt_ssocket_service_base::base_implementation_type& impl, int level, int optname, void* optval, std::size_t* optlen, boost::system::error_code& ec) const { if (!is_open(impl)) { ec = boost::asio::error::bad_descriptor; return; } try { if (level == BOOST_ASIO_OS_DEF(SOL_SOCKET) && optname == BOOST_ASIO_OS_DEF(SO_KEEPALIVE)) { if (*optlen >= sizeof(int)) { int value = impl.socket_->Control->KeepAlive ? 1 : 0; std::memcpy(optval, &value, sizeof(int)); *optlen = sizeof(int); ec = boost::system::error_code(); } else { ec = boost::asio::error::invalid_argument; } } else if (level == BOOST_ASIO_OS_DEF(IPPROTO_TCP) && optname == BOOST_ASIO_OS_DEF(TCP_NODELAY)) { if (*optlen >= sizeof(int)) { int value = impl.socket_->Control->NoDelay ? 1 : 0; std::memcpy(optval, &value, sizeof(int)); *optlen = sizeof(int); ec = boost::system::error_code(); } else { ec = boost::asio::error::invalid_argument; } } else { ec = boost::asio::error::invalid_argument; } } catch (Platform::Exception^ e) { ec = boost::system::error_code(e->HResult, boost::system::system_category()); } } boost::system::error_code winrt_ssocket_service_base::do_connect( winrt_ssocket_service_base::base_implementation_type& impl, const void* addr, boost::system::error_code& ec) { if (!is_open(impl)) { ec = boost::asio::error::bad_descriptor; return ec; } char addr_string[max_addr_v6_str_len]; unsigned short port; switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family) { case BOOST_ASIO_OS_DEF(AF_INET): socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET), &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr, addr_string, sizeof(addr_string), 0, ec); port = socket_ops::network_to_host_short( reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port); break; case BOOST_ASIO_OS_DEF(AF_INET6): socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET6), &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr, addr_string, sizeof(addr_string), 0, ec); port = socket_ops::network_to_host_short( reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port); break; default: ec = boost::asio::error::address_family_not_supported; return ec; } if (!ec) try { async_manager_.sync(impl.socket_->ConnectAsync( ref new Windows::Networking::HostName( winrt_utils::string(addr_string)), winrt_utils::string(port)), ec); } catch (Platform::Exception^ e) { ec = boost::system::error_code(e->HResult, boost::system::system_category()); } return ec; } void winrt_ssocket_service_base::start_connect_op( winrt_ssocket_service_base::base_implementation_type& impl, const void* addr, winrt_async_op<void>* op, bool is_continuation) { if (!is_open(impl)) { op->ec_ = boost::asio::error::bad_descriptor; scheduler_.post_immediate_completion(op, is_continuation); return; } char addr_string[max_addr_v6_str_len]; unsigned short port = 0; switch (reinterpret_cast<const socket_addr_type*>(addr)->sa_family) { case BOOST_ASIO_OS_DEF(AF_INET): socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET), &reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_addr, addr_string, sizeof(addr_string), 0, op->ec_); port = socket_ops::network_to_host_short( reinterpret_cast<const sockaddr_in4_type*>(addr)->sin_port); break; case BOOST_ASIO_OS_DEF(AF_INET6): socket_ops::inet_ntop(BOOST_ASIO_OS_DEF(AF_INET6), &reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_addr, addr_string, sizeof(addr_string), 0, op->ec_); port = socket_ops::network_to_host_short( reinterpret_cast<const sockaddr_in6_type*>(addr)->sin6_port); break; default: op->ec_ = boost::asio::error::address_family_not_supported; break; } if (op->ec_) { scheduler_.post_immediate_completion(op, is_continuation); return; } try { async_manager_.async(impl.socket_->ConnectAsync( ref new Windows::Networking::HostName( winrt_utils::string(addr_string)), winrt_utils::string(port)), op); } catch (Platform::Exception^ e) { op->ec_ = boost::system::error_code( e->HResult, boost::system::system_category()); scheduler_.post_immediate_completion(op, is_continuation); } } std::size_t winrt_ssocket_service_base::do_send( winrt_ssocket_service_base::base_implementation_type& impl, const boost::asio::const_buffer& data, socket_base::message_flags flags, boost::system::error_code& ec) { if (flags) { ec = boost::asio::error::operation_not_supported; return 0; } if (!is_open(impl)) { ec = boost::asio::error::bad_descriptor; return 0; } try { buffer_sequence_adapter<boost::asio::const_buffer, boost::asio::const_buffer> bufs(boost::asio::buffer(data)); if (bufs.all_empty()) { ec = boost::system::error_code(); return 0; } return async_manager_.sync( impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), ec); } catch (Platform::Exception^ e) { ec = boost::system::error_code(e->HResult, boost::system::system_category()); return 0; } } void winrt_ssocket_service_base::start_send_op( winrt_ssocket_service_base::base_implementation_type& impl, const boost::asio::const_buffer& data, socket_base::message_flags flags, winrt_async_op<unsigned int>* op, bool is_continuation) { if (flags) { op->ec_ = boost::asio::error::operation_not_supported; scheduler_.post_immediate_completion(op, is_continuation); return; } if (!is_open(impl)) { op->ec_ = boost::asio::error::bad_descriptor; scheduler_.post_immediate_completion(op, is_continuation); return; } try { buffer_sequence_adapter<boost::asio::const_buffer, boost::asio::const_buffer> bufs(boost::asio::buffer(data)); if (bufs.all_empty()) { scheduler_.post_immediate_completion(op, is_continuation); return; } async_manager_.async( impl.socket_->OutputStream->WriteAsync(bufs.buffers()[0]), op); } catch (Platform::Exception^ e) { op->ec_ = boost::system::error_code(e->HResult, boost::system::system_category()); scheduler_.post_immediate_completion(op, is_continuation); } } std::size_t winrt_ssocket_service_base::do_receive( winrt_ssocket_service_base::base_implementation_type& impl, const boost::asio::mutable_buffer& data, socket_base::message_flags flags, boost::system::error_code& ec) { if (flags) { ec = boost::asio::error::operation_not_supported; return 0; } if (!is_open(impl)) { ec = boost::asio::error::bad_descriptor; return 0; } try { buffer_sequence_adapter<boost::asio::mutable_buffer, boost::asio::mutable_buffer> bufs(boost::asio::buffer(data)); if (bufs.all_empty()) { ec = boost::system::error_code(); return 0; } async_manager_.sync( impl.socket_->InputStream->ReadAsync( bufs.buffers()[0], bufs.buffers()[0]->Capacity, Windows::Storage::Streams::InputStreamOptions::Partial), ec); std::size_t bytes_transferred = bufs.buffers()[0]->Length; if (bytes_transferred == 0 && !ec) { ec = boost::asio::error::eof; } return bytes_transferred; } catch (Platform::Exception^ e) { ec = boost::system::error_code(e->HResult, boost::system::system_category()); return 0; } } void winrt_ssocket_service_base::start_receive_op( winrt_ssocket_service_base::base_implementation_type& impl, const boost::asio::mutable_buffer& data, socket_base::message_flags flags, winrt_async_op<Windows::Storage::Streams::IBuffer^>* op, bool is_continuation) { if (flags) { op->ec_ = boost::asio::error::operation_not_supported; scheduler_.post_immediate_completion(op, is_continuation); return; } if (!is_open(impl)) { op->ec_ = boost::asio::error::bad_descriptor; scheduler_.post_immediate_completion(op, is_continuation); return; } try { buffer_sequence_adapter<boost::asio::mutable_buffer, boost::asio::mutable_buffer> bufs(boost::asio::buffer(data)); if (bufs.all_empty()) { scheduler_.post_immediate_completion(op, is_continuation); return; } async_manager_.async( impl.socket_->InputStream->ReadAsync( bufs.buffers()[0], bufs.buffers()[0]->Capacity, Windows::Storage::Streams::InputStreamOptions::Partial), op); } catch (Platform::Exception^ e) { op->ec_ = boost::system::error_code(e->HResult, boost::system::system_category()); scheduler_.post_immediate_completion(op, is_continuation); } } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_IMPL_WINRT_SSOCKET_SERVICE_BASE_IPP detail/impl/socket_select_interrupter.ipp 0000644 00000013342 15125530236 0014760 0 ustar 00 // // detail/impl/socket_select_interrupter.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_WINDOWS_RUNTIME) #if defined(BOOST_ASIO_WINDOWS) \ || defined(__CYGWIN__) \ || defined(__SYMBIAN32__) #include <cstdlib> #include <boost/asio/detail/socket_holder.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/socket_select_interrupter.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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; for (;;) { int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); if (bytes_read == sizeof(data)) continue; if (bytes_read > 0) return true; if (bytes_read == 0) return false; if (ec == boost::asio::error::would_block || ec == boost::asio::error::try_again) return true; return false; } } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) #endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_IMPL_SOCKET_SELECT_INTERRUPTER_IPP detail/impl/win_iocp_handle_service.ipp 0000644 00000034072 15125530236 0014333 0 ustar 00 // // detail/impl/win_iocp_handle_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/win_iocp_handle_service.hpp> #include <boost/asio/detail/push_options.hpp> 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<DWORD_PTR>(hEvent); hEvent = reinterpret_cast<HANDLE>(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<win_iocp_handle_service>(context), iocp_service_(boost::asio::use_service<win_iocp_io_context>(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<uintmax_t>(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<uintmax_t>(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<cancel_io_ex_t>( reinterpret_cast<void*>(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<DWORD>(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<DWORD>(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<DWORD>(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<DWORD>(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<uintmax_t>(impl.handle_), "close")); ::CloseHandle(impl.handle_); impl.handle_ = INVALID_HANDLE_VALUE; impl.safe_cancellation_thread_id_ = 0; } } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_HANDLE_SERVICE_IPP detail/impl/kqueue_reactor.ipp 0000644 00000041225 15125530236 0012505 0 ustar 00 // // detail/impl/kqueue_reactor.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_KQUEUE) #include <boost/asio/detail/kqueue_reactor.hpp> #include <boost/asio/detail/scheduler.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #if defined(__NetBSD__) # include <sys/param.h> #endif #include <boost/asio/detail/push_options.hpp> #if defined(__NetBSD__) && __NetBSD_Version__ < 999001500 # define BOOST_ASIO_KQUEUE_EV_SET(ev, ident, filt, flags, fflags, data, udata) \ EV_SET(ev, ident, filt, flags, fflags, data, \ reinterpret_cast<intptr_t>(static_cast<void*>(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<kqueue_reactor>(ctx), scheduler_(use_service<scheduler>(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<operation> 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<uintmax_t>(descriptor), reinterpret_cast<uintmax_t>(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<uintmax_t>(descriptor), reinterpret_cast<uintmax_t>(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<operation> 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<operation> 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<uintmax_t>(descriptor), reinterpret_cast<uintmax_t>(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<operation> 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<uintmax_t>(descriptor), reinterpret_cast<uintmax_t>(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<operation>& 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<void*>(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<uintmax_t>(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<void*>(events[i].udata); if (ptr == &interrupter_) { interrupter_.reset(); } else { descriptor_state* descriptor_data = static_cast<descriptor_state*>(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<int>(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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_KQUEUE) #endif // BOOST_ASIO_DETAIL_IMPL_KQUEUE_REACTOR_IPP detail/impl/win_iocp_serial_port_service.ipp 0000644 00000013605 15125530236 0015422 0 ustar 00 // // detail/impl/win_iocp_serial_port_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) && defined(BOOST_ASIO_HAS_SERIAL_PORT) #include <cstring> #include <boost/asio/detail/win_iocp_serial_port_service.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { win_iocp_serial_port_service::win_iocp_serial_port_service( execution_context& context) : execution_context_service_base<win_iocp_serial_port_service>(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 = CBR_9600; // 9600 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 = RTS_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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) && defined(BOOST_ASIO_HAS_SERIAL_PORT) #endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SERIAL_PORT_SERVICE_IPP detail/impl/strand_service.ipp 0000644 00000011655 15125530236 0012506 0 ustar 00 // // detail/impl/strand_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/call_stack.hpp> #include <boost/asio/detail/strand_service.hpp> #include <boost/asio/detail/push_options.hpp> 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<strand_service>(io_context), io_context_(io_context), io_context_impl_(boost::asio::use_service<io_context_impl>(io_context)), mutex_(), salt_(0) { } void strand_service::shutdown() { op_queue<operation> 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<std::size_t>(&impl); index += (reinterpret_cast<std::size_t>(&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<strand_impl>::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_impl_.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_impl_.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_impl_.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<strand_impl*>(base); // Indicate that this strand is executing on the current thread. call_stack<strand_impl>::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<io_context_impl*>(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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_IMPL_STRAND_SERVICE_IPP detail/impl/win_tss_ptr.ipp 0000644 00000002650 15125530236 0012041 0 ustar 00 // // detail/impl/win_tss_ptr.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS) #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/win_tss_ptr.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS) #endif // BOOST_ASIO_DETAIL_IMPL_WIN_TSS_PTR_IPP detail/impl/pipe_select_interrupter.ipp 0000644 00000006150 15125530236 0014424 0 ustar 00 // // detail/impl/pipe_select_interrupter.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_WINDOWS_RUNTIME) #if !defined(BOOST_ASIO_WINDOWS) #if !defined(__CYGWIN__) #if !defined(__SYMBIAN32__) #if !defined(BOOST_ASIO_HAS_EVENTFD) #include <fcntl.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <boost/asio/detail/pipe_select_interrupter.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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 == sizeof(data)) continue; if (bytes_read > 0) return true; if (bytes_read == 0) return false; if (errno == EINTR) continue; if (errno == EWOULDBLOCK || errno == EAGAIN) return true; return false; } } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #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 detail/impl/posix_mutex.ipp 0000644 00000002323 15125530236 0012047 0 ustar 00 // // detail/impl/posix_mutex.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_PTHREADS) #include <boost/asio/detail/posix_mutex.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_PTHREADS) #endif // BOOST_ASIO_DETAIL_IMPL_POSIX_MUTEX_IPP detail/impl/win_event.ipp 0000644 00000004024 15125530236 0011461 0 ustar 00 // // detail/win_event.ipp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS) #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/win_event.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS) #endif // BOOST_ASIO_DETAIL_IMPL_WIN_EVENT_IPP detail/impl/buffer_sequence_adapter.ipp 0000644 00000006030 15125530236 0014323 0 ustar 00 // // detail/impl/buffer_sequence_adapter.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <robuffer.h> #include <windows.storage.streams.h> #include <wrl/implements.h> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/push_options.hpp> 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<byte*>(static_cast<const byte*>(b.data())); length_ = b.size(); capacity_ = b.size(); } explicit winrt_buffer_impl(const boost::asio::mutable_buffer& b) { bytes_ = static_cast<byte*>(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<IInspectable> insp = Microsoft::WRL::Make<winrt_buffer_impl>(buffer); buf = reinterpret_cast<Windows::Storage::Streams::IBuffer^>(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<IInspectable> insp = Microsoft::WRL::Make<winrt_buffer_impl>(buffer); Platform::Object^ buf_obj = reinterpret_cast<Platform::Object^>(insp.Get()); buf = reinterpret_cast<Windows::Storage::Streams::IBuffer^>(insp.Get()); } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_IMPL_BUFFER_SEQUENCE_ADAPTER_IPP detail/impl/winrt_timer_scheduler.ipp 0000644 00000005622 15125530236 0014071 0 ustar 00 // // detail/impl/winrt_timer_scheduler.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/winrt_timer_scheduler.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { winrt_timer_scheduler::winrt_timer_scheduler(execution_context& context) : execution_context_service_base<winrt_timer_scheduler>(context), scheduler_(use_service<scheduler_impl>(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<operation> 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<operation> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_IMPL_WINRT_TIMER_SCHEDULER_IPP detail/impl/select_reactor.hpp 0000644 00000005651 15125530236 0012467 0 ustar 00 // // detail/impl/select_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #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 <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Time_Traits> void select_reactor::add_timer_queue(timer_queue<Time_Traits>& queue) { do_add_timer_queue(queue); } // Remove a timer queue from the reactor. template <typename Time_Traits> void select_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue) { do_remove_timer_queue(queue); } template <typename Time_Traits> void select_reactor::schedule_timer(timer_queue<Time_Traits>& queue, const typename Time_Traits::time_type& time, typename timer_queue<Time_Traits>::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 <typename Time_Traits> std::size_t select_reactor::cancel_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled) { boost::asio::detail::mutex::scoped_lock lock(mutex_); op_queue<operation> ops; std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); lock.unlock(); scheduler_.post_deferred_completions(ops); return n; } template <typename Time_Traits> void select_reactor::move_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& target, typename timer_queue<Time_Traits>::per_timer_data& source) { boost::asio::detail::mutex::scoped_lock lock(mutex_); op_queue<operation> 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 <boost/asio/detail/pop_options.hpp> #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 detail/impl/service_registry.ipp 0000644 00000012526 15125530236 0013061 0 ustar 00 // // detail/impl/service_registry.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <vector> #include <boost/asio/detail/service_registry.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/detail/push_options.hpp> 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<execution_context::service*> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_IMPL_SERVICE_REGISTRY_IPP detail/impl/posix_event.ipp 0000644 00000003360 15125530236 0012030 0 ustar 00 // // detail/impl/posix_event.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_PTHREADS) #include <boost/asio/detail/posix_event.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_PTHREADS) #endif // BOOST_ASIO_DETAIL_IMPL_POSIX_EVENT_IPP detail/impl/dev_poll_reactor.hpp 0000644 00000005033 15125530236 0013006 0 ustar 00 // // detail/impl/dev_poll_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_DEV_POLL) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Time_Traits> void dev_poll_reactor::add_timer_queue(timer_queue<Time_Traits>& queue) { do_add_timer_queue(queue); } template <typename Time_Traits> void dev_poll_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue) { do_remove_timer_queue(queue); } template <typename Time_Traits> void dev_poll_reactor::schedule_timer(timer_queue<Time_Traits>& queue, const typename Time_Traits::time_type& time, typename timer_queue<Time_Traits>::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 <typename Time_Traits> std::size_t dev_poll_reactor::cancel_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled) { boost::asio::detail::mutex::scoped_lock lock(mutex_); op_queue<operation> ops; std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); lock.unlock(); scheduler_.post_deferred_completions(ops); return n; } template <typename Time_Traits> void dev_poll_reactor::move_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& target, typename timer_queue<Time_Traits>::per_timer_data& source) { boost::asio::detail::mutex::scoped_lock lock(mutex_); op_queue<operation> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_DEV_POLL) #endif // BOOST_ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_HPP detail/impl/win_mutex.ipp 0000644 00000004245 15125530236 0011507 0 ustar 00 // // detail/impl/win_mutex.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS) #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/win_mutex.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS) #endif // BOOST_ASIO_DETAIL_IMPL_WIN_MUTEX_IPP detail/impl/kqueue_reactor.hpp 0000644 00000005036 15125530236 0012504 0 ustar 00 // // detail/impl/kqueue_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_KQUEUE) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Time_Traits> void kqueue_reactor::add_timer_queue(timer_queue<Time_Traits>& queue) { do_add_timer_queue(queue); } // Remove a timer queue from the reactor. template <typename Time_Traits> void kqueue_reactor::remove_timer_queue(timer_queue<Time_Traits>& queue) { do_remove_timer_queue(queue); } template <typename Time_Traits> void kqueue_reactor::schedule_timer(timer_queue<Time_Traits>& queue, const typename Time_Traits::time_type& time, typename timer_queue<Time_Traits>::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 <typename Time_Traits> std::size_t kqueue_reactor::cancel_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled) { mutex::scoped_lock lock(mutex_); op_queue<operation> ops; std::size_t n = queue.cancel_timer(timer, ops, max_cancelled); lock.unlock(); scheduler_.post_deferred_completions(ops); return n; } template <typename Time_Traits> void kqueue_reactor::move_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& target, typename timer_queue<Time_Traits>::per_timer_data& source) { mutex::scoped_lock lock(mutex_); op_queue<operation> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_KQUEUE) #endif // BOOST_ASIO_DETAIL_IMPL_KQUEUE_REACTOR_HPP detail/impl/socket_ops.ipp 0000644 00000336426 15125530236 0011652 0 ustar 00 // // detail/impl/socket_ops.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cctype> #include <cstdio> #include <cstdlib> #include <cstring> #include <cerrno> #include <new> #include <boost/asio/detail/assert.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/error.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <codecvt> # include <locale> # include <string> #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) \ || defined(__MACH__) && defined(__APPLE__) # if defined(BOOST_ASIO_HAS_PTHREADS) # include <pthread.h> # endif // defined(BOOST_ASIO_HAS_PTHREADS) #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) // || defined(__MACH__) && defined(__APPLE__) #include <boost/asio/detail/push_options.hpp> 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) inline void get_last_error( boost::system::error_code& ec, bool is_error_condition) { if (!is_error_condition) { ec.assign(0, ec.category()); } else { #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 } } template <typename SockLenType> 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; } socket_type new_s = call_accept(&msghdr::msg_namelen, s, addr, addrlen); get_last_error(ec, new_s == invalid_socket); if (new_s == invalid_socket) return new_s; #if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) int optval = 1; int result = ::setsockopt(new_s, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)); get_last_error(ec, result != 0); if (result != 0) { ::close(new_s); return invalid_socket; } #endif ec.assign(0, ec.category()); 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<std::size_t>(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<std::size_t>(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 <typename SockLenType> 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; } int result = call_bind(&msghdr::msg_namelen, s, addr, addrlen); get_last_error(ec, result != 0); 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); } #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) result = ::closesocket(s); #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) result = ::close(s); #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) get_last_error(ec, result != 0); 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__) || defined(__EMSCRIPTEN__) int flags = ::fcntl(s, F_GETFL, 0); if (flags >= 0) ::fcntl(s, F_SETFL, flags & ~O_NONBLOCK); # else // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) ioctl_arg_type arg = 0; ::ioctl(s, FIONBIO, &arg); # endif // defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) state &= ~non_blocking; #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) result = ::closesocket(s); #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) result = ::close(s); #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) get_last_error(ec, result != 0); } } 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; } #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) ioctl_arg_type arg = (value ? 1 : 0); int result = ::ioctlsocket(s, FIONBIO, &arg); get_last_error(ec, result < 0); #elif defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) int result = ::fcntl(s, F_GETFL, 0); get_last_error(ec, result < 0); if (result >= 0) { int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); result = ::fcntl(s, F_SETFL, flag); get_last_error(ec, result < 0); } #else ioctl_arg_type arg = (value ? 1 : 0); int result = ::ioctl(s, FIONBIO, &arg); get_last_error(ec, result < 0); #endif if (result >= 0) { 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; } #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) ioctl_arg_type arg = (value ? 1 : 0); int result = ::ioctlsocket(s, FIONBIO, &arg); get_last_error(ec, result < 0); #elif defined(__SYMBIAN32__) || defined(__EMSCRIPTEN__) int result = ::fcntl(s, F_GETFL, 0); get_last_error(ec, result < 0); if (result >= 0) { int flag = (value ? (result | O_NONBLOCK) : (result & ~O_NONBLOCK)); result = ::fcntl(s, F_SETFL, flag); get_last_error(ec, result < 0); } #else ioctl_arg_type arg = (value ? 1 : 0); int result = ::ioctl(s, FIONBIO, &arg); get_last_error(ec, result < 0); #endif if (result >= 0) { 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; } int result = ::shutdown(s, what); get_last_error(ec, result != 0); return result; } template <typename SockLenType> 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; } int result = call_connect(&msghdr::msg_namelen, s, addr, addrlen); get_last_error(ec, result != 0); #if defined(__linux__) if (result != 0 && 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.assign(0, ec.category()); } 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 int result = ::socketpair(af, type, protocol, sv); get_last_error(ec, result != 0); 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 = ::ioctlsocket(s, SIOCATMARK, &value); # else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) int result = ::ioctl(s, SIOCATMARK, &value); # endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) get_last_error(ec, result < 0); # if defined(ENOTTY) if (ec.value() == ENOTTY) ec = boost::asio::error::not_socket; # endif // defined(ENOTTY) #else // defined(SIOCATMARK) int value = ::sockatmark(s); get_last_error(ec, result < 0); #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 = ::ioctlsocket(s, FIONREAD, &value); #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) int result = ::ioctl(s, FIONREAD, &value); #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) get_last_error(ec, result < 0); #if defined(ENOTTY) if (ec.value() == ENOTTY) ec = boost::asio::error::not_socket; #endif // defined(ENOTTY) return ec ? static_cast<size_t>(0) : static_cast<size_t>(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; } int result = ::listen(s, backlog); get_last_error(ec, result != 0); return result; } inline void init_buf_iov_base(void*& base, void* addr) { base = addr; } template <typename T> inline void init_buf_iov_base(T& base, void* addr) { base = static_cast<T>(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<char*>(data); b.len = static_cast<u_long>(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<char*>(const_cast<void*>(data)); b.len = static_cast<u_long>(size); #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) init_buf_iov_base(b.iov_base, const_cast<void*>(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<socket_addr_type*>(addr); } template <typename T> inline void init_msghdr_msg_name(T& name, socket_addr_type* addr) { name = reinterpret_cast<T>(addr); } template <typename T> inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr) { name = reinterpret_cast<T>(const_cast<socket_addr_type*>(addr)); } signed_size_type recv(socket_type s, buf* bufs, size_t count, int flags, boost::system::error_code& ec) { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) // Receive some data. DWORD recv_buf_count = static_cast<DWORD>(count); DWORD bytes_transferred = 0; DWORD recv_flags = flags; int result = ::WSARecv(s, bufs, recv_buf_count, &bytes_transferred, &recv_flags, 0, 0); get_last_error(ec, true); 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.assign(0, ec.category()); return bytes_transferred; #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); msg.msg_iov = bufs; msg.msg_iovlen = static_cast<int>(count); signed_size_type result = ::recvmsg(s, &msg, flags); get_last_error(ec, result < 0); return result; #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) } signed_size_type recv1(socket_type s, void* data, size_t size, int flags, boost::system::error_code& ec) { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) // Receive some data. WSABUF buf; buf.buf = const_cast<char*>(static_cast<const char*>(data)); buf.len = static_cast<ULONG>(size); DWORD bytes_transferred = 0; DWORD recv_flags = flags; int result = ::WSARecv(s, &buf, 1, &bytes_transferred, &recv_flags, 0, 0); get_last_error(ec, true); 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.assign(0, ec.category()); return bytes_transferred; #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) signed_size_type result = ::recv(s, static_cast<char*>(data), size, flags); get_last_error(ec, result < 0); 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.assign(0, ec.category()); 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 for EOF. if ((state & stream_oriented) && bytes == 0) { ec = boost::asio::error::eof; return 0; } // 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; } } size_t sync_recv1(socket_type s, state_type state, void* data, size_t size, int flags, 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 (size == 0 && (state & stream_oriented)) { ec.assign(0, ec.category()); return 0; } // Read some data. for (;;) { // Try to complete the operation without blocking. signed_size_type bytes = socket_ops::recv1(s, data, size, flags, ec); // Check for EOF. if ((state & stream_oriented) && bytes == 0) { ec = boost::asio::error::eof; return 0; } // 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_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; } // Check if operation succeeded. if (bytes >= 0) { bytes_transferred = bytes; 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 failed. bytes_transferred = 0; return true; } } bool non_blocking_recv1(socket_type s, void* data, size_t size, int flags, bool is_stream, boost::system::error_code& ec, size_t& bytes_transferred) { for (;;) { // Read some data. signed_size_type bytes = socket_ops::recv1(s, data, size, flags, ec); // Check for end of stream. if (is_stream && bytes == 0) { ec = boost::asio::error::eof; return true; } // Check if operation succeeded. if (bytes >= 0) { bytes_transferred = bytes; 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 failed. 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) { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) // Receive some data. DWORD recv_buf_count = static_cast<DWORD>(count); DWORD bytes_transferred = 0; DWORD recv_flags = flags; int tmp_addrlen = (int)*addrlen; int result = ::WSARecvFrom(s, bufs, recv_buf_count, &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0); get_last_error(ec, true); *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.assign(0, ec.category()); 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<int>(*addrlen); msg.msg_iov = bufs; msg.msg_iovlen = static_cast<int>(count); signed_size_type result = ::recvmsg(s, &msg, flags); get_last_error(ec, result < 0); *addrlen = msg.msg_namelen; return result; #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) } template <typename SockLenType> inline signed_size_type call_recvfrom(SockLenType msghdr::*, socket_type s, void* data, size_t size, int flags, socket_addr_type* addr, std::size_t* addrlen) { SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; signed_size_type result = ::recvfrom(s, static_cast<char*>(data), size, flags, addr, addrlen ? &tmp_addrlen : 0); if (addrlen) *addrlen = (std::size_t)tmp_addrlen; return result; } signed_size_type recvfrom1(socket_type s, void* data, size_t size, int flags, socket_addr_type* addr, std::size_t* addrlen, boost::system::error_code& ec) { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) // Receive some data. WSABUF buf; buf.buf = static_cast<char*>(data); buf.len = static_cast<ULONG>(size); DWORD bytes_transferred = 0; DWORD recv_flags = flags; int tmp_addrlen = (int)*addrlen; int result = ::WSARecvFrom(s, &buf, 1, &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0); get_last_error(ec, true); *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.assign(0, ec.category()); return bytes_transferred; #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) signed_size_type result = call_recvfrom(&msghdr::msg_namelen, s, data, size, flags, addr, addrlen); get_last_error(ec, result < 0); 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; } } size_t sync_recvfrom1(socket_type s, state_type state, void* data, size_t size, 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::recvfrom1( s, data, size, 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); // Check if operation succeeded. if (bytes >= 0) { bytes_transferred = bytes; 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 failed. bytes_transferred = 0; return true; } } bool non_blocking_recvfrom1(socket_type s, void* data, size_t size, 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::recvfrom1( s, data, size, flags, addr, addrlen, ec); // Check if operation succeeded. if (bytes >= 0) { bytes_transferred = bytes; 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 failed. 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) { #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<int>(count); signed_size_type result = ::recvmsg(s, &msg, in_flags); get_last_error(ec, result < 0); if (result >= 0) 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); // Check if operation succeeded. if (bytes >= 0) { bytes_transferred = bytes; 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 failed. 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) { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) // Send the data. DWORD send_buf_count = static_cast<DWORD>(count); DWORD bytes_transferred = 0; DWORD send_flags = flags; int result = ::WSASend(s, const_cast<buf*>(bufs), send_buf_count, &bytes_transferred, send_flags, 0, 0); get_last_error(ec, true); 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.assign(0, ec.category()); return bytes_transferred; #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) msghdr msg = msghdr(); msg.msg_iov = const_cast<buf*>(bufs); msg.msg_iovlen = static_cast<int>(count); #if defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) flags |= MSG_NOSIGNAL; #endif // defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) signed_size_type result = ::sendmsg(s, &msg, flags); get_last_error(ec, result < 0); return result; #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) } signed_size_type send1(socket_type s, const void* data, size_t size, int flags, boost::system::error_code& ec) { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) // Send the data. WSABUF buf; buf.buf = const_cast<char*>(static_cast<const char*>(data)); buf.len = static_cast<ULONG>(size); DWORD bytes_transferred = 0; DWORD send_flags = flags; int result = ::WSASend(s, &buf, 1, &bytes_transferred, send_flags, 0, 0); get_last_error(ec, true); 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.assign(0, ec.category()); return bytes_transferred; #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) #if defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) flags |= MSG_NOSIGNAL; #endif // defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) signed_size_type result = ::send(s, static_cast<const char*>(data), size, flags); get_last_error(ec, result < 0); 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.assign(0, ec.category()); 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; } } size_t sync_send1(socket_type s, state_type state, const void* data, size_t size, int flags, 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 (size == 0 && (state & stream_oriented)) { ec.assign(0, ec.category()); return 0; } // Read some data. for (;;) { // Try to complete the operation without blocking. signed_size_type bytes = socket_ops::send1(s, data, size, 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); // Check if operation succeeded. if (bytes >= 0) { bytes_transferred = bytes; 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 failed. bytes_transferred = 0; return true; } } bool non_blocking_send1(socket_type s, const void* data, size_t size, int flags, boost::system::error_code& ec, size_t& bytes_transferred) { for (;;) { // Write some data. signed_size_type bytes = socket_ops::send1(s, data, size, flags, ec); // Check if operation succeeded. if (bytes >= 0) { bytes_transferred = bytes; 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 failed. 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) { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) // Send the data. DWORD send_buf_count = static_cast<DWORD>(count); DWORD bytes_transferred = 0; int result = ::WSASendTo(s, const_cast<buf*>(bufs), send_buf_count, &bytes_transferred, flags, addr, static_cast<int>(addrlen), 0, 0); get_last_error(ec, true); 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.assign(0, ec.category()); 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<int>(addrlen); msg.msg_iov = const_cast<buf*>(bufs); msg.msg_iovlen = static_cast<int>(count); #if defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) flags |= MSG_NOSIGNAL; #endif // defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) signed_size_type result = ::sendmsg(s, &msg, flags); get_last_error(ec, result < 0); return result; #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) } template <typename SockLenType> inline signed_size_type call_sendto(SockLenType msghdr::*, socket_type s, const void* data, size_t size, int flags, const socket_addr_type* addr, std::size_t addrlen) { return ::sendto(s, static_cast<char*>(const_cast<void*>(data)), size, flags, addr, (SockLenType)addrlen); } signed_size_type sendto1(socket_type s, const void* data, size_t size, int flags, const socket_addr_type* addr, std::size_t addrlen, boost::system::error_code& ec) { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) // Send the data. WSABUF buf; buf.buf = const_cast<char*>(static_cast<const char*>(data)); buf.len = static_cast<ULONG>(size); DWORD bytes_transferred = 0; int result = ::WSASendTo(s, &buf, 1, &bytes_transferred, flags, addr, static_cast<int>(addrlen), 0, 0); get_last_error(ec, true); 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.assign(0, ec.category()); return bytes_transferred; #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) #if defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) flags |= MSG_NOSIGNAL; #endif // defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) signed_size_type result = call_sendto(&msghdr::msg_namelen, s, data, size, flags, addr, addrlen); get_last_error(ec, result < 0); 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; } } size_t sync_sendto1(socket_type s, state_type state, const void* data, size_t size, 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::sendto1( s, data, size, 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); // Check if operation succeeded. if (bytes >= 0) { bytes_transferred = bytes; 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 failed. bytes_transferred = 0; return true; } } bool non_blocking_sendto1(socket_type s, const void* data, size_t size, 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::sendto1( s, data, size, flags, addr, addrlen, ec); // Check if operation succeeded. if (bytes >= 0) { bytes_transferred = bytes; 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 failed. 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) { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) socket_type s = ::WSASocketW(af, type, protocol, 0, 0, WSA_FLAG_OVERLAPPED); get_last_error(ec, s == invalid_socket); 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<const char*>(&optval), sizeof(optval)); } return s; #elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) socket_type s = ::socket(af, type, protocol); get_last_error(ec, s < 0); int optval = 1; int result = ::setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)); get_last_error(ec, result != 0); if (result != 0) { ::close(s); return invalid_socket; } return s; #else int s = ::socket(af, type, protocol); get_last_error(ec, s < 0); return s; #endif } template <typename SockLenType> 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<const int*>(optval)) state |= enable_connection_aborted; else state &= ~enable_connection_aborted; ec.assign(0, ec.category()); 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")) { int result = sso(s, level, optname, reinterpret_cast<const char*>(optval), static_cast<int>(optlen)); get_last_error(ec, result != 0); return result; } } ec = boost::asio::error::fault; return socket_error_retval; #else // defined(__BORLANDC__) int result = call_setsockopt(&msghdr::msg_namelen, s, level, optname, optval, optlen); get_last_error(ec, result != 0); if (result == 0) { #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 <typename SockLenType> 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<int*>(optval) = (state & enable_connection_aborted) ? 1 : 0; ec.assign(0, ec.category()); 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")) { int tmp_optlen = static_cast<int>(*optlen); int result = gso(s, level, optname, reinterpret_cast<char*>(optval), &tmp_optlen); get_last_error(ec, result != 0); *optlen = static_cast<size_t>(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<DWORD*>(optval) = 1; ec.assign(0, ec.category()); } return result; } } ec = boost::asio::error::fault; return socket_error_retval; #elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) int result = call_getsockopt(&msghdr::msg_namelen, s, level, optname, optval, optlen); get_last_error(ec, result != 0); 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<DWORD*>(optval) = 1; ec.assign(0, ec.category()); } return result; #else // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) int result = call_getsockopt(&msghdr::msg_namelen, s, level, optname, optval, optlen); get_last_error(ec, result != 0); #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<int*>(optval) /= 2; } #endif // defined(__linux__) return result; #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) } template <typename SockLenType> 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.assign(0, ec.category()); 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__) int result = call_getpeername(&msghdr::msg_namelen, s, addr, addrlen); get_last_error(ec, result != 0); return result; } template <typename SockLenType> 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; } int result = call_getsockname(&msghdr::msg_namelen, s, addr, addrlen); get_last_error(ec, result != 0); 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; } #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) int result = ::ioctlsocket(s, cmd, arg); #elif defined(__MACH__) && defined(__APPLE__) \ || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) int result = ::ioctl(s, static_cast<unsigned int>(cmd), arg); #else int result = ::ioctl(s, cmd, arg); #endif get_last_error(ec, result < 0); if (result >= 0) { // 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<int>(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) { #if defined(__EMSCRIPTEN__) exceptfds = 0; #endif // defined(__EMSCRIPTEN__) #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.assign(0, ec.category()); 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; int result = ::pselect(nfds, readfds, writefds, exceptfds, timeout ? &ts : 0, 0); #else int result = ::select(nfds, readfds, writefds, exceptfds, timeout); #endif get_last_error(ec, result < 0); return result; } 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; int result = ::select(s + 1, &fds, 0, 0, timeout); get_last_error(ec, result < 0); #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; int result = ::poll(&fds, 1, timeout); get_last_error(ec, result < 0); #endif // defined(BOOST_ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) if (result == 0) if (state & user_set_non_blocking) ec = boost::asio::error::would_block; 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; int result = ::select(s + 1, 0, &fds, 0, timeout); get_last_error(ec, result < 0); #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; int result = ::poll(&fds, 1, timeout); get_last_error(ec, result < 0); #endif // defined(BOOST_ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) if (result == 0) if (state & user_set_non_blocking) ec = boost::asio::error::would_block; 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; int result = ::select(s + 1, 0, 0, &fds, timeout); get_last_error(ec, result < 0); #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; int result = ::poll(&fds, 1, timeout); get_last_error(ec, result < 0); #endif // defined(BOOST_ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) if (result == 0) if (state & user_set_non_blocking) ec = boost::asio::error::would_block; 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; int result = ::select(s + 1, 0, &write_fds, &except_fds, timeout); get_last_error(ec, result < 0); return result; #else // defined(BOOST_ASIO_WINDOWS) // || defined(__CYGWIN__) // || defined(__SYMBIAN32__) pollfd fds; fds.fd = s; fds.events = POLLOUT; fds.revents = 0; int result = ::poll(&fds, 1, msec); get_last_error(ec, result < 0); 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<const unsigned char*>(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<u_long_type>(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<DWORD>(length); #if defined(BOOST_NO_ANSI_APIS) || (defined(_MSC_VER) && (_MSC_VER >= 1800)) LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); int result = ::WSAAddressToStringW(&address.base, address_length, 0, string_buffer, &string_length); get_last_error(ec, true); ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, static_cast<int>(length), 0, 0); #else int result = ::WSAAddressToStringA(&address.base, address_length, 0, dest, &string_length); get_last_error(ec, true); #endif // Windows may set error code on success. if (result != socket_error_retval) ec.assign(0, ec.category()); // 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 = ::inet_ntop(af, src, dest, static_cast<int>(length)); get_last_error(ec, true); 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<const in6_addr_type*>(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<unsigned>(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<unsigned char*>(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<unsigned char>(b0); bytes[1] = static_cast<unsigned char>(b1); bytes[2] = static_cast<unsigned char>(b2); bytes[3] = static_cast<unsigned char>(b3); ec.assign(0, ec.category()); return 1; } else if (af == BOOST_ASIO_OS_DEF(AF_INET6)) { unsigned char* bytes = static_cast<unsigned char*>(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.assign(0, ec.category()); 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<int>(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 = ::WSAStringToAddressW(wide_buffer, af, 0, &address.base, &address_length); get_last_error(ec, true); #else int result = ::WSAStringToAddressA(const_cast<char*>(src), af, 0, &address.base, &address_length); get_last_error(ec, true); #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.assign(0, ec.category()); } else if (strcmp(src, "255.255.255.255") == 0) { static_cast<in4_addr_type*>(dest)->s_addr = INADDR_NONE; ec.assign(0, ec.category()); } } 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.assign(0, ec.category()); } } // 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.assign(0, ec.category()); 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 = ::inet_pton(af, src_ptr, dest); get_last_error(ec, true); 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<in6_addr_type*>(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) { #if defined(BOOST_ASIO_WINDOWS_RUNTIME) try { using namespace Windows::Foundation::Collections; using namespace Windows::Networking; using namespace Windows::Networking::Connectivity; IVectorView<HostName^>^ hostnames = NetworkInformation::GetHostNames(); for (unsigned i = 0; i < hostnames->Size; ++i) { HostName^ hostname = hostnames->GetAt(i); if (hostname->Type == HostNameType::DomainName) { std::wstring_convert<std::codecvt_utf8<wchar_t>> converter; std::string raw_name = converter.to_bytes(hostname->RawName->Data()); if (namelen > 0 && raw_name.size() < static_cast<std::size_t>(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 = ::gethostname(name, namelen); get_last_error(ec, result != 0); 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) { #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) (void)(buffer); (void)(buflength); hostent* retval = ::gethostbyaddr(addr, length, af); get_last_error(ec, !retval); if (!retval) return 0; *result = *retval; return retval; #elif defined(__sun) || defined(__QNX__) int error = 0; hostent* retval = ::gethostbyaddr_r(addr, length, af, result, buffer, buflength, &error); get_last_error(ec, !retval); if (error) ec = translate_netdb_error(error); return retval; #elif defined(__MACH__) && defined(__APPLE__) (void)(buffer); (void)(buflength); int error = 0; hostent* retval = ::getipnodebyaddr(addr, length, af, &error); get_last_error(ec, !retval); if (error) ec = translate_netdb_error(error); if (!retval) return 0; *result = *retval; return retval; #else hostent* retval = 0; int error = 0; clear_last_error(); ::gethostbyaddr_r(addr, length, af, result, buffer, buflength, &retval, &error); get_last_error(ec, true); 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) { #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 = ::gethostbyname(name); get_last_error(ec, !retval); if (!retval) return 0; *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 = ::gethostbyname_r(name, result, buffer, buflength, &error); get_last_error(ec, !retval); if (error) ec = translate_netdb_error(error); return retval; #elif defined(__MACH__) && defined(__APPLE__) (void)(buffer); (void)(buflength); int error = 0; hostent* retval = ::getipnodebyname(name, af, ai_flags, &error); get_last_error(ec, !retval); 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; clear_last_error(); ::gethostbyname_r(name, result, buffer, buflength, &retval, &error); get_last_error(ec, true); 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 <typename T> inline T* gai_alloc(std::size_t size = sizeof(T)) { using namespace std; T* p = static_cast<T*>(::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<addrinfo_type>(); 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<sockaddr_in4_type>(); 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<sockaddr*>(sinptr); ai->ai_addrlen = sizeof(sockaddr_in4_type); break; } case BOOST_ASIO_OS_DEF(AF_INET6): { sockaddr_in6_type* sin6ptr = gai_alloc<sockaddr_in6_type>(); 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<sockaddr*>(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<addrinfo_type>(); 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<sockaddr>(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<sockaddr_in4_type*>(ai->ai_addr); sinptr->sin_port = port; ++num_found; break; } case BOOST_ASIO_OS_DEF(AF_INET6): { sockaddr_in6_type* sin6ptr = reinterpret_cast<sockaddr_in6_type*>(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<unsigned char>(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<char>(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<char>(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<const char*>( &reinterpret_cast<const sockaddr_in4_type*>(sa)->sin_addr); addr_len = sizeof(in4_addr_type); port = reinterpret_cast<const sockaddr_in4_type*>(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<const char*>( &reinterpret_cast<const sockaddr_in6_type*>(sa)->sin6_addr); addr_len = sizeof(in6_addr_type); port = reinterpret_cast<const sockaddr_in6_type*>(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<int>(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.assign(0, ec.category()); 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<unsigned char>(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<sockaddr_in4_type*>(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<sockaddr_in6_type*>(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<socklen_t>(addrlen), host, static_cast<DWORD>(hostlen), serv, static_cast<DWORD>(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<int>(addrlen), host, static_cast<DWORD>(hostlen), serv, static_cast<DWORD>(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<socket_addr_type*>(&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<unsigned char*>(&value); u_long_type result = (static_cast<u_long_type>(value_p[0]) << 24) | (static_cast<u_long_type>(value_p[1]) << 16) | (static_cast<u_long_type>(value_p[2]) << 8) | static_cast<u_long_type>(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<unsigned char*>(&result); result_p[0] = static_cast<unsigned char>((value >> 24) & 0xFF); result_p[1] = static_cast<unsigned char>((value >> 16) & 0xFF); result_p[2] = static_cast<unsigned char>((value >> 8) & 0xFF); result_p[3] = static_cast<unsigned char>(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<unsigned char*>(&value); u_short_type result = (static_cast<u_short_type>(value_p[0]) << 8) | static_cast<u_short_type>(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<unsigned char*>(&result); result_p[0] = static_cast<unsigned char>((value >> 8) & 0xFF); result_p[1] = static_cast<unsigned char>(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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_SOCKET_OPS_IPP detail/impl/reactive_descriptor_service.ipp 0000644 00000014364 15125530236 0015253 0 ustar 00 // // detail/impl/reactive_descriptor_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_WINDOWS) \ && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ && !defined(__CYGWIN__) #include <boost/asio/error.hpp> #include <boost/asio/detail/reactive_descriptor_service.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { reactive_descriptor_service::reactive_descriptor_service( execution_context& context) : execution_context_service_base<reactive_descriptor_service>(context), reactor_(boost::asio::use_service<reactor>(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) BOOST_ASIO_NOEXCEPT { 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 <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_WINDOWS) // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) // && !defined(__CYGWIN__) #endif // BOOST_ASIO_DETAIL_IMPL_REACTIVE_DESCRIPTOR_SERVICE_IPP detail/impl/dev_poll_reactor.ipp 0000644 00000031522 15125530236 0013011 0 ustar 00 // // detail/impl/dev_poll_reactor.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_DEV_POLL) #include <boost/asio/detail/dev_poll_reactor.hpp> #include <boost/asio/detail/assert.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { dev_poll_reactor::dev_poll_reactor(boost::asio::execution_context& ctx) : boost::asio::detail::execution_context_service_base<dev_poll_reactor>(ctx), scheduler_(use_service<scheduler>(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<operation> 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<socket_type>::iterator iter = op_queue_[i].begin(); reactor_op_queue<socket_type>::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<operation> 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<operation>& 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<int>(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<operation> 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<int, std::size_t>::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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_DEV_POLL) #endif // BOOST_ASIO_DETAIL_IMPL_DEV_POLL_REACTOR_IPP detail/impl/win_object_handle_service.ipp 0000644 00000030317 15125530236 0014645 0 ustar 00 // // detail/impl/win_object_handle_service.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) #include <boost/asio/detail/win_object_handle_service.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { win_object_handle_service::win_object_handle_service(execution_context& context) : execution_context_service_base<win_object_handle_service>(context), scheduler_(boost::asio::use_service<scheduler_impl>(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<operation> 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<uintmax_t>(impl.wait_handle_), "close")); HANDLE wait_handle = impl.wait_handle_; impl.wait_handle_ = INVALID_HANDLE_VALUE; op_queue<operation> 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<uintmax_t>(impl.wait_handle_), "close")); mutex::scoped_lock lock(mutex_); HANDLE wait_handle = impl.wait_handle_; impl.wait_handle_ = INVALID_HANDLE_VALUE; op_queue<operation> 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<uintmax_t>(impl.wait_handle_), "cancel")); mutex::scoped_lock lock(mutex_); HANDLE wait_handle = impl.wait_handle_; impl.wait_handle_ = INVALID_HANDLE_VALUE; op_queue<operation> 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<operation> 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<implementation_type*>(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<operation> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) #endif // BOOST_ASIO_DETAIL_IMPL_WIN_OBJECT_HANDLE_SERVICE_IPP detail/impl/win_thread.ipp 0000644 00000010006 15125530236 0011604 0 ustar 00 // // detail/impl/win_thread.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS) \ && !defined(BOOST_ASIO_WINDOWS_APP) \ && !defined(UNDER_CE) #include <process.h> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/win_thread.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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<HANDLE>(::_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<win_thread::func_base*>(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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS) // && !defined(BOOST_ASIO_WINDOWS_APP) // && !defined(UNDER_CE) #endif // BOOST_ASIO_DETAIL_IMPL_WIN_THREAD_IPP detail/impl/win_static_mutex.ipp 0000644 00000007064 15125530236 0013060 0 ustar 00 // // detail/impl/win_static_mutex.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS) #include <cstdio> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/win_static_mutex.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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<unsigned int>(::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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS) #endif // BOOST_ASIO_DETAIL_IMPL_WIN_STATIC_MUTEX_IPP detail/impl/posix_tss_ptr.ipp 0000644 00000002355 15125530236 0012410 0 ustar 00 // // detail/impl/posix_tss_ptr.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_PTHREADS) #include <boost/asio/detail/posix_tss_ptr.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_PTHREADS) #endif // BOOST_ASIO_DETAIL_IMPL_POSIX_TSS_PTR_IPP detail/impl/throw_error.ipp 0000644 00000002364 15125530236 0012044 0 ustar 00 // // detail/impl/throw_error.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/system/system_error.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_IMPL_THROW_ERROR_IPP detail/impl/win_iocp_socket_service_base.ipp 0000644 00000060721 15125530236 0015362 0 ustar 00 // // detail/impl/win_iocp_socket_service_base.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/win_iocp_socket_service_base.hpp> #include <boost/asio/detail/push_options.hpp> 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<win_iocp_io_context>(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) BOOST_ASIO_NOEXCEPT { 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<select_reactor*>( interlocked_compare_exchange_pointer( reinterpret_cast<void**>(&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<HANDLE>(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<cancel_io_ex_t>( reinterpret_cast<void*>(cancel_io_ex_ptr)); socket_type sock = impl.socket_; HANDLE sock_as_handle = reinterpret_cast<HANDLE>(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<HANDLE>(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<select_reactor*>( interlocked_compare_exchange_pointer( reinterpret_cast<void**>(&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<HANDLE>(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<void*>(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<HANDLE>(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<void*>(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<DWORD>(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<DWORD>(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<DWORD>(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<DWORD>(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<int>(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<select_reactor*>( interlocked_compare_exchange_pointer( reinterpret_cast<void**>(&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<select_reactor*>( interlocked_compare_exchange_pointer( reinterpret_cast<void**>(&reactor_), 0, 0)); if (!r) { r = &(use_service<select_reactor>(context_)); interlocked_exchange_pointer(reinterpret_cast<void**>(&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<connect_ex_fn>(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<void*>(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<nt_set_info_fn>(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<void*>(InterlockedCompareExchange( reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(exch), reinterpret_cast<LONG>(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<void*>(InterlockedExchange( reinterpret_cast<PLONG>(dest), reinterpret_cast<LONG>(val))); #else return InterlockedExchangePointer(dest, val); #endif } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_IMPL_WIN_IOCP_SOCKET_SERVICE_BASE_IPP detail/impl/timer_queue_set.ipp 0000644 00000004415 15125530236 0012666 0 ustar 00 // // detail/impl/timer_queue_set.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/timer_queue_set.hpp> #include <boost/asio/detail/push_options.hpp> 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<operation>& 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<operation>& ops) { for (timer_queue_base* p = first_; p; p = p->next_) p->get_all_timers(ops); } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_IMPL_TIMER_QUEUE_SET_IPP detail/impl/null_event.ipp 0000644 00000003562 15125530236 0011644 0 ustar 00 // // detail/impl/null_event.ipp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <thread> #elif defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) # include <boost/asio/detail/socket_types.hpp> #else # include <unistd.h> # if defined(__hpux) # include <sys/time.h> # endif # if !defined(__hpux) || defined(__SELECT) # include <sys/select.h> # endif #endif #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_IMPL_NULL_EVENT_IPP detail/reactive_socket_service_base.hpp 0000644 00000046341 15125530236 0014415 0 ustar 00 // // detail/reactive_socket_service_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_HAS_IOCP) \ && !defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <boost/asio/buffer.hpp> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/socket_base.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactive_null_buffers_op.hpp> #include <boost/asio/detail/reactive_socket_recv_op.hpp> #include <boost/asio/detail/reactive_socket_recvmsg_op.hpp> #include <boost/asio/detail/reactive_socket_send_op.hpp> #include <boost/asio/detail/reactive_wait_op.hpp> #include <boost/asio/detail/reactor.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_holder.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/push_options.hpp> 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) BOOST_ASIO_NOEXCEPT; // 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 <typename IO_Control_Command> 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<ioctl_arg_type*>(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 <typename Handler, typename IoExecutor> 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<Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, 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 <typename ConstBufferSequence> size_t send(base_implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, boost::system::error_code& ec) { typedef buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence> bufs_type; if (bufs_type::is_single_buffer) { return socket_ops::sync_send1(impl.socket_, impl.state_, bufs_type::first(buffers).data(), bufs_type::first(buffers).size(), flags, ec); } else { bufs_type 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 <typename ConstBufferSequence, typename Handler, typename IoExecutor> 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(success_ec_, 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<boost::asio::const_buffer, ConstBufferSequence>::all_empty(buffers))); p.v = p.p = 0; } // Start an asynchronous wait until data can be sent without blocking. template <typename Handler, typename IoExecutor> 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<Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, 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 <typename MutableBufferSequence> size_t receive(base_implementation_type& impl, const MutableBufferSequence& buffers, socket_base::message_flags flags, boost::system::error_code& ec) { typedef buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence> bufs_type; if (bufs_type::is_single_buffer) { return socket_ops::sync_recv1(impl.socket_, impl.state_, bufs_type::first(buffers).data(), bufs_type::first(buffers).size(), flags, ec); } else { bufs_type 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 <typename MutableBufferSequence, typename Handler, typename IoExecutor> 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(success_ec_, 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<boost::asio::mutable_buffer, MutableBufferSequence>::all_empty(buffers))); p.v = p.p = 0; } // Wait until data can be received without blocking. template <typename Handler, typename IoExecutor> 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<Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, 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 <typename MutableBufferSequence> 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<boost::asio::mutable_buffer, MutableBufferSequence> 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 <typename MutableBufferSequence, typename Handler, typename IoExecutor> 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(success_ec_, 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 <typename Handler, typename IoExecutor> 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<Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, 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_; // Cached success value to avoid accessing category singleton. const boost::system::error_code success_ec_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/reactive_socket_service_base.ipp> #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 detail/handler_work.hpp 0000644 00000030016 15125530236 0011200 0 ustar 00 // // detail/handler_work.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/allocator.hpp> #include <boost/asio/execution/blocking.hpp> #include <boost/asio/execution/execute.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/outstanding_work.hpp> #include <boost/asio/executor_work_guard.hpp> #include <boost/asio/prefer.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { class executor; class io_context; namespace execution { #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename...> class any_executor; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename, typename, typename, typename, typename, typename, typename, typename, typename> class any_executor; #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) } // namespace execution namespace detail { template <typename Executor, typename CandidateExecutor = void, typename IoContext = io_context, typename PolymorphicExecutor = executor, typename = void> class handler_work_base { public: explicit handler_work_base(const Executor& ex) BOOST_ASIO_NOEXCEPT : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) { } template <typename OtherExecutor> handler_work_base(const Executor& ex, const OtherExecutor&) BOOST_ASIO_NOEXCEPT : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) { } handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT : executor_(other.executor_) { } #if defined(BOOST_ASIO_HAS_MOVE) handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT : executor_(BOOST_ASIO_MOVE_CAST(executor_type)(other.executor_)) { } #endif // defined(BOOST_ASIO_HAS_MOVE) bool owns_work() const BOOST_ASIO_NOEXCEPT { return true; } template <typename Function, typename Handler> void dispatch(Function& function, Handler& handler) { execution::execute( boost::asio::prefer(executor_, execution::blocking.possibly, execution::allocator((get_associated_allocator)(handler))), BOOST_ASIO_MOVE_CAST(Function)(function)); } private: typedef typename decay< typename prefer_result<Executor, execution::outstanding_work_t::tracked_t >::type >::type executor_type; executor_type executor_; }; template <typename Executor, typename CandidateExecutor, typename IoContext, typename PolymorphicExecutor> class handler_work_base<Executor, CandidateExecutor, IoContext, PolymorphicExecutor, typename enable_if< !execution::is_executor<Executor>::value && (!is_same<Executor, PolymorphicExecutor>::value || !is_same<CandidateExecutor, void>::value) >::type> { public: explicit handler_work_base(const Executor& ex) BOOST_ASIO_NOEXCEPT : executor_(ex), owns_work_(true) { executor_.on_work_started(); } handler_work_base(const Executor& ex, const Executor& candidate) BOOST_ASIO_NOEXCEPT : executor_(ex), owns_work_(ex != candidate) { if (owns_work_) executor_.on_work_started(); } template <typename OtherExecutor> handler_work_base(const Executor& ex, const OtherExecutor&) BOOST_ASIO_NOEXCEPT : executor_(ex), owns_work_(true) { executor_.on_work_started(); } handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT : executor_(other.executor_), owns_work_(other.owns_work_) { if (owns_work_) executor_.on_work_started(); } #if defined(BOOST_ASIO_HAS_MOVE) handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)), owns_work_(other.owns_work_) { other.owns_work_ = false; } #endif // defined(BOOST_ASIO_HAS_MOVE) ~handler_work_base() { if (owns_work_) executor_.on_work_finished(); } bool owns_work() const BOOST_ASIO_NOEXCEPT { return owns_work_; } template <typename Function, typename Handler> void dispatch(Function& function, Handler& handler) { executor_.dispatch(BOOST_ASIO_MOVE_CAST(Function)(function), boost::asio::get_associated_allocator(handler)); } private: Executor executor_; bool owns_work_; }; template <typename Executor, typename IoContext, typename PolymorphicExecutor> class handler_work_base<Executor, void, IoContext, PolymorphicExecutor, typename enable_if< is_same< Executor, typename IoContext::executor_type >::value >::type> { public: explicit handler_work_base(const Executor&) { } bool owns_work() const BOOST_ASIO_NOEXCEPT { return false; } template <typename Function, typename Handler> void dispatch(Function& function, Handler& handler) { // 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. boost_asio_handler_invoke_helpers::invoke(function, handler); } }; template <typename Executor, typename IoContext> class handler_work_base<Executor, void, IoContext, Executor> { public: explicit handler_work_base(const Executor& ex) BOOST_ASIO_NOEXCEPT #if !defined(BOOST_ASIO_NO_TYPEID) : executor_( ex.target_type() == typeid(typename IoContext::executor_type) ? Executor() : ex) #else // !defined(BOOST_ASIO_NO_TYPEID) : executor_(ex) #endif // !defined(BOOST_ASIO_NO_TYPEID) { if (executor_) executor_.on_work_started(); } handler_work_base(const Executor& ex, const Executor& candidate) BOOST_ASIO_NOEXCEPT : executor_(ex != candidate ? ex : Executor()) { if (executor_) executor_.on_work_started(); } template <typename OtherExecutor> handler_work_base(const Executor& ex, const OtherExecutor&) BOOST_ASIO_NOEXCEPT : executor_(ex) { executor_.on_work_started(); } handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT : executor_(other.executor_) { if (executor_) executor_.on_work_started(); } #if defined(BOOST_ASIO_HAS_MOVE) handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT : executor_(BOOST_ASIO_MOVE_CAST(Executor)(other.executor_)) { } #endif // defined(BOOST_ASIO_HAS_MOVE) ~handler_work_base() { if (executor_) executor_.on_work_finished(); } bool owns_work() const BOOST_ASIO_NOEXCEPT { return !!executor_; } template <typename Function, typename Handler> void dispatch(Function& function, Handler& handler) { executor_.dispatch(BOOST_ASIO_MOVE_CAST(Function)(function), boost::asio::get_associated_allocator(handler)); } private: Executor executor_; }; template < #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) typename... SupportableProperties, #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) typename IoContext, typename PolymorphicExecutor> class handler_work_base< #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) execution::any_executor<SupportableProperties...>, #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) execution::any_executor<T1, T2, T3, T4, T5, T6, T7, T8, T9>, #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) void, IoContext, PolymorphicExecutor> { public: typedef #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) execution::any_executor<SupportableProperties...> #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) execution::any_executor<T1, T2, T3, T4, T5, T6, T7, T8, T9> #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) executor_type; explicit handler_work_base(const executor_type& ex) BOOST_ASIO_NOEXCEPT #if !defined(BOOST_ASIO_NO_TYPEID) : executor_( ex.target_type() == typeid(typename IoContext::executor_type) ? executor_type() : boost::asio::prefer(ex, execution::outstanding_work.tracked)) #else // !defined(BOOST_ASIO_NO_TYPEID) : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) #endif // !defined(BOOST_ASIO_NO_TYPEID) { } handler_work_base(const executor_type& ex, const executor_type& candidate) BOOST_ASIO_NOEXCEPT : executor_(ex != candidate ? ex : executor_type()) { } template <typename OtherExecutor> handler_work_base(const executor_type& ex, const OtherExecutor&) BOOST_ASIO_NOEXCEPT : executor_(boost::asio::prefer(ex, execution::outstanding_work.tracked)) { } handler_work_base(const handler_work_base& other) BOOST_ASIO_NOEXCEPT : executor_(other.executor_) { } #if defined(BOOST_ASIO_HAS_MOVE) handler_work_base(handler_work_base&& other) BOOST_ASIO_NOEXCEPT : executor_(BOOST_ASIO_MOVE_CAST(executor_type)(other.executor_)) { } #endif // defined(BOOST_ASIO_HAS_MOVE) bool owns_work() const BOOST_ASIO_NOEXCEPT { return !!executor_; } template <typename Function, typename Handler> void dispatch(Function& function, Handler& handler) { execution::execute( boost::asio::prefer(executor_, execution::blocking.possibly, execution::allocator((get_associated_allocator)(handler))), BOOST_ASIO_MOVE_CAST(Function)(function)); } private: executor_type executor_; }; template <typename Handler, typename IoExecutor, typename = void> class handler_work : handler_work_base<IoExecutor>, handler_work_base<typename associated_executor< Handler, IoExecutor>::type, IoExecutor> { public: typedef handler_work_base<IoExecutor> base1_type; typedef handler_work_base<typename associated_executor< Handler, IoExecutor>::type, IoExecutor> base2_type; handler_work(Handler& handler, const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT : base1_type(io_ex), base2_type(boost::asio::get_associated_executor(handler, io_ex), io_ex) { } template <typename Function> void complete(Function& function, Handler& handler) { if (!base1_type::owns_work() && !base2_type::owns_work()) { // 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. boost_asio_handler_invoke_helpers::invoke(function, handler); } else { base2_type::dispatch(function, handler); } } }; template <typename Handler, typename IoExecutor> class handler_work< Handler, IoExecutor, typename enable_if< is_same< typename associated_executor<Handler, IoExecutor>::asio_associated_executor_is_unspecialised, void >::value >::type> : handler_work_base<IoExecutor> { public: typedef handler_work_base<IoExecutor> base1_type; handler_work(Handler&, const IoExecutor& io_ex) BOOST_ASIO_NOEXCEPT : base1_type(io_ex) { } template <typename Function> void complete(Function& function, Handler& handler) { if (!base1_type::owns_work()) { // 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. boost_asio_handler_invoke_helpers::invoke(function, handler); } else { base1_type::dispatch(function, handler); } } }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_HANDLER_WORK_HPP detail/is_buffer_sequence.hpp 0000644 00000017421 15125530236 0012362 0 ustar 00 // // detail/is_buffer_sequence.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename T> struct buffer_sequence_memfns_derived : T, buffer_sequence_memfns_base { }; template <typename T, T> struct buffer_sequence_memfns_check { }; #if defined(BOOST_ASIO_HAS_DECLTYPE) template <typename> char buffer_sequence_begin_helper(...); template <typename T> char (&buffer_sequence_begin_helper(T* t, typename enable_if<!is_same< decltype(boost::asio::buffer_sequence_begin(*t)), void>::value>::type*))[2]; #else // defined(BOOST_ASIO_HAS_DECLTYPE) template <typename> char (&buffer_sequence_begin_helper(...))[2]; template <typename T> char buffer_sequence_begin_helper(T* t, buffer_sequence_memfns_check< void (buffer_sequence_memfns_base::*)(), &buffer_sequence_memfns_derived<T>::begin>*); #endif // defined(BOOST_ASIO_HAS_DECLTYPE) #if defined(BOOST_ASIO_HAS_DECLTYPE) template <typename> char buffer_sequence_end_helper(...); template <typename T> char (&buffer_sequence_end_helper(T* t, typename enable_if<!is_same< decltype(boost::asio::buffer_sequence_end(*t)), void>::value>::type*))[2]; #else // defined(BOOST_ASIO_HAS_DECLTYPE) template <typename> char (&buffer_sequence_end_helper(...))[2]; template <typename T> char buffer_sequence_end_helper(T* t, buffer_sequence_memfns_check< void (buffer_sequence_memfns_base::*)(), &buffer_sequence_memfns_derived<T>::end>*); #endif // defined(BOOST_ASIO_HAS_DECLTYPE) template <typename> char (&size_memfn_helper(...))[2]; template <typename T> char size_memfn_helper( buffer_sequence_memfns_check< void (buffer_sequence_memfns_base::*)(), &buffer_sequence_memfns_derived<T>::size>*); template <typename> char (&max_size_memfn_helper(...))[2]; template <typename T> char max_size_memfn_helper( buffer_sequence_memfns_check< void (buffer_sequence_memfns_base::*)(), &buffer_sequence_memfns_derived<T>::max_size>*); template <typename> char (&capacity_memfn_helper(...))[2]; template <typename T> char capacity_memfn_helper( buffer_sequence_memfns_check< void (buffer_sequence_memfns_base::*)(), &buffer_sequence_memfns_derived<T>::capacity>*); template <typename> char (&data_memfn_helper(...))[2]; template <typename T> char data_memfn_helper( buffer_sequence_memfns_check< void (buffer_sequence_memfns_base::*)(), &buffer_sequence_memfns_derived<T>::data>*); template <typename> char (&prepare_memfn_helper(...))[2]; template <typename T> char prepare_memfn_helper( buffer_sequence_memfns_check< void (buffer_sequence_memfns_base::*)(), &buffer_sequence_memfns_derived<T>::prepare>*); template <typename> char (&commit_memfn_helper(...))[2]; template <typename T> char commit_memfn_helper( buffer_sequence_memfns_check< void (buffer_sequence_memfns_base::*)(), &buffer_sequence_memfns_derived<T>::commit>*); template <typename> char (&consume_memfn_helper(...))[2]; template <typename T> char consume_memfn_helper( buffer_sequence_memfns_check< void (buffer_sequence_memfns_base::*)(), &buffer_sequence_memfns_derived<T>::consume>*); template <typename> char (&grow_memfn_helper(...))[2]; template <typename T> char grow_memfn_helper( buffer_sequence_memfns_check< void (buffer_sequence_memfns_base::*)(), &buffer_sequence_memfns_derived<T>::grow>*); template <typename> char (&shrink_memfn_helper(...))[2]; template <typename T> char shrink_memfn_helper( buffer_sequence_memfns_check< void (buffer_sequence_memfns_base::*)(), &buffer_sequence_memfns_derived<T>::shrink>*); template <typename, typename> char (&buffer_sequence_element_type_helper(...))[2]; #if defined(BOOST_ASIO_HAS_DECLTYPE) template <typename T, typename Buffer> char buffer_sequence_element_type_helper(T* t, typename enable_if<is_convertible< decltype(*boost::asio::buffer_sequence_begin(*t)), Buffer>::value>::type*); #else // defined(BOOST_ASIO_HAS_DECLTYPE) template <typename T, typename Buffer> char buffer_sequence_element_type_helper( typename T::const_iterator*, typename enable_if<is_convertible< typename T::value_type, Buffer>::value>::type*); #endif // defined(BOOST_ASIO_HAS_DECLTYPE) template <typename> char (&const_buffers_type_typedef_helper(...))[2]; template <typename T> char const_buffers_type_typedef_helper( typename T::const_buffers_type*); template <typename> char (&mutable_buffers_type_typedef_helper(...))[2]; template <typename T> char mutable_buffers_type_typedef_helper( typename T::mutable_buffers_type*); template <typename T, typename Buffer> struct is_buffer_sequence_class : integral_constant<bool, sizeof(buffer_sequence_begin_helper<T>(0, 0)) != 1 && sizeof(buffer_sequence_end_helper<T>(0, 0)) != 1 && sizeof(buffer_sequence_element_type_helper<T, Buffer>(0, 0)) == 1> { }; template <typename T, typename Buffer> struct is_buffer_sequence : conditional<is_class<T>::value, is_buffer_sequence_class<T, Buffer>, false_type>::type { }; template <> struct is_buffer_sequence<mutable_buffer, mutable_buffer> : true_type { }; template <> struct is_buffer_sequence<mutable_buffer, const_buffer> : true_type { }; template <> struct is_buffer_sequence<const_buffer, const_buffer> : true_type { }; template <> struct is_buffer_sequence<const_buffer, mutable_buffer> : false_type { }; template <typename T> struct is_dynamic_buffer_class_v1 : integral_constant<bool, sizeof(size_memfn_helper<T>(0)) != 1 && sizeof(max_size_memfn_helper<T>(0)) != 1 && sizeof(capacity_memfn_helper<T>(0)) != 1 && sizeof(data_memfn_helper<T>(0)) != 1 && sizeof(consume_memfn_helper<T>(0)) != 1 && sizeof(prepare_memfn_helper<T>(0)) != 1 && sizeof(commit_memfn_helper<T>(0)) != 1 && sizeof(const_buffers_type_typedef_helper<T>(0)) == 1 && sizeof(mutable_buffers_type_typedef_helper<T>(0)) == 1> { }; template <typename T> struct is_dynamic_buffer_v1 : conditional<is_class<T>::value, is_dynamic_buffer_class_v1<T>, false_type>::type { }; template <typename T> struct is_dynamic_buffer_class_v2 : integral_constant<bool, sizeof(size_memfn_helper<T>(0)) != 1 && sizeof(max_size_memfn_helper<T>(0)) != 1 && sizeof(capacity_memfn_helper<T>(0)) != 1 && sizeof(data_memfn_helper<T>(0)) != 1 && sizeof(consume_memfn_helper<T>(0)) != 1 && sizeof(grow_memfn_helper<T>(0)) != 1 && sizeof(shrink_memfn_helper<T>(0)) != 1 && sizeof(const_buffers_type_typedef_helper<T>(0)) == 1 && sizeof(mutable_buffers_type_typedef_helper<T>(0)) == 1> { }; template <typename T> struct is_dynamic_buffer_v2 : conditional<is_class<T>::value, is_dynamic_buffer_class_v2<T>, false_type>::type { }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_IS_BUFFER_SEQUENCE_HPP detail/dependent_type.hpp 0000644 00000001573 15125530236 0011536 0 ustar 00 // // detail/dependent_type.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename DependsOn, typename T> struct dependent_type { typedef T type; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_DEPENDENT_TYPE_HPP detail/reactive_wait_op.hpp 0000644 00000006121 15125530236 0012045 0 ustar 00 // // detail/reactive_wait_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Handler, typename IoExecutor> class reactive_wait_op : public reactor_op { public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_wait_op); reactive_wait_op(const boost::system::error_code& success_ec, Handler& handler, const IoExecutor& io_ex) : reactor_op(success_ec, &reactive_wait_op::do_perform, &reactive_wait_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), work_(handler_, io_ex) { } 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<reactive_wait_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_REACTIVE_WAIT_OP_HPP detail/signal_handler.hpp 0000644 00000005563 15125530236 0011504 0 ustar 00 // // detail/signal_handler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/signal_op.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Handler, typename IoExecutor> 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)), work_(handler_, io_ex) { } 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<signal_handler*>(base)); ptr p = { boost::asio::detail::addressof(h->handler_), h, h }; BOOST_ASIO_HANDLER_COMPLETION((*h)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( h->work_)); // 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, boost::system::error_code, int> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_SIGNAL_HANDLER_HPP detail/handler_tracking.hpp 0000644 00000021736 15125530236 0012031 0 ustar 00 // // detail/handler_tracking.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> 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 <boost/system/error_code.hpp> # include <boost/asio/detail/cstdint.hpp> # include <boost/asio/detail/static_mutex.hpp> # include <boost/asio/detail/tss_ptr.hpp> #endif // defined(BOOST_ASIO_ENABLE_HANDLER_TRACKING) #include <boost/asio/detail/push_options.hpp> 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(); class location { public: // Constructor adds a location to the stack. BOOST_ASIO_DECL explicit location(const char* file, int line, const char* func); // Destructor removes a location from the stack. BOOST_ASIO_DECL ~location(); private: // Disallow copying and assignment. location(const location&) BOOST_ASIO_DELETED; location& operator=(const location&) BOOST_ASIO_DELETED; friend class handler_tracking; const char* file_; int line_; const char* func_; location* next_; }; // 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_LOCATION(args) \ boost::asio::detail::handler_tracking::location tracked_location args # 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_LOCATION(loc) (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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/handler_tracking.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_DETAIL_HANDLER_TRACKING_HPP detail/blocking_executor_op.hpp 0000644 00000005407 15125530236 0012733 0 ustar 00 // // detail/blocking_executor_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_BLOCKING_EXECUTOR_OP_HPP #define BOOST_ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/event.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/scheduler_operation.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Operation = scheduler_operation> class blocking_executor_op_base : public Operation { public: blocking_executor_op_base(typename Operation::func_type complete_func) : Operation(complete_func), is_complete_(false) { } void wait() { boost::asio::detail::mutex::scoped_lock lock(mutex_); while (!is_complete_) event_.wait(lock); } protected: struct do_complete_cleanup { ~do_complete_cleanup() { boost::asio::detail::mutex::scoped_lock lock(op_->mutex_); op_->is_complete_ = true; op_->event_.unlock_and_signal_one_for_destruction(lock); } blocking_executor_op_base* op_; }; private: boost::asio::detail::mutex mutex_; boost::asio::detail::event event_; bool is_complete_; }; template <typename Handler, typename Operation = scheduler_operation> class blocking_executor_op : public blocking_executor_op_base<Operation> { public: blocking_executor_op(Handler& h) : blocking_executor_op_base<Operation>(&blocking_executor_op::do_complete), handler_(h) { } static void do_complete(void* owner, Operation* base, const boost::system::error_code& /*ec*/, std::size_t /*bytes_transferred*/) { blocking_executor_op* o(static_cast<blocking_executor_op*>(base)); typename blocking_executor_op_base<Operation>::do_complete_cleanup on_exit = { o }; (void)on_exit; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Make the upcall if required. if (owner) { fenced_block b(fenced_block::half); BOOST_ASIO_HANDLER_INVOCATION_BEGIN(()); boost_asio_handler_invoke_helpers::invoke(o->handler_, o->handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } private: Handler& handler_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_BLOCKING_EXECUTOR_OP_HPP detail/wait_handler.hpp 0000644 00000005460 15125530236 0011167 0 ustar 00 // // detail/wait_handler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/wait_op.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Handler, typename IoExecutor> class wait_handler : public wait_op { public: BOOST_ASIO_DEFINE_HANDLER_PTR(wait_handler); wait_handler(Handler& h, const IoExecutor& io_ex) : wait_op(&wait_handler::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(h)), work_(handler_, io_ex) { } 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<wait_handler*>(base)); ptr p = { boost::asio::detail::addressof(h->handler_), h, h }; BOOST_ASIO_HANDLER_COMPLETION((*h)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( h->work_)); // 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, boost::system::error_code> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_WAIT_HANDLER_HPP detail/posix_global.hpp 0000644 00000003417 15125530236 0011210 0 ustar 00 // // detail/posix_global.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_PTHREADS) #include <exception> #include <pthread.h> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename T> 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 <typename T> ::pthread_once_t posix_global_impl<T>::init_once_ = PTHREAD_ONCE_INIT; template <typename T> T* posix_global_impl<T>::static_ptr_ = 0; template <typename T> posix_global_impl<T> posix_global_impl<T>::instance_; template <typename T> T& posix_global() { int result = ::pthread_once( &posix_global_impl<T>::init_once_, &posix_global_impl<T>::do_init); if (result != 0) std::terminate(); return *posix_global_impl<T>::instance_.ptr_; } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_PTHREADS) #endif // BOOST_ASIO_DETAIL_POSIX_GLOBAL_HPP detail/win_iocp_socket_send_op.hpp 0000644 00000007607 15125530236 0013421 0 ustar 00 // // detail/win_iocp_socket_send_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename ConstBufferSequence, typename Handler, typename IoExecutor> 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)), work_(handler_, io_ex) { } 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<win_iocp_socket_send_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) { buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence>::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, boost::system::error_code, std::size_t> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SEND_OP_HPP detail/posix_thread.hpp 0000644 00000004213 15125530236 0011212 0 ustar 00 // // detail/posix_thread.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_PTHREADS) #include <cstddef> #include <pthread.h> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Function> posix_thread(Function f, unsigned int = 0) : joined_(false) { start_thread(new func<Function>(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 <typename Function> 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/posix_thread.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_HAS_PTHREADS) #endif // BOOST_ASIO_DETAIL_POSIX_THREAD_HPP detail/winsock_init.hpp 0000644 00000006240 15125530236 0011223 0 ustar 00 // // detail/winsock_init.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) #include <boost/asio/detail/push_options.hpp> 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 <int Major = 2, int Minor = 0> 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 <int Major, int Minor> winsock_init_base::data winsock_init<Major, Minor>::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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/winsock_init.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) #endif // BOOST_ASIO_DETAIL_WINSOCK_INIT_HPP detail/service_registry.hpp 0000644 00000013015 15125530236 0012111 0 ustar 00 // // detail/service_registry.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <typeinfo> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { class io_context; namespace detail { template <typename T> 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 <typename Service> 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 <typename Service> 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 <typename Service> void add_service(Service* new_service); // Check whether a service object of the specified type already exists. template <typename Service> bool has_service() const; private: // Initalise a service's key when the key_type typedef is not available. template <typename Service> 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 <typename Service> static void init_key(execution_context::service::key& key, typename enable_if< is_base_of<typename Service::key_type, Service>::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 <typename Service> static void init_key_from_id(execution_context::service::key& key, const service_id<Service>& /*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 <typename Service, typename Owner> 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 <boost/asio/detail/pop_options.hpp> #include <boost/asio/detail/impl/service_registry.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/service_registry.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_DETAIL_SERVICE_REGISTRY_HPP detail/reactive_socket_recv_op.hpp 0000644 00000012471 15125530236 0013415 0 ustar 00 // // detail/reactive_socket_recv_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename MutableBufferSequence> class reactive_socket_recv_op_base : public reactor_op { public: reactive_socket_recv_op_base(const boost::system::error_code& success_ec, socket_type socket, socket_ops::state_type state, const MutableBufferSequence& buffers, socket_base::message_flags flags, func_type complete_func) : reactor_op(success_ec, &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<reactive_socket_recv_op_base*>(base)); typedef buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence> bufs_type; status result; if (bufs_type::is_single_buffer) { result = socket_ops::non_blocking_recv1(o->socket_, bufs_type::first(o->buffers_).data(), bufs_type::first(o->buffers_).size(), o->flags_, (o->state_ & socket_ops::stream_oriented) != 0, o->ec_, o->bytes_transferred_) ? done : not_done; } else { bufs_type bufs(o->buffers_); 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 <typename MutableBufferSequence, typename Handler, typename IoExecutor> class reactive_socket_recv_op : public reactive_socket_recv_op_base<MutableBufferSequence> { public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recv_op); reactive_socket_recv_op(const boost::system::error_code& success_ec, 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<MutableBufferSequence>(success_ec, socket, state, buffers, flags, &reactive_socket_recv_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), work_(handler_, io_ex) { } 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<reactive_socket_recv_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code, std::size_t> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECV_OP_HPP detail/local_free_on_block_exit.hpp 0000644 00000002676 15125530236 0013526 0 ustar 00 // // detail/local_free_on_block_exit.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_LOCAL_FREE_ON_BLOCK_EXIT_HPP #define BOOST_ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) #if !defined(BOOST_ASIO_WINDOWS_APP) #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class local_free_on_block_exit : private noncopyable { public: // Constructor blocks all signals for the calling thread. explicit local_free_on_block_exit(void* p) : p_(p) { } // Destructor restores the previous signal mask. ~local_free_on_block_exit() { ::LocalFree(p_); } private: void* p_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_WINDOWS_APP) #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) #endif // BOOST_ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP detail/win_iocp_socket_service.hpp 0000644 00000047361 15125530236 0013433 0 ustar 00 // // detail/win_iocp_socket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <cstring> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/socket_base.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/select_reactor.hpp> #include <boost/asio/detail/socket_holder.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/win_iocp_io_context.hpp> #include <boost/asio/detail/win_iocp_null_buffers_op.hpp> #include <boost/asio/detail/win_iocp_socket_accept_op.hpp> #include <boost/asio/detail/win_iocp_socket_connect_op.hpp> #include <boost/asio/detail/win_iocp_socket_recvfrom_op.hpp> #include <boost/asio/detail/win_iocp_socket_send_op.hpp> #include <boost/asio/detail/win_iocp_socket_service_base.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Protocol> class win_iocp_socket_service : public execution_context_service_base<win_iocp_socket_service<Protocol> >, 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<Protocol> >(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) BOOST_ASIO_NOEXCEPT { 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 <typename Protocol1> void converting_move_construct(implementation_type& impl, win_iocp_socket_service<Protocol1>&, 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 <typename Option> 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 <typename Option> 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 <typename ConstBufferSequence> 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<boost::asio::const_buffer, ConstBufferSequence> 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 <typename ConstBufferSequence, typename Handler, typename IoExecutor> 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<boost::asio::const_buffer, ConstBufferSequence> bufs(buffers); start_send_to_op(impl, bufs.buffers(), bufs.count(), destination.data(), static_cast<int>(destination.size()), flags, p.p); p.v = p.p = 0; } // Start an asynchronous wait until data can be sent without blocking. template <typename Handler, typename IoExecutor> 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<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_, 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 <typename MutableBufferSequence> 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<boost::asio::mutable_buffer, MutableBufferSequence> 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 <typename MutableBufferSequence, typename Handler, typename IoExecutor> 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<MutableBufferSequence, endpoint_type, Handler, IoExecutor> 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<boost::asio::mutable_buffer, MutableBufferSequence> 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 <typename Handler, typename IoExecutor> 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<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_, 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 <typename Socket> 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 <typename Socket, typename Handler, typename IoExecutor> 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<Socket, protocol_type, 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_, 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 <typename PeerIoExecutor, typename Handler, typename IoExecutor> 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 <typename Handler, typename IoExecutor> 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<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_, 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<int>(peer_endpoint.size()), p.p); p.v = p.p = 0; } }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_HPP detail/win_event.hpp 0000644 00000007540 15125530236 0010525 0 ustar 00 // // detail/win_event.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS) #include <cstddef> #include <boost/asio/detail/assert.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Lock> void signal(Lock& lock) { this->signal_all(lock); } // Signal all waiters. template <typename Lock> 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 <typename Lock> 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]); } // Unlock the mutex and signal one waiter who may destroy us. template <typename Lock> void unlock_and_signal_one_for_destruction(Lock& lock) { BOOST_ASIO_ASSERT(lock.locked()); state_ |= 1; bool have_waiters = (state_ > 1); if (have_waiters) ::SetEvent(events_[1]); lock.unlock(); } // If there's a waiter, unlock the mutex and signal it. template <typename Lock> 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 <typename Lock> 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 <typename Lock> 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 <typename Lock> 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/win_event.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_WINDOWS) #endif // BOOST_ASIO_DETAIL_WIN_EVENT_HPP detail/posix_event.hpp 0000644 00000010704 15125530236 0011066 0 ustar 00 // // detail/posix_event.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_PTHREADS) #include <cstddef> #include <pthread.h> #include <boost/asio/detail/assert.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Lock> void signal(Lock& lock) { this->signal_all(lock); } // Signal all waiters. template <typename Lock> 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 <typename Lock> 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. } // Unlock the mutex and signal one waiter who may destroy us. template <typename Lock> void unlock_and_signal_one_for_destruction(Lock& lock) { BOOST_ASIO_ASSERT(lock.locked()); state_ |= 1; bool have_waiters = (state_ > 1); if (have_waiters) ::pthread_cond_signal(&cond_); // Ignore EINVAL. lock.unlock(); } // If there's a waiter, unlock the mutex and signal it. template <typename Lock> 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 <typename Lock> void clear(Lock& lock) { BOOST_ASIO_ASSERT(lock.locked()); (void)lock; state_ &= ~std::size_t(1); } // Wait for the event to become signalled. template <typename Lock> 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 <typename Lock> 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/posix_event.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_HAS_PTHREADS) #endif // BOOST_ASIO_DETAIL_POSIX_EVENT_HPP detail/config.hpp 0000644 00000227106 15125530236 0007776 0 ustar 00 // // detail/config.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/config.hpp> # include <boost/version.hpp> # 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) // Helper macro for documentation. #define BOOST_ASIO_UNSPECIFIED(e) e // 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 <android/api-level.h> #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__ >= 8)) || (__GNUC__ > 4) # if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_MOVE 1 # endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__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<type&&> # define BOOST_ASIO_MOVE_CAST2(type1, type2) static_cast<type1, type2&&> # define BOOST_ASIO_MOVE_OR_LVALUE(type) static_cast<type&&> # define BOOST_ASIO_MOVE_OR_LVALUE_TYPE(type) type #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<const type&> # define BOOST_ASIO_MOVE_CAST2(type1, type2) static_cast<const type1, type2&> # define BOOST_ASIO_MOVE_OR_LVALUE(type) # define BOOST_ASIO_MOVE_OR_LVALUE_TYPE(type) type& #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__ >= 8)) || (__GNUC__ > 4) # if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_VARIADIC_TEMPLATES 1 # endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__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) #if !defined(BOOST_ASIO_ELLIPSIS) # if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) # define BOOST_ASIO_ELLIPSIS ... # else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) # define BOOST_ASIO_ELLIPSIS # endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #endif // !defined(BOOST_ASIO_ELLIPSIS) // 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 (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_DELETED = delete # endif // (__cplusplus >= 201103) || 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_constexpr__) # endif // defined(__clang__) # if defined(__GNUC__) # if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) # if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_CONSTEXPR 1 # endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__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) #if !defined(BOOST_ASIO_STATIC_CONSTEXPR) # if defined(BOOST_ASIO_HAS_CONSTEXPR) # define BOOST_ASIO_STATIC_CONSTEXPR(type, assignment) \ static constexpr type assignment # else // defined(BOOST_ASIO_HAS_CONSTEXPR) # define BOOST_ASIO_STATIC_CONSTEXPR(type, assignment) \ static const type assignment # endif // defined(BOOST_ASIO_HAS_CONSTEXPR) #endif // !defined(BOOST_ASIO_STATIC_CONSTEXPR) #if !defined(BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT) # if defined(BOOST_ASIO_HAS_CONSTEXPR) # if defined(__GNUC__) # if (__GNUC__ >= 8) # define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ static constexpr const type name{} # else // (__GNUC__ >= 8) # define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ static const type name # endif // (__GNUC__ >= 8) # elif defined(BOOST_ASIO_MSVC) # define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ static const type name # else // defined(BOOST_ASIO_MSVC) # define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ static constexpr const type name{} # endif // defined(BOOST_ASIO_MSVC) # else // defined(BOOST_ASIO_HAS_CONSTEXPR) # define BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT(type, name) \ static const type name # endif // defined(BOOST_ASIO_HAS_CONSTEXPR) #endif // !defined(BOOST_ASIO_STATIC_CONSTEXPR_DEFAULT_INIT) // Support noexcept on compilers known to allow it. #if !defined(BOOST_ASIO_HAS_NOEXCEPT) # if !defined(BOOST_ASIO_DISABLE_NOEXCEPT) # if defined(BOOST_ASIO_HAS_BOOST_CONFIG) && (BOOST_VERSION >= 105300) # if !defined(BOOST_NO_NOEXCEPT) # define BOOST_ASIO_HAS_NOEXCEPT 1 # endif // !defined(BOOST_NO_NOEXCEPT) # define BOOST_ASIO_NOEXCEPT BOOST_NOEXCEPT # define BOOST_ASIO_NOEXCEPT_OR_NOTHROW BOOST_NOEXCEPT_OR_NOTHROW # define BOOST_ASIO_NOEXCEPT_IF(c) BOOST_NOEXCEPT_IF(c) # elif defined(__clang__) # if __has_feature(__cxx_noexcept__) # define BOOST_ASIO_HAS_NOEXCEPT 1 # endif // __has_feature(__cxx_noexcept__) # elif defined(__GNUC__) # if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) # if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_NOEXCEPT 1 # endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) # elif defined(BOOST_ASIO_MSVC) # if (_MSC_VER >= 1900) # define BOOST_ASIO_HAS_NOEXCEPT 1 # endif // (_MSC_VER >= 1900) # endif // defined(BOOST_ASIO_MSVC) # endif // !defined(BOOST_ASIO_DISABLE_NOEXCEPT) # if !defined(BOOST_ASIO_NOEXCEPT) # endif // !defined(BOOST_ASIO_NOEXCEPT) # if !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) # endif // !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) #endif // !defined(BOOST_ASIO_HAS_NOEXCEPT) #if !defined(BOOST_ASIO_NOEXCEPT) # if defined(BOOST_ASIO_HAS_NOEXCEPT) # define BOOST_ASIO_NOEXCEPT noexcept(true) # else // defined(BOOST_ASIO_HAS_NOEXCEPT) # define BOOST_ASIO_NOEXCEPT # endif // defined(BOOST_ASIO_HAS_NOEXCEPT) #endif // !defined(BOOST_ASIO_NOEXCEPT) #if !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) # if defined(BOOST_ASIO_HAS_NOEXCEPT) # define BOOST_ASIO_NOEXCEPT_OR_NOTHROW noexcept(true) # else // defined(BOOST_ASIO_HAS_NOEXCEPT) # define BOOST_ASIO_NOEXCEPT_OR_NOTHROW throw() # endif // defined(BOOST_ASIO_HAS_NOEXCEPT) #endif // !defined(BOOST_ASIO_NOEXCEPT_OR_NOTHROW) #if !defined(BOOST_ASIO_NOEXCEPT_IF) # if defined(BOOST_ASIO_HAS_NOEXCEPT) # define BOOST_ASIO_NOEXCEPT_IF(c) noexcept(c) # else // defined(BOOST_ASIO_HAS_NOEXCEPT) # define BOOST_ASIO_NOEXCEPT_IF(c) # endif // defined(BOOST_ASIO_HAS_NOEXCEPT) #endif // !defined(BOOST_ASIO_NOEXCEPT_IF) // 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__ >= 8)) || (__GNUC__ > 4) # if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_DECLTYPE 1 # endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__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 (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_ALIAS_TEMPLATES 1 # endif // (__cplusplus >= 201103) || 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) // Support return type deduction on compilers known to allow it. #if !defined(BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION) # if !defined(BOOST_ASIO_DISABLE_RETURN_TYPE_DEDUCTION) # if defined(__clang__) # if __has_feature(__cxx_return_type_deduction__) # define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 # endif // __has_feature(__cxx_return_type_deduction__) # elif (__cplusplus >= 201402) # define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 # elif defined(__cpp_return_type_deduction) # if (__cpp_return_type_deduction >= 201304) # define BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION 1 # endif // (__cpp_return_type_deduction >= 201304) # endif // defined(__cpp_return_type_deduction) # endif // !defined(BOOST_ASIO_DISABLE_RETURN_TYPE_DEDUCTION) #endif // !defined(BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION) // Support default function template arguments on compilers known to allow it. #if !defined(BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) # if !defined(BOOST_ASIO_DISABLE_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) # if (__cplusplus >= 201103) # define BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS 1 # endif // (__cplusplus >= 201103) # endif // !defined(BOOST_ASIO_DISABLE_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) #endif // !defined(BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) // Support concepts on compilers known to allow them. #if !defined(BOOST_ASIO_HAS_CONCEPTS) # if !defined(BOOST_ASIO_DISABLE_CONCEPTS) # if defined(__cpp_concepts) # define BOOST_ASIO_HAS_CONCEPTS 1 # if (__cpp_concepts >= 201707) # define BOOST_ASIO_CONCEPT concept # else // (__cpp_concepts >= 201707) # define BOOST_ASIO_CONCEPT concept bool # endif // (__cpp_concepts >= 201707) # endif // defined(__cpp_concepts) # endif // !defined(BOOST_ASIO_DISABLE_CONCEPTS) #endif // !defined(BOOST_ASIO_HAS_CONCEPTS) // Support template variables on compilers known to allow it. #if !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) # if !defined(BOOST_ASIO_DISABLE_VARIABLE_TEMPLATES) # if defined(__clang__) # if (__cplusplus >= 201402) # if __has_feature(__cxx_variable_templates__) # define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 # endif // __has_feature(__cxx_variable_templates__) # endif // (__cplusplus >= 201402) # endif // defined(__clang__) # if defined(__GNUC__) && !defined(__INTEL_COMPILER) # if (__GNUC__ >= 6) # if (__cplusplus >= 201402) # define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 # endif // (__cplusplus >= 201402) # endif // (__GNUC__ >= 6) # endif // defined(__GNUC__) && !defined(__INTEL_COMPILER) # if defined(BOOST_ASIO_MSVC) # if (_MSC_VER >= 1901) # define BOOST_ASIO_HAS_VARIABLE_TEMPLATES 1 # endif // (_MSC_VER >= 1901) # endif // defined(BOOST_ASIO_MSVC) # endif // !defined(BOOST_ASIO_DISABLE_VARIABLE_TEMPLATES) #endif // !defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) // Support SFINAEd template variables on compilers known to allow it. #if !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) # if !defined(BOOST_ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES) # if defined(__clang__) # if (__cplusplus >= 201703) # if __has_feature(__cxx_variable_templates__) # define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 # endif // __has_feature(__cxx_variable_templates__) # endif // (__cplusplus >= 201703) # endif // defined(__clang__) # if defined(__GNUC__) # if ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8) # if (__cplusplus >= 201402) # define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 # endif // (__cplusplus >= 201402) # endif // ((__GNUC__ == 8) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 8) # endif // defined(__GNUC__) # if defined(BOOST_ASIO_MSVC) # if (_MSC_VER >= 1901) # define BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES 1 # endif // (_MSC_VER >= 1901) # endif // defined(BOOST_ASIO_MSVC) # endif // !defined(BOOST_ASIO_DISABLE_SFINAE_VARIABLE_TEMPLATES) #endif // !defined(BOOST_ASIO_HAS_SFINAE_VARIABLE_TEMPLATES) // Support SFINAE use of constant expressions on compilers known to allow it. #if !defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) # if !defined(BOOST_ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE) # if defined(__clang__) # if (__cplusplus >= 201402) # define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 # endif // (__cplusplus >= 201402) # endif // defined(__clang__) # if defined(__GNUC__) && !defined(__INTEL_COMPILER) # if (__GNUC__ >= 7) # if (__cplusplus >= 201402) # define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 # endif // (__cplusplus >= 201402) # endif // (__GNUC__ >= 7) # endif // defined(__GNUC__) && !defined(__INTEL_COMPILER) # if defined(BOOST_ASIO_MSVC) # if (_MSC_VER >= 1901) # define BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE 1 # endif // (_MSC_VER >= 1901) # endif // defined(BOOST_ASIO_MSVC) # endif // !defined(BOOST_ASIO_DISABLE_CONSTANT_EXPRESSION_SFINAE) #endif // !defined(BOOST_ASIO_HAS_CONSTANT_EXPRESSION_SFINAE) // Enable workarounds for lack of working expression SFINAE. #if !defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) # if !defined(BOOST_ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) # if !defined(BOOST_ASIO_MSVC) && !defined(__INTEL_COMPILER) # if (__cplusplus >= 201103) # define BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE 1 # endif // (__cplusplus >= 201103) # endif // !defined(BOOST_ASIO_MSVC) && !defined(__INTEL_COMPILER) # endif // !defined(BOOST_ASIO_DISABLE_WORKING_EXPRESSION_SFINAE) #endif // !defined(BOOST_ASIO_HAS_WORKING_EXPRESSION_SFINAE) // Support ref-qualified functions on compilers known to allow it. #if !defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) # if !defined(BOOST_ASIO_DISABLE_REF_QUALIFIED_FUNCTIONS) # if defined(__clang__) # if __has_feature(__cxx_reference_qualified_functions__) # define BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1 # endif // __has_feature(__cxx_reference_qualified_functions__) # endif // defined(__clang__) # if defined(__GNUC__) # if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) # if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1 # endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)) || (__GNUC__ > 4) # endif // defined(__GNUC__) # if defined(BOOST_ASIO_MSVC) # if (_MSC_VER >= 1900) # define BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS 1 # endif // (_MSC_VER >= 1900) # endif // defined(BOOST_ASIO_MSVC) # endif // !defined(BOOST_ASIO_DISABLE_REF_QUALIFIED_FUNCTIONS) #endif // !defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) #if defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) # if !defined(BOOST_ASIO_LVALUE_REF_QUAL) # define BOOST_ASIO_LVALUE_REF_QUAL & # endif // !defined(BOOST_ASIO_LVALUE_REF_QUAL) # if !defined(BOOST_ASIO_RVALUE_REF_QUAL) # define BOOST_ASIO_RVALUE_REF_QUAL && # endif // !defined(BOOST_ASIO_RVALUE_REF_QUAL) #else // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) # if !defined(BOOST_ASIO_LVALUE_REF_QUAL) # define BOOST_ASIO_LVALUE_REF_QUAL # endif // !defined(BOOST_ASIO_LVALUE_REF_QUAL) # if !defined(BOOST_ASIO_RVALUE_REF_QUAL) # define BOOST_ASIO_RVALUE_REF_QUAL # endif // !defined(BOOST_ASIO_RVALUE_REF_QUAL) #endif // defined(BOOST_ASIO_HAS_REF_QUALIFIED_FUNCTIONS) // 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(<system_error>) # define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 # endif // __has_include(<system_error>) # endif // (__cplusplus >= 201103) # endif // defined(__clang__) # if defined(__GNUC__) # if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) # if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_STD_SYSTEM_ERROR 1 # endif // (__cplusplus >= 201103) || 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 (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_ERROR_CATEGORY_NOEXCEPT noexcept(true) # endif // (__cplusplus >= 201103) || 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(<array>) # define BOOST_ASIO_HAS_STD_ARRAY 1 # endif // __has_include(<array>) # endif // (__cplusplus >= 201103) # endif // defined(__clang__) # if defined(__GNUC__) # if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 4) # if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_STD_ARRAY 1 # endif // (__cplusplus >= 201103) || 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 (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_STD_SHARED_PTR 1 # endif // (__cplusplus >= 201103) || 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 (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_STD_ALLOCATOR_ARG 1 # endif // (__cplusplus >= 201103) || 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(<atomic>) # define BOOST_ASIO_HAS_STD_ATOMIC 1 # endif // __has_include(<atomic>) # elif defined(__apple_build_version__) && defined(_LIBCPP_VERSION) # if (__clang_major__ >= 10) # if __has_include(<atomic>) # define BOOST_ASIO_HAS_STD_ATOMIC 1 # endif // __has_include(<atomic>) # 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 (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_STD_ATOMIC 1 # endif // (__cplusplus >= 201103) || 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(<chrono>) # define BOOST_ASIO_HAS_STD_CHRONO 1 # endif // __has_include(<chrono>) # endif // (__cplusplus >= 201103) # endif // defined(__clang__) # if defined(__GNUC__) # if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) # if (__cplusplus >= 201103) || 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 // (__cplusplus >= 201103) || 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 (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_STD_ADDRESSOF 1 # endif // (__cplusplus >= 201103) || 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 (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_STD_FUNCTION 1 # endif // (__cplusplus >= 201103) || 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(<type_traits>) # define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 # endif // __has_include(<type_traits>) # endif // (__cplusplus >= 201103) # endif // defined(__clang__) # if defined(__GNUC__) # if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__GNUC__ > 4) # if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_STD_TYPE_TRAITS 1 # endif // (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # endif // ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) || (__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_nullptr__) # elif defined(__GNUC__) # if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6)) || (__GNUC__ > 4) # if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_NULLPTR 1 # endif // (__cplusplus >= 201103) || 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 (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_CXX11_ALLOCATORS 1 # endif // (__cplusplus >= 201103) || 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 (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_CSTDINT 1 # endif // (__cplusplus >= 201103) || 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(<thread>) # define BOOST_ASIO_HAS_STD_THREAD 1 # endif // __has_include(<thread>) # endif // (__cplusplus >= 201103) # endif // defined(__clang__) # if defined(__GNUC__) # if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) # if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_STD_THREAD 1 # endif // (__cplusplus >= 201103) || 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(<mutex>) # define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 # endif // __has_include(<mutex>) # endif // (__cplusplus >= 201103) # endif // defined(__clang__) # if defined(__GNUC__) # if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) # if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR 1 # endif // (__cplusplus >= 201103) || 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(<mutex>) # define BOOST_ASIO_HAS_STD_CALL_ONCE 1 # endif // __has_include(<mutex>) # endif // (__cplusplus >= 201103) # endif // defined(__clang__) # if defined(__GNUC__) # if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) # if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_STD_CALL_ONCE 1 # endif // (__cplusplus >= 201103) || 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(<future>) # define BOOST_ASIO_HAS_STD_FUTURE 1 # endif // __has_include(<future>) # endif // (__cplusplus >= 201103) # endif // defined(__clang__) # if defined(__GNUC__) # if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) # if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_STD_FUTURE 1 # endif // (__cplusplus >= 201103) || 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(<string_view>) # define BOOST_ASIO_HAS_STD_STRING_VIEW 1 # endif // __has_include(<string_view>) # endif // (__cplusplus >= 201402) # else // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) # if (__cplusplus >= 201703) # if __has_include(<string_view>) # define BOOST_ASIO_HAS_STD_STRING_VIEW 1 # endif // __has_include(<string_view>) # 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(<experimental/string_view>) # define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 # endif // __has_include(<experimental/string_view>) # endif // (__cplusplus >= 201402) # endif // (_LIBCPP_VERSION < 7000) # else // defined(BOOST_ASIO_HAS_CLANG_LIBCXX) # if (__cplusplus >= 201402) # if __has_include(<experimental/string_view>) # define BOOST_ASIO_HAS_STD_EXPERIMENTAL_STRING_VIEW 1 # endif // __has_include(<experimental/string_view>) # 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 (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_STD_IOSTREAM_MOVE 1 # endif // (__cplusplus >= 201103) || 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) // Standard library support for std::exception_ptr and std::current_exception. #if !defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) # if !defined(BOOST_ASIO_DISABLE_STD_EXCEPTION_PTR) # if defined(__clang__) # if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) # define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 # elif (__cplusplus >= 201103) # define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 # endif // (__cplusplus >= 201103) # elif defined(__GNUC__) # if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) # if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_STD_EXCEPTION_PTR 1 # endif // (__cplusplus >= 201103) || 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_STD_EXCEPTION_PTR 1 # endif // (_MSC_VER >= 1800) # endif // defined(BOOST_ASIO_MSVC) # endif // !defined(BOOST_ASIO_DISABLE_STD_EXCEPTION_PTR) #endif // !defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) // Standard library support for std::nested_exception. #if !defined(BOOST_ASIO_HAS_STD_NESTED_EXCEPTION) # if !defined(BOOST_ASIO_DISABLE_STD_NESTED_EXCEPTION) # if defined(__clang__) # if defined(BOOST_ASIO_HAS_CLANG_LIBCXX) # define BOOST_ASIO_HAS_STD_NESTED_EXCEPTION 1 # elif (__cplusplus >= 201103) # define BOOST_ASIO_HAS_STD_NESTED_EXCEPTION 1 # endif // (__cplusplus >= 201103) # elif defined(__GNUC__) # if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) || (__GNUC__ > 4) # if (__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__) # define BOOST_ASIO_HAS_STD_NESTED_EXCEPTION 1 # endif // (__cplusplus >= 201103) || 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_STD_NESTED_EXCEPTION 1 # endif // (_MSC_VER >= 1900) # endif // defined(BOOST_ASIO_MSVC) # endif // !defined(BOOST_ASIO_DISABLE_STD_NESTED_EXCEPTION) #endif // !defined(BOOST_ASIO_HAS_STD_NESTED_EXCEPTION) // Standard library support for std::any. #if !defined(BOOST_ASIO_HAS_STD_ANY) # if !defined(BOOST_ASIO_DISABLE_STD_ANY) # if defined(__clang__) # if (__cplusplus >= 201703) # if __has_include(<any>) # define BOOST_ASIO_HAS_STD_ANY 1 # endif // __has_include(<any>) # endif // (__cplusplus >= 201703) # elif defined(__GNUC__) # if (__GNUC__ >= 7) # if (__cplusplus >= 201703) # define BOOST_ASIO_HAS_STD_ANY 1 # endif // (__cplusplus >= 201703) # endif // (__GNUC__ >= 7) # endif // defined(__GNUC__) # if defined(BOOST_ASIO_MSVC) # if (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) # define BOOST_ASIO_HAS_STD_ANY 1 # endif // (_MSC_VER >= 1910) && (_MSVC_LANG >= 201703) # endif // defined(BOOST_ASIO_MSVC) # endif // !defined(BOOST_ASIO_DISABLE_STD_ANY) #endif // !defined(BOOST_ASIO_HAS_STD_ANY) // Standard library support for std::source_location. #if !defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) # if !defined(BOOST_ASIO_DISABLE_STD_SOURCE_LOCATION) // ... # endif // !defined(BOOST_ASIO_DISABLE_STD_SOURCE_LOCATION) #endif // !defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) // Standard library support for std::experimental::source_location. #if !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) # if !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION) # if defined(__GNUC__) # if (__cplusplus >= 201709) # if __has_include(<experimental/source_location>) # define BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION 1 # endif // __has_include(<experimental/source_location>) # endif // (__cplusplus >= 201709) # endif // defined(__GNUC__) # endif // !defined(BOOST_ASIO_DISABLE_STD_EXPERIMENTAL_SOURCE_LOCATION) #endif // !defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) // Standard library has a source_location that we can use. #if !defined(BOOST_ASIO_HAS_SOURCE_LOCATION) # if !defined(BOOST_ASIO_DISABLE_SOURCE_LOCATION) # if defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) # define BOOST_ASIO_HAS_SOURCE_LOCATION 1 # elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) # define BOOST_ASIO_HAS_SOURCE_LOCATION 1 # endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) # endif // !defined(BOOST_ASIO_DISABLE_SOURCE_LOCATION) #endif // !defined(BOOST_ASIO_HAS_SOURCE_LOCATION) // Windows App target. Windows but with a limited API. #if !defined(BOOST_ASIO_WINDOWS_APP) # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0603) # include <winapifamily.h> # if (WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) \ || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_TV_TITLE)) \ && !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 <winapifamily.h> # 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__) && !defined(__clang__)) # 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__) && !defined(__clang__)) # 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__) && !defined(__clang__)) # 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 <unistd.h> #endif // defined(BOOST_ASIO_HAS_UNISTD_H) // Linux: epoll, eventfd and timerfd. #if defined(__linux__) # include <linux/version.h> # 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_RUNTIME) # define BOOST_ASIO_HAS_LOCAL_SOCKETS 1 # endif // !defined(BOOST_ASIO_WINDOWS_RUNTIME) # 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__) || defined(__clang__) # define BOOST_ASIO_HAS_HANDLER_HOOKS 1 # endif // !defined(__BORLANDC__) || defined(__clang__) # 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 the co_await keyword 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_VER >= 1928) && (_MSVC_LANG >= 201705) # define BOOST_ASIO_HAS_CO_AWAIT 1 # elif (_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) # if defined(__clang__) # if (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) # if __has_include(<experimental/coroutine>) # define BOOST_ASIO_HAS_CO_AWAIT 1 # endif // __has_include(<experimental/coroutine>) # endif // (__cplusplus >= 201703) && (__cpp_coroutines >= 201703) # elif defined(__GNUC__) # if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) # if __has_include(<coroutine>) # define BOOST_ASIO_HAS_CO_AWAIT 1 # endif // __has_include(<coroutine>) # endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) # endif // defined(__GNUC__) # endif // !defined(BOOST_ASIO_DISABLE_CO_AWAIT) #endif // !defined(BOOST_ASIO_HAS_CO_AWAIT) // Standard library support for coroutines. #if !defined(BOOST_ASIO_HAS_STD_COROUTINE) # if !defined(BOOST_ASIO_DISABLE_STD_COROUTINE) # if defined(BOOST_ASIO_MSVC) # if (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) # define BOOST_ASIO_HAS_STD_COROUTINE 1 # endif // (_MSC_VER >= 1928) && (_MSVC_LANG >= 201705) # endif // defined(BOOST_ASIO_MSVC) # if defined(__GNUC__) # if (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) # if __has_include(<coroutine>) # define BOOST_ASIO_HAS_STD_COROUTINE 1 # endif // __has_include(<coroutine>) # endif // (__cplusplus >= 201709) && (__cpp_impl_coroutine >= 201902) # endif // defined(__GNUC__) # endif // !defined(BOOST_ASIO_DISABLE_STD_COROUTINE) #endif // !defined(BOOST_ASIO_HAS_STD_COROUTINE) // Compiler support for the the [[nodiscard]] attribute. #if !defined(BOOST_ASIO_NODISCARD) # if defined(__has_cpp_attribute) # if __has_cpp_attribute(nodiscard) # if (__cplusplus >= 201703) # define BOOST_ASIO_NODISCARD [[nodiscard]] # endif // (__cplusplus >= 201703) # endif // __has_cpp_attribute(nodiscard) # endif // defined(__has_cpp_attribute) #endif // !defined(BOOST_ASIO_NODISCARD) #if !defined(BOOST_ASIO_NODISCARD) # define BOOST_ASIO_NODISCARD #endif // !defined(BOOST_ASIO_NODISCARD) // Kernel support for MSG_NOSIGNAL. #if !defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) # if defined(__linux__) # define BOOST_ASIO_HAS_MSG_NOSIGNAL 1 # elif defined(_POSIX_VERSION) # if (_POSIX_VERSION >= 200809L) # define BOOST_ASIO_HAS_MSG_NOSIGNAL 1 # endif // _POSIX_VERSION >= 200809L # endif // defined(_POSIX_VERSION) #endif // !defined(BOOST_ASIO_HAS_MSG_NOSIGNAL) #endif // BOOST_ASIO_DETAIL_CONFIG_HPP detail/array_fwd.hpp 0000644 00000001666 15125530236 0010510 0 ustar 00 // // detail/array_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> namespace boost { template<class T, std::size_t N> 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 <array> #endif // defined(BOOST_ASIO_HAS_STD_ARRAY) #endif // BOOST_ASIO_DETAIL_ARRAY_FWD_HPP detail/win_iocp_socket_recv_op.hpp 0000644 00000010210 15125530236 0013407 0 ustar 00 // // detail/win_iocp_socket_recv_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename MutableBufferSequence, typename Handler, typename IoExecutor> 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)), work_(handler_, io_ex) { } 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<win_iocp_socket_recv_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) { buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence>::validate(o->buffers_); } #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) socket_ops::complete_iocp_recv(o->state_, o->cancel_token_, buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence>::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, boost::system::error_code, std::size_t> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECV_OP_HPP detail/chrono_time_traits.hpp 0000644 00000010565 15125530236 0012424 0 ustar 00 // // detail/chrono_time_traits.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/cstdint.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { // Helper template to compute the greatest common divisor. template <int64_t v1, int64_t v2> struct gcd { enum { value = gcd<v2, v1 % v2>::value }; }; template <int64_t v1> struct gcd<v1, 0> { enum { value = v1 }; }; // Adapts std::chrono clocks for use with a deadline timer. template <typename Clock, typename WaitTraits> 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 Num, int64_t Den> int64_t duration_cast() const { const int64_t num1 = period_type::num / gcd<period_type::num, Num>::value; const int64_t num2 = Num / gcd<period_type::num, Num>::value; const int64_t den1 = period_type::den / gcd<period_type::den, Den>::value; const int64_t den2 = Den / gcd<period_type::den, Den>::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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_CHRONO_TIME_TRAITS_HPP detail/winrt_ssocket_service_base.hpp 0000644 00000031106 15125530236 0014132 0 ustar 00 // // detail/winrt_ssocket_service_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_SSOCKET_SERVICE_BASE_HPP #define BOOST_ASIO_DETAIL_WINRT_SSOCKET_SERVICE_BASE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <boost/asio/buffer.hpp> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/socket_base.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/winrt_async_manager.hpp> #include <boost/asio/detail/winrt_socket_recv_op.hpp> #include <boost/asio/detail/winrt_socket_send_op.hpp> #if defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/win_iocp_io_context.hpp> #else // defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/scheduler.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class winrt_ssocket_service_base { public: // The native type of a socket. typedef Windows::Networking::Sockets::StreamSocket^ native_handle_type; // The implementation type of the socket. struct base_implementation_type { // Default constructor. base_implementation_type() : socket_(nullptr), next_(0), prev_(0) { } // The underlying native socket. native_handle_type socket_; // Pointers to adjacent socket implementations in linked list. base_implementation_type* next_; base_implementation_type* prev_; }; // Constructor. BOOST_ASIO_DECL winrt_ssocket_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&); // Move-construct a new socket implementation. BOOST_ASIO_DECL void base_move_construct(base_implementation_type& impl, base_implementation_type& other_impl) BOOST_ASIO_NOEXCEPT; // Move-assign from another socket implementation. BOOST_ASIO_DECL void base_move_assign(base_implementation_type& impl, winrt_ssocket_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_ != nullptr; } // 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 native_handle_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::system::error_code cancel(base_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 base_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 base_implementation_type&, boost::system::error_code& ec) const { ec = boost::asio::error::operation_not_supported; return 0; } // Perform an IO control command on the socket. template <typename IO_Control_Command> boost::system::error_code io_control(base_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 base_implementation_type&) const { return false; } // Sets the non-blocking mode of the socket. boost::system::error_code non_blocking(base_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 base_implementation_type&) const { return false; } // Sets the non-blocking mode of the native socket implementation. boost::system::error_code native_non_blocking(base_implementation_type&, bool, boost::system::error_code& ec) { ec = boost::asio::error::operation_not_supported; return ec; } // Send the given data to the peer. template <typename ConstBufferSequence> std::size_t send(base_implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, boost::system::error_code& ec) { return do_send(impl, buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence>::first(buffers), flags, ec); } // Wait until data can be sent without blocking. std::size_t send(base_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 <typename ConstBufferSequence, typename Handler, typename IoExecutor> 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 winrt_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(buffers, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((scheduler_.context(), *p.p, "socket", &impl, 0, "async_send")); start_send_op(impl, buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence>::first(buffers), flags, p.p, is_continuation); p.v = p.p = 0; } // Start an asynchronous wait until data can be sent without blocking. template <typename Handler, typename IoExecutor> void async_send(base_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 <typename MutableBufferSequence> std::size_t receive(base_implementation_type& impl, const MutableBufferSequence& buffers, socket_base::message_flags flags, boost::system::error_code& ec) { return do_receive(impl, buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence>::first(buffers), flags, ec); } // Wait until data can be received without blocking. std::size_t receive(base_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 <typename MutableBufferSequence, typename Handler, typename IoExecutor> 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 winrt_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(buffers, handler, io_ex); BOOST_ASIO_HANDLER_CREATION((scheduler_.context(), *p.p, "socket", &impl, 0, "async_receive")); start_receive_op(impl, buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence>::first(buffers), flags, p.p, is_continuation); p.v = p.p = 0; } // Wait until data can be received without blocking. template <typename Handler, typename IoExecutor> void async_receive(base_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)); } protected: // Helper function to obtain endpoints associated with the connection. BOOST_ASIO_DECL std::size_t do_get_endpoint( const base_implementation_type& impl, bool local, void* addr, std::size_t addr_len, boost::system::error_code& ec) const; // Helper function to set a socket option. BOOST_ASIO_DECL boost::system::error_code do_set_option( base_implementation_type& impl, int level, int optname, const void* optval, std::size_t optlen, boost::system::error_code& ec); // Helper function to get a socket option. BOOST_ASIO_DECL void do_get_option( const base_implementation_type& impl, int level, int optname, void* optval, std::size_t* optlen, boost::system::error_code& ec) const; // Helper function to perform a synchronous connect. BOOST_ASIO_DECL boost::system::error_code do_connect( base_implementation_type& impl, const void* addr, boost::system::error_code& ec); // Helper function to start an asynchronous connect. BOOST_ASIO_DECL void start_connect_op( base_implementation_type& impl, const void* addr, winrt_async_op<void>* op, bool is_continuation); // Helper function to perform a synchronous send. BOOST_ASIO_DECL std::size_t do_send( base_implementation_type& impl, const boost::asio::const_buffer& data, socket_base::message_flags flags, boost::system::error_code& ec); // Helper function to start an asynchronous send. BOOST_ASIO_DECL void start_send_op(base_implementation_type& impl, const boost::asio::const_buffer& data, socket_base::message_flags flags, winrt_async_op<unsigned int>* op, bool is_continuation); // Helper function to perform a synchronous receive. BOOST_ASIO_DECL std::size_t do_receive( base_implementation_type& impl, const boost::asio::mutable_buffer& data, socket_base::message_flags flags, boost::system::error_code& ec); // Helper function to start an asynchronous receive. BOOST_ASIO_DECL void start_receive_op(base_implementation_type& impl, const boost::asio::mutable_buffer& data, socket_base::message_flags flags, winrt_async_op<Windows::Storage::Streams::IBuffer^>* op, bool is_continuation); // 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_; // The manager that keeps track of outstanding operations. winrt_async_manager& async_manager_; // 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/winrt_ssocket_service_base.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_WINRT_SSOCKET_SERVICE_BASE_HPP detail/regex_fwd.hpp 0000644 00000001516 15125530236 0010476 0 ustar 00 // // detail/regex_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/regex_fwd.hpp> #include <boost/regex/v4/match_flags.hpp> namespace boost { template <class BidiIterator> struct sub_match; template <class BidiIterator, class Allocator> class match_results; } // namespace boost #endif // defined(BOOST_ASIO_HAS_BOOST_REGEX) #endif // BOOST_ASIO_DETAIL_REGEX_FWD_HPP detail/solaris_fenced_block.hpp 0000644 00000002472 15125530236 0012660 0 ustar 00 // // detail/solaris_fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(__sun) #include <atomic.h> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(__sun) #endif // BOOST_ASIO_DETAIL_SOLARIS_FENCED_BLOCK_HPP detail/posix_signal_blocker.hpp 0000644 00000003667 15125530236 0012735 0 ustar 00 // // detail/posix_signal_blocker.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_PTHREADS) #include <csignal> #include <pthread.h> #include <signal.h> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_PTHREADS) #endif // BOOST_ASIO_DETAIL_POSIX_SIGNAL_BLOCKER_HPP detail/socket_ops.hpp 0000644 00000033135 15125530236 0010677 0 ustar 00 // // detail/socket_ops.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/system/error_code.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/push_options.hpp> 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<void> shared_cancel_token_type; typedef weak_ptr<void> 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 signed_size_type recv1(socket_type s, void* data, size_t size, 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); BOOST_ASIO_DECL size_t sync_recv1(socket_type s, state_type state, void* data, size_t size, int flags, 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); BOOST_ASIO_DECL bool non_blocking_recv1(socket_type s, void* data, size_t size, 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 signed_size_type recvfrom1(socket_type s, void* data, size_t size, 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); BOOST_ASIO_DECL size_t sync_recvfrom1(socket_type s, state_type state, void* data, size_t size, 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); BOOST_ASIO_DECL bool non_blocking_recvfrom1(socket_type s, void* data, size_t size, 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 signed_size_type send1(socket_type s, const void* data, size_t size, 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); BOOST_ASIO_DECL size_t sync_send1(socket_type s, state_type state, const void* data, size_t size, int flags, 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); BOOST_ASIO_DECL bool non_blocking_send1(socket_type s, const void* data, size_t size, 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 signed_size_type sendto1(socket_type s, const void* data, size_t size, 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); BOOST_ASIO_DECL size_t sync_sendto1(socket_type s, state_type state, const void* data, size_t size, 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); BOOST_ASIO_DECL bool non_blocking_sendto1(socket_type s, const void* data, size_t size, 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/socket_ops.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_DETAIL_SOCKET_OPS_HPP detail/win_iocp_socket_connect_op.hpp 0000644 00000010062 15125530236 0014106 0 ustar 00 // // detail/win_iocp_socket_connect_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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(boost::system::error_code(), &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<win_iocp_socket_connect_op_base*>(base)); return socket_ops::non_blocking_connect( o->socket_, o->ec_) ? done : not_done; } socket_type socket_; bool connect_ex_; }; template <typename Handler, typename IoExecutor> 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)), work_(handler_, io_ex) { } 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<win_iocp_socket_connect_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; if (owner) { if (o->connect_ex_) socket_ops::complete_iocp_connect(o->socket_, ec); else ec = o->ec_; } BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_CONNECT_OP_HPP detail/win_iocp_io_context.hpp 0000644 00000026743 15125530236 0012577 0 ustar 00 // // detail/win_iocp_io_context.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/limits.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/scoped_ptr.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/thread.hpp> #include <boost/asio/detail/thread_context.hpp> #include <boost/asio/detail/timer_queue_base.hpp> #include <boost/asio/detail/timer_queue_set.hpp> #include <boost/asio/detail/wait_op.hpp> #include <boost/asio/detail/win_iocp_operation.hpp> #include <boost/asio/detail/win_iocp_thread_info.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class wait_op; class win_iocp_io_context : public execution_context_service_base<win_iocp_io_context>, 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; } /// Capture the current exception so it can be rethrown from a run function. BOOST_ASIO_DECL void capture_current_exception(); // 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<win_iocp_operation>& 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<operation>& 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 <typename Time_Traits> void add_timer_queue(timer_queue<Time_Traits>& timer_queue); // Remove a timer queue from the service. template <typename Time_Traits> void remove_timer_queue(timer_queue<Time_Traits>& timer_queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template <typename Time_Traits> void schedule_timer(timer_queue<Time_Traits>& queue, const typename Time_Traits::time_type& time, typename timer_queue<Time_Traits>::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 <typename Time_Traits> std::size_t cancel_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); // Move the timer operations associated with the given timer. template <typename Time_Traits> void move_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& to, typename timer_queue<Time_Traits>::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, win_iocp_thread_info& this_thread, 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<thread> 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<win_iocp_operation> 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> thread_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/detail/impl/win_iocp_io_context.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/win_iocp_io_context.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_WIN_IOCP_IO_CONTEXT_HPP detail/cstdint.hpp 0000644 00000003026 15125530236 0010172 0 ustar 00 // // detail/cstdint.hpp // ~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_CSTDINT) # include <cstdint> #else // defined(BOOST_ASIO_HAS_CSTDINT) # include <boost/cstdint.hpp> #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 detail/win_fenced_block.hpp 0000644 00000004132 15125530236 0011774 0 ustar 00 // // detail/win_fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS) && !defined(UNDER_CE) #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS) && !defined(UNDER_CE) #endif // BOOST_ASIO_DETAIL_WIN_FENCED_BLOCK_HPP detail/timer_queue.hpp 0000644 00000023221 15125530236 0011045 0 ustar 00 // // detail/timer_queue.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <vector> #include <boost/asio/detail/cstdint.hpp> #include <boost/asio/detail/date_time_fwd.hpp> #include <boost/asio/detail/limits.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/timer_queue_base.hpp> #include <boost/asio/detail/wait_op.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Time_Traits> 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<std::size_t>::max)()), next_(0), prev_(0) { } private: friend class timer_queue; // The operations waiting on the timer. op_queue<wait_op> 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<std::size_t>::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<operation>& 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<operation>& 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<operation>& ops, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::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<std::size_t>::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<std::size_t>::max)(); heap_.pop_back(); } else { swap_heap(index, heap_.size() - 1); timer.heap_index_ = (std::numeric_limits<std::size_t>::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 <typename Time_Type> static bool is_positive_infinity(const Time_Type&) { return false; } // Determine if the specified absolute time is positive infinity. template <typename T, typename TimeSystem> static bool is_positive_infinity( const boost::date_time::base_time<T, TimeSystem>& time) { return time.is_pos_infinity(); } // Helper function to convert a duration into milliseconds. template <typename Duration> 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<long>(msec); } // Helper function to convert a duration into microseconds. template <typename Duration> 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<long>(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_entry> heap_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_HPP detail/concurrency_hint.hpp 0000644 00000007736 15125530236 0012112 0 ustar 00 // // detail/concurrency_hint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/noncopyable.hpp> // 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<unsigned>(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<unsigned>(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<int>(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<int>(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<int>(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 detail/handler_alloc_helpers.hpp 0000644 00000020054 15125530236 0013033 0 ustar 00 // // detail/handler_alloc_helpers.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/recycling_allocator.hpp> #include <boost/asio/detail/thread_info_base.hpp> #include <boost/asio/associated_allocator.hpp> #include <boost/asio/handler_alloc_hook.hpp> #include <boost/asio/detail/push_options.hpp> // 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 { #if defined(BOOST_ASIO_NO_DEPRECATED) template <typename Handler> inline void error_if_hooks_are_defined(Handler& h) { using boost::asio::asio_handler_allocate; // If you get an error here it is because some of your handlers still // overload asio_handler_allocate, but this hook is no longer used. (void)static_cast<boost::asio::asio_handler_allocate_is_no_longer_used>( asio_handler_allocate(static_cast<std::size_t>(0), boost::asio::detail::addressof(h))); using boost::asio::asio_handler_deallocate; // If you get an error here it is because some of your handlers still // overload asio_handler_deallocate, but this hook is no longer used. (void)static_cast<boost::asio::asio_handler_deallocate_is_no_longer_used>( asio_handler_deallocate(static_cast<void*>(0), static_cast<std::size_t>(0), boost::asio::detail::addressof(h))); } #endif // defined(BOOST_ASIO_NO_DEPRECATED) template <typename Handler> inline void* allocate(std::size_t s, Handler& h) { #if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) return ::operator new(s); #elif defined(BOOST_ASIO_NO_DEPRECATED) // The asio_handler_allocate hook is no longer used to obtain memory. (void)&error_if_hooks_are_defined<Handler>; (void)h; #if !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) return boost::asio::detail::thread_info_base::allocate( boost::asio::detail::thread_context::thread_call_stack::top(), s); #else // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) return ::operator new(size); #endif // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) #else using boost::asio::asio_handler_allocate; return asio_handler_allocate(s, boost::asio::detail::addressof(h)); #endif } template <typename Handler> inline void deallocate(void* p, std::size_t s, Handler& h) { #if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) ::operator delete(p); #elif defined(BOOST_ASIO_NO_DEPRECATED) // The asio_handler_allocate hook is no longer used to obtain memory. (void)&error_if_hooks_are_defined<Handler>; (void)h; #if !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) boost::asio::detail::thread_info_base::deallocate( boost::asio::detail::thread_context::thread_call_stack::top(), p, s); #else // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) (void)s; ::operator delete(p); #endif // !defined(BOOST_ASIO_DISABLE_SMALL_BLOCK_RECYCLING) #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 <typename Handler, typename T> class hook_allocator { public: typedef T value_type; template <typename U> struct rebind { typedef hook_allocator<Handler, U> other; }; explicit hook_allocator(Handler& h) : handler_(h) { } template <typename U> hook_allocator(const hook_allocator<Handler, U>& a) : handler_(a.handler_) { } T* allocate(std::size_t n) { return static_cast<T*>( 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 <typename Handler> class hook_allocator<Handler, void> { public: typedef void value_type; template <typename U> struct rebind { typedef hook_allocator<Handler, U> other; }; explicit hook_allocator(Handler& h) : handler_(h) { } template <typename U> hook_allocator(const hook_allocator<Handler, U>& a) : handler_(a.handler_) { } //private: Handler& handler_; }; template <typename Handler, typename Allocator> struct get_hook_allocator { typedef Allocator type; static type get(Handler&, const Allocator& a) { return a; } }; template <typename Handler, typename T> struct get_hook_allocator<Handler, std::allocator<T> > { typedef hook_allocator<Handler, T> type; static type get(Handler& handler, const std::allocator<T>&) { 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<op*>(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<op*>(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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_HANDLER_ALLOC_HELPERS_HPP detail/handler_invoke_helpers.hpp 0000644 00000005233 15125530236 0013236 0 ustar 00 // // detail/handler_invoke_helpers.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/handler_invoke_hook.hpp> #include <boost/asio/detail/push_options.hpp> // 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 { #if defined(BOOST_ASIO_NO_DEPRECATED) template <typename Function, typename Context> inline void error_if_hook_is_defined(Function& function, Context& context) { using boost::asio::asio_handler_invoke; // If you get an error here it is because some of your handlers still // overload asio_handler_invoke, but this hook is no longer used. (void)static_cast<boost::asio::asio_handler_invoke_is_no_longer_used>( asio_handler_invoke(function, boost::asio::detail::addressof(context))); } #endif // defined(BOOST_ASIO_NO_DEPRECATED) template <typename Function, typename Context> inline void invoke(Function& function, Context& context) { #if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) Function tmp(function); tmp(); #elif defined(BOOST_ASIO_NO_DEPRECATED) // The asio_handler_invoke hook is no longer used to invoke the function. (void)&error_if_hook_is_defined<Function, Context>; (void)context; function(); #else using boost::asio::asio_handler_invoke; asio_handler_invoke(function, boost::asio::detail::addressof(context)); #endif } template <typename Function, typename Context> inline void invoke(const Function& function, Context& context) { #if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) Function tmp(function); tmp(); #elif defined(BOOST_ASIO_NO_DEPRECATED) // The asio_handler_invoke hook is no longer used to invoke the function. (void)&error_if_hook_is_defined<const Function, Context>; (void)context; 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_HANDLER_INVOKE_HELPERS_HPP detail/reactive_socket_service.hpp 0000644 00000044335 15125530236 0013424 0 ustar 00 // // detail/reactive_socket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/buffer.hpp> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/socket_base.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/reactive_null_buffers_op.hpp> #include <boost/asio/detail/reactive_socket_accept_op.hpp> #include <boost/asio/detail/reactive_socket_connect_op.hpp> #include <boost/asio/detail/reactive_socket_recvfrom_op.hpp> #include <boost/asio/detail/reactive_socket_sendto_op.hpp> #include <boost/asio/detail/reactive_socket_service_base.hpp> #include <boost/asio/detail/reactor.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_holder.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Protocol> class reactive_socket_service : public execution_context_service_base<reactive_socket_service<Protocol> >, 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<Protocol> >(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) BOOST_ASIO_NOEXCEPT { 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 <typename Protocol1> void converting_move_construct(implementation_type& impl, reactive_socket_service<Protocol1>&, 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 <typename Option> 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 <typename Option> 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 <typename ConstBufferSequence> size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, boost::system::error_code& ec) { typedef buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence> bufs_type; if (bufs_type::is_single_buffer) { return socket_ops::sync_sendto1(impl.socket_, impl.state_, bufs_type::first(buffers).data(), bufs_type::first(buffers).size(), flags, destination.data(), destination.size(), ec); } else { bufs_type 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 <typename ConstBufferSequence, typename Handler, typename IoExecutor> 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<ConstBufferSequence, endpoint_type, Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, 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 <typename Handler, typename IoExecutor> 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<Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, 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 <typename MutableBufferSequence> size_t receive_from(implementation_type& impl, const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, boost::system::error_code& ec) { typedef buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence> bufs_type; std::size_t addr_len = sender_endpoint.capacity(); std::size_t bytes_recvd; if (bufs_type::is_single_buffer) { bytes_recvd = socket_ops::sync_recvfrom1(impl.socket_, impl.state_, bufs_type::first(buffers).data(), bufs_type::first(buffers).size(), flags, sender_endpoint.data(), &addr_len, ec); } else { bufs_type bufs(buffers); 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 <typename MutableBufferSequence, typename Handler, typename IoExecutor> 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<MutableBufferSequence, endpoint_type, Handler, IoExecutor> 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(success_ec_, 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 <typename Handler, typename IoExecutor> 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<Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, 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 <typename Socket> 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 <typename Socket, typename Handler, typename IoExecutor> 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<Socket, Protocol, Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, 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 <typename PeerIoExecutor, typename Handler, typename IoExecutor> 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<Protocol, PeerIoExecutor, Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, 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 <typename Handler, typename IoExecutor> 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<Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, 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 <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SERVICE_HPP detail/reactor_fwd.hpp 0000644 00000002203 15125530236 0011015 0 ustar 00 // // detail/reactor_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> 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 detail/thread_group.hpp 0000644 00000004046 15125530236 0011210 0 ustar 00 // // detail/thread_group.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/scoped_ptr.hpp> #include <boost/asio/detail/thread.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Function> void create_thread(Function f) { first_ = new item(f, first_); } // Create new threads in the group. template <typename Function> 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 <typename Function> 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 #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_THREAD_GROUP_HPP detail/array.hpp 0000644 00000001751 15125530236 0007643 0 ustar 00 // // detail/array.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_STD_ARRAY) # include <array> #else // defined(BOOST_ASIO_HAS_STD_ARRAY) # include <boost/array.hpp> #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 detail/win_iocp_wait_op.hpp 0000644 00000007660 15125530236 0012063 0 ustar 00 // // detail/win_iocp_wait_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Handler, typename IoExecutor> 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(boost::system::error_code(), &win_iocp_wait_op::do_perform, &win_iocp_wait_op::do_complete), cancel_token_(cancel_token), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), work_(handler_, io_ex) { } 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<win_iocp_wait_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_WIN_IOCP_WAIT_OP_HPP detail/win_iocp_handle_service.hpp 0000644 00000031144 15125530236 0013366 0 ustar 00 // // detail/win_iocp_handle_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/cstdint.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/win_iocp_handle_read_op.hpp> #include <boost/asio/detail/win_iocp_handle_write_op.hpp> #include <boost/asio/detail/win_iocp_io_context.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class win_iocp_handle_service : public execution_context_service_base<win_iocp_handle_service> { 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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<boost::asio::const_buffer, ConstBufferSequence>::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 <typename ConstBufferSequence, typename Handler, typename IoExecutor> 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<uintmax_t>(impl.handle_), "async_write_some")); start_write_op(impl, 0, buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence>::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 <typename ConstBufferSequence, typename Handler, typename IoExecutor> 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<uintmax_t>(impl.handle_), "async_write_some_at")); start_write_op(impl, offset, buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence>::first(buffers), p.p); p.v = p.p = 0; } // Read some data. Returns the number of bytes received. template <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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<boost::asio::mutable_buffer, MutableBufferSequence>::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 <typename MutableBufferSequence, typename Handler, typename IoExecutor> 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<uintmax_t>(impl.handle_), "async_read_some")); start_read_op(impl, 0, buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence>::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 <typename MutableBufferSequence, typename Handler, typename IoExecutor> 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<uintmax_t>(impl.handle_), "async_read_some_at")); start_read_op(impl, offset, buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence>::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 <typename Handler, typename IoExecutor> void async_write_some(implementation_type& impl, const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex); template <typename Handler, typename IoExecutor> 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 <typename Handler, typename IoExecutor> void async_read_some(implementation_type& impl, const null_buffers& buffers, Handler& handler, const IoExecutor& io_ex); template <typename Handler, typename IoExecutor> 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/win_iocp_handle_service.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_SERVICE_HPP detail/select_interrupter.hpp 0000644 00000002622 15125530236 0012445 0 ustar 00 // // detail/select_interrupter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_WINDOWS_RUNTIME) #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) || defined(__SYMBIAN32__) # include <boost/asio/detail/socket_select_interrupter.hpp> #elif defined(BOOST_ASIO_HAS_EVENTFD) # include <boost/asio/detail/eventfd_select_interrupter.hpp> #else # include <boost/asio/detail/pipe_select_interrupter.hpp> #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 detail/event.hpp 0000644 00000002524 15125530236 0007645 0 ustar 00 // // detail/event.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_HAS_THREADS) # include <boost/asio/detail/null_event.hpp> #elif defined(BOOST_ASIO_WINDOWS) # include <boost/asio/detail/win_event.hpp> #elif defined(BOOST_ASIO_HAS_PTHREADS) # include <boost/asio/detail/posix_event.hpp> #elif defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) # include <boost/asio/detail/std_event.hpp> #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 detail/std_fenced_block.hpp 0000644 00000002600 15125530236 0011767 0 ustar 00 // // detail/std_fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_STD_ATOMIC) #include <atomic> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_STD_ATOMIC) #endif // BOOST_ASIO_DETAIL_STD_FENCED_BLOCK_HPP detail/pop_options.hpp 0000644 00000005475 15125530236 0011105 0 ustar 00 // // detail/pop_options.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the 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) # pragma GCC diagnostic pop #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) # pragma GCC diagnostic pop #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__) && !defined(__clang__) // 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 detail/handler_cont_helpers.hpp 0000644 00000002524 15125530236 0012706 0 ustar 00 // // detail/handler_cont_helpers.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/handler_continuation_hook.hpp> #include <boost/asio/detail/push_options.hpp> // 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 <typename Context> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_HANDLER_CONT_HELPERS_HPP detail/push_options.hpp 0000644 00000011615 15125530236 0011257 0 ustar 00 // // detail/push_options.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the 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) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wnon-virtual-dtor" # if (__clang_major__ >= 6) # pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" # endif // (__clang_major__ >= 6) #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) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wnon-virtual-dtor" # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || (__GNUC__ > 4) # pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" # endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || (__GNUC__ > 4) # if (__GNUC__ >= 7) # 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__) && !defined(__clang__) // 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 detail/strand_service.hpp 0000644 00000011440 15125530236 0011534 0 ustar 00 // // detail/strand_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/io_context.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/scoped_ptr.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { // Default service implementation for a strand. class strand_service : public boost::asio::detail::service_base<strand_service> { 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<operation> 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<operation> 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 <typename Handler> void dispatch(implementation_type& impl, Handler& handler); // Request the io_context to invoke the given handler and return immediately. template <typename Handler> 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 used to obtain an I/O executor. io_context& io_context_; // The io_context implementation used to post completions. io_context_impl& io_context_impl_; // 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<strand_impl> 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 <boost/asio/detail/pop_options.hpp> #include <boost/asio/detail/impl/strand_service.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/strand_service.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_DETAIL_STRAND_SERVICE_HPP detail/std_global.hpp 0000644 00000003040 15125530236 0010630 0 ustar 00 // // detail/std_global.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_STD_CALL_ONCE) #include <exception> #include <mutex> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename T> 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 <typename T> std::once_flag std_global_impl<T>::init_once_; template <typename T> std_global_impl<T> std_global_impl<T>::instance_; template <typename T> T& std_global() { std::call_once(std_global_impl<T>::init_once_, &std_global_impl<T>::do_init); return *std_global_impl<T>::instance_.ptr_; } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_STD_CALL_ONCE) #endif // BOOST_ASIO_DETAIL_STD_GLOBAL_HPP detail/wince_thread.hpp 0000644 00000005173 15125530236 0011163 0 ustar 00 // // detail/wince_thread.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/scoped_ptr.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { DWORD WINAPI wince_thread_function(LPVOID arg); class wince_thread : private noncopyable { public: // Constructor. template <typename Function> wince_thread(Function f, unsigned int = 0) { scoped_ptr<func_base> arg(new func<Function>(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 <typename Function> 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<wince_thread::func_base> func( static_cast<wince_thread::func_base*>(arg)); func->run(); return 0; } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE) #endif // BOOST_ASIO_DETAIL_WINCE_THREAD_HPP detail/cstddef.hpp 0000644 00000001460 15125530236 0010136 0 ustar 00 // // detail/cstddef.hpp // ~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> 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 detail/timer_queue_ptime.hpp 0000644 00000006074 15125530236 0012252 0 ustar 00 // // detail/timer_queue_ptime.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) #include <boost/asio/time_traits.hpp> #include <boost/asio/detail/timer_queue.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { struct forwarding_posix_time_traits : time_traits<boost::posix_time::ptime> {}; // Template specialisation for the commonly used instantation. template <> class timer_queue<time_traits<boost::posix_time::ptime> > : 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<forwarding_posix_time_traits>::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<operation>& ops); // Dequeue all timers. BOOST_ASIO_DECL virtual void get_all_timers(op_queue<operation>& ops); // Cancel and dequeue operations for the given timer. BOOST_ASIO_DECL std::size_t cancel_timer( per_timer_data& timer, op_queue<operation>& ops, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::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<forwarding_posix_time_traits> impl_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/timer_queue_ptime.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) #endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_PTIME_HPP detail/macos_fenced_block.hpp 0000644 00000002544 15125530236 0012306 0 ustar 00 // // detail/macos_fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(__MACH__) && defined(__APPLE__) #include <libkern/OSAtomic.h> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(__MACH__) && defined(__APPLE__) #endif // BOOST_ASIO_DETAIL_MACOS_FENCED_BLOCK_HPP detail/win_iocp_overlapped_ptr.hpp 0000644 00000010502 15125530236 0013434 0 ustar 00 // // detail/win_iocp_overlapped_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/io_context.hpp> #include <boost/asio/query.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/win_iocp_overlapped_op.hpp> #include <boost/asio/detail/win_iocp_io_context.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Executor, typename Handler> 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 <typename Executor, typename Handler> void reset(const Executor& ex, Handler handler) { win_iocp_io_context* iocp_service = this->get_iocp_service(ex); typedef win_iocp_overlapped_op<Handler, Executor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler, ex); 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<DWORD>(bytes_transferred)); ptr_ = 0; iocp_service_ = 0; } } private: template <typename Executor> static win_iocp_io_context* get_iocp_service(const Executor& ex, typename enable_if< can_query<const Executor&, execution::context_t>::value >::type* = 0) { return &use_service<win_iocp_io_context>( boost::asio::query(ex, execution::context)); } template <typename Executor> static win_iocp_io_context* get_iocp_service(const Executor& ex, typename enable_if< !can_query<const Executor&, execution::context_t>::value >::type* = 0) { return &use_service<win_iocp_io_context>(ex.context()); } static win_iocp_io_context* get_iocp_service( const io_context::executor_type& ex) { return &boost::asio::query(ex, execution::context).impl_; } win_iocp_operation* ptr_; win_iocp_io_context* iocp_service_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_PTR_HPP detail/winrt_socket_send_op.hpp 0000644 00000007135 15125530236 0012751 0 ustar 00 // // detail/winrt_socket_send_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_SOCKET_SEND_OP_HPP #define BOOST_ASIO_DETAIL_WINRT_SOCKET_SEND_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/winrt_async_op.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename ConstBufferSequence, typename Handler, typename IoExecutor> class winrt_socket_send_op : public winrt_async_op<unsigned int> { public: BOOST_ASIO_DEFINE_HANDLER_PTR(winrt_socket_send_op); winrt_socket_send_op(const ConstBufferSequence& buffers, Handler& handler, const IoExecutor& io_ex) : winrt_async_op<unsigned int>(&winrt_socket_send_op::do_complete), buffers_(buffers), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), work_(handler_, io_ex) { } static void do_complete(void* owner, operation* base, const boost::system::error_code&, std::size_t) { // Take ownership of the operation object. winrt_socket_send_op* o(static_cast<winrt_socket_send_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) { buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence>::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, boost::system::error_code, std::size_t> handler(o->handler_, o->ec_, o->result_); 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_; handler_work<Handler, IoExecutor> executor_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_WINRT_SOCKET_SEND_OP_HPP detail/thread_info_base.hpp 0000644 00000012170 15125530236 0011776 0 ustar 00 // // detail/thread_info_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <climits> #include <cstddef> #include <boost/asio/detail/noncopyable.hpp> #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ && !defined(BOOST_ASIO_NO_EXCEPTIONS) # include <exception> # include <boost/asio/multiple_exceptions.hpp> #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) // && !defined(BOOST_ASIO_NO_EXCEPTIONS) #include <boost/asio/detail/push_options.hpp> 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() #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ && !defined(BOOST_ASIO_NO_EXCEPTIONS) : has_pending_exception_(0) #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) // && !defined(BOOST_ASIO_NO_EXCEPTIONS) { 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) { // The following test for non-null pointers is technically redundant, but // it is significantly faster when using a tight io_context::poll() loop // in latency sensitive applications. 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 <typename Purpose> 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<unsigned char*>(pointer); if (static_cast<std::size_t>(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<unsigned char*>(pointer); mem[size] = (chunks <= UCHAR_MAX) ? static_cast<unsigned char>(chunks) : 0; return pointer; } template <typename Purpose> 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<unsigned char*>(pointer); mem[0] = mem[size]; this_thread->reusable_memory_[Purpose::mem_index] = pointer; return; } } ::operator delete(pointer); } void capture_current_exception() { #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ && !defined(BOOST_ASIO_NO_EXCEPTIONS) switch (has_pending_exception_) { case 0: has_pending_exception_ = 1; pending_exception_ = std::current_exception(); break; case 1: has_pending_exception_ = 2; pending_exception_ = std::make_exception_ptr<multiple_exceptions>( multiple_exceptions(pending_exception_)); break; default: break; } #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) // && !defined(BOOST_ASIO_NO_EXCEPTIONS) } void rethrow_pending_exception() { #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ && !defined(BOOST_ASIO_NO_EXCEPTIONS) if (has_pending_exception_ > 0) { has_pending_exception_ = 0; std::exception_ptr ex( BOOST_ASIO_MOVE_CAST(std::exception_ptr)( pending_exception_)); std::rethrow_exception(ex); } #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) // && !defined(BOOST_ASIO_NO_EXCEPTIONS) } private: enum { chunk_size = 4 }; enum { max_mem_index = 3 }; void* reusable_memory_[max_mem_index]; #if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \ && !defined(BOOST_ASIO_NO_EXCEPTIONS) int has_pending_exception_; std::exception_ptr pending_exception_; #endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) // && !defined(BOOST_ASIO_NO_EXCEPTIONS) }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_THREAD_INFO_BASE_HPP detail/non_const_lvalue.hpp 0000644 00000002742 15125530236 0012076 0 ustar 00 // // detail/non_const_lvalue.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename T> struct non_const_lvalue { #if defined(BOOST_ASIO_HAS_MOVE) explicit non_const_lvalue(T& t) : value(static_cast<typename conditional< is_same<T, typename decay<T>::type>::value, typename decay<T>::type&, T&&>::type>(t)) { } typename conditional<is_same<T, typename decay<T>::type>::value, typename decay<T>::type&, typename decay<T>::type>::type value; #else // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) explicit non_const_lvalue(const typename decay<T>::type& t) : value(t) { } typename decay<T>::type value; #endif // defined(BOOST_ASIO_HAS_MOVE) }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_NON_CONST_LVALUE_HPP detail/tss_ptr.hpp 0000644 00000003533 15125530236 0010223 0 ustar 00 // // detail/tss_ptr.hpp // ~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_HAS_THREADS) # include <boost/asio/detail/null_tss_ptr.hpp> #elif defined(BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION) # include <boost/asio/detail/keyword_tss_ptr.hpp> #elif defined(BOOST_ASIO_WINDOWS) # include <boost/asio/detail/win_tss_ptr.hpp> #elif defined(BOOST_ASIO_HAS_PTHREADS) # include <boost/asio/detail/posix_tss_ptr.hpp> #else # error Only Windows and POSIX are supported! #endif #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename T> class tss_ptr #if !defined(BOOST_ASIO_HAS_THREADS) : public null_tss_ptr<T> #elif defined(BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION) : public keyword_tss_ptr<T> #elif defined(BOOST_ASIO_WINDOWS) : public win_tss_ptr<T> #elif defined(BOOST_ASIO_HAS_PTHREADS) : public posix_tss_ptr<T> #endif { public: void operator=(T* value) { #if !defined(BOOST_ASIO_HAS_THREADS) null_tss_ptr<T>::operator=(value); #elif defined(BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION) keyword_tss_ptr<T>::operator=(value); #elif defined(BOOST_ASIO_WINDOWS) win_tss_ptr<T>::operator=(value); #elif defined(BOOST_ASIO_HAS_PTHREADS) posix_tss_ptr<T>::operator=(value); #endif } }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_TSS_PTR_HPP detail/keyword_tss_ptr.hpp 0000644 00000002621 15125530236 0011764 0 ustar 00 // // detail/keyword_tss_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION) #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename T> 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 <typename T> BOOST_ASIO_THREAD_KEYWORD T* keyword_tss_ptr<T>::value_; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_THREAD_KEYWORD_EXTENSION) #endif // BOOST_ASIO_DETAIL_KEYWORD_TSS_PTR_HPP detail/resolve_endpoint_op.hpp 0000644 00000011444 15125530236 0012602 0 ustar 00 // // detail/resolve_endpoint_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/resolve_op.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/error.hpp> #include <boost/asio/ip/basic_resolver_results.hpp> #if defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/win_iocp_io_context.hpp> #else // defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/scheduler.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Protocol, typename Handler, typename IoExecutor> 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<Protocol> 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)), work_(handler_, io_ex) { } 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<resolve_endpoint_op*>(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 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)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code, results_type> 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_; handler_work<Handler, IoExecutor> work_; results_type results_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_RESOLVER_ENDPOINT_OP_HPP detail/scheduler_thread_info.hpp 0000644 00000002067 15125530236 0013046 0 ustar 00 // // detail/scheduler_thread_info.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/thread_info_base.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class scheduler; class scheduler_operation; struct scheduler_thread_info : public thread_info_base { op_queue<scheduler_operation> private_op_queue; long private_outstanding_work; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_SCHEDULER_THREAD_INFO_HPP detail/win_static_mutex.hpp 0000644 00000003621 15125530236 0012111 0 ustar 00 // // detail/win_static_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS) #include <boost/asio/detail/scoped_lock.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { struct win_static_mutex { typedef boost::asio::detail::scoped_lock<win_static_mutex> 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/win_static_mutex.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_WINDOWS) #endif // BOOST_ASIO_DETAIL_WIN_STATIC_MUTEX_HPP detail/null_tss_ptr.hpp 0000644 00000002370 15125530236 0011253 0 ustar 00 // // detail/null_tss_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_HAS_THREADS) #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename T> 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 <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_HAS_THREADS) #endif // BOOST_ASIO_DETAIL_NULL_TSS_PTR_HPP detail/deadline_timer_service.hpp 0000644 00000022031 15125530236 0013204 0 ustar 00 // // detail/deadline_timer_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/timer_queue.hpp> #include <boost/asio/detail/timer_queue_ptime.hpp> #include <boost/asio/detail/timer_scheduler.hpp> #include <boost/asio/detail/wait_handler.hpp> #include <boost/asio/detail/wait_op.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <chrono> # include <thread> #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Time_Traits> class deadline_timer_service : public execution_context_service_base<deadline_timer_service<Time_Traits> > { 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<Time_Traits>::per_timer_data timer_data; }; // Constructor. deadline_timer_service(execution_context& context) : execution_context_service_base< deadline_timer_service<Time_Traits> >(context), scheduler_(boost::asio::use_service<timer_scheduler>(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 timer 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 timer 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; } // Move-construct a new timer implementation. void converting_move_construct(implementation_type& impl, deadline_timer_service&, implementation_type& other_impl) { move_construct(impl, other_impl); } // Move-assign from another timer implementation. void converting_move_assign(implementation_type& impl, deadline_timer_service& other_service, implementation_type& other_impl) { move_assign(impl, other_service, other_impl); } // 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 <typename Handler, typename IoExecutor> void async_wait(implementation_type& impl, Handler& handler, const IoExecutor& io_ex) { // Allocate and construct an operation to wrap the handler. typedef wait_handler<Handler, IoExecutor> 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 <typename Duration> 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<Time_Traits> timer_queue_; // The object that schedules and executes timers. Usually a reactor. timer_scheduler& scheduler_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_DEADLINE_TIMER_SERVICE_HPP detail/reactive_socket_recvfrom_op.hpp 0000644 00000013034 15125530236 0014275 0 ustar 00 // // detail/reactive_socket_recvfrom_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename MutableBufferSequence, typename Endpoint> class reactive_socket_recvfrom_op_base : public reactor_op { public: reactive_socket_recvfrom_op_base(const boost::system::error_code& success_ec, socket_type socket, int protocol_type, const MutableBufferSequence& buffers, Endpoint& endpoint, socket_base::message_flags flags, func_type complete_func) : reactor_op(success_ec, &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<reactive_socket_recvfrom_op_base*>(base)); typedef buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence> bufs_type; std::size_t addr_len = o->sender_endpoint_.capacity(); status result; if (bufs_type::is_single_buffer) { result = socket_ops::non_blocking_recvfrom1( o->socket_, bufs_type::first(o->buffers_).data(), bufs_type::first(o->buffers_).size(), o->flags_, o->sender_endpoint_.data(), &addr_len, o->ec_, o->bytes_transferred_) ? done : not_done; } else { bufs_type bufs(o->buffers_); 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 <typename MutableBufferSequence, typename Endpoint, typename Handler, typename IoExecutor> class reactive_socket_recvfrom_op : public reactive_socket_recvfrom_op_base<MutableBufferSequence, Endpoint> { public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvfrom_op); reactive_socket_recvfrom_op(const boost::system::error_code& success_ec, 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<MutableBufferSequence, Endpoint>( success_ec, socket, protocol_type, buffers, endpoint, flags, &reactive_socket_recvfrom_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), work_(handler_, io_ex) { } 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<reactive_socket_recvfrom_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code, std::size_t> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVFROM_OP_HPP detail/io_object_impl.hpp 0000644 00000011604 15125530236 0011501 0 ustar 00 // // io_object_impl.hpp // ~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <new> #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/context.hpp> #include <boost/asio/io_context.hpp> #include <boost/asio/query.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename IoObjectService, typename Executor = io_context::executor_type> 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; // Construct an I/O object using an executor. explicit io_object_impl(const executor_type& ex) : service_(&boost::asio::use_service<IoObjectService>( io_object_impl::get_context(ex))), executor_(ex) { service_->construct(implementation_); } // Construct an I/O object using an execution context. template <typename ExecutionContext> explicit io_object_impl(ExecutionContext& context, typename enable_if<is_convertible< ExecutionContext&, execution_context&>::value>::type* = 0) : service_(&boost::asio::use_service<IoObjectService>(context)), executor_(context.get_executor()) { 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()), executor_(other.get_executor()) { service_->move_construct(implementation_, other.implementation_); } // Perform a converting move-construction of an I/O object. template <typename IoObjectService1, typename Executor1> io_object_impl(io_object_impl<IoObjectService1, Executor1>&& other) : service_(&boost::asio::use_service<IoObjectService>( io_object_impl::get_context(other.get_executor()))), executor_(other.get_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_); executor_.~executor_type(); new (&executor_) executor_type(other.executor_); service_ = other.service_; } return *this; } #endif // defined(BOOST_ASIO_HAS_MOVE) // Get the executor associated with the object. const executor_type& get_executor() BOOST_ASIO_NOEXCEPT { return 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: // Helper function to get an executor's context. template <typename T> static execution_context& get_context(const T& t, typename enable_if<execution::is_executor<T>::value>::type* = 0) { return boost::asio::query(t, execution::context); } // Helper function to get an executor's context. template <typename T> static execution_context& get_context(const T& t, typename enable_if<!execution::is_executor<T>::value>::type* = 0) { return t.context(); } // 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. executor_type executor_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_IO_OBJECT_IMPL_HPP detail/reactive_serial_port_service.hpp 0000644 00000020172 15125530236 0014450 0 ustar 00 // // detail/reactive_serial_port_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_SERIAL_PORT) #if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) #include <string> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/serial_port_base.hpp> #include <boost/asio/detail/descriptor_ops.hpp> #include <boost/asio/detail/reactive_descriptor_service.hpp> #include <boost/asio/detail/push_options.hpp> 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<reactive_serial_port_service> { 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 <typename SettableSerialPortOption> 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<SettableSerialPortOption>, &option, ec); } // Get an option from the serial port. template <typename GettableSerialPortOption> 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<GettableSerialPortOption>, &option, ec); } // Send a break sequence to the serial port. boost::system::error_code send_break(implementation_type& impl, boost::system::error_code& ec) { int result = ::tcsendbreak(descriptor_service_.native_handle(impl), 0); descriptor_ops::get_last_error(ec, result < 0); return ec; } // Write the given data. Returns the number of bytes sent. template <typename ConstBufferSequence> 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 <typename ConstBufferSequence, typename Handler, typename IoExecutor> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence, typename Handler, typename IoExecutor> 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 <typename SettableSerialPortOption> static boost::system::error_code store_option(const void* option, termios& storage, boost::system::error_code& ec) { static_cast<const SettableSerialPortOption*>(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 <typename GettableSerialPortOption> static boost::system::error_code load_option(void* option, const termios& storage, boost::system::error_code& ec) { static_cast<GettableSerialPortOption*>(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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/reactive_serial_port_service.ipp> #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 detail/reactive_socket_recvmsg_op.hpp 0000644 00000011624 15125530236 0014123 0 ustar 00 // // detail/reactive_socket_recvmsg_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/socket_base.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename MutableBufferSequence> class reactive_socket_recvmsg_op_base : public reactor_op { public: reactive_socket_recvmsg_op_base(const boost::system::error_code& success_ec, socket_type socket, const MutableBufferSequence& buffers, socket_base::message_flags in_flags, socket_base::message_flags& out_flags, func_type complete_func) : reactor_op(success_ec, &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<reactive_socket_recvmsg_op_base*>(base)); buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence> 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 <typename MutableBufferSequence, typename Handler, typename IoExecutor> class reactive_socket_recvmsg_op : public reactive_socket_recvmsg_op_base<MutableBufferSequence> { public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_recvmsg_op); reactive_socket_recvmsg_op(const boost::system::error_code& success_ec, 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<MutableBufferSequence>( success_ec, socket, buffers, in_flags, out_flags, &reactive_socket_recvmsg_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), work_(handler_, io_ex) { } 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<reactive_socket_recvmsg_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code, std::size_t> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_RECVMSG_OP_HPP detail/win_iocp_socket_service_base.hpp 0000644 00000055705 15125530236 0014426 0 ustar 00 // // detail/win_iocp_socket_service_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/socket_base.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/select_reactor.hpp> #include <boost/asio/detail/socket_holder.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/win_iocp_io_context.hpp> #include <boost/asio/detail/win_iocp_null_buffers_op.hpp> #include <boost/asio/detail/win_iocp_socket_connect_op.hpp> #include <boost/asio/detail/win_iocp_socket_send_op.hpp> #include <boost/asio/detail/win_iocp_socket_recv_op.hpp> #include <boost/asio/detail/win_iocp_socket_recvmsg_op.hpp> #include <boost/asio/detail/win_iocp_wait_op.hpp> #include <boost/asio/detail/push_options.hpp> 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) BOOST_ASIO_NOEXCEPT; // 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 <typename IO_Control_Command> 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<ioctl_arg_type*>(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 <typename Handler, typename IoExecutor> 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<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_, 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 <typename ConstBufferSequence> size_t send(base_implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, boost::system::error_code& ec) { buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence> 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 <typename ConstBufferSequence, typename Handler, typename IoExecutor> 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<boost::asio::const_buffer, ConstBufferSequence> 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 <typename Handler, typename IoExecutor> 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<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_, 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 <typename MutableBufferSequence> size_t receive(base_implementation_type& impl, const MutableBufferSequence& buffers, socket_base::message_flags flags, boost::system::error_code& ec) { buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence> 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 <typename MutableBufferSequence, typename Handler, typename IoExecutor> 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<boost::asio::mutable_buffer, MutableBufferSequence> 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 <typename Handler, typename IoExecutor> 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<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_, 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 <typename MutableBufferSequence> 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<boost::asio::mutable_buffer, MutableBufferSequence> 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 <typename MutableBufferSequence, typename Handler, typename IoExecutor> 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<boost::asio::mutable_buffer, MutableBufferSequence> 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 <typename Handler, typename IoExecutor> 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<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_, 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/win_iocp_socket_service_base.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_SERVICE_BASE_HPP detail/conditionally_enabled_event.hpp 0000644 00000006064 15125530236 0014252 0 ustar 00 // // detail/conditionally_enabled_event.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/conditionally_enabled_mutex.hpp> #include <boost/asio/detail/event.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/null_event.hpp> #include <boost/asio/detail/scoped_lock.hpp> #include <boost/asio/detail/push_options.hpp> 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); } // Unlock the mutex and signal one waiter who may destroy us. void unlock_and_signal_one_for_destruction( 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_EVENT_HPP detail/timer_scheduler_fwd.hpp 0000644 00000002311 15125530236 0012534 0 ustar 00 // // detail/timer_scheduler_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> 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 detail/posix_tss_ptr.hpp 0000644 00000003410 15125530236 0011437 0 ustar 00 // // detail/posix_tss_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_PTHREADS) #include <pthread.h> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename T> 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<T*>(::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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/posix_tss_ptr.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_HAS_PTHREADS) #endif // BOOST_ASIO_DETAIL_POSIX_TSS_PTR_HPP detail/conditionally_enabled_mutex.hpp 0000644 00000006066 15125530236 0014275 0 ustar 00 // // detail/conditionally_enabled_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/scoped_lock.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_CONDITIONALLY_ENABLED_MUTEX_HPP detail/win_iocp_operation.hpp 0000644 00000004213 15125530236 0012410 0 ustar 00 // // detail/win_iocp_operation.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/handler_tracking.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/system/error_code.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_WIN_IOCP_OPERATION_HPP detail/scoped_ptr.hpp 0000644 00000002650 15125530236 0010666 0 ustar 00 // // detail/scoped_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename T> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_SCOPED_PTR_HPP detail/win_global.hpp 0000644 00000003376 15125530236 0010647 0 ustar 00 // // detail/win_global.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/static_mutex.hpp> #include <boost/asio/detail/tss_ptr.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename T> 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<T> tss_ptr_; }; template <typename T> win_global_impl<T> win_global_impl<T>::instance_ = { 0 }; template <typename T> static_mutex win_global_impl<T>::mutex_ = BOOST_ASIO_STATIC_MUTEX_INIT; template <typename T> tss_ptr<T> win_global_impl<T>::tss_ptr_; template <typename T> T& win_global() { if (static_cast<T*>(win_global_impl<T>::tss_ptr_) == 0) { win_global_impl<T>::mutex_.init(); static_mutex::scoped_lock lock(win_global_impl<T>::mutex_); if (win_global_impl<T>::instance_.ptr_ == 0) win_global_impl<T>::instance_.ptr_ = new T; win_global_impl<T>::tss_ptr_ = win_global_impl<T>::instance_.ptr_; } return *win_global_impl<T>::tss_ptr_; } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_WIN_GLOBAL_HPP detail/win_object_handle_service.hpp 0000644 00000014401 15125530236 0013677 0 ustar 00 // // detail/win_object_handle_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/wait_handler.hpp> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #if defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/win_iocp_io_context.hpp> #else // defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/scheduler.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class win_object_handle_service : public execution_context_service_base<win_object_handle_service> { 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<wait_op> 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 <typename Handler, typename IoExecutor> void async_wait(implementation_type& impl, Handler& handler, const IoExecutor& io_ex) { // Allocate and construct an operation to wrap the handler. typedef wait_handler<Handler, IoExecutor> 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<uintmax_t>(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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/win_object_handle_service.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) #endif // BOOST_ASIO_DETAIL_WIN_OBJECT_HANDLE_SERVICE_HPP detail/date_time_fwd.hpp 0000644 00000001430 15125530236 0011312 0 ustar 00 // // detail/date_time_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> namespace boost { namespace date_time { template<class T, class TimeSystem> class base_time; } // namespace date_time namespace posix_time { class ptime; } // namespace posix_time } // namespace boost #endif // BOOST_ASIO_DETAIL_DATE_TIME_FWD_HPP detail/bulk_executor_op.hpp 0000644 00000005341 15125530236 0012075 0 ustar 00 // // detail/bulk_executor_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_BULK_EXECUTOR_OP_HPP #define BOOST_ASIO_DETAIL_BULK_EXECUTOR_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/scheduler_operation.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Handler, typename Alloc, typename Operation = scheduler_operation> class bulk_executor_op : public Operation { public: BOOST_ASIO_DEFINE_HANDLER_ALLOCATOR_PTR(bulk_executor_op); template <typename H> bulk_executor_op(BOOST_ASIO_MOVE_ARG(H) h, const Alloc& allocator, std::size_t i) : Operation(&bulk_executor_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(H)(h)), allocator_(allocator), index_(i) { } 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. bulk_executor_op* o(static_cast<bulk_executor_op*>(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. detail::binder1<Handler, std::size_t> handler(o->handler_, o->index_); 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.handler_); BOOST_ASIO_HANDLER_INVOCATION_END; } } private: Handler handler_; Alloc allocator_; std::size_t index_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_BULK_EXECUTOR_OP_HPP detail/old_win_sdk_compat.hpp 0000644 00000010576 15125530236 0012371 0 ustar 00 // // detail/old_win_sdk_compat.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #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 <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #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 detail/future.hpp 0000644 00000002331 15125530236 0010032 0 ustar 00 // // detail/future.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_STD_FUTURE) # include <future> // 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 detail/win_iocp_null_buffers_op.hpp 0000644 00000010002 15125530236 0013565 0 ustar 00 // // detail/win_iocp_null_buffers_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Handler, typename IoExecutor> 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(boost::system::error_code(), &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)), work_(handler_, io_ex) { } 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<win_iocp_null_buffers_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code, std::size_t> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_WIN_IOCP_NULL_BUFFERS_OP_HPP detail/reactive_descriptor_service.hpp 0000644 00000034253 15125530236 0014310 0 ustar 00 // // detail/reactive_descriptor_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_WINDOWS) \ && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ && !defined(__CYGWIN__) #include <boost/asio/buffer.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/descriptor_ops.hpp> #include <boost/asio/detail/descriptor_read_op.hpp> #include <boost/asio/detail/descriptor_write_op.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/reactive_null_buffers_op.hpp> #include <boost/asio/detail/reactive_wait_op.hpp> #include <boost/asio/detail/reactor.hpp> #include <boost/asio/posix/descriptor_base.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class reactive_descriptor_service : public execution_context_service_base<reactive_descriptor_service> { 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) BOOST_ASIO_NOEXCEPT; // 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 <typename IO_Control_Command> 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<ioctl_arg_type*>(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 <typename Handler, typename IoExecutor> 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<Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, 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 <typename ConstBufferSequence> size_t write_some(implementation_type& impl, const ConstBufferSequence& buffers, boost::system::error_code& ec) { typedef buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence> bufs_type; if (bufs_type::is_single_buffer) { return descriptor_ops::sync_write1(impl.descriptor_, impl.state_, bufs_type::first(buffers).data(), bufs_type::first(buffers).size(), ec); } else { bufs_type 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 <typename ConstBufferSequence, typename Handler, typename IoExecutor> 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<ConstBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, 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<boost::asio::const_buffer, ConstBufferSequence>::all_empty(buffers)); p.v = p.p = 0; } // Start an asynchronous wait until data can be written without blocking. template <typename Handler, typename IoExecutor> 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<Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, 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 <typename MutableBufferSequence> size_t read_some(implementation_type& impl, const MutableBufferSequence& buffers, boost::system::error_code& ec) { typedef buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence> bufs_type; if (bufs_type::is_single_buffer) { return descriptor_ops::sync_read1(impl.descriptor_, impl.state_, bufs_type::first(buffers).data(), bufs_type::first(buffers).size(), ec); } else { bufs_type 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 <typename MutableBufferSequence, typename Handler, typename IoExecutor> 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<MutableBufferSequence, Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, 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<boost::asio::mutable_buffer, MutableBufferSequence>::all_empty(buffers)); p.v = p.p = 0; } // Wait until data can be read without blocking. template <typename Handler, typename IoExecutor> 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<Handler, IoExecutor> op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(success_ec_, 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_; // Cached success value to avoid accessing category singleton. const boost::system::error_code success_ec_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/reactive_descriptor_service.ipp> #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 detail/winrt_socket_connect_op.hpp 0000644 00000006245 15125530236 0013452 0 ustar 00 // // detail/winrt_socket_connect_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_SOCKET_CONNECT_OP_HPP #define BOOST_ASIO_DETAIL_WINRT_SOCKET_CONNECT_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/winrt_async_op.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Handler, typename IoExecutor> class winrt_socket_connect_op : public winrt_async_op<void> { public: BOOST_ASIO_DEFINE_HANDLER_PTR(winrt_socket_connect_op); winrt_socket_connect_op(Handler& handler, const IoExecutor& io_ex) : winrt_async_op<void>(&winrt_socket_connect_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), work_(handler_, io_ex) { } static void do_complete(void* owner, operation* base, const boost::system::error_code&, std::size_t) { // Take ownership of the operation object. winrt_socket_connect_op* o(static_cast<winrt_socket_connect_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code> 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_; handler_work<Handler, IoExecutor> executor_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_WINRT_SOCKET_CONNECT_OP_HPP detail/throw_error.hpp 0000644 00000002541 15125530236 0011077 0 ustar 00 // // detail/throw_error.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/system/error_code.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/throw_error.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_DETAIL_THROW_ERROR_HPP detail/socket_holder.hpp 0000644 00000004144 15125530236 0011351 0 ustar 00 // // detail/socket_holder.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_SOCKET_HOLDER_HPP detail/std_mutex.hpp 0000644 00000002574 15125530236 0010545 0 ustar 00 // // detail/std_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) #include <mutex> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/scoped_lock.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class std_event; class std_mutex : private noncopyable { public: typedef boost::asio::detail::scoped_lock<std_mutex> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) #endif // BOOST_ASIO_DETAIL_STD_MUTEX_HPP detail/reactive_null_buffers_op.hpp 0000644 00000006344 15125530236 0013576 0 ustar 00 // // detail/reactive_null_buffers_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Handler, typename IoExecutor> class reactive_null_buffers_op : public reactor_op { public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_null_buffers_op); reactive_null_buffers_op(const boost::system::error_code& success_ec, Handler& handler, const IoExecutor& io_ex) : reactor_op(success_ec, &reactive_null_buffers_op::do_perform, &reactive_null_buffers_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), work_(handler_, io_ex) { } 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<reactive_null_buffers_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code, std::size_t> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_REACTIVE_NULL_BUFFERS_OP_HPP detail/work_dispatcher.hpp 0000644 00000010017 15125530236 0011710 0 ustar 00 // // detail/work_dispatcher.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/associated_executor.hpp> #include <boost/asio/associated_allocator.hpp> #include <boost/asio/executor_work_guard.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/execution/allocator.hpp> #include <boost/asio/execution/blocking.hpp> #include <boost/asio/execution/outstanding_work.hpp> #include <boost/asio/prefer.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Handler, typename Executor, typename = void> struct is_work_dispatcher_required : true_type { }; template <typename Handler, typename Executor> struct is_work_dispatcher_required<Handler, Executor, typename enable_if< is_same< typename associated_executor<Handler, Executor>::asio_associated_executor_is_unspecialised, void >::value >::type> : false_type { }; template <typename Handler, typename Executor, typename = void> class work_dispatcher { public: template <typename CompletionHandler> work_dispatcher(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, const Executor& handler_ex) : handler_(BOOST_ASIO_MOVE_CAST(CompletionHandler)(handler)), executor_(boost::asio::prefer(handler_ex, execution::outstanding_work.tracked)) { } #if defined(BOOST_ASIO_HAS_MOVE) work_dispatcher(const work_dispatcher& other) : handler_(other.handler_), executor_(other.executor_) { } work_dispatcher(work_dispatcher&& other) : handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)), executor_(BOOST_ASIO_MOVE_CAST(work_executor_type)(other.executor_)) { } #endif // defined(BOOST_ASIO_HAS_MOVE) void operator()() { execution::execute( boost::asio::prefer(executor_, execution::blocking.possibly, execution::allocator((get_associated_allocator)(handler_))), BOOST_ASIO_MOVE_CAST(Handler)(handler_)); } private: typedef typename decay< typename prefer_result<const Executor&, execution::outstanding_work_t::tracked_t >::type >::type work_executor_type; Handler handler_; work_executor_type executor_; }; #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) template <typename Handler, typename Executor> class work_dispatcher<Handler, Executor, typename enable_if<!execution::is_executor<Executor>::value>::type> { public: template <typename CompletionHandler> work_dispatcher(BOOST_ASIO_MOVE_ARG(CompletionHandler) handler, const Executor& handler_ex) : work_(handler_ex), 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<Executor>)(other.work_)), handler_(BOOST_ASIO_MOVE_CAST(Handler)(other.handler_)) { } #endif // defined(BOOST_ASIO_HAS_MOVE) void operator()() { typename associated_allocator<Handler>::type alloc( (get_associated_allocator)(handler_)); work_.get_executor().dispatch( BOOST_ASIO_MOVE_CAST(Handler)(handler_), alloc); work_.reset(); } private: executor_work_guard<Executor> work_; Handler handler_; }; #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_WORK_DISPATCHER_HPP detail/socket_types.hpp 0000644 00000037562 15125530236 0011252 0 ustar 00 // // detail/socket_types.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #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 <stdlib.h> // Needed for __errno # if !defined(_WSPIAPI_H_) # define _WSPIAPI_H_ # define BOOST_ASIO_WSPIAPI_H_DEFINED # endif // !defined(_WSPIAPI_H_) # endif // defined(__BORLANDC__) # include <winsock2.h> # include <ws2tcpip.h> # if defined(WINAPI_FAMILY) # if ((WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP) != 0) # include <windows.h> # endif // ((WINAPI_FAMILY & WINAPI_PARTITION_DESKTOP) != 0) # endif // defined(WINAPI_FAMILY) # if !defined(BOOST_ASIO_WINDOWS_APP) # include <mswsock.h> # 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 <boost/asio/detail/old_win_sdk_compat.hpp> #else # include <sys/ioctl.h> # if (defined(__MACH__) && defined(__APPLE__)) \ || defined(__FreeBSD__) || defined(__NetBSD__) \ || defined(__OpenBSD__) || defined(__linux__) \ || defined(__EMSCRIPTEN__) # include <poll.h> # elif !defined(__SYMBIAN32__) # include <sys/poll.h> # endif # include <sys/types.h> # include <sys/stat.h> # include <fcntl.h> # if defined(__hpux) # include <sys/time.h> # endif # if !defined(__hpux) || defined(__SELECT) # include <sys/select.h> # endif # include <sys/socket.h> # include <sys/uio.h> # include <sys/un.h> # include <netinet/in.h> # if !defined(__SYMBIAN32__) # include <netinet/tcp.h> # endif # include <arpa/inet.h> # include <netdb.h> # include <net/if.h> # include <limits.h> # if defined(__sun) # include <sys/filio.h> # include <sys/sockio.h> # endif #endif #include <boost/asio/detail/push_options.hpp> 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; struct sockaddr_un_type { u_short sun_family; char sun_path[108]; }; # 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_SOCKET_TYPES_HPP detail/reactor_op_queue.hpp 0000644 00000011563 15125530236 0012070 0 ustar 00 // // detail/reactor_op_queue.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/hash_map.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Descriptor> class reactor_op_queue : private noncopyable { public: typedef Descriptor key_type; struct mapped_type : op_queue<reactor_op> { mapped_type() {} mapped_type(const mapped_type&) {} void operator=(const mapped_type&) {} }; typedef typename hash_map<key_type, mapped_type>::value_type value_type; typedef typename hash_map<key_type, mapped_type>::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<iterator, bool> 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<operation>& 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<operation>& 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<operation>& 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<operation>& ops) { return this->perform_operations(operations_.find(descriptor), ops); } // Get all operations owned by the queue. void get_all_operations(op_queue<operation>& 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<key_type, mapped_type> operations_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_REACTOR_OP_QUEUE_HPP detail/posix_mutex.hpp 0000644 00000003225 15125530236 0011107 0 ustar 00 // // detail/posix_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_PTHREADS) #include <pthread.h> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/scoped_lock.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class posix_event; class posix_mutex : private noncopyable { public: typedef boost::asio::detail::scoped_lock<posix_mutex> 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/posix_mutex.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_HAS_PTHREADS) #endif // BOOST_ASIO_DETAIL_POSIX_MUTEX_HPP detail/reactive_socket_connect_op.hpp 0000644 00000007652 15125530236 0014114 0 ustar 00 // // detail/reactive_socket_connect_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class reactive_socket_connect_op_base : public reactor_op { public: reactive_socket_connect_op_base(const boost::system::error_code& success_ec, socket_type socket, func_type complete_func) : reactor_op(success_ec, &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<reactive_socket_connect_op_base*>(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 <typename Handler, typename IoExecutor> 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(const boost::system::error_code& success_ec, socket_type socket, Handler& handler, const IoExecutor& io_ex) : reactive_socket_connect_op_base(success_ec, socket, &reactive_socket_connect_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), work_(handler_, io_ex) { } 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<reactive_socket_connect_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_CONNECT_OP_HPP detail/winapp_thread.hpp 0000644 00000005264 15125530236 0011355 0 ustar 00 // // detail/winapp_thread.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS) && defined(BOOST_ASIO_WINDOWS_APP) #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/scoped_ptr.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { DWORD WINAPI winapp_thread_function(LPVOID arg); class winapp_thread : private noncopyable { public: // Constructor. template <typename Function> winapp_thread(Function f, unsigned int = 0) { scoped_ptr<func_base> arg(new func<Function>(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 <typename Function> 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<winapp_thread::func_base> func( static_cast<winapp_thread::func_base*>(arg)); func->run(); return 0; } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS) && defined(BOOST_ASIO_WINDOWS_APP) #endif // BOOST_ASIO_DETAIL_WINAPP_THREAD_HPP detail/timer_queue_base.hpp 0000644 00000003332 15125530236 0012040 0 ustar 00 // // detail/timer_queue_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/push_options.hpp> 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<operation>& ops) = 0; // Dequeue all timers. virtual void get_all_timers(op_queue<operation>& ops) = 0; private: friend class timer_queue_set; // Next timer queue in the set. timer_queue_base* next_; }; template <typename Time_Traits> class timer_queue; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_BASE_HPP detail/handler_type_requirements.hpp 0000644 00000047577 15125530236 0014026 0 ustar 00 // // detail/handler_type_requirements.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> // 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 <boost/asio/async_result.hpp> #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 <typename Handler> auto zero_arg_copyable_handler_test(Handler h, void*) -> decltype( sizeof(Handler(static_cast<const Handler&>(h))), ((h)()), char(0)); template <typename Handler> char (&zero_arg_copyable_handler_test(Handler, ...))[2]; template <typename Handler, typename Arg1> auto one_arg_handler_test(Handler h, Arg1* a1) -> decltype( sizeof(Handler(BOOST_ASIO_MOVE_CAST(Handler)(h))), ((h)(*a1)), char(0)); template <typename Handler> char (&one_arg_handler_test(Handler h, ...))[2]; template <typename Handler, typename Arg1, typename Arg2> 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 <typename Handler> char (&two_arg_handler_test(Handler, ...))[2]; template <typename Handler, typename Arg1, typename Arg2> 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 <typename Handler> 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 <typename T> T& lvref(); template <typename T> T& lvref(T); template <typename T> const T& clvref(); template <typename T> const T& clvref(T); #if defined(BOOST_ASIO_HAS_MOVE) template <typename T> T rvref(); template <typename T> T rvref(T); #else // defined(BOOST_ASIO_HAS_MOVE) template <typename T> const T& rvref(); template <typename T> const T& rvref(T); #endif // defined(BOOST_ASIO_HAS_MOVE) template <typename T> char argbyv(T); template <int> 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<const boost::system::error_code*>(0), \ static_cast<const std::size_t*>(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<const boost::system::error_code>(), \ boost::asio::detail::lvref<const std::size_t>()), \ 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<const boost::system::error_code*>(0), \ static_cast<const std::size_t*>(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<const boost::system::error_code>(), \ boost::asio::detail::lvref<const std::size_t>()), \ 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<const boost::system::error_code*>(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<const boost::system::error_code>()), \ 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<const boost::system::error_code*>(0), \ static_cast<socket_type*>(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<const boost::system::error_code>(), \ boost::asio::detail::rvref<socket_type>()), \ 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<const boost::system::error_code*>(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<const boost::system::error_code>()), \ 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<const boost::system::error_code*>(0), \ static_cast<const endpoint_type*>(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<const boost::system::error_code>(), \ boost::asio::detail::lvref<const endpoint_type>()), \ 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<const boost::system::error_code*>(0), \ static_cast<const iter_type*>(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<const boost::system::error_code>(), \ boost::asio::detail::lvref<const iter_type>()), \ 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<const boost::system::error_code*>(0), \ static_cast<const range_type*>(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<const boost::system::error_code>(), \ boost::asio::detail::lvref<const range_type>()), \ 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<const boost::system::error_code*>(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<const boost::system::error_code>()), \ 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<const boost::system::error_code*>(0), \ static_cast<const int*>(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<const boost::system::error_code>(), \ boost::asio::detail::lvref<const int>()), \ 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<const boost::system::error_code*>(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<const boost::system::error_code>()), \ 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<const boost::system::error_code*>(0), \ static_cast<const std::size_t*>(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<const boost::system::error_code>(), \ boost::asio::detail::lvref<const std::size_t>()), \ 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<const boost::system::error_code*>(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<const boost::system::error_code>()), \ 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 detail/null_reactor.hpp 0000644 00000003033 15125530236 0011211 0 ustar 00 // // detail/null_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) || defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <boost/asio/detail/scheduler_operation.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class null_reactor : public execution_context_service_base<null_reactor> { public: // Constructor. null_reactor(boost::asio::execution_context& ctx) : execution_context_service_base<null_reactor>(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<scheduler_operation>& /*ops*/) { } // No-op. void interrupt() { } }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) || defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_NULL_REACTOR_HPP detail/resolve_query_op.hpp 0000644 00000011646 15125530236 0012133 0 ustar 00 // // detail/resolve_query_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/resolve_op.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/error.hpp> #include <boost/asio/ip/basic_resolver_query.hpp> #include <boost/asio/ip/basic_resolver_results.hpp> #if defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/win_iocp_io_context.hpp> #else // defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/scheduler.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Protocol, typename Handler, typename IoExecutor> class resolve_query_op : public resolve_op { public: BOOST_ASIO_DEFINE_HANDLER_PTR(resolve_query_op); typedef boost::asio::ip::basic_resolver_query<Protocol> query_type; typedef boost::asio::ip::basic_resolver_results<Protocol> 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& qry, scheduler_impl& sched, Handler& handler, const IoExecutor& io_ex) : resolve_op(&resolve_query_op::do_complete), cancel_token_(cancel_token), query_(qry), scheduler_(sched), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), work_(handler_, io_ex), addrinfo_(0) { } ~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<resolve_query_op*>(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. BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code, results_type> 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_; handler_work<Handler, IoExecutor> work_; boost::asio::detail::addrinfo_type* addrinfo_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_RESOLVE_QUERY_OP_HPP detail/win_iocp_socket_recvmsg_op.hpp 0000644 00000010163 15125530236 0014125 0 ustar 00 // // detail/win_iocp_socket_recvmsg_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/error.hpp> #include <boost/asio/socket_base.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename MutableBufferSequence, typename Handler, typename IoExecutor> 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)), work_(handler_, io_ex) { } 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<win_iocp_socket_recvmsg_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) { buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence>::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, boost::system::error_code, std::size_t> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_WIN_IOCP_SOCKET_RECVMSG_OP_HPP detail/buffer_sequence_adapter.hpp 0000644 00000036336 15125530236 0013375 0 ustar 00 // // detail/buffer_sequence_adapter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/detail/array_fwd.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/push_options.hpp> 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<char*>(buffer.data()); buf.len = static_cast<ULONG>(buffer.size()); } static void init_native_buffer(WSABUF& buf, const boost::asio::const_buffer& buffer) { buf.buf = const_cast<char*>(static_cast<const char*>(buffer.data())); buf.len = static_cast<ULONG>(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 <typename T> static void init_iov_base(T& base, void* addr) { base = static_cast<T>(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<void*>(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 <typename Buffer, typename Buffers> class buffer_sequence_adapter : buffer_sequence_adapter_base { public: enum { is_single_buffer = false }; 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)); } enum { linearisation_storage_size = 8192 }; static Buffer linearise(const Buffers& buffer_sequence, const boost::asio::mutable_buffer& storage) { return buffer_sequence_adapter::linearise( boost::asio::buffer_sequence_begin(buffer_sequence), boost::asio::buffer_sequence_end(buffer_sequence), storage); } private: template <typename Iterator> 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 <typename Iterator> 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 <typename Iterator> static void validate(Iterator begin, Iterator end) { Iterator iter = begin; for (; iter != end; ++iter) { Buffer buffer(*iter); buffer.data(); } } template <typename Iterator> 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(); } template <typename Iterator> static Buffer linearise(Iterator begin, Iterator end, const boost::asio::mutable_buffer& storage) { boost::asio::mutable_buffer unused_storage = storage; Iterator iter = begin; while (iter != end && unused_storage.size() != 0) { Buffer buffer(*iter); ++iter; if (buffer.size() == 0) continue; if (unused_storage.size() == storage.size()) { if (iter == end) return buffer; if (buffer.size() >= unused_storage.size()) return buffer; } unused_storage += boost::asio::buffer_copy(unused_storage, buffer); } return Buffer(storage.data(), storage.size() - unused_storage.size()); } native_buffer_type buffers_[max_buffers]; std::size_t count_; std::size_t total_buffer_size_; }; template <typename Buffer> class buffer_sequence_adapter<Buffer, boost::asio::mutable_buffer> : buffer_sequence_adapter_base { public: enum { is_single_buffer = true }; 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); } enum { linearisation_storage_size = 1 }; static Buffer linearise(const boost::asio::mutable_buffer& buffer_sequence, const Buffer&) { return Buffer(buffer_sequence); } private: native_buffer_type buffer_; std::size_t total_buffer_size_; }; template <typename Buffer> class buffer_sequence_adapter<Buffer, boost::asio::const_buffer> : buffer_sequence_adapter_base { public: enum { is_single_buffer = true }; 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); } enum { linearisation_storage_size = 1 }; static Buffer linearise(const boost::asio::const_buffer& buffer_sequence, const Buffer&) { return Buffer(buffer_sequence); } private: native_buffer_type buffer_; std::size_t total_buffer_size_; }; #if !defined(BOOST_ASIO_NO_DEPRECATED) template <typename Buffer> class buffer_sequence_adapter<Buffer, boost::asio::mutable_buffers_1> : buffer_sequence_adapter_base { public: enum { is_single_buffer = true }; 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); } enum { linearisation_storage_size = 1 }; static Buffer linearise(const boost::asio::mutable_buffers_1& buffer_sequence, const Buffer&) { return Buffer(buffer_sequence); } private: native_buffer_type buffer_; std::size_t total_buffer_size_; }; template <typename Buffer> class buffer_sequence_adapter<Buffer, boost::asio::const_buffers_1> : buffer_sequence_adapter_base { public: enum { is_single_buffer = true }; 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); } enum { linearisation_storage_size = 1 }; static Buffer linearise(const boost::asio::const_buffers_1& buffer_sequence, const Buffer&) { return Buffer(buffer_sequence); } private: native_buffer_type buffer_; std::size_t total_buffer_size_; }; #endif // !defined(BOOST_ASIO_NO_DEPRECATED) template <typename Buffer, typename Elem> class buffer_sequence_adapter<Buffer, boost::array<Elem, 2> > : buffer_sequence_adapter_base { public: enum { is_single_buffer = false }; explicit buffer_sequence_adapter( const boost::array<Elem, 2>& 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<Elem, 2>& buffer_sequence) { return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0; } static void validate(const boost::array<Elem, 2>& buffer_sequence) { buffer_sequence[0].data(); buffer_sequence[1].data(); } static Buffer first(const boost::array<Elem, 2>& buffer_sequence) { return Buffer(buffer_sequence[0].size() != 0 ? buffer_sequence[0] : buffer_sequence[1]); } enum { linearisation_storage_size = 8192 }; static Buffer linearise(const boost::array<Elem, 2>& buffer_sequence, const boost::asio::mutable_buffer& storage) { if (buffer_sequence[0].size() == 0) return Buffer(buffer_sequence[1]); if (buffer_sequence[1].size() == 0) return Buffer(buffer_sequence[0]); return Buffer(storage.data(), boost::asio::buffer_copy(storage, buffer_sequence)); } private: native_buffer_type buffers_[2]; std::size_t total_buffer_size_; }; #if defined(BOOST_ASIO_HAS_STD_ARRAY) template <typename Buffer, typename Elem> class buffer_sequence_adapter<Buffer, std::array<Elem, 2> > : buffer_sequence_adapter_base { public: enum { is_single_buffer = false }; explicit buffer_sequence_adapter( const std::array<Elem, 2>& 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<Elem, 2>& buffer_sequence) { return buffer_sequence[0].size() == 0 && buffer_sequence[1].size() == 0; } static void validate(const std::array<Elem, 2>& buffer_sequence) { buffer_sequence[0].data(); buffer_sequence[1].data(); } static Buffer first(const std::array<Elem, 2>& buffer_sequence) { return Buffer(buffer_sequence[0].size() != 0 ? buffer_sequence[0] : buffer_sequence[1]); } enum { linearisation_storage_size = 8192 }; static Buffer linearise(const std::array<Elem, 2>& buffer_sequence, const boost::asio::mutable_buffer& storage) { if (buffer_sequence[0].size() == 0) return Buffer(buffer_sequence[1]); if (buffer_sequence[1].size() == 0) return Buffer(buffer_sequence[0]); return Buffer(storage.data(), boost::asio::buffer_copy(storage, buffer_sequence)); } 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/buffer_sequence_adapter.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_DETAIL_BUFFER_SEQUENCE_ADAPTER_HPP detail/descriptor_ops.hpp 0000644 00000010224 15125530236 0011557 0 ustar 00 // // detail/descriptor_ops.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_WINDOWS) \ && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ && !defined(__CYGWIN__) #include <cstddef> #include <boost/asio/error.hpp> #include <boost/system/error_code.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/push_options.hpp> 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; inline void get_last_error( boost::system::error_code& ec, bool is_error_condition) { if (!is_error_condition) { ec.assign(0, ec.category()); } else { ec = boost::system::error_code(errno, boost::asio::error::get_system_category()); } } 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 std::size_t sync_read1(int d, state_type state, void* data, std::size_t size, 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 bool non_blocking_read1(int d, void* data, std::size_t size, 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 std::size_t sync_write1(int d, state_type state, const void* data, std::size_t size, 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 bool non_blocking_write1(int d, const void* data, std::size_t size, 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/descriptor_ops.ipp> #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 detail/resolve_op.hpp 0000644 00000002102 15125530236 0010671 0 ustar 00 // // detail/resolve_op.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_RESOLVE_OP_HPP detail/io_control.hpp 0000644 00000003533 15125530236 0010674 0 ustar 00 // // detail/io_control.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/push_options.hpp> 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<detail::ioctl_arg_type>(value)) { } // Get the name of the IO control command. int name() const { return static_cast<int>(BOOST_ASIO_OS_DEF(FIONREAD)); } // Set the value of the I/O control command. void set(std::size_t value) { value_ = static_cast<detail::ioctl_arg_type>(value); } // Get the current value of the I/O control command. std::size_t get() const { return static_cast<std::size_t>(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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_IO_CONTROL_HPP detail/select_reactor.hpp 0000644 00000021155 15125530236 0011523 0 ustar 00 // // detail/select_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #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 <cstddef> #include <boost/asio/detail/fd_set_adapter.hpp> #include <boost/asio/detail/limits.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/reactor_op_queue.hpp> #include <boost/asio/detail/select_interrupter.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/timer_queue_base.hpp> #include <boost/asio/detail/timer_queue_set.hpp> #include <boost/asio/detail/wait_op.hpp> #include <boost/asio/execution_context.hpp> #if defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/thread.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class select_reactor : public execution_context_service_base<select_reactor> { 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 <typename Time_Traits> void add_timer_queue(timer_queue<Time_Traits>& queue); // Remove a timer queue from the reactor. template <typename Time_Traits> void remove_timer_queue(timer_queue<Time_Traits>& queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template <typename Time_Traits> void schedule_timer(timer_queue<Time_Traits>& queue, const typename Time_Traits::time_type& time, typename timer_queue<Time_Traits>::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 <typename Time_Traits> std::size_t cancel_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); // Move the timer operations associated with the given timer. template <typename Time_Traits> void move_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& target, typename timer_queue<Time_Traits>::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<operation>& 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<socket_type> 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 <boost/asio/detail/pop_options.hpp> #include <boost/asio/detail/impl/select_reactor.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/select_reactor.ipp> #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 detail/null_static_mutex.hpp 0000644 00000002353 15125530236 0012267 0 ustar 00 // // detail/null_static_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_HAS_THREADS) #include <boost/asio/detail/scoped_lock.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { struct null_static_mutex { typedef boost::asio::detail::scoped_lock<null_static_mutex> 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 <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_HAS_THREADS) #endif // BOOST_ASIO_DETAIL_NULL_STATIC_MUTEX_HPP detail/descriptor_write_op.hpp 0000644 00000011301 15125530236 0012603 0 ustar 00 // // detail/descriptor_write_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/descriptor_ops.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename ConstBufferSequence> class descriptor_write_op_base : public reactor_op { public: descriptor_write_op_base(const boost::system::error_code& success_ec, int descriptor, const ConstBufferSequence& buffers, func_type complete_func) : reactor_op(success_ec, &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<descriptor_write_op_base*>(base)); typedef buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence> bufs_type; status result; if (bufs_type::is_single_buffer) { result = descriptor_ops::non_blocking_write1(o->descriptor_, bufs_type::first(o->buffers_).data(), bufs_type::first(o->buffers_).size(), o->ec_, o->bytes_transferred_) ? done : not_done; } else { bufs_type bufs(o->buffers_); 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 <typename ConstBufferSequence, typename Handler, typename IoExecutor> class descriptor_write_op : public descriptor_write_op_base<ConstBufferSequence> { public: BOOST_ASIO_DEFINE_HANDLER_PTR(descriptor_write_op); descriptor_write_op(const boost::system::error_code& success_ec, int descriptor, const ConstBufferSequence& buffers, Handler& handler, const IoExecutor& io_ex) : descriptor_write_op_base<ConstBufferSequence>(success_ec, descriptor, buffers, &descriptor_write_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), work_(handler_, io_ex) { } 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<descriptor_write_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code, std::size_t> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) #endif // BOOST_ASIO_DETAIL_DESCRIPTOR_WRITE_OP_HPP detail/winrt_utils.hpp 0000644 00000005310 15125530236 0011103 0 ustar 00 // // detail/winrt_utils.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <codecvt> #include <cstdlib> #include <future> #include <locale> #include <robuffer.h> #include <windows.storage.streams.h> #include <wrl/implements.h> #include <boost/asio/buffer.hpp> #include <boost/system/error_code.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/push_options.hpp> 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<std::codecvt_utf8<wchar_t>> converter; return converter.to_bytes(from->Data()); } inline Platform::String^ string(unsigned short from) { return string(std::to_string(from)); } template <typename T> inline Platform::String^ string(const T& from) { return string(from.to_string()); } inline int integer(Platform::String^ from) { return _wtoi(from->Data()); } template <typename T> inline Windows::Networking::HostName^ host_name(const T& from) { return ref new Windows::Networking::HostName((string)(from)); } template <typename ConstBufferSequence> 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<IInspectable> insp = reinterpret_cast<IInspectable*>(b); ComPtr<Windows::Storage::Streams::IBufferByteAccess> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_WINRT_UTILS_HPP detail/win_iocp_overlapped_op.hpp 0000644 00000006162 15125530236 0013254 0 ustar 00 // // detail/win_iocp_overlapped_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Handler, typename IoExecutor> 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)), work_(handler_, io_ex) { } 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<win_iocp_overlapped_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code, std::size_t> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_WIN_IOCP_OVERLAPPED_OP_HPP detail/reactive_socket_accept_op.hpp 0000644 00000020202 15125530236 0013704 0 ustar 00 // // detail/reactive_socket_accept_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_holder.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Socket, typename Protocol> class reactive_socket_accept_op_base : public reactor_op { public: reactive_socket_accept_op_base(const boost::system::error_code& success_ec, socket_type socket, socket_ops::state_type state, Socket& peer, const Protocol& protocol, typename Protocol::endpoint* peer_endpoint, func_type complete_func) : reactor_op(success_ec, &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<reactive_socket_accept_op_base*>(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 <typename Socket, typename Protocol, typename Handler, typename IoExecutor> class reactive_socket_accept_op : public reactive_socket_accept_op_base<Socket, Protocol> { public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_accept_op); reactive_socket_accept_op(const boost::system::error_code& success_ec, 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, Protocol>( success_ec, socket, state, peer, protocol, peer_endpoint, &reactive_socket_accept_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), work_(handler_, io_ex) { } 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<reactive_socket_accept_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; // On success, assign new connection to peer socket object. if (owner) o->do_assign(); BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code> 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_; handler_work<Handler, IoExecutor> work_; }; #if defined(BOOST_ASIO_HAS_MOVE) template <typename Protocol, typename PeerIoExecutor, typename Handler, typename IoExecutor> class reactive_socket_move_accept_op : private Protocol::socket::template rebind_executor<PeerIoExecutor>::other, public reactive_socket_accept_op_base< typename Protocol::socket::template rebind_executor<PeerIoExecutor>::other, Protocol> { public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_move_accept_op); reactive_socket_move_accept_op(const boost::system::error_code& success_ec, 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<peer_socket_type, Protocol>( success_ec, socket, state, *this, protocol, peer_endpoint, &reactive_socket_move_accept_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), work_(handler_, io_ex) { } 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<reactive_socket_move_accept_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; // On success, assign new connection to peer socket object. if (owner) o->do_assign(); BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code, peer_socket_type> 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<PeerIoExecutor>::other peer_socket_type; Handler handler_; handler_work<Handler, IoExecutor> work_; }; #endif // defined(BOOST_ASIO_HAS_MOVE) } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_ACCEPT_OP_HPP detail/eventfd_select_interrupter.hpp 0000644 00000004734 15125530236 0014166 0 ustar 00 // // detail/eventfd_select_interrupter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_EVENTFD) #include <boost/asio/detail/push_options.hpp> 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 interrupter. Returns true if the reset was successful. 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/eventfd_select_interrupter.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_HAS_EVENTFD) #endif // BOOST_ASIO_DETAIL_EVENTFD_SELECT_INTERRUPTER_HPP detail/executor_function.hpp 0000644 00000011544 15125530236 0012271 0 ustar 00 // // detail/executor_function.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { #if defined(BOOST_ASIO_HAS_MOVE) // Lightweight, move-only function object wrapper. class executor_function { public: template <typename F, typename Alloc> explicit executor_function(F f, const Alloc& a) { // Allocate and construct an object to wrap the function. typedef impl<F, Alloc> impl_type; typename impl_type::ptr p = { detail::addressof(a), impl_type::ptr::allocate(a), 0 }; impl_ = new (p.v) impl_type(BOOST_ASIO_MOVE_CAST(F)(f), a); p.v = 0; } executor_function(executor_function&& other) BOOST_ASIO_NOEXCEPT : impl_(other.impl_) { other.impl_ = 0; } ~executor_function() { if (impl_) impl_->complete_(impl_, false); } void operator()() { if (impl_) { impl_base* i = impl_; impl_ = 0; i->complete_(i, true); } } private: // Base class for polymorphic function implementations. struct impl_base { void (*complete_)(impl_base*, bool); }; // Polymorphic function implementation. template <typename Function, typename Alloc> struct impl : impl_base { BOOST_ASIO_DEFINE_TAGGED_HANDLER_ALLOCATOR_PTR( thread_info_base::executor_function_tag, impl); template <typename F> impl(BOOST_ASIO_MOVE_ARG(F) f, const Alloc& a) : function_(BOOST_ASIO_MOVE_CAST(F)(f)), allocator_(a) { complete_ = &executor_function::complete<Function, Alloc>; } Function function_; Alloc allocator_; }; // Helper to complete function invocation. template <typename Function, typename Alloc> static void complete(impl_base* base, bool call) { // Take ownership of the function object. impl<Function, Alloc>* i(static_cast<impl<Function, Alloc>*>(base)); Alloc allocator(i->allocator_); typename impl<Function, Alloc>::ptr p = { detail::addressof(allocator), i, i }; // 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)(i->function_)); p.reset(); // Make the upcall if required. if (call) { boost_asio_handler_invoke_helpers::invoke(function, function); } } impl_base* impl_; }; #else // defined(BOOST_ASIO_HAS_MOVE) // Not so lightweight, copyable function object wrapper. class executor_function { public: template <typename F, typename Alloc> explicit executor_function(const F& f, const Alloc&) : impl_(new impl<typename decay<F>::type>(f)) { } void operator()() { impl_->complete_(impl_.get()); } private: // Base class for polymorphic function implementations. struct impl_base { void (*complete_)(impl_base*); }; // Polymorphic function implementation. template <typename F> struct impl : impl_base { impl(const F& f) : function_(f) { complete_ = &executor_function::complete<F>; } F function_; }; // Helper to complete function invocation. template <typename F> static void complete(impl_base* i) { static_cast<impl<F>*>(i)->function_(); } shared_ptr<impl_base> impl_; }; #endif // defined(BOOST_ASIO_HAS_MOVE) // Lightweight, non-owning, copyable function object wrapper. class executor_function_view { public: template <typename F> explicit executor_function_view(F& f) BOOST_ASIO_NOEXCEPT : complete_(&executor_function_view::complete<F>), function_(&f) { } void operator()() { complete_(function_); } private: // Helper to complete function invocation. template <typename F> static void complete(void* f) { (*static_cast<F*>(f))(); } void (*complete_)(void*); void* function_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_EXECUTOR_FUNCTION_HPP detail/null_fenced_block.hpp 0000644 00000002024 15125530236 0012147 0 ustar 00 // // detail/null_fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_NULL_FENCED_BLOCK_HPP detail/reactor_op.hpp 0000644 00000003343 15125530236 0010661 0 ustar 00 // // detail/reactor_op.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/push_options.hpp> 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(const boost::system::error_code& success_ec, perform_func_type perform_func, func_type complete_func) : operation(complete_func), ec_(success_ec), bytes_transferred_(0), perform_func_(perform_func) { } private: perform_func_type perform_func_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_REACTOR_OP_HPP detail/winrt_async_manager.hpp 0000644 00000021500 15125530236 0012551 0 ustar 00 // // detail/winrt_async_manager.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <future> #include <boost/asio/detail/atomic_count.hpp> #include <boost/asio/detail/winrt_async_op.hpp> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #if defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/win_iocp_io_context.hpp> #else // defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/scheduler.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class winrt_async_manager : public execution_context_service_base<winrt_async_manager> { public: // Constructor. winrt_async_manager(execution_context& context) : execution_context_service_base<winrt_async_manager>(context), scheduler_(use_service<scheduler_impl>(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<void> 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<std::promise<boost::system::error_code>>(); 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 <typename TResult> TResult sync(Windows::Foundation::IAsyncOperation<TResult>^ operation, boost::system::error_code& ec) { using namespace Windows::Foundation; using Windows::Foundation::AsyncStatus; auto promise = std::make_shared<std::promise<boost::system::error_code>>(); auto future = promise->get_future(); operation->Completed = ref new AsyncOperationCompletedHandler<TResult>( [promise](IAsyncOperation<TResult>^ 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 <typename TResult, typename TProgress> 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<std::promise<boost::system::error_code>>(); auto future = promise->get_future(); operation->Completed = ref new AsyncOperationWithProgressCompletedHandler<TResult, TProgress>( [promise](IAsyncOperationWithProgress<TResult, TProgress>^ 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<void>* 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 <typename TResult> void async(Windows::Foundation::IAsyncOperation<TResult>^ operation, winrt_async_op<TResult>* handler) { using namespace Windows::Foundation; using Windows::Foundation::AsyncStatus; auto on_completed = ref new AsyncOperationCompletedHandler<TResult>( [this, handler](IAsyncOperation<TResult>^ 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 <typename TResult, typename TProgress> void async( Windows::Foundation::IAsyncOperationWithProgress< TResult, TProgress>^ operation, winrt_async_op<TResult>* handler) { using namespace Windows::Foundation; using Windows::Foundation::AsyncStatus; auto on_completed = ref new AsyncOperationWithProgressCompletedHandler<TResult, TProgress>( [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<void> promise_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_WINRT_ASYNC_MANAGER_HPP detail/timer_queue_set.hpp 0000644 00000003415 15125530236 0011723 0 ustar 00 // // detail/timer_queue_set.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/timer_queue_base.hpp> #include <boost/asio/detail/push_options.hpp> 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<operation>& ops); // Dequeue all timers. BOOST_ASIO_DECL void get_all_timers(op_queue<operation>& ops); private: timer_queue_base* first_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/timer_queue_set.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_DETAIL_TIMER_QUEUE_SET_HPP detail/null_global.hpp 0000644 00000002417 15125530236 0011017 0 ustar 00 // // detail/null_global.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename T> 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 <typename T> null_global_impl<T> null_global_impl<T>::instance_; template <typename T> T& null_global() { if (null_global_impl<T>::instance_.ptr_ == 0) null_global_impl<T>::instance_.ptr_ = new T; return *null_global_impl<T>::instance_.ptr_; } } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_NULL_GLOBAL_HPP detail/resolver_service_base.hpp 0000644 00000011375 15125530236 0013103 0 ustar 00 // // detail/resolver_service_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/resolve_op.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/scoped_ptr.hpp> #include <boost/asio/detail/thread.hpp> #if defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/win_iocp_io_context.hpp> #else // defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/scheduler.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/push_options.hpp> 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); // Move-construct a new timer implementation. void converting_move_construct(implementation_type& impl, resolver_service_base&, implementation_type& other_impl) { move_construct(impl, other_impl); } // Move-assign from another timer implementation. void converting_move_assign(implementation_type& impl, resolver_service_base& other_service, implementation_type& other_impl) { move_assign(impl, other_service, 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<scheduler_impl> work_scheduler_; // Thread used for running the work io_context's run loop. boost::asio::detail::scoped_ptr<boost::asio::detail::thread> work_thread_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/resolver_service_base.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_DETAIL_RESOLVER_SERVICE_BASE_HPP detail/variadic_templates.hpp 0000644 00000031655 15125530236 0012373 0 ustar 00 // // detail/variadic_templates.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #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_TPARAMS_6 \ typename T1, typename T2, typename T3, typename T4, typename T5, \ typename T6 # define BOOST_ASIO_VARIADIC_TPARAMS_7 \ typename T1, typename T2, typename T3, typename T4, typename T5, \ typename T6, typename T7 # define BOOST_ASIO_VARIADIC_TPARAMS_8 \ typename T1, typename T2, typename T3, typename T4, typename T5, \ typename T6, typename T7, typename T8 # 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_TARGS_6 T1, T2, T3, T4, T5, T6 # define BOOST_ASIO_VARIADIC_TARGS_7 T1, T2, T3, T4, T5, T6, T7 # define BOOST_ASIO_VARIADIC_TARGS_8 T1, T2, T3, T4, T5, T6, T7, T8 # 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_PARAMS_6 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, \ T6 x6 # define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_7 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, \ T6 x6, T7 x7 # define BOOST_ASIO_VARIADIC_BYVAL_PARAMS_8 T1 x1, T2 x2, T3 x3, T4 x4, T5 x5, \ T6 x6, T7 x7, T8 x8 # 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_BYVAL_ARGS_6 x1, x2, x3, x4, x5, x6 # define BOOST_ASIO_VARIADIC_BYVAL_ARGS_7 x1, x2, x3, x4, x5, x6, x7 # define BOOST_ASIO_VARIADIC_BYVAL_ARGS_8 x1, x2, x3, x4, x5, x6, x7, x8 # 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_CONSTREF_PARAMS_6 \ const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5, \ const T6& x6 # define BOOST_ASIO_VARIADIC_CONSTREF_PARAMS_7 \ const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5, \ const T6& x6, const T7& x7 # define BOOST_ASIO_VARIADIC_CONSTREF_PARAMS_8 \ const T1& x1, const T2& x2, const T3& x3, const T4& x4, const T5& x5, \ const T6& x6, const T7& x7, const T8& x8 # 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_PARAMS_6 \ 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, BOOST_ASIO_MOVE_ARG(T6) x6 # define BOOST_ASIO_VARIADIC_MOVE_PARAMS_7 \ 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, BOOST_ASIO_MOVE_ARG(T6) x6, \ BOOST_ASIO_MOVE_ARG(T7) x7 # define BOOST_ASIO_VARIADIC_MOVE_PARAMS_8 \ 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, BOOST_ASIO_MOVE_ARG(T6) x6, \ BOOST_ASIO_MOVE_ARG(T7) x7, BOOST_ASIO_MOVE_ARG(T8) x8 # define BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS(n) \ BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_##n # define BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_1 \ BOOST_ASIO_MOVE_ARG(T1) # define BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_2 \ BOOST_ASIO_MOVE_ARG(T1), BOOST_ASIO_MOVE_ARG(T2) # define BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_3 \ BOOST_ASIO_MOVE_ARG(T1), BOOST_ASIO_MOVE_ARG(T2), \ BOOST_ASIO_MOVE_ARG(T3) # define BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_4 \ BOOST_ASIO_MOVE_ARG(T1), BOOST_ASIO_MOVE_ARG(T2), \ BOOST_ASIO_MOVE_ARG(T3), BOOST_ASIO_MOVE_ARG(T4) # define BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_5 \ BOOST_ASIO_MOVE_ARG(T1), BOOST_ASIO_MOVE_ARG(T2), \ BOOST_ASIO_MOVE_ARG(T3), BOOST_ASIO_MOVE_ARG(T4), \ BOOST_ASIO_MOVE_ARG(T5) # define BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_6 \ BOOST_ASIO_MOVE_ARG(T1), BOOST_ASIO_MOVE_ARG(T2), \ BOOST_ASIO_MOVE_ARG(T3), BOOST_ASIO_MOVE_ARG(T4), \ BOOST_ASIO_MOVE_ARG(T5), BOOST_ASIO_MOVE_ARG(T6) # define BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_7 \ BOOST_ASIO_MOVE_ARG(T1), BOOST_ASIO_MOVE_ARG(T2), \ BOOST_ASIO_MOVE_ARG(T3), BOOST_ASIO_MOVE_ARG(T4), \ BOOST_ASIO_MOVE_ARG(T5), BOOST_ASIO_MOVE_ARG(T6), \ BOOST_ASIO_MOVE_ARG(T7) # define BOOST_ASIO_VARIADIC_UNNAMED_MOVE_PARAMS_8 \ BOOST_ASIO_MOVE_ARG(T1), BOOST_ASIO_MOVE_ARG(T2), \ BOOST_ASIO_MOVE_ARG(T3), BOOST_ASIO_MOVE_ARG(T4), \ BOOST_ASIO_MOVE_ARG(T5), BOOST_ASIO_MOVE_ARG(T6), \ BOOST_ASIO_MOVE_ARG(T7), BOOST_ASIO_MOVE_ARG(T8) # 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_MOVE_ARGS_6 \ 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), BOOST_ASIO_MOVE_CAST(T6)(x6) # define BOOST_ASIO_VARIADIC_MOVE_ARGS_7 \ 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), BOOST_ASIO_MOVE_CAST(T6)(x6), \ BOOST_ASIO_MOVE_CAST(T7)(x7) # define BOOST_ASIO_VARIADIC_MOVE_ARGS_8 \ 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), BOOST_ASIO_MOVE_CAST(T6)(x6), \ BOOST_ASIO_MOVE_CAST(T7)(x7), BOOST_ASIO_MOVE_CAST(T8)(x8) # define BOOST_ASIO_VARIADIC_DECLVAL(n) \ BOOST_ASIO_VARIADIC_DECLVAL_##n # define BOOST_ASIO_VARIADIC_DECLVAL_1 \ declval<T1>() # define BOOST_ASIO_VARIADIC_DECLVAL_2 \ declval<T1>(), declval<T2>() # define BOOST_ASIO_VARIADIC_DECLVAL_3 \ declval<T1>(), declval<T2>(), declval<T3>() # define BOOST_ASIO_VARIADIC_DECLVAL_4 \ declval<T1>(), declval<T2>(), declval<T3>(), declval<T4>() # define BOOST_ASIO_VARIADIC_DECLVAL_5 \ declval<T1>(), declval<T2>(), declval<T3>(), declval<T4>(), \ declval<T5>() # define BOOST_ASIO_VARIADIC_DECLVAL_6 \ declval<T1>(), declval<T2>(), declval<T3>(), declval<T4>(), \ declval<T5>(), declval<T6>() # define BOOST_ASIO_VARIADIC_DECLVAL_7 \ declval<T1>(), declval<T2>(), declval<T3>(), declval<T4>(), \ declval<T5>(), declval<T6>(), declval<T7>() # define BOOST_ASIO_VARIADIC_DECLVAL_8 \ declval<T1>(), declval<T2>(), declval<T3>(), declval<T4>(), \ declval<T5>(), declval<T6>(), declval<T7>(), declval<T8>() # define BOOST_ASIO_VARIADIC_MOVE_DECLVAL(n) \ BOOST_ASIO_VARIADIC_MOVE_DECLVAL_##n # define BOOST_ASIO_VARIADIC_MOVE_DECLVAL_1 \ declval<BOOST_ASIO_MOVE_ARG(T1)>() # define BOOST_ASIO_VARIADIC_MOVE_DECLVAL_2 \ declval<BOOST_ASIO_MOVE_ARG(T1)>(), declval<BOOST_ASIO_MOVE_ARG(T2)>() # define BOOST_ASIO_VARIADIC_MOVE_DECLVAL_3 \ declval<BOOST_ASIO_MOVE_ARG(T1)>(), declval<BOOST_ASIO_MOVE_ARG(T2)>(), \ declval<BOOST_ASIO_MOVE_ARG(T3)>() # define BOOST_ASIO_VARIADIC_MOVE_DECLVAL_4 \ declval<BOOST_ASIO_MOVE_ARG(T1)>(), declval<BOOST_ASIO_MOVE_ARG(T2)>(), \ declval<BOOST_ASIO_MOVE_ARG(T3)>(), declval<BOOST_ASIO_MOVE_ARG(T4)>() # define BOOST_ASIO_VARIADIC_MOVE_DECLVAL_5 \ declval<BOOST_ASIO_MOVE_ARG(T1)>(), declval<BOOST_ASIO_MOVE_ARG(T2)>(), \ declval<BOOST_ASIO_MOVE_ARG(T3)>(), declval<BOOST_ASIO_MOVE_ARG(T4)>(), \ declval<BOOST_ASIO_MOVE_ARG(T5)>() # define BOOST_ASIO_VARIADIC_MOVE_DECLVAL_6 \ declval<BOOST_ASIO_MOVE_ARG(T1)>(), declval<BOOST_ASIO_MOVE_ARG(T2)>(), \ declval<BOOST_ASIO_MOVE_ARG(T3)>(), declval<BOOST_ASIO_MOVE_ARG(T4)>(), \ declval<BOOST_ASIO_MOVE_ARG(T5)>(), declval<BOOST_ASIO_MOVE_ARG(T6)>() # define BOOST_ASIO_VARIADIC_MOVE_DECLVAL_7 \ declval<BOOST_ASIO_MOVE_ARG(T1)>(), declval<BOOST_ASIO_MOVE_ARG(T2)>(), \ declval<BOOST_ASIO_MOVE_ARG(T3)>(), declval<BOOST_ASIO_MOVE_ARG(T4)>(), \ declval<BOOST_ASIO_MOVE_ARG(T5)>(), declval<BOOST_ASIO_MOVE_ARG(T6)>(), \ declval<BOOST_ASIO_MOVE_ARG(T7)>() # define BOOST_ASIO_VARIADIC_MOVE_DECLVAL_8 \ declval<BOOST_ASIO_MOVE_ARG(T1)>(), declval<BOOST_ASIO_MOVE_ARG(T2)>(), \ declval<BOOST_ASIO_MOVE_ARG(T3)>(), declval<BOOST_ASIO_MOVE_ARG(T4)>(), \ declval<BOOST_ASIO_MOVE_ARG(T5)>(), declval<BOOST_ASIO_MOVE_ARG(T6)>(), \ declval<BOOST_ASIO_MOVE_ARG(T7)>(), declval<BOOST_ASIO_MOVE_ARG(T8)>() # define BOOST_ASIO_VARIADIC_DECAY(n) \ BOOST_ASIO_VARIADIC_DECAY_##n # define BOOST_ASIO_VARIADIC_DECAY_1 \ typename decay<T1>::type # define BOOST_ASIO_VARIADIC_DECAY_2 \ typename decay<T1>::type, typename decay<T2>::type # define BOOST_ASIO_VARIADIC_DECAY_3 \ typename decay<T1>::type, typename decay<T2>::type, \ typename decay<T3>::type # define BOOST_ASIO_VARIADIC_DECAY_4 \ typename decay<T1>::type, typename decay<T2>::type, \ typename decay<T3>::type, typename decay<T4>::type # define BOOST_ASIO_VARIADIC_DECAY_5 \ typename decay<T1>::type, typename decay<T2>::type, \ typename decay<T3>::type, typename decay<T4>::type, \ typename decay<T5>::type # define BOOST_ASIO_VARIADIC_DECAY_6 \ typename decay<T1>::type, typename decay<T2>::type, \ typename decay<T3>::type, typename decay<T4>::type, \ typename decay<T5>::type, typename decay<T6>::type # define BOOST_ASIO_VARIADIC_DECAY_7 \ typename decay<T1>::type, typename decay<T2>::type, \ typename decay<T3>::type, typename decay<T4>::type, \ typename decay<T5>::type, typename decay<T6>::type, \ typename decay<T7>::type # define BOOST_ASIO_VARIADIC_DECAY_8 \ typename decay<T1>::type, typename decay<T2>::type, \ typename decay<T3>::type, typename decay<T4>::type, \ typename decay<T5>::type, typename decay<T6>::type, \ typename decay<T7>::type, typename decay<T8>::type # define BOOST_ASIO_VARIADIC_GENERATE(m) m(1) m(2) m(3) m(4) m(5) m(6) m(7) m(8) # define BOOST_ASIO_VARIADIC_GENERATE_5(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 detail/null_event.hpp 0000644 00000004225 15125530236 0010677 0 ustar 00 // // detail/null_event.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Lock> void signal(Lock&) { } // Signal all waiters. template <typename Lock> void signal_all(Lock&) { } // Unlock the mutex and signal one waiter. template <typename Lock> void unlock_and_signal_one(Lock&) { } // Unlock the mutex and signal one waiter who may destroy us. template <typename Lock> void unlock_and_signal_one_for_destruction(Lock&) { } // If there's a waiter, unlock the mutex and signal it. template <typename Lock> bool maybe_unlock_and_signal_one(Lock&) { return false; } // Reset the event. template <typename Lock> void clear(Lock&) { } // Wait for the event to become signalled. template <typename Lock> void wait(Lock&) { do_wait(); } // Timed wait for the event to become signalled. template <typename Lock> 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/null_event.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_DETAIL_NULL_EVENT_HPP detail/global.hpp 0000644 00000002565 15125530236 0007771 0 ustar 00 // // detail/global.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_HAS_THREADS) # include <boost/asio/detail/null_global.hpp> #elif defined(BOOST_ASIO_WINDOWS) # include <boost/asio/detail/win_global.hpp> #elif defined(BOOST_ASIO_HAS_PTHREADS) # include <boost/asio/detail/posix_global.hpp> #elif defined(BOOST_ASIO_HAS_STD_CALL_ONCE) # include <boost/asio/detail/std_global.hpp> #else # error Only Windows, POSIX and std::call_once are supported! #endif namespace boost { namespace asio { namespace detail { template <typename T> inline T& global() { #if !defined(BOOST_ASIO_HAS_THREADS) return null_global<T>(); #elif defined(BOOST_ASIO_WINDOWS) return win_global<T>(); #elif defined(BOOST_ASIO_HAS_PTHREADS) return posix_global<T>(); #elif defined(BOOST_ASIO_HAS_STD_CALL_ONCE) return std_global<T>(); #endif } } // namespace detail } // namespace asio } // namespace boost #endif // BOOST_ASIO_DETAIL_GLOBAL_HPP detail/winrt_async_op.hpp 0000644 00000002717 15125530236 0011566 0 ustar 00 // // detail/winrt_async_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename TResult> 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<void> : 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_WINRT_ASYNC_OP_HPP detail/socket_option.hpp 0000644 00000014412 15125530236 0011403 0 ustar 00 // // detail/socket_option.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <stdexcept> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { namespace socket_option { // Helper template for implementing boolean-based options. template <int Level, int Name> 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 <typename Protocol> int level(const Protocol&) const { return Level; } // Get the name of the socket option. template <typename Protocol> int name(const Protocol&) const { return Name; } // Get the address of the boolean data. template <typename Protocol> int* data(const Protocol&) { return &value_; } // Get the address of the boolean data. template <typename Protocol> const int* data(const Protocol&) const { return &value_; } // Get the size of the boolean data. template <typename Protocol> std::size_t size(const Protocol&) const { return sizeof(value_); } // Set the size of the boolean data. template <typename Protocol> 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<char*>(&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 <int Level, int Name> 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 <typename Protocol> int level(const Protocol&) const { return Level; } // Get the name of the socket option. template <typename Protocol> int name(const Protocol&) const { return Name; } // Get the address of the int data. template <typename Protocol> int* data(const Protocol&) { return &value_; } // Get the address of the int data. template <typename Protocol> const int* data(const Protocol&) const { return &value_; } // Get the size of the int data. template <typename Protocol> std::size_t size(const Protocol&) const { return sizeof(value_); } // Set the size of the int data. template <typename Protocol> 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 <int Level, int Name> 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<u_short>(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<int>(value_.l_linger); } // Get the level of the socket option. template <typename Protocol> int level(const Protocol&) const { return Level; } // Get the name of the socket option. template <typename Protocol> int name(const Protocol&) const { return Name; } // Get the address of the linger data. template <typename Protocol> detail::linger_type* data(const Protocol&) { return &value_; } // Get the address of the linger data. template <typename Protocol> const detail::linger_type* data(const Protocol&) const { return &value_; } // Get the size of the linger data. template <typename Protocol> std::size_t size(const Protocol&) const { return sizeof(value_); } // Set the size of the int data. template <typename Protocol> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_SOCKET_OPTION_HPP detail/win_fd_set_adapter.hpp 0000644 00000007507 15125530236 0012353 0 ustar 00 // // detail/win_fd_set_adapter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/reactor_op_queue.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/push_options.hpp> 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<win_fd_set*>(::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<socket_type>& operations, op_queue<operation>&) { reactor_op_queue<socket_type>::iterator i = operations.begin(); while (i != operations.end()) { reactor_op_queue<socket_type>::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<fd_set*>(reinterpret_cast<const fd_set*>(fd_set_))); } operator fd_set*() { return reinterpret_cast<fd_set*>(fd_set_); } socket_type max_descriptor() const { return max_descriptor_; } void perform(reactor_op_queue<socket_type>& operations, op_queue<operation>& 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<win_fd_set*>(::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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) #endif // BOOST_ASIO_DETAIL_WIN_FD_SET_ADAPTER_HPP detail/chrono.hpp 0000644 00000004041 15125530236 0010010 0 ustar 00 // // detail/chrono.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_STD_CHRONO) # include <chrono> #elif defined(BOOST_ASIO_HAS_BOOST_CHRONO) # include <boost/chrono/system_clocks.hpp> #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 detail/fd_set_adapter.hpp 0000644 00000002050 15125530236 0011462 0 ustar 00 // // detail/fd_set_adapter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <boost/asio/detail/posix_fd_set_adapter.hpp> #include <boost/asio/detail/win_fd_set_adapter.hpp> 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 detail/limits.hpp 0000644 00000001336 15125530236 0010025 0 ustar 00 // // 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_BOOST_LIMITS) # include <boost/limits.hpp> #else // defined(BOOST_ASIO_HAS_BOOST_LIMITS) # include <limits> #endif // defined(BOOST_ASIO_HAS_BOOST_LIMITS) #endif // BOOST_ASIO_DETAIL_LIMITS_HPP detail/signal_op.hpp 0000644 00000002172 15125530236 0010476 0 ustar 00 // // detail/signal_op.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_SIGNAL_OP_HPP detail/dev_poll_reactor.hpp 0000644 00000017547 15125530236 0012062 0 ustar 00 // // detail/dev_poll_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_DEV_POLL) #include <cstddef> #include <vector> #include <sys/devpoll.h> #include <boost/asio/detail/hash_map.hpp> #include <boost/asio/detail/limits.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/reactor_op_queue.hpp> #include <boost/asio/detail/select_interrupter.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/timer_queue_base.hpp> #include <boost/asio/detail/timer_queue_set.hpp> #include <boost/asio/detail/wait_op.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class dev_poll_reactor : public execution_context_service_base<dev_poll_reactor> { 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 <typename Time_Traits> void add_timer_queue(timer_queue<Time_Traits>& queue); // Remove a timer queue from the reactor. template <typename Time_Traits> void remove_timer_queue(timer_queue<Time_Traits>& queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template <typename Time_Traits> void schedule_timer(timer_queue<Time_Traits>& queue, const typename Time_Traits::time_type& time, typename timer_queue<Time_Traits>::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 <typename Time_Traits> std::size_t cancel_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); // Move the timer operations associated with the given timer. template <typename Time_Traits> void move_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& target, typename timer_queue<Time_Traits>::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<operation>& 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<int, std::size_t> 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<socket_type> 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 <boost/asio/detail/pop_options.hpp> #include <boost/asio/detail/impl/dev_poll_reactor.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/dev_poll_reactor.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_HAS_DEV_POLL) #endif // BOOST_ASIO_DETAIL_DEV_POLL_REACTOR_HPP detail/win_iocp_handle_write_op.hpp 0000644 00000007256 15125530236 0013565 0 ustar 00 // // detail/win_iocp_handle_write_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename ConstBufferSequence, typename Handler, typename IoExecutor> 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)), work_(handler_, io_ex) { } 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<win_iocp_handle_write_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) if (owner) { // Check whether buffers are still valid. buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence>::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, boost::system::error_code, std::size_t> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #endif // BOOST_ASIO_DETAIL_WIN_IOCP_HANDLE_WRITE_OP_HPP detail/fenced_block.hpp 0000644 00000005772 15125530236 0011132 0 ustar 00 // // detail/fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_HAS_THREADS) \ || defined(BOOST_ASIO_DISABLE_FENCED_BLOCK) # include <boost/asio/detail/null_fenced_block.hpp> #elif defined(BOOST_ASIO_HAS_STD_ATOMIC) # include <boost/asio/detail/std_fenced_block.hpp> #elif defined(__MACH__) && defined(__APPLE__) # include <boost/asio/detail/macos_fenced_block.hpp> #elif defined(__sun) # include <boost/asio/detail/solaris_fenced_block.hpp> #elif defined(__GNUC__) && defined(__arm__) \ && !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) # include <boost/asio/detail/gcc_arm_fenced_block.hpp> #elif defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) # include <boost/asio/detail/gcc_hppa_fenced_block.hpp> #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) # include <boost/asio/detail/gcc_x86_fenced_block.hpp> #elif defined(__GNUC__) \ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) # include <boost/asio/detail/gcc_sync_fenced_block.hpp> #elif defined(BOOST_ASIO_WINDOWS) && !defined(UNDER_CE) # include <boost/asio/detail/win_fenced_block.hpp> #else # include <boost/asio/detail/null_fenced_block.hpp> #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 detail/win_tss_ptr.hpp 0000644 00000003320 15125530236 0011072 0 ustar 00 // // detail/win_tss_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS) #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { // Helper function to create thread-specific storage. BOOST_ASIO_DECL DWORD win_tss_ptr_create(); template <typename T> 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<T*>(::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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/win_tss_ptr.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_WINDOWS) #endif // BOOST_ASIO_DETAIL_WIN_TSS_PTR_HPP detail/signal_blocker.hpp 0000644 00000002546 15125530236 0011506 0 ustar 00 // // detail/signal_blocker.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_HAS_THREADS) || defined(BOOST_ASIO_WINDOWS) \ || defined(BOOST_ASIO_WINDOWS_RUNTIME) \ || defined(__CYGWIN__) || defined(__SYMBIAN32__) # include <boost/asio/detail/null_signal_blocker.hpp> #elif defined(BOOST_ASIO_HAS_PTHREADS) # include <boost/asio/detail/posix_signal_blocker.hpp> #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 detail/std_static_mutex.hpp 0000644 00000003062 15125530236 0012105 0 ustar 00 // // detail/std_static_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) #include <mutex> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/scoped_lock.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class std_event; class std_static_mutex : private noncopyable { public: typedef boost::asio::detail::scoped_lock<std_static_mutex> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) #endif // BOOST_ASIO_DETAIL_STD_STATIC_MUTEX_HPP detail/kqueue_reactor.hpp 0000644 00000020125 15125530236 0011537 0 ustar 00 // // detail/kqueue_reactor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_KQUEUE) #include <cstddef> #include <sys/types.h> #include <sys/event.h> #include <sys/time.h> #include <boost/asio/detail/limits.hpp> #include <boost/asio/detail/mutex.hpp> #include <boost/asio/detail/object_pool.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/select_interrupter.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/timer_queue_base.hpp> #include <boost/asio/detail/timer_queue_set.hpp> #include <boost/asio/detail/wait_op.hpp> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> // 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 <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class scheduler; class kqueue_reactor : public execution_context_service_base<kqueue_reactor> { 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<reactor_op> 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 <typename Time_Traits> void add_timer_queue(timer_queue<Time_Traits>& queue); // Remove a timer queue from the reactor. template <typename Time_Traits> void remove_timer_queue(timer_queue<Time_Traits>& queue); // Schedule a new operation in the given timer queue to expire at the // specified absolute time. template <typename Time_Traits> void schedule_timer(timer_queue<Time_Traits>& queue, const typename Time_Traits::time_type& time, typename timer_queue<Time_Traits>::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 <typename Time_Traits> std::size_t cancel_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& timer, std::size_t max_cancelled = (std::numeric_limits<std::size_t>::max)()); // Move the timer operations associated with the given timer. template <typename Time_Traits> void move_timer(timer_queue<Time_Traits>& queue, typename timer_queue<Time_Traits>::per_timer_data& target, typename timer_queue<Time_Traits>::per_timer_data& source); // Run the kqueue loop. BOOST_ASIO_DECL void run(long usec, op_queue<operation>& 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<descriptor_state> registered_descriptors_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/detail/impl/kqueue_reactor.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/kqueue_reactor.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // defined(BOOST_ASIO_HAS_KQUEUE) #endif // BOOST_ASIO_DETAIL_KQUEUE_REACTOR_HPP detail/completion_handler.hpp 0000644 00000005420 15125530236 0012370 0 ustar 00 // // detail/completion_handler.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/operation.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Handler, typename IoExecutor> class completion_handler : public operation { public: BOOST_ASIO_DEFINE_HANDLER_PTR(completion_handler); completion_handler(Handler& h, const IoExecutor& io_ex) : operation(&completion_handler::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(h)), work_(handler_, io_ex) { } 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<completion_handler*>(base)); ptr p = { boost::asio::detail::addressof(h->handler_), h, h }; BOOST_ASIO_HANDLER_COMPLETION((*h)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( h->work_)); // 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_COMPLETION_HANDLER_HPP detail/pipe_select_interrupter.hpp 0000644 00000005053 15125530236 0013463 0 ustar 00 // // detail/pipe_select_interrupter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_WINDOWS) #if !defined(BOOST_ASIO_WINDOWS_RUNTIME) #if !defined(__CYGWIN__) #if !defined(__SYMBIAN32__) #if !defined(BOOST_ASIO_HAS_EVENTFD) #include <boost/asio/detail/push_options.hpp> 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 interrupter. Returns true if the reset was successful. 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/pipe_select_interrupter.ipp> #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 detail/recycling_allocator.hpp 0000644 00000004643 15125530236 0012547 0 ustar 00 // // detail/recycling_allocator.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/thread_context.hpp> #include <boost/asio/detail/thread_info_base.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename T, typename Purpose = thread_info_base::default_tag> class recycling_allocator { public: typedef T value_type; template <typename U> struct rebind { typedef recycling_allocator<U, Purpose> other; }; recycling_allocator() { } template <typename U> recycling_allocator(const recycling_allocator<U, Purpose>&) { } 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<T*>(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 <typename Purpose> class recycling_allocator<void, Purpose> { public: typedef void value_type; template <typename U> struct rebind { typedef recycling_allocator<U, Purpose> other; }; recycling_allocator() { } template <typename U> recycling_allocator(const recycling_allocator<U, Purpose>&) { } }; template <typename Allocator, typename Purpose> struct get_recycling_allocator { typedef Allocator type; static type get(const Allocator& a) { return a; } }; template <typename T, typename Purpose> struct get_recycling_allocator<std::allocator<T>, Purpose> { typedef recycling_allocator<T, Purpose> type; static type get(const std::allocator<T>&) { return type(); } }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_RECYCLING_ALLOCATOR_HPP detail/reactive_socket_send_op.hpp 0000644 00000012632 15125530236 0013406 0 ustar 00 // // detail/reactive_socket_send_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename ConstBufferSequence> class reactive_socket_send_op_base : public reactor_op { public: reactive_socket_send_op_base(const boost::system::error_code& success_ec, socket_type socket, socket_ops::state_type state, const ConstBufferSequence& buffers, socket_base::message_flags flags, func_type complete_func) : reactor_op(success_ec, &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<reactive_socket_send_op_base*>(base)); typedef buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence> bufs_type; status result; if (bufs_type::is_single_buffer) { result = socket_ops::non_blocking_send1(o->socket_, bufs_type::first(o->buffers_).data(), bufs_type::first(o->buffers_).size(), 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_type::first(o->buffers_).size()) result = done_and_exhausted; } else { bufs_type bufs(o->buffers_); 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 <typename ConstBufferSequence, typename Handler, typename IoExecutor> class reactive_socket_send_op : public reactive_socket_send_op_base<ConstBufferSequence> { public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_send_op); reactive_socket_send_op(const boost::system::error_code& success_ec, 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<ConstBufferSequence>(success_ec, socket, state, buffers, flags, &reactive_socket_send_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), work_(handler_, io_ex) { } 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<reactive_socket_send_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code, std::size_t> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SEND_OP_HPP detail/null_thread.hpp 0000644 00000002642 15125530236 0011026 0 ustar 00 // // detail/null_thread.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_HAS_THREADS) #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class null_thread : private noncopyable { public: // Constructor. template <typename Function> 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 <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_HAS_THREADS) #endif // BOOST_ASIO_DETAIL_NULL_THREAD_HPP detail/thread_context.hpp 0000644 00000002157 15125530236 0011541 0 ustar 00 // // detail/thread_context.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <climits> #include <cstddef> #include <boost/asio/detail/call_stack.hpp> #include <boost/asio/detail/push_options.hpp> 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_context, thread_info_base> thread_call_stack; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_THREAD_CONTEXT_HPP detail/throw_exception.hpp 0000644 00000002750 15125530236 0011746 0 ustar 00 // // detail/throw_exception.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_BOOST_THROW_EXCEPTION) # include <boost/throw_exception.hpp> #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 <typename Exception> 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 <typename Exception> 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 detail/win_iocp_serial_port_service.hpp 0000644 00000017455 15125530236 0014467 0 ustar 00 // // detail/win_iocp_serial_port_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) && defined(BOOST_ASIO_HAS_SERIAL_PORT) #include <string> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/detail/win_iocp_handle_service.hpp> #include <boost/asio/detail/push_options.hpp> 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<win_iocp_serial_port_service> { 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 <typename SettableSerialPortOption> 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<SettableSerialPortOption>, &option, ec); } // Get an option from the serial port. template <typename GettableSerialPortOption> 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<GettableSerialPortOption>, &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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence, typename Handler, typename IoExecutor> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence, typename Handler, typename IoExecutor> 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 <typename SettableSerialPortOption> static boost::system::error_code store_option(const void* option, ::DCB& storage, boost::system::error_code& ec) { static_cast<const SettableSerialPortOption*>(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 <typename GettableSerialPortOption> static boost::system::error_code load_option(void* option, const ::DCB& storage, boost::system::error_code& ec) { static_cast<GettableSerialPortOption*>(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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/win_iocp_serial_port_service.ipp> #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 detail/consuming_buffers.hpp 0000644 00000024607 15125530236 0012250 0 ustar 00 // // detail/consuming_buffers.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/buffer.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/limits.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { // Helper template to determine the maximum number of prepared buffers. template <typename Buffers> struct prepared_buffers_max { enum { value = buffer_sequence_adapter_base::max_buffers }; }; template <typename Elem, std::size_t N> struct prepared_buffers_max<boost::array<Elem, N> > { enum { value = N }; }; #if defined(BOOST_ASIO_HAS_STD_ARRAY) template <typename Elem, std::size_t N> struct prepared_buffers_max<std::array<Elem, N> > { enum { value = N }; }; #endif // defined(BOOST_ASIO_HAS_STD_ARRAY) // A buffer sequence used to represent a subsequence of the buffers. template <typename Buffer, std::size_t MaxBuffers> 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 <typename Buffer, typename Buffers, typename Buffer_Iterator> class consuming_buffers { public: typedef prepared_buffers<Buffer, prepared_buffers_max<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 <typename Buffer> class consuming_single_buffer { public: // Construct to represent the entire list of buffers. template <typename Buffer1> 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<mutable_buffer, mutable_buffer, const mutable_buffer*> : public consuming_single_buffer<BOOST_ASIO_MUTABLE_BUFFER> { public: explicit consuming_buffers(const mutable_buffer& buffer) : consuming_single_buffer<BOOST_ASIO_MUTABLE_BUFFER>(buffer) { } }; template <> class consuming_buffers<const_buffer, mutable_buffer, const mutable_buffer*> : public consuming_single_buffer<BOOST_ASIO_CONST_BUFFER> { public: explicit consuming_buffers(const mutable_buffer& buffer) : consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>(buffer) { } }; template <> class consuming_buffers<const_buffer, const_buffer, const const_buffer*> : public consuming_single_buffer<BOOST_ASIO_CONST_BUFFER> { public: explicit consuming_buffers(const const_buffer& buffer) : consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>(buffer) { } }; #if !defined(BOOST_ASIO_NO_DEPRECATED) template <> class consuming_buffers<mutable_buffer, mutable_buffers_1, const mutable_buffer*> : public consuming_single_buffer<BOOST_ASIO_MUTABLE_BUFFER> { public: explicit consuming_buffers(const mutable_buffers_1& buffer) : consuming_single_buffer<BOOST_ASIO_MUTABLE_BUFFER>(buffer) { } }; template <> class consuming_buffers<const_buffer, mutable_buffers_1, const mutable_buffer*> : public consuming_single_buffer<BOOST_ASIO_CONST_BUFFER> { public: explicit consuming_buffers(const mutable_buffers_1& buffer) : consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>(buffer) { } }; template <> class consuming_buffers<const_buffer, const_buffers_1, const const_buffer*> : public consuming_single_buffer<BOOST_ASIO_CONST_BUFFER> { public: explicit consuming_buffers(const const_buffers_1& buffer) : consuming_single_buffer<BOOST_ASIO_CONST_BUFFER>(buffer) { } }; #endif // !defined(BOOST_ASIO_NO_DEPRECATED) template <typename Buffer, typename Elem> class consuming_buffers<Buffer, boost::array<Elem, 2>, typename boost::array<Elem, 2>::const_iterator> { public: // Construct to represent the entire list of buffers. explicit consuming_buffers(const boost::array<Elem, 2>& 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<Buffer, 2> prepare(std::size_t max_size) { boost::array<Buffer, 2> 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<Elem, 2> buffers_; std::size_t total_consumed_; }; #if defined(BOOST_ASIO_HAS_STD_ARRAY) template <typename Buffer, typename Elem> class consuming_buffers<Buffer, std::array<Elem, 2>, typename std::array<Elem, 2>::const_iterator> { public: // Construct to represent the entire list of buffers. explicit consuming_buffers(const std::array<Elem, 2>& 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<Buffer, 2> prepare(std::size_t max_size) { std::array<Buffer, 2> 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<Elem, 2> 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 <typename Buffer> class consuming_buffers<Buffer, null_buffers, const mutable_buffer*> : 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_CONSUMING_BUFFERS_HPP detail/operation.hpp 0000644 00000001703 15125530236 0010522 0 ustar 00 // // detail/operation.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/win_iocp_operation.hpp> #else # include <boost/asio/detail/scheduler_operation.hpp> #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 detail/winrt_ssocket_service.hpp 0000644 00000016437 15125530236 0013152 0 ustar 00 // // detail/winrt_ssocket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_SSOCKET_SERVICE_HPP #define BOOST_ASIO_DETAIL_WINRT_SSOCKET_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/winrt_socket_connect_op.hpp> #include <boost/asio/detail/winrt_ssocket_service_base.hpp> #include <boost/asio/detail/winrt_utils.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Protocol> class winrt_ssocket_service : public execution_context_service_base<winrt_ssocket_service<Protocol> >, public winrt_ssocket_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 Windows::Networking::Sockets::StreamSocket^ native_handle_type; // The implementation type of the socket. struct implementation_type : base_implementation_type { // Default constructor. implementation_type() : base_implementation_type(), protocol_(endpoint_type().protocol()) { } // The protocol associated with the socket. protocol_type protocol_; }; // Constructor. winrt_ssocket_service(execution_context& context) : execution_context_service_base<winrt_ssocket_service<Protocol> >(context), winrt_ssocket_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) BOOST_ASIO_NOEXCEPT { 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, winrt_ssocket_service& 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 <typename Protocol1> void converting_move_construct(implementation_type& impl, winrt_ssocket_service<Protocol1>&, typename winrt_ssocket_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 (is_open(impl)) { ec = boost::asio::error::already_open; return ec; } try { impl.socket_ = ref new Windows::Networking::Sockets::StreamSocket; impl.protocol_ = protocol; ec = boost::system::error_code(); } catch (Platform::Exception^ e) { ec = boost::system::error_code(e->HResult, boost::system::system_category()); } 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 (is_open(impl)) { ec = boost::asio::error::already_open; return ec; } impl.socket_ = native_socket; impl.protocol_ = protocol; ec = boost::system::error_code(); 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; } // Get the local endpoint. endpoint_type local_endpoint(const implementation_type& impl, boost::system::error_code& ec) const { endpoint_type endpoint; endpoint.resize(do_get_endpoint(impl, true, endpoint.data(), endpoint.size(), ec)); return endpoint; } // Get the remote endpoint. endpoint_type remote_endpoint(const implementation_type& impl, boost::system::error_code& ec) const { endpoint_type endpoint; endpoint.resize(do_get_endpoint(impl, false, endpoint.data(), endpoint.size(), ec)); return endpoint; } // 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; } // Set a socket option. template <typename Option> boost::system::error_code set_option(implementation_type& impl, const Option& option, boost::system::error_code& ec) { return do_set_option(impl, option.level(impl.protocol_), option.name(impl.protocol_), option.data(impl.protocol_), option.size(impl.protocol_), ec); } // Get a socket option. template <typename Option> 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_); do_get_option(impl, option.level(impl.protocol_), option.name(impl.protocol_), option.data(impl.protocol_), &size, ec); if (!ec) option.resize(impl.protocol_, size); return ec; } // 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) { return do_connect(impl, peer_endpoint.data(), ec); } // Start an asynchronous connect. template <typename Handler, typename IoExecutor> 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 winrt_socket_connect_op<Handler, IoExecutor> 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, "socket", &impl, 0, "async_connect")); start_connect_op(impl, peer_endpoint.data(), p.p, is_continuation); p.v = p.p = 0; } }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_WINRT_SSOCKET_SERVICE_HPP detail/std_thread.hpp 0000644 00000002621 15125530236 0010643 0 ustar 00 // // detail/std_thread.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_STD_THREAD) #include <thread> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { class std_thread : private noncopyable { public: // Constructor. template <typename Function> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_STD_THREAD) #endif // BOOST_ASIO_DETAIL_STD_THREAD_HPP detail/reactive_socket_sendto_op.hpp 0000644 00000012362 15125530236 0013751 0 ustar 00 // // detail/reactive_socket_sendto_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename ConstBufferSequence, typename Endpoint> class reactive_socket_sendto_op_base : public reactor_op { public: reactive_socket_sendto_op_base(const boost::system::error_code& success_ec, socket_type socket, const ConstBufferSequence& buffers, const Endpoint& endpoint, socket_base::message_flags flags, func_type complete_func) : reactor_op(success_ec, &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<reactive_socket_sendto_op_base*>(base)); typedef buffer_sequence_adapter<boost::asio::const_buffer, ConstBufferSequence> bufs_type; status result; if (bufs_type::is_single_buffer) { result = socket_ops::non_blocking_sendto1(o->socket_, bufs_type::first(o->buffers_).data(), bufs_type::first(o->buffers_).size(), o->flags_, o->destination_.data(), o->destination_.size(), o->ec_, o->bytes_transferred_) ? done : not_done; } else { bufs_type bufs(o->buffers_); 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 <typename ConstBufferSequence, typename Endpoint, typename Handler, typename IoExecutor> class reactive_socket_sendto_op : public reactive_socket_sendto_op_base<ConstBufferSequence, Endpoint> { public: BOOST_ASIO_DEFINE_HANDLER_PTR(reactive_socket_sendto_op); reactive_socket_sendto_op(const boost::system::error_code& success_ec, 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<ConstBufferSequence, Endpoint>( success_ec, socket, buffers, endpoint, flags, &reactive_socket_sendto_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), work_(handler_, io_ex) { } 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<reactive_socket_sendto_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code, std::size_t> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_REACTIVE_SOCKET_SENDTO_OP_HPP detail/descriptor_read_op.hpp 0000644 00000011276 15125530236 0012377 0 ustar 00 // // detail/descriptor_read_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/descriptor_ops.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/reactor_op.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename MutableBufferSequence> class descriptor_read_op_base : public reactor_op { public: descriptor_read_op_base(const boost::system::error_code& success_ec, int descriptor, const MutableBufferSequence& buffers, func_type complete_func) : reactor_op(success_ec, &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<descriptor_read_op_base*>(base)); typedef buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence> bufs_type; status result; if (bufs_type::is_single_buffer) { result = descriptor_ops::non_blocking_read1(o->descriptor_, bufs_type::first(o->buffers_).data(), bufs_type::first(o->buffers_).size(), o->ec_, o->bytes_transferred_) ? done : not_done; } else { bufs_type bufs(o->buffers_); 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 <typename MutableBufferSequence, typename Handler, typename IoExecutor> class descriptor_read_op : public descriptor_read_op_base<MutableBufferSequence> { public: BOOST_ASIO_DEFINE_HANDLER_PTR(descriptor_read_op); descriptor_read_op(const boost::system::error_code& success_ec, int descriptor, const MutableBufferSequence& buffers, Handler& handler, const IoExecutor& io_ex) : descriptor_read_op_base<MutableBufferSequence>(success_ec, descriptor, buffers, &descriptor_read_op::do_complete), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), work_(handler_, io_ex) { } 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<descriptor_read_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); // 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, boost::system::error_code, std::size_t> 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_; handler_work<Handler, IoExecutor> work_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) #endif // BOOST_ASIO_DETAIL_DESCRIPTOR_READ_OP_HPP detail/memory.hpp 0000644 00000004067 15125530236 0010040 0 ustar 00 // // detail/memory.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <memory> #if !defined(BOOST_ASIO_HAS_STD_SHARED_PTR) # include <boost/make_shared.hpp> # include <boost/shared_ptr.hpp> # include <boost/weak_ptr.hpp> #endif // !defined(BOOST_ASIO_HAS_STD_SHARED_PTR) #if !defined(BOOST_ASIO_HAS_STD_ADDRESSOF) # include <boost/utility/addressof.hpp> #endif // !defined(BOOST_ASIO_HAS_STD_ADDRESSOF) namespace boost { namespace asio { namespace detail { #if defined(BOOST_ASIO_HAS_STD_SHARED_PTR) using std::make_shared; using std::shared_ptr; using std::weak_ptr; #else // defined(BOOST_ASIO_HAS_STD_SHARED_PTR) using boost::make_shared; 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 <typename Allocator> \ struct uses_allocator<t, Allocator> : true_type {}; \ } \ /**/ # define BOOST_ASIO_REBIND_ALLOC(alloc, t) \ typename std::allocator_traits<alloc>::template rebind_alloc<t> /**/ #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<t>::other /**/ #endif // defined(BOOST_ASIO_HAS_CXX11_ALLOCATORS) } // namespace asio } // namespace boost #endif // BOOST_ASIO_DETAIL_MEMORY_HPP detail/reactor.hpp 0000644 00000001753 15125530236 0010166 0 ustar 00 // // detail/reactor.hpp // ~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/reactor_fwd.hpp> #if defined(BOOST_ASIO_HAS_EPOLL) # include <boost/asio/detail/epoll_reactor.hpp> #elif defined(BOOST_ASIO_HAS_KQUEUE) # include <boost/asio/detail/kqueue_reactor.hpp> #elif defined(BOOST_ASIO_HAS_DEV_POLL) # include <boost/asio/detail/dev_poll_reactor.hpp> #elif defined(BOOST_ASIO_HAS_IOCP) || defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <boost/asio/detail/null_reactor.hpp> #else # include <boost/asio/detail/select_reactor.hpp> #endif #endif // BOOST_ASIO_DETAIL_REACTOR_HPP detail/gcc_sync_fenced_block.hpp 0000644 00000003217 15125530236 0012772 0 ustar 00 // // detail/gcc_sync_fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(__GNUC__) \ && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)) \ && !defined(__INTEL_COMPILER) && !defined(__ICL) \ && !defined(__ICC) && !defined(__ECC) && !defined(__PATHSCALE__) #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #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 detail/socket_select_interrupter.hpp 0000644 00000005074 15125530236 0014021 0 ustar 00 // // detail/socket_select_interrupter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_WINDOWS_RUNTIME) #if defined(BOOST_ASIO_WINDOWS) \ || defined(__CYGWIN__) \ || defined(__SYMBIAN32__) #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/push_options.hpp> 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 interrupter. Returns true if the reset was successful. 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/socket_select_interrupter.ipp> #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 detail/object_pool.hpp 0000644 00000006654 15125530236 0011033 0 ustar 00 // // detail/object_pool.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Object> class object_pool; class object_pool_access { public: template <typename Object> static Object* create() { return new Object; } template <typename Object, typename Arg> static Object* create(Arg arg) { return new Object(arg); } template <typename Object> static void destroy(Object* o) { delete o; } template <typename Object> static Object*& next(Object* o) { return o->next_; } template <typename Object> static Object*& prev(Object* o) { return o->prev_; } }; template <typename Object> 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>(); 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 <typename Arg> Object* alloc(Arg arg) { Object* o = free_list_; if (o) free_list_ = object_pool_access::next(free_list_); else o = object_pool_access::create<Object>(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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_OBJECT_POOL_HPP detail/buffered_stream_storage.hpp 0000644 00000005653 15125530236 0013413 0 ustar 00 // // detail/buffered_stream_storage.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/detail/assert.hpp> #include <cstddef> #include <cstring> #include <vector> #include <boost/asio/detail/push_options.hpp> 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<byte_type> buffer_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_BUFFERED_STREAM_STORAGE_HPP detail/scheduler.hpp 0000644 00000016671 15125530236 0010512 0 ustar 00 // // detail/scheduler.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/system/error_code.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/detail/atomic_count.hpp> #include <boost/asio/detail/conditionally_enabled_event.hpp> #include <boost/asio/detail/conditionally_enabled_mutex.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/reactor_fwd.hpp> #include <boost/asio/detail/scheduler_operation.hpp> #include <boost/asio/detail/thread.hpp> #include <boost/asio/detail/thread_context.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { struct scheduler_thread_info; class scheduler : public execution_context_service_base<scheduler>, 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; } /// Capture the current exception so it can be rethrown from a run function. BOOST_ASIO_DECL void capture_current_exception(); // 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 operations and return immediately. Assumes // that work_started() has not yet been called for the operations. BOOST_ASIO_DECL void post_immediate_completions(std::size_t n, op_queue<operation>& ops, 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<operation>& 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<operation>& 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<operation> 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/scheduler.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_DETAIL_SCHEDULER_HPP detail/signal_set_service.hpp 0000644 00000015552 15125530236 0012401 0 ustar 00 // // detail/signal_set_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <signal.h> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/signal_handler.hpp> #include <boost/asio/detail/signal_op.hpp> #include <boost/asio/detail/socket_types.hpp> #if defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/win_iocp_io_context.hpp> #else // defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/scheduler.hpp> #endif // defined(BOOST_ASIO_HAS_IOCP) #if !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) # include <boost/asio/detail/reactor.hpp> #endif // !defined(BOOST_ASIO_WINDOWS) && !defined(__CYGWIN__) #include <boost/asio/detail/push_options.hpp> 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<signal_set_service> { 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<signal_op>* 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<signal_op> 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 <typename Handler, typename IoExecutor> void async_wait(implementation_type& impl, Handler& handler, const IoExecutor& io_ex) { // Allocate and construct an operation to wrap the handler. typedef signal_handler<Handler, IoExecutor> 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/detail/impl/signal_set_service.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_DETAIL_SIGNAL_SET_SERVICE_HPP detail/static_mutex.hpp 0000644 00000003321 15125530236 0011231 0 ustar 00 // // detail/static_mutex.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_HAS_THREADS) # include <boost/asio/detail/null_static_mutex.hpp> #elif defined(BOOST_ASIO_WINDOWS) # include <boost/asio/detail/win_static_mutex.hpp> #elif defined(BOOST_ASIO_HAS_PTHREADS) # include <boost/asio/detail/posix_static_mutex.hpp> #elif defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR) # include <boost/asio/detail/std_static_mutex.hpp> #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 detail/source_location.hpp 0000644 00000002664 15125530236 0011721 0 ustar 00 // // detail/source_location.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_SOURCE_LOCATION_HPP #define BOOST_ASIO_DETAIL_SOURCE_LOCATION_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_SOURCE_LOCATION) #if defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) # include <source_location> #elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) # include <experimental/source_location> #else // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) # error BOOST_ASIO_HAS_SOURCE_LOCATION is set \ but no source_location is available #endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) namespace boost { namespace asio { namespace detail { #if defined(BOOST_ASIO_HAS_STD_SOURCE_LOCATION) using std::source_location; #elif defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) using std::experimental::source_location; #endif // defined(BOOST_ASIO_HAS_STD_EXPERIMENTAL_SOURCE_LOCATION) } // namespace detail } // namespace asio } // namespace boost #endif // defined(BOOST_ASIO_HAS_SOURCE_LOCATION) #endif // BOOST_ASIO_DETAIL_SOURCE_LOCATION_HPP detail/is_executor.hpp 0000644 00000005731 15125530236 0011060 0 ustar 00 // // detail/is_executor.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename T> struct executor_memfns_derived : T, executor_memfns_base { }; template <typename T, T> struct executor_memfns_check { }; template <typename> char (&context_memfn_helper(...))[2]; template <typename T> char context_memfn_helper( executor_memfns_check< void (executor_memfns_base::*)(), &executor_memfns_derived<T>::context>*); template <typename> char (&on_work_started_memfn_helper(...))[2]; template <typename T> char on_work_started_memfn_helper( executor_memfns_check< void (executor_memfns_base::*)(), &executor_memfns_derived<T>::on_work_started>*); template <typename> char (&on_work_finished_memfn_helper(...))[2]; template <typename T> char on_work_finished_memfn_helper( executor_memfns_check< void (executor_memfns_base::*)(), &executor_memfns_derived<T>::on_work_finished>*); template <typename> char (&dispatch_memfn_helper(...))[2]; template <typename T> char dispatch_memfn_helper( executor_memfns_check< void (executor_memfns_base::*)(), &executor_memfns_derived<T>::dispatch>*); template <typename> char (&post_memfn_helper(...))[2]; template <typename T> char post_memfn_helper( executor_memfns_check< void (executor_memfns_base::*)(), &executor_memfns_derived<T>::post>*); template <typename> char (&defer_memfn_helper(...))[2]; template <typename T> char defer_memfn_helper( executor_memfns_check< void (executor_memfns_base::*)(), &executor_memfns_derived<T>::defer>*); template <typename T> struct is_executor_class : integral_constant<bool, sizeof(context_memfn_helper<T>(0)) != 1 && sizeof(on_work_started_memfn_helper<T>(0)) != 1 && sizeof(on_work_finished_memfn_helper<T>(0)) != 1 && sizeof(dispatch_memfn_helper<T>(0)) != 1 && sizeof(post_memfn_helper<T>(0)) != 1 && sizeof(defer_memfn_helper<T>(0)) != 1> { }; template <typename T> struct is_executor : conditional<is_class<T>::value, is_executor_class<T>, false_type>::type { }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_IS_EXECUTOR_HPP detail/buffer_resize_guard.hpp 0000644 00000003071 15125530236 0012536 0 ustar 00 // // detail/buffer_resize_guard.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/limits.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { // Helper class to manage buffer resizing in an exception safe way. template <typename Buffer> 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<size_t>::max)()) { buffer_.resize(old_size_); } } // Commit the resize transaction. void commit() { old_size_ = (std::numeric_limits<size_t>::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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_BUFFER_RESIZE_GUARD_HPP detail/winrt_socket_recv_op.hpp 0000644 00000007712 15125530236 0012760 0 ustar 00 // // detail/winrt_socket_recv_op.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_SOCKET_RECV_OP_HPP #define BOOST_ASIO_DETAIL_WINRT_SOCKET_RECV_OP_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/fenced_block.hpp> #include <boost/asio/detail/handler_alloc_helpers.hpp> #include <boost/asio/detail/handler_invoke_helpers.hpp> #include <boost/asio/detail/handler_work.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/winrt_async_op.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename MutableBufferSequence, typename Handler, typename IoExecutor> class winrt_socket_recv_op : public winrt_async_op<Windows::Storage::Streams::IBuffer^> { public: BOOST_ASIO_DEFINE_HANDLER_PTR(winrt_socket_recv_op); winrt_socket_recv_op(const MutableBufferSequence& buffers, Handler& handler, const IoExecutor& io_ex) : winrt_async_op<Windows::Storage::Streams::IBuffer^>( &winrt_socket_recv_op::do_complete), buffers_(buffers), handler_(BOOST_ASIO_MOVE_CAST(Handler)(handler)), work_(handler_, io_ex) { } static void do_complete(void* owner, operation* base, const boost::system::error_code&, std::size_t) { // Take ownership of the operation object. winrt_socket_recv_op* o(static_cast<winrt_socket_recv_op*>(base)); ptr p = { boost::asio::detail::addressof(o->handler_), o, o }; BOOST_ASIO_HANDLER_COMPLETION((*o)); // Take ownership of the operation's outstanding work. handler_work<Handler, IoExecutor> w( BOOST_ASIO_MOVE_CAST2(handler_work<Handler, IoExecutor>)( o->work_)); #if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) // Check whether buffers are still valid. if (owner) { buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence>::validate(o->buffers_); } #endif // defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING) std::size_t bytes_transferred = o->result_ ? o->result_->Length : 0; if (bytes_transferred == 0 && !o->ec_ && !buffer_sequence_adapter<boost::asio::mutable_buffer, MutableBufferSequence>::all_empty(o->buffers_)) { o->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, boost::system::error_code, std::size_t> handler(o->handler_, o->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_; handler_work<Handler, IoExecutor> executor_; }; } // namespace detail } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_WINDOWS_RUNTIME) #endif // BOOST_ASIO_DETAIL_WINRT_SOCKET_RECV_OP_HPP detail/thread.hpp 0000644 00000003172 15125530236 0007773 0 ustar 00 // // detail/thread.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_HAS_THREADS) # include <boost/asio/detail/null_thread.hpp> #elif defined(BOOST_ASIO_HAS_PTHREADS) # include <boost/asio/detail/posix_thread.hpp> #elif defined(BOOST_ASIO_WINDOWS) # if defined(UNDER_CE) # include <boost/asio/detail/wince_thread.hpp> # elif defined(BOOST_ASIO_WINDOWS_APP) # include <boost/asio/detail/winapp_thread.hpp> # else # include <boost/asio/detail/win_thread.hpp> # endif #elif defined(BOOST_ASIO_HAS_STD_THREAD) # include <boost/asio/detail/std_thread.hpp> #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_HAS_PTHREADS) typedef posix_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_STD_THREAD) typedef std_thread thread; #endif } // namespace detail } // namespace asio } // namespace boost #endif // BOOST_ASIO_DETAIL_THREAD_HPP detail/scheduler_operation.hpp 0000644 00000003602 15125530236 0012560 0 ustar 00 // // detail/scheduler_operation.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/system/error_code.hpp> #include <boost/asio/detail/handler_tracking.hpp> #include <boost/asio/detail/op_queue.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_DETAIL_SCHEDULER_OPERATION_HPP detail/gcc_hppa_fenced_block.hpp 0000644 00000003030 15125530236 0012737 0 ustar 00 // // detail/gcc_hppa_fenced_block.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // defined(__GNUC__) && (defined(__hppa) || defined(__hppa__)) #endif // BOOST_ASIO_DETAIL_GCC_HPPA_FENCED_BLOCK_HPP detail/assert.hpp 0000644 00000001710 15125530236 0010021 0 ustar 00 // // detail/assert.hpp // ~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_BOOST_ASSERT) # include <boost/assert.hpp> #else // defined(BOOST_ASIO_HAS_BOOST_ASSERT) # include <cassert> #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 read_at.hpp 0000644 00000066166 15125530236 0006675 0 ustar 00 // // read_at.hpp // ~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/cstdint.hpp> #include <boost/asio/error.hpp> #if !defined(BOOST_ASIO_NO_EXTENSIONS) # include <boost/asio/basic_streambuf_fwd.hpp> #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) #include <boost/asio/detail/push_options.hpp> 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 <typename SyncRandomAccessReadDevice, typename MutableBufferSequence> 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 <typename SyncRandomAccessReadDevice, typename MutableBufferSequence> 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 <typename SyncRandomAccessReadDevice, typename MutableBufferSequence, typename CompletionCondition> 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 <typename SyncRandomAccessReadDevice, typename MutableBufferSequence, typename CompletionCondition> 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 <typename SyncRandomAccessReadDevice, typename Allocator> std::size_t read_at(SyncRandomAccessReadDevice& d, uint64_t offset, basic_streambuf<Allocator>& 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 <typename SyncRandomAccessReadDevice, typename Allocator> std::size_t read_at(SyncRandomAccessReadDevice& d, uint64_t offset, basic_streambuf<Allocator>& 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 <typename SyncRandomAccessReadDevice, typename Allocator, typename CompletionCondition> std::size_t read_at(SyncRandomAccessReadDevice& d, uint64_t offset, basic_streambuf<Allocator>& 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 <typename SyncRandomAccessReadDevice, typename Allocator, typename CompletionCondition> std::size_t read_at(SyncRandomAccessReadDevice& d, uint64_t offset, basic_streambuf<Allocator>& 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 <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncRandomAccessReadDevice::executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncRandomAccessReadDevice::executor_type)); /// 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 <typename AsyncRandomAccessReadDevice, typename MutableBufferSequence, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncRandomAccessReadDevice::executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncRandomAccessReadDevice::executor_type)); #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 <typename AsyncRandomAccessReadDevice, typename Allocator, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncRandomAccessReadDevice::executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, basic_streambuf<Allocator>& b, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncRandomAccessReadDevice::executor_type)); /// 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 <typename AsyncRandomAccessReadDevice, typename Allocator, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncRandomAccessReadDevice::executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_at(AsyncRandomAccessReadDevice& d, uint64_t offset, basic_streambuf<Allocator>& b, CompletionCondition completion_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncRandomAccessReadDevice::executor_type)); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) /*@}*/ } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/read_at.hpp> #endif // BOOST_ASIO_READ_AT_HPP use_future.hpp 0000644 00000011324 15125530236 0007446 0 ustar 00 // // use_future.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/future.hpp> #if defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS) \ || defined(GENERATING_DOCUMENTATION) #include <memory> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Function, typename Allocator> class packaged_token; template <typename Function, typename Allocator, typename Result> 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<std::size_t> 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 <typename Allocator = std::allocator<void> > 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 <typename OtherAllocator> use_future_t<OtherAllocator> operator[](const OtherAllocator& allocator) const { return use_future_t<OtherAllocator>(allocator); } #endif // !defined(BOOST_ASIO_NO_DEPRECATED) /// Specify an alternate allocator. template <typename OtherAllocator> use_future_t<OtherAllocator> rebind(const OtherAllocator& allocator) const { return use_future_t<OtherAllocator>(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<std::size_t> 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 <typename Function> #if defined(GENERATING_DOCUMENTATION) unspecified #else // defined(GENERATING_DOCUMENTATION) detail::packaged_token<typename decay<Function>::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<void> can't be. struct std_allocator_void { BOOST_ASIO_CONSTEXPR std_allocator_void() { } operator std::allocator<void>() const { return std::allocator<void>(); } }; typename conditional< is_same<std::allocator<void>, 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 <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/use_future.hpp> #endif // defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS) // || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_USE_FUTURE_HPP io_service_strand.hpp 0000644 00000001077 15125530236 0010766 0 ustar 00 // // io_service_strand.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/io_context_strand.hpp> #endif // BOOST_ASIO_IO_SERVICE_STRAND_HPP prefer.hpp 0000644 00000044605 15125530236 0006553 0 ustar 00 // // prefer.hpp // ~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_PREFER_HPP #define BOOST_ASIO_PREFER_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/is_applicable_property.hpp> #include <boost/asio/traits/prefer_free.hpp> #include <boost/asio/traits/prefer_member.hpp> #include <boost/asio/traits/require_free.hpp> #include <boost/asio/traits/require_member.hpp> #include <boost/asio/traits/static_require.hpp> #include <boost/asio/detail/push_options.hpp> #if defined(GENERATING_DOCUMENTATION) namespace boost { namespace asio { /// A customisation point that attempts to apply a property to an object. /** * The name <tt>prefer</tt> denotes a customisation point object. The * expression <tt>boost::asio::prefer(E, P0, Pn...)</tt> for some subexpressions * <tt>E</tt> and <tt>P0</tt>, and where <tt>Pn...</tt> represents <tt>N</tt> * subexpressions (where <tt>N</tt> is 0 or more, and with types <tt>T = * decay_t<decltype(E)></tt> and <tt>Prop0 = decay_t<decltype(P0)></tt>) is * expression-equivalent to: * * @li If <tt>is_applicable_property_v<T, Prop0> && Prop0::is_preferable</tt> is * not a well-formed constant expression with value <tt>true</tt>, * <tt>boost::asio::prefer(E, P0, Pn...)</tt> is ill-formed. * * @li Otherwise, <tt>E</tt> if <tt>N == 0</tt> and the expression * <tt>Prop0::template static_query_v<T> == Prop0::value()</tt> is a * well-formed constant expression with value <tt>true</tt>. * * @li Otherwise, <tt>(E).require(P0)</tt> if <tt>N == 0</tt> and the expression * <tt>(E).require(P0)</tt> is a valid expression. * * @li Otherwise, <tt>require(E, P0)</tt> if <tt>N == 0</tt> and the expression * <tt>require(E, P0)</tt> is a valid expression with overload resolution * performed in a context that does not include the declaration of the * <tt>require</tt> customization point object. * * @li Otherwise, <tt>(E).prefer(P0)</tt> if <tt>N == 0</tt> and the expression * <tt>(E).prefer(P0)</tt> is a valid expression. * * @li Otherwise, <tt>prefer(E, P0)</tt> if <tt>N == 0</tt> and the expression * <tt>prefer(E, P0)</tt> is a valid expression with overload resolution * performed in a context that does not include the declaration of the * <tt>prefer</tt> customization point object. * * @li Otherwise, <tt>E</tt> if <tt>N == 0</tt>. * * @li Otherwise, * <tt>boost::asio::prefer(boost::asio::prefer(E, P0), Pn...)</tt> * if <tt>N > 0</tt> and the expression * <tt>boost::asio::prefer(boost::asio::prefer(E, P0), Pn...)</tt> * is a valid expression. * * @li Otherwise, <tt>boost::asio::prefer(E, P0, Pn...)</tt> is ill-formed. */ inline constexpr unspecified prefer = unspecified; /// A type trait that determines whether a @c prefer expression is well-formed. /** * Class template @c can_prefer is a trait that is derived from * @c true_type if the expression <tt>boost::asio::prefer(std::declval<T>(), * std::declval<Properties>()...)</tt> is well formed; otherwise @c false_type. */ template <typename T, typename... Properties> struct can_prefer : integral_constant<bool, automatically_determined> { }; /// A type trait that determines whether a @c prefer expression will not throw. /** * Class template @c is_nothrow_prefer is a trait that is derived from * @c true_type if the expression <tt>boost::asio::prefer(std::declval<T>(), * std::declval<Properties>()...)</tt> is @c noexcept; otherwise @c false_type. */ template <typename T, typename... Properties> struct is_nothrow_prefer : integral_constant<bool, automatically_determined> { }; /// A type trait that determines the result type of a @c prefer expression. /** * Class template @c prefer_result is a trait that determines the result * type of the expression <tt>boost::asio::prefer(std::declval<T>(), * std::declval<Properties>()...)</tt>. */ template <typename T, typename... Properties> struct prefer_result { /// The result of the @c prefer expression. typedef automatically_determined type; }; } // namespace asio } // namespace boost #else // defined(GENERATING_DOCUMENTATION) namespace asio_prefer_fn { using boost::asio::decay; using boost::asio::declval; using boost::asio::enable_if; using boost::asio::is_applicable_property; using boost::asio::traits::prefer_free; using boost::asio::traits::prefer_member; using boost::asio::traits::require_free; using boost::asio::traits::require_member; using boost::asio::traits::static_require; void prefer(); void require(); enum overload_type { identity, call_require_member, call_require_free, call_prefer_member, call_prefer_free, two_props, n_props, ill_formed }; template <typename T, typename Properties, typename = void> struct call_traits { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; template <typename T, typename Property> struct call_traits<T, void(Property), typename enable_if< ( is_applicable_property< typename decay<T>::type, typename decay<Property>::type >::value && decay<Property>::type::is_preferable && static_require<T, Property>::is_valid ) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = identity); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); #if defined(BOOST_ASIO_HAS_MOVE) typedef BOOST_ASIO_MOVE_ARG(T) result_type; #else // defined(BOOST_ASIO_HAS_MOVE) typedef BOOST_ASIO_MOVE_ARG(typename decay<T>::type) result_type; #endif // defined(BOOST_ASIO_HAS_MOVE) }; template <typename T, typename Property> struct call_traits<T, void(Property), typename enable_if< ( is_applicable_property< typename decay<T>::type, typename decay<Property>::type >::value && decay<Property>::type::is_preferable && !static_require<T, Property>::is_valid && require_member<T, Property>::is_valid ) >::type> : require_member<T, Property> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_require_member); }; template <typename T, typename Property> struct call_traits<T, void(Property), typename enable_if< ( is_applicable_property< typename decay<T>::type, typename decay<Property>::type >::value && decay<Property>::type::is_preferable && !static_require<T, Property>::is_valid && !require_member<T, Property>::is_valid && require_free<T, Property>::is_valid ) >::type> : require_free<T, Property> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_require_free); }; template <typename T, typename Property> struct call_traits<T, void(Property), typename enable_if< ( is_applicable_property< typename decay<T>::type, typename decay<Property>::type >::value && decay<Property>::type::is_preferable && !static_require<T, Property>::is_valid && !require_member<T, Property>::is_valid && !require_free<T, Property>::is_valid && prefer_member<T, Property>::is_valid ) >::type> : prefer_member<T, Property> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_prefer_member); }; template <typename T, typename Property> struct call_traits<T, void(Property), typename enable_if< ( is_applicable_property< typename decay<T>::type, typename decay<Property>::type >::value && decay<Property>::type::is_preferable && !static_require<T, Property>::is_valid && !require_member<T, Property>::is_valid && !require_free<T, Property>::is_valid && !prefer_member<T, Property>::is_valid && prefer_free<T, Property>::is_valid ) >::type> : prefer_free<T, Property> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_prefer_free); }; template <typename T, typename Property> struct call_traits<T, void(Property), typename enable_if< ( is_applicable_property< typename decay<T>::type, typename decay<Property>::type >::value && decay<Property>::type::is_preferable && !static_require<T, Property>::is_valid && !require_member<T, Property>::is_valid && !require_free<T, Property>::is_valid && !prefer_member<T, Property>::is_valid && !prefer_free<T, Property>::is_valid ) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = identity); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); #if defined(BOOST_ASIO_HAS_MOVE) typedef BOOST_ASIO_MOVE_ARG(T) result_type; #else // defined(BOOST_ASIO_HAS_MOVE) typedef BOOST_ASIO_MOVE_ARG(typename decay<T>::type) result_type; #endif // defined(BOOST_ASIO_HAS_MOVE) }; template <typename T, typename P0, typename P1> struct call_traits<T, void(P0, P1), typename enable_if< call_traits<T, void(P0)>::overload != ill_formed && call_traits< typename call_traits<T, void(P0)>::result_type, void(P1) >::overload != ill_formed >::type> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = two_props); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = ( call_traits<T, void(P0)>::is_noexcept && call_traits< typename call_traits<T, void(P0)>::result_type, void(P1) >::is_noexcept )); typedef typename decay< typename call_traits< typename call_traits<T, void(P0)>::result_type, void(P1) >::result_type >::type result_type; }; template <typename T, typename P0, typename P1, typename BOOST_ASIO_ELLIPSIS PN> struct call_traits<T, void(P0, P1, PN BOOST_ASIO_ELLIPSIS), typename enable_if< call_traits<T, void(P0)>::overload != ill_formed && call_traits< typename call_traits<T, void(P0)>::result_type, void(P1, PN BOOST_ASIO_ELLIPSIS) >::overload != ill_formed >::type> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = n_props); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = ( call_traits<T, void(P0)>::is_noexcept && call_traits< typename call_traits<T, void(P0)>::result_type, void(P1, PN BOOST_ASIO_ELLIPSIS) >::is_noexcept )); typedef typename decay< typename call_traits< typename call_traits<T, void(P0)>::result_type, void(P1, PN BOOST_ASIO_ELLIPSIS) >::result_type >::type result_type; }; struct impl { template <typename T, typename Property> BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(Property)>::overload == identity, typename call_traits<T, void(Property)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(Property)) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(Property)>::is_noexcept)) { return BOOST_ASIO_MOVE_CAST(T)(t); } template <typename T, typename Property> BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(Property)>::overload == call_require_member, typename call_traits<T, void(Property)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(Property) p) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(Property)>::is_noexcept)) { return BOOST_ASIO_MOVE_CAST(T)(t).require( BOOST_ASIO_MOVE_CAST(Property)(p)); } template <typename T, typename Property> BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(Property)>::overload == call_require_free, typename call_traits<T, void(Property)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(Property) p) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(Property)>::is_noexcept)) { return require( BOOST_ASIO_MOVE_CAST(T)(t), BOOST_ASIO_MOVE_CAST(Property)(p)); } template <typename T, typename Property> BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(Property)>::overload == call_prefer_member, typename call_traits<T, void(Property)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(Property) p) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(Property)>::is_noexcept)) { return BOOST_ASIO_MOVE_CAST(T)(t).prefer( BOOST_ASIO_MOVE_CAST(Property)(p)); } template <typename T, typename Property> BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(Property)>::overload == call_prefer_free, typename call_traits<T, void(Property)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(Property) p) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(Property)>::is_noexcept)) { return prefer( BOOST_ASIO_MOVE_CAST(T)(t), BOOST_ASIO_MOVE_CAST(Property)(p)); } template <typename T, typename P0, typename P1> BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(P0, P1)>::overload == two_props, typename call_traits<T, void(P0, P1)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(P0) p0, BOOST_ASIO_MOVE_ARG(P1) p1) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(P0, P1)>::is_noexcept)) { return (*this)( (*this)( BOOST_ASIO_MOVE_CAST(T)(t), BOOST_ASIO_MOVE_CAST(P0)(p0)), BOOST_ASIO_MOVE_CAST(P1)(p1)); } template <typename T, typename P0, typename P1, typename BOOST_ASIO_ELLIPSIS PN> BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(P0, P1, PN BOOST_ASIO_ELLIPSIS)>::overload == n_props, typename call_traits<T, void(P0, P1, PN BOOST_ASIO_ELLIPSIS)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(P0) p0, BOOST_ASIO_MOVE_ARG(P1) p1, BOOST_ASIO_MOVE_ARG(PN) BOOST_ASIO_ELLIPSIS pn) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(P0, P1, PN BOOST_ASIO_ELLIPSIS)>::is_noexcept)) { return (*this)( (*this)( BOOST_ASIO_MOVE_CAST(T)(t), BOOST_ASIO_MOVE_CAST(P0)(p0)), BOOST_ASIO_MOVE_CAST(P1)(p1), BOOST_ASIO_MOVE_CAST(PN)(pn) BOOST_ASIO_ELLIPSIS); } }; template <typename T = impl> struct static_instance { static const T instance; }; template <typename T> const T static_instance<T>::instance = {}; } // namespace asio_prefer_fn namespace boost { namespace asio { namespace { static BOOST_ASIO_CONSTEXPR const asio_prefer_fn::impl& prefer = asio_prefer_fn::static_instance<>::instance; } // namespace #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T, typename... Properties> struct can_prefer : integral_constant<bool, asio_prefer_fn::call_traits<T, void(Properties...)>::overload != asio_prefer_fn::ill_formed> { }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T, typename P0 = void, typename P1 = void, typename P2 = void> struct can_prefer : integral_constant<bool, asio_prefer_fn::call_traits<T, void(P0, P1, P2)>::overload != asio_prefer_fn::ill_formed> { }; template <typename T, typename P0, typename P1> struct can_prefer<T, P0, P1> : integral_constant<bool, asio_prefer_fn::call_traits<T, void(P0, P1)>::overload != asio_prefer_fn::ill_formed> { }; template <typename T, typename P0> struct can_prefer<T, P0> : integral_constant<bool, asio_prefer_fn::call_traits<T, void(P0)>::overload != asio_prefer_fn::ill_formed> { }; template <typename T> struct can_prefer<T> : false_type { }; #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename BOOST_ASIO_ELLIPSIS Properties> constexpr bool can_prefer_v = can_prefer<T, Properties BOOST_ASIO_ELLIPSIS>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T, typename... Properties> struct is_nothrow_prefer : integral_constant<bool, asio_prefer_fn::call_traits<T, void(Properties...)>::is_noexcept> { }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T, typename P0 = void, typename P1 = void, typename P2 = void> struct is_nothrow_prefer : integral_constant<bool, asio_prefer_fn::call_traits<T, void(P0, P1, P2)>::is_noexcept> { }; template <typename T, typename P0, typename P1> struct is_nothrow_prefer<T, P0, P1> : integral_constant<bool, asio_prefer_fn::call_traits<T, void(P0, P1)>::is_noexcept> { }; template <typename T, typename P0> struct is_nothrow_prefer<T, P0> : integral_constant<bool, asio_prefer_fn::call_traits<T, void(P0)>::is_noexcept> { }; template <typename T> struct is_nothrow_prefer<T> : false_type { }; #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename BOOST_ASIO_ELLIPSIS Properties> constexpr bool is_nothrow_prefer_v = is_nothrow_prefer<T, Properties BOOST_ASIO_ELLIPSIS>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T, typename... Properties> struct prefer_result { typedef typename asio_prefer_fn::call_traits< T, void(Properties...)>::result_type type; }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T, typename P0 = void, typename P1 = void, typename P2 = void> struct prefer_result { typedef typename asio_prefer_fn::call_traits< T, void(P0, P1, P2)>::result_type type; }; template <typename T, typename P0, typename P1> struct prefer_result<T, P0, P1> { typedef typename asio_prefer_fn::call_traits< T, void(P0, P1)>::result_type type; }; template <typename T, typename P0> struct prefer_result<T, P0> { typedef typename asio_prefer_fn::call_traits< T, void(P0)>::result_type type; }; template <typename T> struct prefer_result<T> { }; #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) } // namespace asio } // namespace boost #endif // defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_PREFER_HPP basic_datagram_socket.hpp 0000644 00000134641 15125530236 0011561 0 ustar 00 // // basic_datagram_socket.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/basic_socket.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Protocol, typename Executor = any_io_executor> 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 <typename Protocol, typename Executor> class basic_datagram_socket : public basic_socket<Protocol, Executor> { public: /// The type of the executor associated with the object. typedef Executor executor_type; /// Rebinds the socket type to another executor. template <typename Executor1> struct rebind_executor { /// The socket type when rebound to the specified executor. typedef basic_datagram_socket<Protocol, Executor1> other; }; /// The native representation of a socket. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; #else typedef typename basic_socket<Protocol, Executor>::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<Protocol, Executor>(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 <typename ExecutionContext> explicit basic_datagram_socket(ExecutionContext& context, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_socket<Protocol, Executor>(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<Protocol, Executor>(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 <typename ExecutionContext> basic_datagram_socket(ExecutionContext& context, const protocol_type& protocol, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_socket<Protocol, Executor>(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<Protocol, Executor>(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 <typename ExecutionContext> basic_datagram_socket(ExecutionContext& context, const endpoint_type& endpoint, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_socket<Protocol, Executor>(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<Protocol, Executor>(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 <typename ExecutionContext> basic_datagram_socket(ExecutionContext& context, const protocol_type& protocol, const native_handle_type& native_socket, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_socket<Protocol, Executor>(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) BOOST_ASIO_NOEXCEPT : basic_socket<Protocol, Executor>(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<Protocol, Executor>::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 <typename Protocol1, typename Executor1> basic_datagram_socket(basic_datagram_socket<Protocol1, Executor1>&& other, typename enable_if< is_convertible<Protocol1, Protocol>::value && is_convertible<Executor1, Executor>::value >::type* = 0) : basic_socket<Protocol, Executor>(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 Protocol1, typename Executor1> typename enable_if< is_convertible<Protocol1, Protocol>::value && is_convertible<Executor1, Executor>::value, basic_datagram_socket& >::type operator=(basic_datagram_socket<Protocol1, Executor1>&& other) { basic_socket<Protocol, Executor>::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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_send(const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( initiate_async_send(this), handler, 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 <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( initiate_async_send(this), handler, 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( initiate_async_send_to(this), handler, 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 <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( initiate_async_send_to(this), handler, 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_receive(const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( initiate_async_receive(this), handler, 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( initiate_async_receive(this), handler, 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( initiate_async_receive_from(this), handler, 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( initiate_async_receive_from(this), handler, buffers, &sender_endpoint, flags); } private: // Disallow copying and assignment. basic_datagram_socket(const basic_datagram_socket&) BOOST_ASIO_DELETED; basic_datagram_socket& operator=( const basic_datagram_socket&) BOOST_ASIO_DELETED; class initiate_async_send { public: typedef Executor executor_type; explicit initiate_async_send(basic_datagram_socket* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename WriteHandler, typename ConstBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, 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<WriteHandler> handler2(handler); self_->impl_.get_service().async_send( self_->impl_.get_implementation(), buffers, flags, handler2.value, self_->impl_.get_executor()); } private: basic_datagram_socket* self_; }; class initiate_async_send_to { public: typedef Executor executor_type; explicit initiate_async_send_to(basic_datagram_socket* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename WriteHandler, typename ConstBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, 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<WriteHandler> handler2(handler); self_->impl_.get_service().async_send_to( self_->impl_.get_implementation(), buffers, destination, flags, handler2.value, self_->impl_.get_executor()); } private: basic_datagram_socket* self_; }; class initiate_async_receive { public: typedef Executor executor_type; explicit initiate_async_receive(basic_datagram_socket* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename ReadHandler, typename MutableBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); self_->impl_.get_service().async_receive( self_->impl_.get_implementation(), buffers, flags, handler2.value, self_->impl_.get_executor()); } private: basic_datagram_socket* self_; }; class initiate_async_receive_from { public: typedef Executor executor_type; explicit initiate_async_receive_from(basic_datagram_socket* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename ReadHandler, typename MutableBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); self_->impl_.get_service().async_receive_from( self_->impl_.get_implementation(), buffers, *sender_endpoint, flags, handler2.value, self_->impl_.get_executor()); } private: basic_datagram_socket* self_; }; }; } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_BASIC_DATAGRAM_SOCKET_HPP windows/overlapped_handle.hpp 0000644 00000002316 15125530236 0012427 0 ustar 00 // // windows/overlapped_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/windows/basic_overlapped_handle.hpp> 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 windows/object_handle.hpp 0000644 00000002145 15125530236 0011534 0 ustar 00 // // windows/object_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/windows/basic_object_handle.hpp> 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 windows/basic_object_handle.hpp 0000644 00000034072 15125530236 0012701 0 ustar 00 // // windows/basic_object_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/any_io_executor.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/io_object_impl.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/win_object_handle_service.hpp> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #if defined(BOOST_ASIO_HAS_MOVE) # include <utility> #endif // defined(BOOST_ASIO_HAS_MOVE) #include <boost/asio/detail/push_options.hpp> 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 <typename Executor = any_io_executor> class basic_object_handle { public: /// The type of the executor associated with the object. typedef Executor executor_type; /// Rebinds the handle type to another executor. template <typename Executor1> struct rebind_executor { /// The handle type when rebound to the specified executor. typedef basic_object_handle<Executor1> other; }; /// 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 <typename ExecutionContext> explicit basic_object_handle(ExecutionContext& context, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename ExecutionContext> basic_object_handle(ExecutionContext& context, const native_handle_type& native_handle, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) WaitHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (boost::system::error_code)) async_wait( BOOST_ASIO_MOVE_ARG(WaitHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WaitHandler, void (boost::system::error_code)>( initiate_async_wait(this), handler); } 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; class initiate_async_wait { public: typedef Executor executor_type; explicit initiate_async_wait(basic_object_handle* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename WaitHandler> void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler) 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<WaitHandler> handler2(handler); self_->impl_.get_service().async_wait( self_->impl_.get_implementation(), handler2.value, self_->impl_.get_executor()); } private: basic_object_handle* self_; }; boost::asio::detail::io_object_impl< boost::asio::detail::win_object_handle_service, Executor> impl_; }; } // namespace windows } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) // || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_WINDOWS_BASIC_OBJECT_HANDLE_HPP windows/basic_stream_handle.hpp 0000644 00000042174 15125530236 0012730 0 ustar 00 // // windows/basic_stream_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/windows/basic_overlapped_handle.hpp> #if defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/push_options.hpp> 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 <typename Executor = any_io_executor> class basic_stream_handle : public basic_overlapped_handle<Executor> { public: /// The type of the executor associated with the object. typedef Executor executor_type; /// Rebinds the handle type to another executor. template <typename Executor1> struct rebind_executor { /// The handle type when rebound to the specified executor. typedef basic_stream_handle<Executor1> other; }; /// 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<Executor>(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 <typename ExecutionContext> explicit basic_stream_handle(ExecutionContext& context, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value, basic_stream_handle >::type* = 0) : basic_overlapped_handle<Executor>(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<Executor>(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 <typename ExecutionContext> basic_stream_handle(ExecutionContext& context, const native_handle_type& handle, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_overlapped_handle<Executor>(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<Executor>(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<Executor>::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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_some(const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( initiate_async_write_some(this), handler, buffers); } /// 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_some(const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( initiate_async_read_some(this), handler, buffers); } private: class initiate_async_write_some { public: typedef Executor executor_type; explicit initiate_async_write_some(basic_stream_handle* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename WriteHandler, typename ConstBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, 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<WriteHandler> handler2(handler); self_->impl_.get_service().async_write_some( self_->impl_.get_implementation(), buffers, handler2.value, self_->impl_.get_executor()); } private: basic_stream_handle* self_; }; class initiate_async_read_some { public: typedef Executor executor_type; explicit initiate_async_read_some(basic_stream_handle* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename ReadHandler, typename MutableBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); self_->impl_.get_service().async_read_some( self_->impl_.get_implementation(), buffers, handler2.value, self_->impl_.get_executor()); } private: basic_stream_handle* self_; }; }; } // namespace windows } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) // || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_WINDOWS_BASIC_STREAM_HANDLE_HPP windows/overlapped_ptr.hpp 0000644 00000007742 15125530236 0012011 0 ustar 00 // // windows/overlapped_ptr.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/win_iocp_overlapped_ptr.hpp> #include <boost/asio/io_context.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename ExecutionContext, typename Handler> explicit overlapped_ptr(ExecutionContext& context, BOOST_ASIO_MOVE_ARG(Handler) handler, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : impl_(context.get_executor(), BOOST_ASIO_MOVE_CAST(Handler)(handler)) { } /// Construct an overlapped_ptr to contain the specified handler. template <typename Executor, typename Handler> explicit overlapped_ptr(const Executor& ex, BOOST_ASIO_MOVE_ARG(Handler) handler, typename enable_if< execution::is_executor<Executor>::value || is_executor<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 <typename ExecutionContext, typename Handler> void reset(ExecutionContext& context, BOOST_ASIO_MOVE_ARG(Handler) handler, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename Executor, typename Handler> void reset(const Executor& ex, BOOST_ASIO_MOVE_ARG(Handler) handler, typename enable_if< execution::is_executor<Executor>::value || is_executor<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 <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_WINDOWS_OVERLAPPED_PTR) // || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_WINDOWS_OVERLAPPED_PTR_HPP windows/random_access_handle.hpp 0000644 00000002166 15125530236 0013072 0 ustar 00 // // windows/random_access_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/windows/basic_random_access_handle.hpp> 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 windows/basic_random_access_handle.hpp 0000644 00000044400 15125530236 0014230 0 ustar 00 // // windows/basic_random_access_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/windows/basic_overlapped_handle.hpp> #if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/push_options.hpp> 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 <typename Executor = any_io_executor> class basic_random_access_handle : public basic_overlapped_handle<Executor> { public: /// The type of the executor associated with the object. typedef Executor executor_type; /// Rebinds the handle type to another executor. template <typename Executor1> struct rebind_executor { /// The handle type when rebound to the specified executor. typedef basic_random_access_handle<Executor1> other; }; /// 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<Executor>(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 <typename ExecutionContext> explicit basic_random_access_handle(ExecutionContext& context, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value, basic_random_access_handle >::type* = 0) : basic_overlapped_handle<Executor>(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<Executor>(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 <typename ExecutionContext> basic_random_access_handle(ExecutionContext& context, const native_handle_type& handle, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_overlapped_handle<Executor>(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<Executor>(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<Executor>::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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( initiate_async_write_some_at(this), handler, offset, buffers); } /// 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( initiate_async_read_some_at(this), handler, offset, buffers); } private: class initiate_async_write_some_at { public: typedef Executor executor_type; explicit initiate_async_write_some_at(basic_random_access_handle* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename WriteHandler, typename ConstBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, uint64_t offset, 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<WriteHandler> handler2(handler); self_->impl_.get_service().async_write_some_at( self_->impl_.get_implementation(), offset, buffers, handler2.value, self_->impl_.get_executor()); } private: basic_random_access_handle* self_; }; class initiate_async_read_some_at { public: typedef Executor executor_type; explicit initiate_async_read_some_at(basic_random_access_handle* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename ReadHandler, typename MutableBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, uint64_t offset, 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<ReadHandler> handler2(handler); self_->impl_.get_service().async_read_some_at( self_->impl_.get_implementation(), offset, buffers, handler2.value, self_->impl_.get_executor()); } private: basic_random_access_handle* self_; }; }; } // namespace windows } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) // || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_WINDOWS_BASIC_RANDOM_ACCESS_HANDLE_HPP windows/basic_overlapped_handle.hpp 0000644 00000027161 15125530236 0013575 0 ustar 00 // // windows/basic_overlapped_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_WINDOWS_RANDOM_ACCESS_HANDLE) \ || defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(GENERATING_DOCUMENTATION) #include <cstddef> #include <boost/asio/any_io_executor.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/io_object_impl.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/win_iocp_handle_service.hpp> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #if defined(BOOST_ASIO_HAS_MOVE) # include <utility> #endif // defined(BOOST_ASIO_HAS_MOVE) #include <boost/asio/detail/push_options.hpp> 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 <typename Executor = any_io_executor> class basic_overlapped_handle { public: /// The type of the executor associated with the object. typedef Executor executor_type; /// Rebinds the handle type to another executor. template <typename Executor1> struct rebind_executor { /// The handle type when rebound to the specified executor. typedef basic_overlapped_handle<Executor1> other; }; /// 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 <typename ExecutionContext> explicit basic_overlapped_handle(ExecutionContext& context, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename ExecutionContext> basic_overlapped_handle(ExecutionContext& context, const native_handle_type& native_handle, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <boost/asio/detail/pop_options.hpp> #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 windows/stream_handle.hpp 0000644 00000002062 15125530236 0011557 0 ustar 00 // // windows/stream_handle.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_WINDOWS_STREAM_HANDLE) \ || defined(GENERATING_DOCUMENTATION) #include <boost/asio/windows/basic_stream_handle.hpp> 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 executor.hpp 0000644 00000024343 15125530236 0007123 0 ustar 00 // // executor.hpp // ~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) #include <typeinfo> #include <boost/asio/detail/cstddef.hpp> #include <boost/asio/detail/executor_function.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Executor> executor(Executor e); /// Allocator-aware constructor to create a polymorphic wrapper for the /// specified executor. template <typename Executor, typename Allocator> 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 <typename Executor> 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 <typename Function, typename Allocator> 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 <typename Function, typename Allocator> 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 <typename Function, typename Allocator> 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, <tt>typeid(T)</tt>; * otherwise, <tt>typeid(void)</tt>. */ #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 <tt>target_type() == typeid(T)</tt>, a pointer to the stored * executor target; otherwise, a null pointer. */ template <typename Executor> Executor* target() BOOST_ASIO_NOEXCEPT; /// Obtain a pointer to the target executor object. /** * @returns If <tt>target_type() == typeid(T)</tt>, a pointer to the stored * executor target; otherwise, a null pointer. */ template <typename Executor> 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) typedef detail::executor_function function; template <typename, typename> 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 <typename T> 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 <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/executor.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/impl/executor.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) #endif // BOOST_ASIO_EXECUTOR_HPP basic_seq_packet_socket.hpp 0000644 00000071000 15125530236 0012105 0 ustar 00 // // basic_seq_packet_socket.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/basic_socket.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Protocol, typename Executor = any_io_executor> 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 <typename Protocol, typename Executor> class basic_seq_packet_socket : public basic_socket<Protocol, Executor> { public: /// The type of the executor associated with the object. typedef Executor executor_type; /// Rebinds the socket type to another executor. template <typename Executor1> struct rebind_executor { /// The socket type when rebound to the specified executor. typedef basic_seq_packet_socket<Protocol, Executor1> other; }; /// The native representation of a socket. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; #else typedef typename basic_socket<Protocol, Executor>::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<Protocol, Executor>(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 <typename ExecutionContext> explicit basic_seq_packet_socket(ExecutionContext& context, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_socket<Protocol, Executor>(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<Protocol, Executor>(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 <typename ExecutionContext> basic_seq_packet_socket(ExecutionContext& context, const protocol_type& protocol, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_socket<Protocol, Executor>(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<Protocol, Executor>(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 <typename ExecutionContext> basic_seq_packet_socket(ExecutionContext& context, const endpoint_type& endpoint, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_socket<Protocol, Executor>(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<Protocol, Executor>(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 <typename ExecutionContext> basic_seq_packet_socket(ExecutionContext& context, const protocol_type& protocol, const native_handle_type& native_socket, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_socket<Protocol, Executor>(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) BOOST_ASIO_NOEXCEPT : basic_socket<Protocol, Executor>(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<Protocol, Executor>::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 <typename Protocol1, typename Executor1> basic_seq_packet_socket(basic_seq_packet_socket<Protocol1, Executor1>&& other, typename enable_if< is_convertible<Protocol1, Protocol>::value && is_convertible<Executor1, Executor>::value >::type* = 0) : basic_socket<Protocol, Executor>(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 Protocol1, typename Executor1> typename enable_if< is_convertible<Protocol1, Protocol>::value && is_convertible<Executor1, Executor>::value, basic_seq_packet_socket& >::type operator=(basic_seq_packet_socket<Protocol1, Executor1>&& other) { basic_socket<Protocol, Executor>::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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( initiate_async_send(this), handler, 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( initiate_async_receive_with_flags(this), handler, 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( initiate_async_receive_with_flags(this), handler, buffers, in_flags, &out_flags); } private: // Disallow copying and assignment. basic_seq_packet_socket(const basic_seq_packet_socket&) BOOST_ASIO_DELETED; basic_seq_packet_socket& operator=( const basic_seq_packet_socket&) BOOST_ASIO_DELETED; class initiate_async_send { public: typedef Executor executor_type; explicit initiate_async_send(basic_seq_packet_socket* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename WriteHandler, typename ConstBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, 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<WriteHandler> handler2(handler); self_->impl_.get_service().async_send( self_->impl_.get_implementation(), buffers, flags, handler2.value, self_->impl_.get_executor()); } private: basic_seq_packet_socket* self_; }; class initiate_async_receive_with_flags { public: typedef Executor executor_type; explicit initiate_async_receive_with_flags(basic_seq_packet_socket* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename ReadHandler, typename MutableBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); self_->impl_.get_service().async_receive_with_flags( self_->impl_.get_implementation(), buffers, in_flags, *out_flags, handler2.value, self_->impl_.get_executor()); } private: basic_seq_packet_socket* self_; }; }; } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_BASIC_SEQ_PACKET_SOCKET_HPP read.hpp 0000644 00000151206 15125530236 0006177 0 ustar 00 // // read.hpp // ~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/async_result.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/error.hpp> #if !defined(BOOST_ASIO_NO_EXTENSIONS) # include <boost/asio/basic_streambuf_fwd.hpp> #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) #include <boost/asio/detail/push_options.hpp> 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 <typename SyncReadStream, typename MutableBufferSequence> std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, typename enable_if< is_mutable_buffer_sequence<MutableBufferSequence>::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 <typename SyncReadStream, typename MutableBufferSequence> std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, boost::system::error_code& ec, typename enable_if< is_mutable_buffer_sequence<MutableBufferSequence>::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 <typename SyncReadStream, typename MutableBufferSequence, typename CompletionCondition> std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, typename enable_if< is_mutable_buffer_sequence<MutableBufferSequence>::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 <typename SyncReadStream, typename MutableBufferSequence, typename CompletionCondition> std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, boost::system::error_code& ec, typename enable_if< is_mutable_buffer_sequence<MutableBufferSequence>::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 <typename SyncReadStream, typename DynamicBuffer_v1> std::size_t read(SyncReadStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, typename enable_if< is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncReadStream, typename DynamicBuffer_v1> 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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition> std::size_t read(SyncReadStream& s, BOOST_ASIO_MOVE_ARG(DynamicBuffer_v1) buffers, CompletionCondition completion_condition, typename enable_if< is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition> 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<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <typename SyncReadStream, typename Allocator> std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& 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 <typename SyncReadStream, typename Allocator> std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& 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 <typename SyncReadStream, typename Allocator, typename CompletionCondition> std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& 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 <typename SyncReadStream, typename Allocator, typename CompletionCondition> std::size_t read(SyncReadStream& s, basic_streambuf<Allocator>& 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 <typename SyncReadStream, typename DynamicBuffer_v2> std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <typename SyncReadStream, typename DynamicBuffer_v2> std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, boost::system::error_code& ec, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <typename SyncReadStream, typename DynamicBuffer_v2, typename CompletionCondition> std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, CompletionCondition completion_condition, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <typename SyncReadStream, typename DynamicBuffer_v2, typename CompletionCondition> std::size_t read(SyncReadStream& s, DynamicBuffer_v2 buffers, CompletionCondition completion_condition, boost::system::error_code& ec, typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <em>composed operation</em>. 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 <typename AsyncReadStream, typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type), typename enable_if< is_mutable_buffer_sequence<MutableBufferSequence>::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 <typename AsyncReadStream, typename MutableBufferSequence, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type), typename enable_if< is_mutable_buffer_sequence<MutableBufferSequence>::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 <em>composed operation</em>. 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 <typename AsyncReadStream, typename DynamicBuffer_v1, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <em>composed operation</em>. 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 <typename AsyncReadStream, typename DynamicBuffer_v1, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v1<typename decay<DynamicBuffer_v1>::type>::value && !is_dynamic_buffer_v2<typename decay<DynamicBuffer_v1>::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 <em>composed operation</em>. 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 <typename AsyncReadStream, typename Allocator, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type)); /// 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 <em>composed operation</em>. 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 <typename AsyncReadStream, typename Allocator, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, basic_streambuf<Allocator>& b, CompletionCondition completion_condition, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type)); #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 <em>composed operation</em>. 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 <typename AsyncReadStream, typename DynamicBuffer_v2, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read(AsyncReadStream& s, DynamicBuffer_v2 buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_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 <em>composed operation</em>. 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 <typename AsyncReadStream, typename DynamicBuffer_v2, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncReadStream::executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncReadStream::executor_type), typename enable_if< is_dynamic_buffer_v2<DynamicBuffer_v2>::value >::type* = 0); /*@}*/ } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/read.hpp> #endif // BOOST_ASIO_READ_HPP completion_condition.hpp 0000644 00000012574 15125530236 0011507 0 ustar 00 // // completion_condition.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/detail/push_options.hpp> 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 <typename Error> 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 <typename Error> 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 <typename Error> 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<char, 128> 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<char, 128> 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<char, 128> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_COMPLETION_CONDITION_HPP basic_stream_socket.hpp 0000644 00000121060 15125530236 0011263 0 ustar 00 // // basic_stream_socket.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/async_result.hpp> #include <boost/asio/basic_socket.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Protocol, typename Executor = any_io_executor> 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 <typename Protocol, typename Executor> class basic_stream_socket : public basic_socket<Protocol, Executor> { public: /// The type of the executor associated with the object. typedef Executor executor_type; /// Rebinds the socket type to another executor. template <typename Executor1> struct rebind_executor { /// The socket type when rebound to the specified executor. typedef basic_stream_socket<Protocol, Executor1> other; }; /// The native representation of a socket. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined native_handle_type; #else typedef typename basic_socket<Protocol, Executor>::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<Protocol, Executor>(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 <typename ExecutionContext> explicit basic_stream_socket(ExecutionContext& context, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_socket<Protocol, Executor>(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<Protocol, Executor>(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 <typename ExecutionContext> basic_stream_socket(ExecutionContext& context, const protocol_type& protocol, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_socket<Protocol, Executor>(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<Protocol, Executor>(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 <typename ExecutionContext> basic_stream_socket(ExecutionContext& context, const endpoint_type& endpoint, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_socket<Protocol, Executor>(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<Protocol, Executor>(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 <typename ExecutionContext> basic_stream_socket(ExecutionContext& context, const protocol_type& protocol, const native_handle_type& native_socket, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::value >::type* = 0) : basic_socket<Protocol, Executor>(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) BOOST_ASIO_NOEXCEPT : basic_socket<Protocol, Executor>(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<Protocol, Executor>::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 <typename Protocol1, typename Executor1> basic_stream_socket(basic_stream_socket<Protocol1, Executor1>&& other, typename enable_if< is_convertible<Protocol1, Protocol>::value && is_convertible<Executor1, Executor>::value >::type* = 0) : basic_socket<Protocol, Executor>(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 Protocol1, typename Executor1> typename enable_if< is_convertible<Protocol1, Protocol>::value && is_convertible<Executor1, Executor>::value, basic_stream_socket& >::type operator=(basic_stream_socket<Protocol1, Executor1>&& other) { basic_socket<Protocol, Executor>::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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_send(const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( initiate_async_send(this), handler, 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 <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( initiate_async_send(this), handler, 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_receive(const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( initiate_async_receive(this), handler, 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( initiate_async_receive(this), handler, 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_some(const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WriteHandler, void (boost::system::error_code, std::size_t)>( initiate_async_send(this), handler, 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_some(const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<ReadHandler, void (boost::system::error_code, std::size_t)>( initiate_async_receive(this), handler, buffers, socket_base::message_flags(0)); } private: // Disallow copying and assignment. basic_stream_socket(const basic_stream_socket&) BOOST_ASIO_DELETED; basic_stream_socket& operator=(const basic_stream_socket&) BOOST_ASIO_DELETED; class initiate_async_send { public: typedef Executor executor_type; explicit initiate_async_send(basic_stream_socket* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename WriteHandler, typename ConstBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(WriteHandler) handler, 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<WriteHandler> handler2(handler); self_->impl_.get_service().async_send( self_->impl_.get_implementation(), buffers, flags, handler2.value, self_->impl_.get_executor()); } private: basic_stream_socket* self_; }; class initiate_async_receive { public: typedef Executor executor_type; explicit initiate_async_receive(basic_stream_socket* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename ReadHandler, typename MutableBufferSequence> void operator()(BOOST_ASIO_MOVE_ARG(ReadHandler) handler, 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<ReadHandler> handler2(handler); self_->impl_.get_service().async_receive( self_->impl_.get_implementation(), buffers, flags, handler2.value, self_->impl_.get_executor()); } private: basic_stream_socket* self_; }; }; } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_BASIC_STREAM_SOCKET_HPP buffered_read_stream.hpp 0000644 00000020350 15125530236 0011407 0 ustar 00 // // buffered_read_stream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/async_result.hpp> #include <boost/asio/buffered_read_stream_fwd.hpp> #include <boost/asio/buffer.hpp> #include <boost/asio/detail/bind_handler.hpp> #include <boost/asio/detail/buffer_resize_guard.hpp> #include <boost/asio/detail/buffered_stream_storage.hpp> #include <boost/asio/detail/noncopyable.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Stream> class buffered_read_stream : private noncopyable { public: /// The type of the next layer. typedef typename remove_reference<Stream>::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 <typename Arg> explicit buffered_read_stream(Arg& a) : next_layer_(a), storage_(default_buffer_size) { } /// Construct, passing the specified argument to initialise the next layer. template <typename Arg> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence> 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 <typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_some(const ConstBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(WriteHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { 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_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_fill( BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)); /// Read some data from the stream. Returns the number of bytes read. Throws /// an exception on failure. template <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) ReadHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler, void (boost::system::error_code, std::size_t)) async_read_some(const MutableBufferSequence& buffers, BOOST_ASIO_MOVE_ARG(ReadHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)); /// Peek at the incoming data on the stream. Returns the number of bytes read. /// Throws an exception on failure. template <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <typename MutableBufferSequence> 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 <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/buffered_read_stream.hpp> #endif // BOOST_ASIO_BUFFERED_READ_STREAM_HPP system_timer.hpp 0000644 00000002432 15125530236 0010004 0 ustar 00 // // system_timer.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) #include <boost/asio/basic_waitable_timer.hpp> #include <boost/asio/detail/chrono.hpp> 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<boost::chrono::system_clock> timer; * @endcode */ typedef basic_waitable_timer<chrono::system_clock> system_timer; } // namespace asio } // namespace boost #endif // defined(BOOST_ASIO_HAS_CHRONO) || defined(GENERATING_DOCUMENTATION) #endif // BOOST_ASIO_SYSTEM_TIMER_HPP basic_signal_set.hpp 0000644 00000047001 15125530236 0010552 0 ustar 00 // // basic_signal_set.hpp // ~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/any_io_executor.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/io_object_impl.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/signal_set_service.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Executor = any_io_executor> class basic_signal_set { public: /// The type of the executor associated with the object. typedef Executor executor_type; /// Rebinds the signal set type to another executor. template <typename Executor1> struct rebind_executor { /// The signal set type when rebound to the specified executor. typedef basic_signal_set<Executor1> other; }; /// 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 <typename ExecutionContext> explicit basic_signal_set(ExecutionContext& context, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename ExecutionContext> basic_signal_set(ExecutionContext& context, int signal_number_1, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename ExecutionContext> basic_signal_set(ExecutionContext& context, int signal_number_1, int signal_number_2, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename ExecutionContext> basic_signal_set(ExecutionContext& context, int signal_number_1, int signal_number_2, int signal_number_3, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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_COMPLETION_TOKEN_FOR(void (boost::system::error_code, int)) SignalHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(SignalHandler, void (boost::system::error_code, int)) async_wait( BOOST_ASIO_MOVE_ARG(SignalHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<SignalHandler, void (boost::system::error_code, int)>( initiate_async_wait(this), handler); } 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; class initiate_async_wait { public: typedef Executor executor_type; explicit initiate_async_wait(basic_signal_set* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename SignalHandler> void operator()(BOOST_ASIO_MOVE_ARG(SignalHandler) handler) 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<SignalHandler> handler2(handler); self_->impl_.get_service().async_wait( self_->impl_.get_implementation(), handler2.value, self_->impl_.get_executor()); } private: basic_signal_set* self_; }; detail::io_object_impl<detail::signal_set_service, Executor> impl_; }; } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_BASIC_SIGNAL_SET_HPP generic/raw_protocol.hpp 0000644 00000006212 15125530236 0011406 0 ustar 00 // // generic/raw_protocol.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <typeinfo> #include <boost/asio/basic_raw_socket.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/generic/basic_endpoint.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Protocol> 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 BOOST_ASIO_NOEXCEPT { return BOOST_ASIO_OS_DEF(SOCK_RAW); } /// Obtain an identifier for the protocol. int protocol() const BOOST_ASIO_NOEXCEPT { return protocol_; } /// Obtain an identifier for the protocol family. int family() const BOOST_ASIO_NOEXCEPT { 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<raw_protocol> endpoint; /// The generic socket type. typedef basic_raw_socket<raw_protocol> socket; private: int family_; int protocol_; }; } // namespace generic } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_GENERIC_RAW_PROTOCOL_HPP generic/basic_endpoint.hpp 0000644 00000011354 15125530236 0011660 0 ustar 00 // // generic/basic_endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/generic/detail/endpoint.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Protocol> 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() BOOST_ASIO_NOEXCEPT { } /// 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 <typename Endpoint> 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<Protocol>& e1, const basic_endpoint<Protocol>& e2) { return e1.impl_ == e2.impl_; } /// Compare two endpoints for inequality. friend bool operator!=(const basic_endpoint<Protocol>& e1, const basic_endpoint<Protocol>& e2) { return !(e1.impl_ == e2.impl_); } /// Compare endpoints for ordering. friend bool operator<(const basic_endpoint<Protocol>& e1, const basic_endpoint<Protocol>& e2) { return e1.impl_ < e2.impl_; } /// Compare endpoints for ordering. friend bool operator>(const basic_endpoint<Protocol>& e1, const basic_endpoint<Protocol>& e2) { return e2.impl_ < e1.impl_; } /// Compare endpoints for ordering. friend bool operator<=(const basic_endpoint<Protocol>& e1, const basic_endpoint<Protocol>& e2) { return !(e2 < e1); } /// Compare endpoints for ordering. friend bool operator>=(const basic_endpoint<Protocol>& e1, const basic_endpoint<Protocol>& e2) { return !(e1 < e2); } private: // The underlying generic endpoint. boost::asio::generic::detail::endpoint impl_; }; } // namespace generic } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_GENERIC_BASIC_ENDPOINT_HPP generic/detail/impl/endpoint.ipp 0000644 00000005436 15125530236 0012727 0 ustar 00 // // generic/detail/impl/endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstring> #include <typeinfo> #include <boost/asio/detail/socket_ops.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/error.hpp> #include <boost/asio/generic/detail/endpoint.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_GENERIC_DETAIL_IMPL_ENDPOINT_IPP generic/detail/endpoint.hpp 0000644 00000006437 15125530236 0011767 0 ustar 00 // // generic/detail/endpoint.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/push_options.hpp> 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 <boost/asio/detail/pop_options.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/generic/detail/impl/endpoint.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_GENERIC_DETAIL_ENDPOINT_HPP generic/stream_protocol.hpp 0000644 00000006703 15125530236 0012115 0 ustar 00 // // generic/stream_protocol.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <typeinfo> #include <boost/asio/basic_socket_iostream.hpp> #include <boost/asio/basic_stream_socket.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/generic/basic_endpoint.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Protocol> 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 BOOST_ASIO_NOEXCEPT { return BOOST_ASIO_OS_DEF(SOCK_STREAM); } /// Obtain an identifier for the protocol. int protocol() const BOOST_ASIO_NOEXCEPT { return protocol_; } /// Obtain an identifier for the protocol family. int family() const BOOST_ASIO_NOEXCEPT { 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<stream_protocol> endpoint; /// The generic socket type. typedef basic_stream_socket<stream_protocol> socket; #if !defined(BOOST_ASIO_NO_IOSTREAM) /// The generic socket iostream type. typedef basic_socket_iostream<stream_protocol> iostream; #endif // !defined(BOOST_ASIO_NO_IOSTREAM) private: int family_; int protocol_; }; } // namespace generic } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_GENERIC_STREAM_PROTOCOL_HPP generic/datagram_protocol.hpp 0000644 00000006426 15125530236 0012404 0 ustar 00 // // generic/datagram_protocol.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <typeinfo> #include <boost/asio/basic_datagram_socket.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/generic/basic_endpoint.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Protocol> 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 BOOST_ASIO_NOEXCEPT { return BOOST_ASIO_OS_DEF(SOCK_DGRAM); } /// Obtain an identifier for the protocol. int protocol() const BOOST_ASIO_NOEXCEPT { return protocol_; } /// Obtain an identifier for the protocol family. int family() const BOOST_ASIO_NOEXCEPT { 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<datagram_protocol> endpoint; /// The generic socket type. typedef basic_datagram_socket<datagram_protocol> socket; private: int family_; int protocol_; }; } // namespace generic } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_GENERIC_DATAGRAM_PROTOCOL_HPP generic/seq_packet_protocol.hpp 0000644 00000006340 15125530236 0012736 0 ustar 00 // // generic/seq_packet_protocol.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <typeinfo> #include <boost/asio/basic_seq_packet_socket.hpp> #include <boost/asio/detail/socket_types.hpp> #include <boost/asio/detail/throw_exception.hpp> #include <boost/asio/generic/basic_endpoint.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Protocol> 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 BOOST_ASIO_NOEXCEPT { return BOOST_ASIO_OS_DEF(SOCK_SEQPACKET); } /// Obtain an identifier for the protocol. int protocol() const BOOST_ASIO_NOEXCEPT { return protocol_; } /// Obtain an identifier for the protocol family. int family() const BOOST_ASIO_NOEXCEPT { 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<seq_packet_protocol> endpoint; /// The generic socket type. typedef basic_seq_packet_socket<seq_packet_protocol> socket; private: int family_; int protocol_; }; } // namespace generic } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_GENERIC_SEQ_PACKET_PROTOCOL_HPP dispatch.hpp 0000644 00000010671 15125530236 0007063 0 ustar 00 // // dispatch.hpp // ~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/is_executor.hpp> #include <boost/asio/detail/push_options.hpp> 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 <tt>dispatch()</tt>. Otherwise, it is queued for execution. * * This function has the following effects: * * @li Constructs a function object handler of type @c Handler, initialized * with <tt>handler(forward<CompletionToken>(token))</tt>. * * @li Constructs an object @c result of type <tt>async_result<Handler></tt>, * initializing the object as <tt>result(handler)</tt>. * * @li Obtains the handler's associated executor object @c ex by performing * <tt>get_associated_executor(handler)</tt>. * * @li Obtains the handler's associated allocator object @c alloc by performing * <tt>get_associated_allocator(handler)</tt>. * * @li Performs <tt>ex.dispatch(std::move(handler), alloc)</tt>. * * @li Returns <tt>result.get()</tt>. */ template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken> BOOST_ASIO_INITFN_AUTO_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 <tt>dispatch()</tt>. Otherwise, it is queued for execution. * * This function has the following effects: * * @li Constructs a function object handler of type @c Handler, initialized * with <tt>handler(forward<CompletionToken>(token))</tt>. * * @li Constructs an object @c result of type <tt>async_result<Handler></tt>, * initializing the object as <tt>result(handler)</tt>. * * @li Obtains the handler's associated executor object @c ex1 by performing * <tt>get_associated_executor(handler)</tt>. * * @li Creates a work object @c w by performing <tt>make_work(ex1)</tt>. * * @li Obtains the handler's associated allocator object @c alloc by performing * <tt>get_associated_allocator(handler)</tt>. * * @li Constructs a function object @c f with a function call operator that * performs <tt>ex1.dispatch(std::move(handler), alloc)</tt> followed by * <tt>w.reset()</tt>. * * @li Performs <tt>Executor(ex).dispatch(std::move(f), alloc)</tt>. * * @li Returns <tt>result.get()</tt>. */ template <typename Executor, BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch( const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if< execution::is_executor<Executor>::value || is_executor<Executor>::value >::type* = 0); /// Submits a completion token or function object for execution. /** * @returns <tt>dispatch(ctx.get_executor(), * forward<CompletionToken>(token))</tt>. */ template <typename ExecutionContext, BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename ExecutionContext::executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) dispatch( ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename ExecutionContext::executor_type), typename enable_if<is_convertible< ExecutionContext&, execution_context&>::value>::type* = 0); } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/dispatch.hpp> #endif // BOOST_ASIO_DISPATCH_HPP spawn.hpp 0000644 00000027021 15125530236 0006411 0 ustar 00 // // spawn.hpp // ~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SPAWN_HPP #define BOOST_ASIO_SPAWN_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/coroutine/all.hpp> #include <boost/asio/any_io_executor.hpp> #include <boost/asio/bind_executor.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/wrapped_handler.hpp> #include <boost/asio/io_context.hpp> #include <boost/asio/is_executor.hpp> #include <boost/asio/strand.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { /// Context object the represents the currently executing coroutine. /** * The basic_yield_context class is used to represent the currently executing * stackful coroutine. A basic_yield_context may be passed as a handler to an * asynchronous operation. For example: * * @code template <typename Handler> * void my_coroutine(basic_yield_context<Handler> yield) * { * ... * std::size_t n = my_socket.async_read_some(buffer, yield); * ... * } @endcode * * The initiating function (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 <typename Handler> class basic_yield_context { public: /// The coroutine callee type, used by the implementation. /** * When using Boost.Coroutine v1, this type is: * @code typename coroutine<void()> @endcode * When using Boost.Coroutine v2 (unidirectional coroutines), this type is: * @code push_coroutine<void> @endcode */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined callee_type; #elif defined(BOOST_COROUTINES_UNIDIRECT) || defined(BOOST_COROUTINES_V2) typedef boost::coroutines::push_coroutine<void> callee_type; #else typedef boost::coroutines::coroutine<void()> callee_type; #endif /// The coroutine caller type, used by the implementation. /** * When using Boost.Coroutine v1, this type is: * @code typename coroutine<void()>::caller_type @endcode * When using Boost.Coroutine v2 (unidirectional coroutines), this type is: * @code pull_coroutine<void> @endcode */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined caller_type; #elif defined(BOOST_COROUTINES_UNIDIRECT) || defined(BOOST_COROUTINES_V2) typedef boost::coroutines::pull_coroutine<void> caller_type; #else typedef boost::coroutines::coroutine<void()>::caller_type caller_type; #endif /// Construct a yield context to represent the specified coroutine. /** * Most applications do not need to use this constructor. Instead, the * spawn() function passes a yield context as an argument to the coroutine * function. */ basic_yield_context( const detail::weak_ptr<callee_type>& coro, caller_type& ca, Handler& handler) : coro_(coro), ca_(ca), handler_(handler), ec_(0) { } /// Construct a yield context from another yield context type. /** * Requires that OtherHandler be convertible to Handler. */ template <typename OtherHandler> basic_yield_context(const basic_yield_context<OtherHandler>& other) : coro_(other.coro_), ca_(other.ca_), handler_(other.handler_), ec_(other.ec_) { } /// Return a yield context that sets the specified error_code. /** * By default, when a yield context is used with an asynchronous operation, a * non-success error_code is converted to system_error and thrown. This * operator may be used to specify an error_code object that should instead be * set with the asynchronous operation's result. For example: * * @code template <typename Handler> * void my_coroutine(basic_yield_context<Handler> yield) * { * ... * std::size_t n = my_socket.async_read_some(buffer, yield[ec]); * if (ec) * { * // An error occurred. * } * ... * } @endcode */ basic_yield_context operator[](boost::system::error_code& ec) const { basic_yield_context tmp(*this); tmp.ec_ = &ec; return tmp; } #if defined(GENERATING_DOCUMENTATION) private: #endif // defined(GENERATING_DOCUMENTATION) detail::weak_ptr<callee_type> coro_; caller_type& ca_; Handler handler_; boost::system::error_code* ec_; }; #if defined(GENERATING_DOCUMENTATION) /// Context object that represents the currently executing coroutine. typedef basic_yield_context<unspecified> yield_context; #else // defined(GENERATING_DOCUMENTATION) typedef basic_yield_context< executor_binder<void(*)(), any_io_executor> > yield_context; #endif // defined(GENERATING_DOCUMENTATION) /** * @defgroup spawn boost::asio::spawn * * @brief Start a new stackful coroutine. * * The spawn() function is a high-level wrapper over the Boost.Coroutine * library. This function enables programs to implement asynchronous logic in a * synchronous manner, as illustrated by the following example: * * @code boost::asio::spawn(my_strand, do_echo); * * // ... * * void do_echo(boost::asio::yield_context yield) * { * try * { * char data[128]; * for (;;) * { * std::size_t length = * my_socket.async_read_some( * boost::asio::buffer(data), yield); * * boost::asio::async_write(my_socket, * boost::asio::buffer(data, length), yield); * } * } * catch (std::exception& e) * { * // ... * } * } @endcode */ /*@{*/ /// Start a new stackful coroutine, calling the specified handler when it /// completes. /** * This function is used to launch a new coroutine. * * @param function The coroutine function. The function must have the signature: * @code void function(basic_yield_context<Handler> yield); @endcode * * @param attributes Boost.Coroutine attributes used to customise the coroutine. */ template <typename Function> void spawn(BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes = boost::coroutines::attributes()); /// Start a new stackful coroutine, calling the specified handler when it /// completes. /** * This function is used to launch a new coroutine. * * @param handler A handler to be called when the coroutine exits. More * importantly, the handler provides an execution context (via the the handler * invocation hook) for the coroutine. The handler must have the signature: * @code void handler(); @endcode * * @param function The coroutine function. The function must have the signature: * @code void function(basic_yield_context<Handler> yield); @endcode * * @param attributes Boost.Coroutine attributes used to customise the coroutine. */ template <typename Handler, typename Function> void spawn(BOOST_ASIO_MOVE_ARG(Handler) handler, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes = boost::coroutines::attributes(), typename enable_if< !is_executor<typename decay<Handler>::type>::value && !execution::is_executor<typename decay<Handler>::type>::value && !is_convertible<Handler&, execution_context&>::value>::type* = 0); /// Start a new stackful coroutine, inheriting the execution context of another. /** * This function is used to launch a new coroutine. * * @param ctx Identifies the current coroutine as a parent of the new * coroutine. This specifies that the new coroutine should inherit the * execution context of the parent. For example, if the parent coroutine is * executing in a particular strand, then the new coroutine will execute in the * same strand. * * @param function The coroutine function. The function must have the signature: * @code void function(basic_yield_context<Handler> yield); @endcode * * @param attributes Boost.Coroutine attributes used to customise the coroutine. */ template <typename Handler, typename Function> void spawn(basic_yield_context<Handler> ctx, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes = boost::coroutines::attributes()); /// Start a new stackful coroutine that executes on a given executor. /** * This function is used to launch a new coroutine. * * @param ex Identifies the executor that will run the coroutine. The new * coroutine is implicitly given its own strand within this executor. * * @param function The coroutine function. The function must have the signature: * @code void function(yield_context yield); @endcode * * @param attributes Boost.Coroutine attributes used to customise the coroutine. */ template <typename Function, typename Executor> void spawn(const Executor& ex, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes = boost::coroutines::attributes(), typename enable_if< is_executor<Executor>::value || execution::is_executor<Executor>::value >::type* = 0); /// Start a new stackful coroutine that executes on a given strand. /** * This function is used to launch a new coroutine. * * @param ex Identifies the strand that will run the coroutine. * * @param function The coroutine function. The function must have the signature: * @code void function(yield_context yield); @endcode * * @param attributes Boost.Coroutine attributes used to customise the coroutine. */ template <typename Function, typename Executor> void spawn(const strand<Executor>& ex, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes = boost::coroutines::attributes()); #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// Start a new stackful coroutine that executes in the context of a strand. /** * This function is used to launch a new coroutine. * * @param s Identifies a strand. By starting multiple coroutines on the same * strand, the implementation ensures that none of those coroutines can execute * simultaneously. * * @param function The coroutine function. The function must have the signature: * @code void function(yield_context yield); @endcode * * @param attributes Boost.Coroutine attributes used to customise the coroutine. */ template <typename Function> void spawn(const boost::asio::io_context::strand& s, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes = boost::coroutines::attributes()); #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// Start a new stackful coroutine that executes on a given execution context. /** * This function is used to launch a new coroutine. * * @param ctx Identifies the execution context that will run the coroutine. The * new coroutine is implicitly given its own strand within this execution * context. * * @param function The coroutine function. The function must have the signature: * @code void function(yield_context yield); @endcode * * @param attributes Boost.Coroutine attributes used to customise the coroutine. */ template <typename Function, typename ExecutionContext> void spawn(ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(Function) function, const boost::coroutines::attributes& attributes = boost::coroutines::attributes(), typename enable_if<is_convertible< ExecutionContext&, execution_context&>::value>::type* = 0); /*@}*/ } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/spawn.hpp> #endif // BOOST_ASIO_SPAWN_HPP is_write_buffered.hpp 0000644 00000003203 15125530236 0010744 0 ustar 00 // // is_write_buffered.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/buffered_stream_fwd.hpp> #include <boost/asio/buffered_write_stream_fwd.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { template <typename Stream> char is_write_buffered_helper(buffered_stream<Stream>* s); template <typename Stream> char is_write_buffered_helper(buffered_write_stream<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 <typename Stream> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IS_WRITE_BUFFERED_HPP basic_socket_iostream.hpp 0000644 00000031762 15125530236 0011624 0 ustar 00 // // basic_socket_iostream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_NO_IOSTREAM) #include <istream> #include <ostream> #include <boost/asio/basic_socket_streambuf.hpp> #if !defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) # include <boost/asio/detail/variadic_templates.hpp> // A macro that should expand to: // template <typename T1, ..., typename Tn> // explicit basic_socket_iostream(T1 x1, ..., Tn xn) // : std::basic_iostream<char>( // &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 <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ explicit basic_socket_iostream(BOOST_ASIO_VARIADIC_BYVAL_PARAMS(n)) \ : std::basic_iostream<char>( \ &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 <typename T1, ..., typename Tn> // 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 <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ 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 <boost/asio/detail/push_options.hpp> 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 <typename Protocol, typename Clock, typename WaitTraits> 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<Protocol> 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<Protocol, Clock, WaitTraits> 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 <typename Protocol, #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) typename Clock = boost::posix_time::ptime, typename WaitTraits = time_traits<Clock> > #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<Clock> > #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 <typename Protocol, typename Clock = chrono::steady_clock, typename WaitTraits = wait_traits<Clock> > #else // defined(GENERATING_DOCUMENTATION) template <typename Protocol, typename Clock, typename WaitTraits> #endif // defined(GENERATING_DOCUMENTATION) class basic_socket_iostream : private detail::socket_iostream_base<Protocol, Clock, WaitTraits>, public std::basic_iostream<char> { 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<Clock, WaitTraits> 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<char>( &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<protocol_type> s) : detail::socket_iostream_base< Protocol, Clock, WaitTraits>(std::move(s)), std::basic_iostream<char>( &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<char>(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<char>::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 <typename T1, ..., typename TN> explicit basic_socket_iostream(T1 t1, ..., TN tn); #elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename... T> explicit basic_socket_iostream(T... x) : std::basic_iostream<char>( &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 <typename T1, ..., typename TN> void connect(T1 t1, ..., TN tn); #elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename... T> 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<Protocol, Clock, WaitTraits>* rdbuf() const { return const_cast<basic_socket_streambuf<Protocol, Clock, WaitTraits>*>( &this->detail::socket_iostream_base< Protocol, Clock, WaitTraits>::streambuf_); } /// Get a reference to the underlying socket. basic_socket<Protocol>& 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 <boost/asio/detail/pop_options.hpp> #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 basic_streambuf_fwd.hpp 0000644 00000001630 15125530236 0011250 0 ustar 00 // // basic_streambuf_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_NO_IOSTREAM) #include <memory> namespace boost { namespace asio { template <typename Allocator = std::allocator<char> > class basic_streambuf; template <typename Allocator = std::allocator<char> > class basic_streambuf_ref; } // namespace asio } // namespace boost #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // BOOST_ASIO_BASIC_STREAMBUF_FWD_HPP async_result.hpp 0000644 00000045737 15125530236 0010012 0 ustar 00 // // async_result.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/variadic_templates.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { #if defined(BOOST_ASIO_HAS_CONCEPTS) \ && defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) \ && defined(BOOST_ASIO_HAS_DECLTYPE) namespace detail { template <typename T> struct is_completion_signature : false_type { }; template <typename R, typename... Args> struct is_completion_signature<R(Args...)> : true_type { }; template <typename T, typename... Args> BOOST_ASIO_CONCEPT callable_with = requires(T t, Args&&... args) { t(static_cast<Args&&>(args)...); }; template <typename T, typename Signature> struct is_completion_handler_for : false_type { }; template <typename T, typename R, typename... Args> struct is_completion_handler_for<T, R(Args...)> : integral_constant<bool, (callable_with<T, Args...>)> { }; } // namespace detail template <typename T> BOOST_ASIO_CONCEPT completion_signature = detail::is_completion_signature<T>::value; #define BOOST_ASIO_COMPLETION_SIGNATURE \ ::boost::asio::completion_signature template <typename T, typename Signature> BOOST_ASIO_CONCEPT completion_handler_for = detail::is_completion_signature<Signature>::value && detail::is_completion_handler_for<T, Signature>::value; #define BOOST_ASIO_COMPLETION_HANDLER_FOR(s) \ ::boost::asio::completion_handler_for<s> #else // defined(BOOST_ASIO_HAS_CONCEPTS) // && defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) // && defined(BOOST_ASIO_HAS_DECLTYPE) #define BOOST_ASIO_COMPLETION_SIGNATURE typename #define BOOST_ASIO_COMPLETION_HANDLER_FOR(s) typename #endif // defined(BOOST_ASIO_HAS_CONCEPTS) // && defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) // && defined(BOOST_ASIO_HAS_DECLTYPE) /// 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 <typename CompletionToken, BOOST_ASIO_COMPLETION_SIGNATURE Signature> 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(GENERATING_DOCUMENTATION) /// Initiate the asynchronous operation that will produce the result, and /// obtain the value to be returned from the initiating function. template <typename Initiation, typename RawCompletionToken, typename... Args> static return_type initiate( BOOST_ASIO_MOVE_ARG(Initiation) initiation, BOOST_ASIO_MOVE_ARG(RawCompletionToken) token, BOOST_ASIO_MOVE_ARG(Args)... args); #elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename Initiation, BOOST_ASIO_COMPLETION_HANDLER_FOR(Signature) RawCompletionToken, typename... Args> 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) template <typename Initiation, BOOST_ASIO_COMPLETION_HANDLER_FOR(Signature) RawCompletionToken> 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 <typename Initiation, \ BOOST_ASIO_COMPLETION_HANDLER_FOR(Signature) RawCompletionToken, \ BOOST_ASIO_VARIADIC_TPARAMS(n)> \ 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) private: async_result(const async_result&) BOOST_ASIO_DELETED; async_result& operator=(const async_result&) BOOST_ASIO_DELETED; }; #if !defined(GENERATING_DOCUMENTATION) template <BOOST_ASIO_COMPLETION_SIGNATURE Signature> class async_result<void, Signature> { // Empty. }; #endif // !defined(GENERATING_DOCUMENTATION) /// 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 <typename CompletionToken, BOOST_ASIO_COMPLETION_SIGNATURE Signature> struct async_completion { /// The real handler type to be used for the asynchronous operation. typedef typename boost::asio::async_result< typename decay<CompletionToken>::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<typename conditional< is_same<CompletionToken, completion_handler_type>::value, completion_handler_type&, CompletionToken&&>::type>(token)), result(completion_handler) { } #else // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) explicit async_completion(typename decay<CompletionToken>::type& token) : completion_handler(token), result(completion_handler) { } explicit async_completion(const typename decay<CompletionToken>::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<CompletionToken, completion_handler_type>::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<typename decay<CompletionToken>::type, Signature> result; }; namespace detail { template <typename CompletionToken, typename Signature> struct async_result_helper : async_result<typename decay<CompletionToken>::type, Signature> { }; struct async_result_memfns_base { void initiate(); }; template <typename T> struct async_result_memfns_derived : T, async_result_memfns_base { }; template <typename T, T> struct async_result_memfns_check { }; template <typename> char (&async_result_initiate_memfn_helper(...))[2]; template <typename T> char async_result_initiate_memfn_helper( async_result_memfns_check< void (async_result_memfns_base::*)(), &async_result_memfns_derived<T>::initiate>*); template <typename CompletionToken, typename Signature> struct async_result_has_initiate_memfn : integral_constant<bool, sizeof(async_result_initiate_memfn_helper< async_result<typename decay<CompletionToken>::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<ct>::type, sig>::return_type #define BOOST_ASIO_HANDLER_TYPE(ct, sig) \ typename ::boost::asio::async_result< \ typename ::boost::asio::decay<ct>::type, sig>::completion_handler_type #endif #if defined(GENERATING_DOCUMENTATION) # define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \ auto #elif defined(BOOST_ASIO_HAS_RETURN_TYPE_DEDUCTION) # define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \ auto #else # define BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ct, sig) \ BOOST_ASIO_INITFN_RESULT_TYPE(ct, sig) #endif #if defined(GENERATING_DOCUMENTATION) # define BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(ct, sig, expr) \ void_or_deduced #elif defined(BOOST_ASIO_HAS_DECLTYPE) # define BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(ct, sig, expr) \ decltype expr #else # define BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(ct, sig, expr) \ BOOST_ASIO_INITFN_RESULT_TYPE(ct, sig) #endif #if defined(GENERATING_DOCUMENTATION) template <typename CompletionToken, completion_signature Signature, typename Initiation, typename... Args> void_or_deduced 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 <typename CompletionToken, BOOST_ASIO_COMPLETION_SIGNATURE Signature, typename Initiation, typename... Args> inline typename enable_if< detail::async_result_has_initiate_memfn<CompletionToken, Signature>::value, BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, Signature, (async_result<typename decay<CompletionToken>::type, Signature>::initiate(declval<BOOST_ASIO_MOVE_ARG(Initiation)>(), declval<BOOST_ASIO_MOVE_ARG(CompletionToken)>(), declval<BOOST_ASIO_MOVE_ARG(Args)>()...)))>::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<typename decay<CompletionToken>::type, Signature>::initiate(BOOST_ASIO_MOVE_CAST(Initiation)(initiation), BOOST_ASIO_MOVE_CAST(CompletionToken)(token), BOOST_ASIO_MOVE_CAST(Args)(args)...); } template <typename CompletionToken, BOOST_ASIO_COMPLETION_SIGNATURE Signature, typename Initiation, typename... Args> 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_MOVE_ARG(Args)... args) { async_completion<CompletionToken, Signature> 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 <typename CompletionToken, BOOST_ASIO_COMPLETION_SIGNATURE Signature, typename Initiation> inline typename enable_if< detail::async_result_has_initiate_memfn<CompletionToken, Signature>::value, BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, Signature, (async_result<typename decay<CompletionToken>::type, Signature>::initiate(declval<BOOST_ASIO_MOVE_ARG(Initiation)>(), declval<BOOST_ASIO_MOVE_ARG(CompletionToken)>())))>::type async_initiate(BOOST_ASIO_MOVE_ARG(Initiation) initiation, BOOST_ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token) { return async_result<typename decay<CompletionToken>::type, Signature>::initiate(BOOST_ASIO_MOVE_CAST(Initiation)(initiation), BOOST_ASIO_MOVE_CAST(CompletionToken)(token)); } template <typename CompletionToken, BOOST_ASIO_COMPLETION_SIGNATURE Signature, typename Initiation> 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) { async_completion<CompletionToken, Signature> 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 <typename CompletionToken, \ BOOST_ASIO_COMPLETION_SIGNATURE Signature, \ typename Initiation, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ inline typename enable_if< \ detail::async_result_has_initiate_memfn< \ CompletionToken, Signature>::value, \ BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, Signature, \ (async_result<typename decay<CompletionToken>::type, \ Signature>::initiate(declval<BOOST_ASIO_MOVE_ARG(Initiation)>(), \ declval<BOOST_ASIO_MOVE_ARG(CompletionToken)>(), \ BOOST_ASIO_VARIADIC_MOVE_DECLVAL(n))))>::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<typename decay<CompletionToken>::type, \ Signature>::initiate(BOOST_ASIO_MOVE_CAST(Initiation)(initiation), \ BOOST_ASIO_MOVE_CAST(CompletionToken)(token), \ BOOST_ASIO_VARIADIC_MOVE_ARGS(n)); \ } \ \ template <typename CompletionToken, \ BOOST_ASIO_COMPLETION_SIGNATURE Signature, \ typename Initiation, BOOST_ASIO_VARIADIC_TPARAMS(n)> \ 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<CompletionToken, Signature> 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) #if defined(BOOST_ASIO_HAS_CONCEPTS) \ && defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) \ && defined(BOOST_ASIO_HAS_DECLTYPE) namespace detail { template <typename Signature> struct initiation_archetype { template <completion_handler_for<Signature> CompletionHandler> void operator()(CompletionHandler&&) const { } }; } // namespace detail template <typename T, typename Signature> BOOST_ASIO_CONCEPT completion_token_for = detail::is_completion_signature<Signature>::value && requires(T&& t) { async_initiate<T, Signature>(detail::initiation_archetype<Signature>{}, t); }; #define BOOST_ASIO_COMPLETION_TOKEN_FOR(s) \ ::boost::asio::completion_token_for<s> #else // defined(BOOST_ASIO_HAS_CONCEPTS) // && defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) // && defined(BOOST_ASIO_HAS_DECLTYPE) #define BOOST_ASIO_COMPLETION_TOKEN_FOR(s) typename #endif // defined(BOOST_ASIO_HAS_CONCEPTS) // && defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) // && defined(BOOST_ASIO_HAS_DECLTYPE) namespace detail { template <typename T, typename = void> struct default_completion_token_impl { typedef void type; }; template <typename T> struct default_completion_token_impl<T, typename void_type<typename T::default_completion_token_type>::type> { typedef typename T::default_completion_token_type type; }; } // namespace detail #if defined(GENERATING_DOCUMENTATION) /// Traits type used to determine the default completion token type associated /// with a type (such as an executor). /** * A program may specialise this traits type if the @c T template parameter in * the specialisation is a user-defined type. * * Specialisations of this trait may provide a nested typedef @c type, which is * a default-constructible completion token type. */ template <typename T> struct default_completion_token { /// If @c T has a nested type @c default_completion_token_type, /// <tt>T::default_completion_token_type</tt>. Otherwise the typedef @c type /// is not defined. typedef see_below type; }; #else template <typename T> struct default_completion_token : detail::default_completion_token_impl<T> { }; #endif #if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) template <typename T> using default_completion_token_t = typename default_completion_token<T>::type; #endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) #if defined(BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) #define BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(e) \ = typename ::boost::asio::default_completion_token<e>::type #define BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(e) \ = typename ::boost::asio::default_completion_token<e>::type() #else // defined(BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) #define BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(e) #define BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(e) #endif // defined(BOOST_ASIO_HAS_DEFAULT_FUNCTION_TEMPLATE_ARGUMENTS) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_ASYNC_RESULT_HPP io_context_strand.hpp 0000644 00000032612 15125530236 0011011 0 ustar 00 // // io_context_strand.hpp // ~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_NO_EXTENSIONS) \ && !defined(BOOST_ASIO_NO_TS_EXECUTORS) #include <boost/asio/async_result.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/strand_service.hpp> #include <boost/asio/detail/wrapped_handler.hpp> #include <boost/asio/io_context.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename Function, typename Allocator> void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const { typename decay<Function>::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 <typename LegacyCompletionHandler> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ()) dispatch(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler) { return async_initiate<LegacyCompletionHandler, void ()>( 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 <typename Function, typename Allocator> void post(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const { typename decay<Function>::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 <typename LegacyCompletionHandler> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(LegacyCompletionHandler, void ()) post(BOOST_ASIO_MOVE_ARG(LegacyCompletionHandler) handler) { return async_initiate<LegacyCompletionHandler, void ()>( 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 <typename Function, typename Allocator> void defer(BOOST_ASIO_MOVE_ARG(Function) f, const Allocator& a) const { typename decay<Function>::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 <typename Handler> #if defined(GENERATING_DOCUMENTATION) unspecified #else detail::wrapped_handler<strand, Handler, detail::is_continuation_if_running> #endif wrap(Handler handler) { return detail::wrapped_handler<io_context::strand, Handler, detail::is_continuation_if_running>(*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 <typename LegacyCompletionHandler> 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<LegacyCompletionHandler> handler2(handler); self->service_.dispatch(self->impl_, handler2.value); } }; struct initiate_post { template <typename LegacyCompletionHandler> 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<LegacyCompletionHandler> 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 <boost/asio/detail/pop_options.hpp> #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) // && !defined(BOOST_ASIO_NO_TS_EXECUTORS) #endif // BOOST_ASIO_IO_CONTEXT_STRAND_HPP ssl.hpp 0000644 00000001520 15125530236 0006056 0 ustar 00 // // ssl.hpp // ~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_SSL_HPP #define BOOST_ASIO_SSL_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/ssl/context.hpp> #include <boost/asio/ssl/context_base.hpp> #include <boost/asio/ssl/error.hpp> #include <boost/asio/ssl/rfc2818_verification.hpp> #include <boost/asio/ssl/host_name_verification.hpp> #include <boost/asio/ssl/stream.hpp> #include <boost/asio/ssl/stream_base.hpp> #include <boost/asio/ssl/verify_context.hpp> #include <boost/asio/ssl/verify_mode.hpp> #endif // BOOST_ASIO_SSL_HPP io_context.hpp 0000644 00000153672 15125530236 0007450 0 ustar 00 // // io_context.hpp // ~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <stdexcept> #include <typeinfo> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/wrapped_handler.hpp> #include <boost/system/error_code.hpp> #include <boost/asio/execution.hpp> #include <boost/asio/execution_context.hpp> #if defined(BOOST_ASIO_HAS_CHRONO) # include <boost/asio/detail/chrono.hpp> #endif // defined(BOOST_ASIO_HAS_CHRONO) #if defined(BOOST_ASIO_WINDOWS) || defined(__CYGWIN__) # include <boost/asio/detail/winsock_init.hpp> #elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \ || defined(__osf__) # include <boost/asio/detail/signal_init.hpp> #endif #if defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/win_iocp_io_context.hpp> #else # include <boost/asio/detail/scheduler.hpp> #endif #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { namespace detail { #if defined(BOOST_ASIO_HAS_IOCP) typedef win_iocp_io_context io_context_impl; class win_iocp_overlapped_ptr; #else typedef scheduler io_context_impl; #endif struct io_context_bits { BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, blocking_never = 1); BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, relationship_continuation = 2); BOOST_ASIO_STATIC_CONSTEXPR(unsigned int, outstanding_work_tracked = 4); }; } // 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 executor that tracks work against the io_context: * * @code boost::asio::io_context io_context; * auto work = boost::asio::require(io_context.get_executor(), * boost::asio::execution::outstanding_work.tracked); * ... @endcode * * If using C++03, which lacks automatic variable type deduction, you may * compute the return type of the require call: * * @code boost::asio::io_context io_context; * typename boost::asio::require_result< * boost::asio::io_context::executor_type, * boost::asio::exeution::outstanding_work_t::tracked_t> * work = boost::asio::require(io_context.get_executor(), * boost::asio::execution::outstanding_work.tracked); * ... @endcode * * or store the result in the type-erasing executor wrapper, any_io_executor: * * @code boost::asio::io_context io_context; * boost::asio::any_io_executor work * = boost::asio::require(io_context.get_executor(), * boost::asio::execution::outstanding_work.tracked); * ... @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, store the work-tracking executor in an * any_io_executor object, so that it may be explicitly reset. * * @code boost::asio::io_context io_context; * boost::asio::any_io_executor work * = boost::asio::require(io_context.get_executor(), * boost::asio::execution::outstanding_work.tracked); * ... * work = boost::asio::any_io_executor(); // 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: template <typename Allocator, unsigned int Bits> class basic_executor_type; template <typename Allocator, unsigned int Bits> friend class basic_executor_type; /// Executor used to submit functions to an io_context. typedef basic_executor_type<std::allocator<void>, 0> 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) \ && !defined(BOOST_ASIO_NO_TS_EXECUTORS) class strand; #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) // && !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// 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 * <tt>delete static_cast<io_context::service*>(svc)</tt>. * * @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 <typename Rep, typename Period> std::size_t run_for(const chrono::duration<Rep, Period>& 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 <typename Clock, typename Duration> std::size_t run_until(const chrono::time_point<Clock, Duration>& 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 <typename Rep, typename Period> std::size_t run_one_for(const chrono::duration<Rep, Period>& 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 <typename Clock, typename Duration> std::size_t run_one_until( const chrono::time_point<Clock, Duration>& 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 <typename LegacyCompletionHandler> BOOST_ASIO_INITFN_AUTO_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 <typename LegacyCompletionHandler> BOOST_ASIO_INITFN_AUTO_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 <typename Handler> #if defined(GENERATING_DOCUMENTATION) unspecified #else detail::wrapped_handler<io_context&, Handler> #endif wrap(Handler handler); #endif // !defined(BOOST_ASIO_NO_DEPRECATED) private: io_context(const io_context&) BOOST_ASIO_DELETED; io_context& operator=(const io_context&) BOOST_ASIO_DELETED; #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 <typename Service> 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_; }; namespace detail { } // namespace detail /// Executor implementation type used to submit functions to an io_context. template <typename Allocator, unsigned int Bits> class io_context::basic_executor_type : detail::io_context_bits { public: /// Copy constructor. basic_executor_type( const basic_executor_type& other) BOOST_ASIO_NOEXCEPT : io_context_(other.io_context_), allocator_(other.allocator_), bits_(other.bits_) { if (Bits & outstanding_work_tracked) if (io_context_) io_context_->impl_.work_started(); } #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move constructor. basic_executor_type(basic_executor_type&& other) BOOST_ASIO_NOEXCEPT : io_context_(other.io_context_), allocator_(BOOST_ASIO_MOVE_CAST(Allocator)(other.allocator_)), bits_(other.bits_) { if (Bits & outstanding_work_tracked) other.io_context_ = 0; } #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Destructor. ~basic_executor_type() BOOST_ASIO_NOEXCEPT { if (Bits & outstanding_work_tracked) if (io_context_) io_context_->impl_.work_finished(); } /// Assignment operator. basic_executor_type& operator=( const basic_executor_type& other) BOOST_ASIO_NOEXCEPT; #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Move assignment operator. basic_executor_type& operator=( basic_executor_type&& other) BOOST_ASIO_NOEXCEPT; #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) /// Obtain an executor with the @c blocking.possibly property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code auto ex1 = my_io_context.get_executor(); * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::blocking.possibly); @endcode */ BOOST_ASIO_CONSTEXPR basic_executor_type require( execution::blocking_t::possibly_t) const { return basic_executor_type(io_context_, allocator_, bits_ & ~blocking_never); } /// Obtain an executor with the @c blocking.never property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code auto ex1 = my_io_context.get_executor(); * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::blocking.never); @endcode */ BOOST_ASIO_CONSTEXPR basic_executor_type require( execution::blocking_t::never_t) const { return basic_executor_type(io_context_, allocator_, bits_ | blocking_never); } /// Obtain an executor with the @c relationship.fork property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code auto ex1 = my_io_context.get_executor(); * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::relationship.fork); @endcode */ BOOST_ASIO_CONSTEXPR basic_executor_type require( execution::relationship_t::fork_t) const { return basic_executor_type(io_context_, allocator_, bits_ & ~relationship_continuation); } /// Obtain an executor with the @c relationship.continuation property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code auto ex1 = my_io_context.get_executor(); * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::relationship.continuation); @endcode */ BOOST_ASIO_CONSTEXPR basic_executor_type require( execution::relationship_t::continuation_t) const { return basic_executor_type(io_context_, allocator_, bits_ | relationship_continuation); } /// Obtain an executor with the @c outstanding_work.tracked property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code auto ex1 = my_io_context.get_executor(); * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::outstanding_work.tracked); @endcode */ BOOST_ASIO_CONSTEXPR basic_executor_type<Allocator, BOOST_ASIO_UNSPECIFIED(Bits | outstanding_work_tracked)> require(execution::outstanding_work_t::tracked_t) const { return basic_executor_type<Allocator, Bits | outstanding_work_tracked>( io_context_, allocator_, bits_); } /// Obtain an executor with the @c outstanding_work.untracked property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code auto ex1 = my_io_context.get_executor(); * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::outstanding_work.untracked); @endcode */ BOOST_ASIO_CONSTEXPR basic_executor_type<Allocator, BOOST_ASIO_UNSPECIFIED(Bits & ~outstanding_work_tracked)> require(execution::outstanding_work_t::untracked_t) const { return basic_executor_type<Allocator, Bits & ~outstanding_work_tracked>( io_context_, allocator_, bits_); } /// Obtain an executor with the specified @c allocator property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code auto ex1 = my_io_context.get_executor(); * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::allocator(my_allocator)); @endcode */ template <typename OtherAllocator> BOOST_ASIO_CONSTEXPR basic_executor_type<OtherAllocator, Bits> require(execution::allocator_t<OtherAllocator> a) const { return basic_executor_type<OtherAllocator, Bits>( io_context_, a.value(), bits_); } /// Obtain an executor with the default @c allocator property. /** * Do not call this function directly. It is intended for use with the * boost::asio::require customisation point. * * For example: * @code auto ex1 = my_io_context.get_executor(); * auto ex2 = boost::asio::require(ex1, * boost::asio::execution::allocator); @endcode */ BOOST_ASIO_CONSTEXPR basic_executor_type<std::allocator<void>, Bits> require(execution::allocator_t<void>) const { return basic_executor_type<std::allocator<void>, Bits>( io_context_, std::allocator<void>(), bits_); } /// Query the current value of the @c mapping property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code auto ex = my_io_context.get_executor(); * if (boost::asio::query(ex, boost::asio::execution::mapping) * == boost::asio::execution::mapping.thread) * ... @endcode */ static BOOST_ASIO_CONSTEXPR execution::mapping_t query( execution::mapping_t) BOOST_ASIO_NOEXCEPT { return execution::mapping.thread; } /// Query the current value of the @c context property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code auto ex = my_io_context.get_executor(); * boost::asio::io_context& ctx = boost::asio::query( * ex, boost::asio::execution::context); @endcode */ io_context& query(execution::context_t) const BOOST_ASIO_NOEXCEPT { return *io_context_; } /// Query the current value of the @c blocking property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code auto ex = my_io_context.get_executor(); * if (boost::asio::query(ex, boost::asio::execution::blocking) * == boost::asio::execution::blocking.always) * ... @endcode */ BOOST_ASIO_CONSTEXPR execution::blocking_t query( execution::blocking_t) const BOOST_ASIO_NOEXCEPT { return (bits_ & blocking_never) ? execution::blocking_t(execution::blocking.never) : execution::blocking_t(execution::blocking.possibly); } /// Query the current value of the @c relationship property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code auto ex = my_io_context.get_executor(); * if (boost::asio::query(ex, boost::asio::execution::relationship) * == boost::asio::execution::relationship.continuation) * ... @endcode */ BOOST_ASIO_CONSTEXPR execution::relationship_t query( execution::relationship_t) const BOOST_ASIO_NOEXCEPT { return (bits_ & relationship_continuation) ? execution::relationship_t(execution::relationship.continuation) : execution::relationship_t(execution::relationship.fork); } /// Query the current value of the @c outstanding_work property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code auto ex = my_io_context.get_executor(); * if (boost::asio::query(ex, boost::asio::execution::outstanding_work) * == boost::asio::execution::outstanding_work.tracked) * ... @endcode */ static BOOST_ASIO_CONSTEXPR execution::outstanding_work_t query( execution::outstanding_work_t) BOOST_ASIO_NOEXCEPT { return (Bits & outstanding_work_tracked) ? execution::outstanding_work_t(execution::outstanding_work.tracked) : execution::outstanding_work_t(execution::outstanding_work.untracked); } /// Query the current value of the @c allocator property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code auto ex = my_io_context.get_executor(); * auto alloc = boost::asio::query(ex, * boost::asio::execution::allocator); @endcode */ template <typename OtherAllocator> BOOST_ASIO_CONSTEXPR Allocator query( execution::allocator_t<OtherAllocator>) const BOOST_ASIO_NOEXCEPT { return allocator_; } /// Query the current value of the @c allocator property. /** * Do not call this function directly. It is intended for use with the * boost::asio::query customisation point. * * For example: * @code auto ex = my_io_context.get_executor(); * auto alloc = boost::asio::query(ex, * boost::asio::execution::allocator); @endcode */ BOOST_ASIO_CONSTEXPR Allocator query( execution::allocator_t<void>) const BOOST_ASIO_NOEXCEPT { return allocator_; } /// 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 basic_executor_type& a, const basic_executor_type& b) BOOST_ASIO_NOEXCEPT { return a.io_context_ == b.io_context_ && a.allocator_ == b.allocator_ && a.bits_ == b.bits_; } /// Compare two executors for inequality. /** * Two executors are equal if they refer to the same underlying io_context. */ friend bool operator!=(const basic_executor_type& a, const basic_executor_type& b) BOOST_ASIO_NOEXCEPT { return a.io_context_ != b.io_context_ || a.allocator_ != b.allocator_ || a.bits_ != b.bits_; } /// Execution function. /** * Do not call this function directly. It is intended for use with the * execution::execute customisation point. * * For example: * @code auto ex = my_io_context.get_executor(); * execution::execute(ex, my_function_object); @endcode */ template <typename Function> void execute(BOOST_ASIO_MOVE_ARG(Function) f) const; #if !defined(BOOST_ASIO_NO_TS_EXECUTORS) /// 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 <typename Function, typename OtherAllocator> void dispatch(BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& 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 <typename Function, typename OtherAllocator> void post(BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& 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 <typename Function, typename OtherAllocator> void defer(BOOST_ASIO_MOVE_ARG(Function) f, const OtherAllocator& a) const; #endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS) private: friend class io_context; template <typename, unsigned int> friend class basic_executor_type; // Constructor used by io_context::get_executor(). explicit basic_executor_type(io_context& i) BOOST_ASIO_NOEXCEPT : io_context_(&i), allocator_(), bits_(0) { if (Bits & outstanding_work_tracked) io_context_->impl_.work_started(); } // Constructor used by require(). basic_executor_type(io_context* i, const Allocator& a, unsigned int bits) BOOST_ASIO_NOEXCEPT : io_context_(i), allocator_(a), bits_(bits) { if (Bits & outstanding_work_tracked) if (io_context_) io_context_->impl_.work_started(); } // The underlying io_context. io_context* io_context_; // The allocator used for execution functions. Allocator allocator_; // The runtime-switched properties of the io_context executor. unsigned int bits_; }; #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 <typename Type> class service_base : public boost::asio::io_context::service { public: static boost::asio::detail::service_id<Type> id; // Constructor. service_base(boost::asio::io_context& io_context) : boost::asio::io_context::service(io_context) { } }; template <typename Type> boost::asio::detail::service_id<Type> service_base<Type>::id; } // namespace detail #if !defined(GENERATING_DOCUMENTATION) namespace traits { #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) template <typename Allocator, unsigned int Bits> struct equality_comparable< boost::asio::io_context::basic_executor_type<Allocator, Bits> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) template <typename Allocator, unsigned int Bits, typename Function> struct execute_member< boost::asio::io_context::basic_executor_type<Allocator, Bits>, Function > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) template <typename Allocator, unsigned int Bits> struct require_member< boost::asio::io_context::basic_executor_type<Allocator, Bits>, boost::asio::execution::blocking_t::possibly_t > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::io_context::basic_executor_type< Allocator, Bits> result_type; }; template <typename Allocator, unsigned int Bits> struct require_member< boost::asio::io_context::basic_executor_type<Allocator, Bits>, boost::asio::execution::blocking_t::never_t > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::io_context::basic_executor_type< Allocator, Bits> result_type; }; template <typename Allocator, unsigned int Bits> struct require_member< boost::asio::io_context::basic_executor_type<Allocator, Bits>, boost::asio::execution::relationship_t::fork_t > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::io_context::basic_executor_type< Allocator, Bits> result_type; }; template <typename Allocator, unsigned int Bits> struct require_member< boost::asio::io_context::basic_executor_type<Allocator, Bits>, boost::asio::execution::relationship_t::continuation_t > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::io_context::basic_executor_type< Allocator, Bits> result_type; }; template <typename Allocator, unsigned int Bits> struct require_member< boost::asio::io_context::basic_executor_type<Allocator, Bits>, boost::asio::execution::outstanding_work_t::tracked_t > : boost::asio::detail::io_context_bits { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::io_context::basic_executor_type< Allocator, Bits | outstanding_work_tracked> result_type; }; template <typename Allocator, unsigned int Bits> struct require_member< boost::asio::io_context::basic_executor_type<Allocator, Bits>, boost::asio::execution::outstanding_work_t::untracked_t > : boost::asio::detail::io_context_bits { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::io_context::basic_executor_type< Allocator, Bits & ~outstanding_work_tracked> result_type; }; template <typename Allocator, unsigned int Bits> struct require_member< boost::asio::io_context::basic_executor_type<Allocator, Bits>, boost::asio::execution::allocator_t<void> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::io_context::basic_executor_type< std::allocator<void>, Bits> result_type; }; template <unsigned int Bits, typename Allocator, typename OtherAllocator> struct require_member< boost::asio::io_context::basic_executor_type<Allocator, Bits>, boost::asio::execution::allocator_t<OtherAllocator> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef boost::asio::io_context::basic_executor_type< OtherAllocator, Bits> result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) template <typename Allocator, unsigned int Bits, typename Property> struct query_static_constexpr_member< boost::asio::io_context::basic_executor_type<Allocator, Bits>, Property, typename boost::asio::enable_if< boost::asio::is_convertible< Property, boost::asio::execution::outstanding_work_t >::value >::type > : boost::asio::detail::io_context_bits { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef boost::asio::execution::outstanding_work_t result_type; static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT { return (Bits & outstanding_work_tracked) ? execution::outstanding_work_t(execution::outstanding_work.tracked) : execution::outstanding_work_t(execution::outstanding_work.untracked); } }; template <typename Allocator, unsigned int Bits, typename Property> struct query_static_constexpr_member< boost::asio::io_context::basic_executor_type<Allocator, Bits>, Property, typename boost::asio::enable_if< boost::asio::is_convertible< Property, boost::asio::execution::mapping_t >::value >::type > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef boost::asio::execution::mapping_t::thread_t result_type; static BOOST_ASIO_CONSTEXPR result_type value() BOOST_ASIO_NOEXCEPT { return result_type(); } }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT) #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) template <typename Allocator, unsigned int Bits, typename Property> struct query_member< boost::asio::io_context::basic_executor_type<Allocator, Bits>, Property, typename boost::asio::enable_if< boost::asio::is_convertible< Property, boost::asio::execution::blocking_t >::value >::type > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef boost::asio::execution::blocking_t result_type; }; template <typename Allocator, unsigned int Bits, typename Property> struct query_member< boost::asio::io_context::basic_executor_type<Allocator, Bits>, Property, typename boost::asio::enable_if< boost::asio::is_convertible< Property, boost::asio::execution::relationship_t >::value >::type > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef boost::asio::execution::relationship_t result_type; }; template <typename Allocator, unsigned int Bits> struct query_member< boost::asio::io_context::basic_executor_type<Allocator, Bits>, boost::asio::execution::context_t > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef boost::asio::io_context& result_type; }; template <typename Allocator, unsigned int Bits> struct query_member< boost::asio::io_context::basic_executor_type<Allocator, Bits>, boost::asio::execution::allocator_t<void> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef Allocator result_type; }; template <typename Allocator, unsigned int Bits, typename OtherAllocator> struct query_member< boost::asio::io_context::basic_executor_type<Allocator, Bits>, boost::asio::execution::allocator_t<OtherAllocator> > { BOOST_ASIO_STATIC_CONSTEXPR(bool, is_valid = true); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); typedef Allocator result_type; }; #endif // !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT) } // namespace traits #endif // !defined(GENERATING_DOCUMENTATION) } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/io_context.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/impl/io_context.ipp> #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 <boost/asio/io_context_strand.hpp> # endif // defined(BOOST_ASIO_STRAND_HPP) #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) #endif // BOOST_ASIO_IO_CONTEXT_HPP require.hpp 0000644 00000035116 15125530236 0006741 0 ustar 00 // // require.hpp // ~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_REQUIRE_HPP #define BOOST_ASIO_REQUIRE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/is_applicable_property.hpp> #include <boost/asio/traits/require_member.hpp> #include <boost/asio/traits/require_free.hpp> #include <boost/asio/traits/static_require.hpp> #include <boost/asio/detail/push_options.hpp> #if defined(GENERATING_DOCUMENTATION) namespace boost { namespace asio { /// A customisation point that applies a concept-preserving property to an /// object. /** * The name <tt>require</tt> denotes a customisation point object. The * expression <tt>boost::asio::require(E, P0, Pn...)</tt> for some * subexpressions <tt>E</tt> and <tt>P0</tt>, and where <tt>Pn...</tt> * represents <tt>N</tt> subexpressions (where <tt>N</tt> is 0 or more, and with * types <tt>T = decay_t<decltype(E)></tt> and <tt>Prop0 = * decay_t<decltype(P0)></tt>) is expression-equivalent to: * * @li If <tt>is_applicable_property_v<T, Prop0> && Prop0::is_requirable</tt> is * not a well-formed constant expression with value <tt>true</tt>, * <tt>boost::asio::require(E, P0, Pn...)</tt> is ill-formed. * * @li Otherwise, <tt>E</tt> if <tt>N == 0</tt> and the expression * <tt>Prop0::template static_query_v<T> == Prop0::value()</tt> is a * well-formed constant expression with value <tt>true</tt>. * * @li Otherwise, <tt>(E).require(P0)</tt> if <tt>N == 0</tt> and the expression * <tt>(E).require(P0)</tt> is a valid expression. * * @li Otherwise, <tt>require(E, P0)</tt> if <tt>N == 0</tt> and the expression * <tt>require(E, P0)</tt> is a valid expression with overload resolution * performed in a context that does not include the declaration of the * <tt>require</tt> customization point object. * * @li Otherwise, * <tt>boost::asio::require(boost::asio::require(E, P0), Pn...)</tt> * if <tt>N > 0</tt> and the expression * <tt>boost::asio::require(boost::asio::require(E, P0), Pn...)</tt> * is a valid expression. * * @li Otherwise, <tt>boost::asio::require(E, P0, Pn...)</tt> is ill-formed. */ inline constexpr unspecified require = unspecified; /// A type trait that determines whether a @c require expression is well-formed. /** * Class template @c can_require is a trait that is derived from * @c true_type if the expression <tt>boost::asio::require(std::declval<T>(), * std::declval<Properties>()...)</tt> is well formed; otherwise @c false_type. */ template <typename T, typename... Properties> struct can_require : integral_constant<bool, automatically_determined> { }; /// A type trait that determines whether a @c require expression will not throw. /** * Class template @c is_nothrow_require is a trait that is derived from * @c true_type if the expression <tt>boost::asio::require(std::declval<T>(), * std::declval<Properties>()...)</tt> is @c noexcept; otherwise @c false_type. */ template <typename T, typename... Properties> struct is_nothrow_require : integral_constant<bool, automatically_determined> { }; /// A type trait that determines the result type of a @c require expression. /** * Class template @c require_result is a trait that determines the result * type of the expression <tt>boost::asio::require(std::declval<T>(), * std::declval<Properties>()...)</tt>. */ template <typename T, typename... Properties> struct require_result { /// The result of the @c require expression. typedef automatically_determined type; }; } // namespace asio } // namespace boost #else // defined(GENERATING_DOCUMENTATION) namespace asio_require_fn { using boost::asio::decay; using boost::asio::declval; using boost::asio::enable_if; using boost::asio::is_applicable_property; using boost::asio::traits::require_free; using boost::asio::traits::require_member; using boost::asio::traits::static_require; void require(); enum overload_type { identity, call_member, call_free, two_props, n_props, ill_formed }; template <typename T, typename Properties, typename = void> struct call_traits { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = ill_formed); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = false); typedef void result_type; }; template <typename T, typename Property> struct call_traits<T, void(Property), typename enable_if< ( is_applicable_property< typename decay<T>::type, typename decay<Property>::type >::value && decay<Property>::type::is_requirable && static_require<T, Property>::is_valid ) >::type> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = identity); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = true); #if defined(BOOST_ASIO_HAS_MOVE) typedef BOOST_ASIO_MOVE_ARG(T) result_type; #else // defined(BOOST_ASIO_HAS_MOVE) typedef BOOST_ASIO_MOVE_ARG(typename decay<T>::type) result_type; #endif // defined(BOOST_ASIO_HAS_MOVE) }; template <typename T, typename Property> struct call_traits<T, void(Property), typename enable_if< ( is_applicable_property< typename decay<T>::type, typename decay<Property>::type >::value && decay<Property>::type::is_requirable && !static_require<T, Property>::is_valid && require_member<T, Property>::is_valid ) >::type> : require_member<T, Property> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_member); }; template <typename T, typename Property> struct call_traits<T, void(Property), typename enable_if< ( is_applicable_property< typename decay<T>::type, typename decay<Property>::type >::value && decay<Property>::type::is_requirable && !static_require<T, Property>::is_valid && !require_member<T, Property>::is_valid && require_free<T, Property>::is_valid ) >::type> : require_free<T, Property> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = call_free); }; template <typename T, typename P0, typename P1> struct call_traits<T, void(P0, P1), typename enable_if< call_traits<T, void(P0)>::overload != ill_formed && call_traits< typename call_traits<T, void(P0)>::result_type, void(P1) >::overload != ill_formed >::type> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = two_props); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = ( call_traits<T, void(P0)>::is_noexcept && call_traits< typename call_traits<T, void(P0)>::result_type, void(P1) >::is_noexcept )); typedef typename decay< typename call_traits< typename call_traits<T, void(P0)>::result_type, void(P1) >::result_type >::type result_type; }; template <typename T, typename P0, typename P1, typename BOOST_ASIO_ELLIPSIS PN> struct call_traits<T, void(P0, P1, PN BOOST_ASIO_ELLIPSIS), typename enable_if< call_traits<T, void(P0)>::overload != ill_formed && call_traits< typename call_traits<T, void(P0)>::result_type, void(P1, PN BOOST_ASIO_ELLIPSIS) >::overload != ill_formed >::type> { BOOST_ASIO_STATIC_CONSTEXPR(overload_type, overload = n_props); BOOST_ASIO_STATIC_CONSTEXPR(bool, is_noexcept = ( call_traits<T, void(P0)>::is_noexcept && call_traits< typename call_traits<T, void(P0)>::result_type, void(P1, PN BOOST_ASIO_ELLIPSIS) >::is_noexcept )); typedef typename decay< typename call_traits< typename call_traits<T, void(P0)>::result_type, void(P1, PN BOOST_ASIO_ELLIPSIS) >::result_type >::type result_type; }; struct impl { template <typename T, typename Property> BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(Property)>::overload == identity, typename call_traits<T, void(Property)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(Property)) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(Property)>::is_noexcept)) { return BOOST_ASIO_MOVE_CAST(T)(t); } template <typename T, typename Property> BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(Property)>::overload == call_member, typename call_traits<T, void(Property)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(Property) p) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(Property)>::is_noexcept)) { return BOOST_ASIO_MOVE_CAST(T)(t).require( BOOST_ASIO_MOVE_CAST(Property)(p)); } template <typename T, typename Property> BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(Property)>::overload == call_free, typename call_traits<T, void(Property)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(Property) p) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(Property)>::is_noexcept)) { return require( BOOST_ASIO_MOVE_CAST(T)(t), BOOST_ASIO_MOVE_CAST(Property)(p)); } template <typename T, typename P0, typename P1> BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(P0, P1)>::overload == two_props, typename call_traits<T, void(P0, P1)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(P0) p0, BOOST_ASIO_MOVE_ARG(P1) p1) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(P0, P1)>::is_noexcept)) { return (*this)( (*this)( BOOST_ASIO_MOVE_CAST(T)(t), BOOST_ASIO_MOVE_CAST(P0)(p0)), BOOST_ASIO_MOVE_CAST(P1)(p1)); } template <typename T, typename P0, typename P1, typename BOOST_ASIO_ELLIPSIS PN> BOOST_ASIO_NODISCARD BOOST_ASIO_CONSTEXPR typename enable_if< call_traits<T, void(P0, P1, PN BOOST_ASIO_ELLIPSIS)>::overload == n_props, typename call_traits<T, void(P0, P1, PN BOOST_ASIO_ELLIPSIS)>::result_type >::type operator()( BOOST_ASIO_MOVE_ARG(T) t, BOOST_ASIO_MOVE_ARG(P0) p0, BOOST_ASIO_MOVE_ARG(P1) p1, BOOST_ASIO_MOVE_ARG(PN) BOOST_ASIO_ELLIPSIS pn) const BOOST_ASIO_NOEXCEPT_IF(( call_traits<T, void(P0, P1, PN BOOST_ASIO_ELLIPSIS)>::is_noexcept)) { return (*this)( (*this)( BOOST_ASIO_MOVE_CAST(T)(t), BOOST_ASIO_MOVE_CAST(P0)(p0)), BOOST_ASIO_MOVE_CAST(P1)(p1), BOOST_ASIO_MOVE_CAST(PN)(pn) BOOST_ASIO_ELLIPSIS); } }; template <typename T = impl> struct static_instance { static const T instance; }; template <typename T> const T static_instance<T>::instance = {}; } // namespace asio_require_fn namespace boost { namespace asio { namespace { static BOOST_ASIO_CONSTEXPR const asio_require_fn::impl& require = asio_require_fn::static_instance<>::instance; } // namespace #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T, typename... Properties> struct can_require : integral_constant<bool, asio_require_fn::call_traits<T, void(Properties...)>::overload != asio_require_fn::ill_formed> { }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T, typename P0 = void, typename P1 = void, typename P2 = void> struct can_require : integral_constant<bool, asio_require_fn::call_traits<T, void(P0, P1, P2)>::overload != asio_require_fn::ill_formed> { }; template <typename T, typename P0, typename P1> struct can_require<T, P0, P1> : integral_constant<bool, asio_require_fn::call_traits<T, void(P0, P1)>::overload != asio_require_fn::ill_formed> { }; template <typename T, typename P0> struct can_require<T, P0> : integral_constant<bool, asio_require_fn::call_traits<T, void(P0)>::overload != asio_require_fn::ill_formed> { }; template <typename T> struct can_require<T> : false_type { }; #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename BOOST_ASIO_ELLIPSIS Properties> constexpr bool can_require_v = can_require<T, Properties BOOST_ASIO_ELLIPSIS>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T, typename... Properties> struct is_nothrow_require : integral_constant<bool, asio_require_fn::call_traits<T, void(Properties...)>::is_noexcept> { }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T, typename P0 = void, typename P1 = void, typename P2 = void> struct is_nothrow_require : integral_constant<bool, asio_require_fn::call_traits<T, void(P0, P1, P2)>::is_noexcept> { }; template <typename T, typename P0, typename P1> struct is_nothrow_require<T, P0, P1> : integral_constant<bool, asio_require_fn::call_traits<T, void(P0, P1)>::is_noexcept> { }; template <typename T, typename P0> struct is_nothrow_require<T, P0> : integral_constant<bool, asio_require_fn::call_traits<T, void(P0)>::is_noexcept> { }; template <typename T> struct is_nothrow_require<T> : false_type { }; #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename BOOST_ASIO_ELLIPSIS Properties> constexpr bool is_nothrow_require_v = is_nothrow_require<T, Properties BOOST_ASIO_ELLIPSIS>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) #if defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T, typename... Properties> struct require_result { typedef typename asio_require_fn::call_traits< T, void(Properties...)>::result_type type; }; #else // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename T, typename P0 = void, typename P1 = void, typename P2 = void> struct require_result { typedef typename asio_require_fn::call_traits< T, void(P0, P1, P2)>::result_type type; }; template <typename T, typename P0, typename P1> struct require_result<T, P0, P1> { typedef typename asio_require_fn::call_traits< T, void(P0, P1)>::result_type type; }; template <typename T, typename P0> struct require_result<T, P0> { typedef typename asio_require_fn::call_traits< T, void(P0)>::result_type type; }; template <typename T> struct require_result<T> { }; #endif // defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) } // namespace asio } // namespace boost #endif // defined(GENERATING_DOCUMENTATION) #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_REQUIRE_HPP defer.hpp 0000644 00000011716 15125530236 0006352 0 ustar 00 // // defer.hpp // ~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/execution/executor.hpp> #include <boost/asio/is_executor.hpp> #include <boost/asio/detail/push_options.hpp> 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 <tt>defer()</tt>. * * 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 <tt>handler(forward<CompletionToken>(token))</tt>. * * @li Constructs an object @c result of type <tt>async_result<Handler></tt>, * initializing the object as <tt>result(handler)</tt>. * * @li Obtains the handler's associated executor object @c ex by performing * <tt>get_associated_executor(handler)</tt>. * * @li Obtains the handler's associated allocator object @c alloc by performing * <tt>get_associated_allocator(handler)</tt>. * * @li Performs <tt>ex.defer(std::move(handler), alloc)</tt>. * * @li Returns <tt>result.get()</tt>. */ template <BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken> BOOST_ASIO_INITFN_AUTO_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 <tt>defer()</tt>. * * 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 <tt>handler(forward<CompletionToken>(token))</tt>. * * @li Constructs an object @c result of type <tt>async_result<Handler></tt>, * initializing the object as <tt>result(handler)</tt>. * * @li Obtains the handler's associated executor object @c ex1 by performing * <tt>get_associated_executor(handler)</tt>. * * @li Creates a work object @c w by performing <tt>make_work(ex1)</tt>. * * @li Obtains the handler's associated allocator object @c alloc by performing * <tt>get_associated_allocator(handler)</tt>. * * @li Constructs a function object @c f with a function call operator that * performs <tt>ex1.dispatch(std::move(handler), alloc)</tt> followed by * <tt>w.reset()</tt>. * * @li Performs <tt>Executor(ex).defer(std::move(f), alloc)</tt>. * * @li Returns <tt>result.get()</tt>. */ template <typename Executor, BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer( const Executor& ex, BOOST_ASIO_MOVE_ARG(CompletionToken) token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor), typename enable_if< execution::is_executor<Executor>::value || is_executor<Executor>::value >::type* = 0); /// Submits a completion token or function object for execution. /** * @returns <tt>defer(ctx.get_executor(), forward<CompletionToken>(token))</tt>. */ template <typename ExecutionContext, BOOST_ASIO_COMPLETION_TOKEN_FOR(void()) CompletionToken BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename ExecutionContext::executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, void()) defer( ExecutionContext& ctx, BOOST_ASIO_MOVE_ARG(CompletionToken) token BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename ExecutionContext::executor_type), typename enable_if<is_convertible< ExecutionContext&, execution_context&>::value>::type* = 0); } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/defer.hpp> #endif // BOOST_ASIO_DEFER_HPP is_applicable_property.hpp 0000644 00000003105 15125530236 0012011 0 ustar 00 // // is_applicable_property.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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_APPLICABLE_PROPERTY_HPP #define BOOST_ASIO_IS_APPLICABLE_PROPERTY_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include <boost/asio/detail/config.hpp> #include <boost/asio/detail/type_traits.hpp> namespace boost { namespace asio { namespace detail { template <typename T, typename Property, typename = void> struct is_applicable_property_trait : false_type { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename Property> struct is_applicable_property_trait<T, Property, typename void_type< typename enable_if< !!Property::template is_applicable_property_v<T> >::type >::type> : true_type { }; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) } // namespace detail template <typename T, typename Property, typename = void> struct is_applicable_property : detail::is_applicable_property_trait<T, Property> { }; #if defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) template <typename T, typename Property> BOOST_ASIO_CONSTEXPR const bool is_applicable_property_v = is_applicable_property<T, Property>::value; #endif // defined(BOOST_ASIO_HAS_VARIABLE_TEMPLATES) } // namespace asio } // namespace boost #endif // BOOST_ASIO_IS_APPLICABLE_PROPERTY_HPP is_executor.hpp 0000644 00000002432 15125530236 0007611 0 ustar 00 // // is_executor.hpp // ~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/is_executor.hpp> #include <boost/asio/detail/push_options.hpp> 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 <typename T> struct is_executor #if defined(GENERATING_DOCUMENTATION) : integral_constant<bool, automatically_determined> #else // defined(GENERATING_DOCUMENTATION) : boost::asio::detail::is_executor<T> #endif // defined(GENERATING_DOCUMENTATION) { }; } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_IS_EXECUTOR_HPP write_at.hpp 0000644 00000071512 15125530236 0007103 0 ustar 00 // // write_at.hpp // ~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <cstddef> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/cstdint.hpp> #include <boost/asio/error.hpp> #if !defined(BOOST_ASIO_NO_EXTENSIONS) # include <boost/asio/basic_streambuf_fwd.hpp> #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) #include <boost/asio/detail/push_options.hpp> 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 <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence> 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 <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence> 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 <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence, typename CompletionCondition> 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 <typename SyncRandomAccessWriteDevice, typename ConstBufferSequence, typename CompletionCondition> 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 <typename SyncRandomAccessWriteDevice, typename Allocator> std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, basic_streambuf<Allocator>& 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 <typename SyncRandomAccessWriteDevice, typename Allocator> std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, basic_streambuf<Allocator>& 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 <typename SyncRandomAccessWriteDevice, typename Allocator, typename CompletionCondition> std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, basic_streambuf<Allocator>& 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 <typename SyncRandomAccessWriteDevice, typename Allocator, typename CompletionCondition> std::size_t write_at(SyncRandomAccessWriteDevice& d, uint64_t offset, basic_streambuf<Allocator>& 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 <em>composed operation</em>. * The program must ensure that the device performs no <em>overlapping</em> * 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 <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncRandomAccessWriteDevice::executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncRandomAccessWriteDevice::executor_type)); /// 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 <em>composed operation</em>. * The program must ensure that the device performs no <em>overlapping</em> * 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 <typename AsyncRandomAccessWriteDevice, typename ConstBufferSequence, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncRandomAccessWriteDevice::executor_type)> BOOST_ASIO_INITFN_AUTO_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 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncRandomAccessWriteDevice::executor_type)); #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 <em>composed operation</em>. * The program must ensure that the device performs no <em>overlapping</em> * 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 <typename AsyncRandomAccessWriteDevice, typename Allocator, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncRandomAccessWriteDevice::executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, basic_streambuf<Allocator>& b, BOOST_ASIO_MOVE_ARG(WriteHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncRandomAccessWriteDevice::executor_type)); /// 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 <em>composed operation</em>. * The program must ensure that the device performs no <em>overlapping</em> * 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 <typename AsyncRandomAccessWriteDevice, typename Allocator, typename CompletionCondition, BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code, std::size_t)) WriteHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE( typename AsyncRandomAccessWriteDevice::executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler, void (boost::system::error_code, std::size_t)) async_write_at(AsyncRandomAccessWriteDevice& d, uint64_t offset, basic_streambuf<Allocator>& b, CompletionCondition completion_condition, BOOST_ASIO_MOVE_ARG(WriteHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN( typename AsyncRandomAccessWriteDevice::executor_type)); #endif // !defined(BOOST_ASIO_NO_IOSTREAM) #endif // !defined(BOOST_ASIO_NO_EXTENSIONS) /*@}*/ } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/write_at.hpp> #endif // BOOST_ASIO_WRITE_AT_HPP wait_traits.hpp 0000644 00000002653 15125530236 0007617 0 ustar 00 // // wait_traits.hpp // ~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { /// Wait traits suitable for use with the basic_waitable_timer class template. template <typename Clock> 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 <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_WAIT_TRAITS_HPP basic_socket.hpp 0000644 00000177754 15125530236 0007735 0 ustar 00 // // basic_socket.hpp // ~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/any_io_executor.hpp> #include <boost/asio/detail/config.hpp> #include <boost/asio/async_result.hpp> #include <boost/asio/detail/handler_type_requirements.hpp> #include <boost/asio/detail/io_object_impl.hpp> #include <boost/asio/detail/non_const_lvalue.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/error.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/post.hpp> #include <boost/asio/socket_base.hpp> #if defined(BOOST_ASIO_WINDOWS_RUNTIME) # include <boost/asio/detail/null_socket_service.hpp> #elif defined(BOOST_ASIO_HAS_IOCP) # include <boost/asio/detail/win_iocp_socket_service.hpp> #else # include <boost/asio/detail/reactive_socket_service.hpp> #endif #if defined(BOOST_ASIO_HAS_MOVE) # include <utility> #endif // defined(BOOST_ASIO_HAS_MOVE) #include <boost/asio/detail/push_options.hpp> 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 <typename Protocol, typename Executor = any_io_executor> 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 <typename Protocol, typename Executor> 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 <typename Executor1> struct rebind_executor { /// The socket type when rebound to the specified executor. typedef basic_socket<Protocol, Executor1> 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<Protocol, Executor> 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 <typename ExecutionContext> explicit basic_socket(ExecutionContext& context, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename ExecutionContext> basic_socket(ExecutionContext& context, const protocol_type& protocol, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename ExecutionContext> basic_socket(ExecutionContext& context, const endpoint_type& endpoint, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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 <typename ExecutionContext> basic_socket(ExecutionContext& context, const protocol_type& protocol, const native_handle_type& native_socket, typename enable_if< is_convertible<ExecutionContext&, execution_context&>::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) BOOST_ASIO_NOEXCEPT : 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 <typename Protocol1, typename Executor1> 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 <typename Protocol1, typename Executor1> basic_socket(basic_socket<Protocol1, Executor1>&& other, typename enable_if< is_convertible<Protocol1, Protocol>::value && is_convertible<Executor1, Executor>::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 Protocol1, typename Executor1> typename enable_if< is_convertible<Protocol1, Protocol>::value && is_convertible<Executor1, Executor>::value, basic_socket& >::type operator=(basic_socket<Protocol1, Executor1> && 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_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) ConnectHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(ConnectHandler, void (boost::system::error_code)) async_connect(const endpoint_type& peer_endpoint, BOOST_ASIO_MOVE_ARG(ConnectHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { 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<ConnectHandler, void (boost::system::error_code)>( initiate_async_connect(this), handler, 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 <typename SettableSocketOption> 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 <typename SettableSocketOption> 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 <typename GettableSocketOption> 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 <typename GettableSocketOption> 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 <typename IoControlCommand> 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 <typename IoControlCommand> 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 <typename Handler> * 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 <typename Handler> * void async_sendfile(tcp::socket& sock, int fd, Handler h) * { * sendfile_op<Handler> 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 <typename Handler> * 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 <typename Handler> * void async_sendfile(tcp::socket& sock, int fd, Handler h) * { * sendfile_op<Handler> 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 <typename Handler> * 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 <typename Handler> * void async_sendfile(tcp::socket& sock, int fd, Handler h) * { * sendfile_op<Handler> 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_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) WaitHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler, void (boost::system::error_code)) async_wait(wait_type w, BOOST_ASIO_MOVE_ARG(WaitHandler) handler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) { return async_initiate<WaitHandler, void (boost::system::error_code)>( initiate_async_wait(this), handler, 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<Protocol>, Executor> impl_; #elif defined(BOOST_ASIO_HAS_IOCP) detail::io_object_impl< detail::win_iocp_socket_service<Protocol>, Executor> impl_; #else detail::io_object_impl< detail::reactive_socket_service<Protocol>, 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; class initiate_async_connect { public: typedef Executor executor_type; explicit initiate_async_connect(basic_socket* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename ConnectHandler> void operator()(BOOST_ASIO_MOVE_ARG(ConnectHandler) handler, 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<ConnectHandler> handler2(handler); self_->impl_.get_service().async_connect( self_->impl_.get_implementation(), peer_endpoint, handler2.value, self_->impl_.get_executor()); } } private: basic_socket* self_; }; class initiate_async_wait { public: typedef Executor executor_type; explicit initiate_async_wait(basic_socket* self) : self_(self) { } executor_type get_executor() const BOOST_ASIO_NOEXCEPT { return self_->get_executor(); } template <typename WaitHandler> void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler, 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<WaitHandler> handler2(handler); self_->impl_.get_service().async_wait( self_->impl_.get_implementation(), w, handler2.value, self_->impl_.get_executor()); } private: basic_socket* self_; }; }; } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #endif // BOOST_ASIO_BASIC_SOCKET_HPP detached.hpp 0000644 00000006675 15125530236 0007036 0 ustar 00 // // detached.hpp // ~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <memory> #include <boost/asio/detail/type_traits.hpp> #include <boost/asio/detail/push_options.hpp> 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() { } /// Adapts an executor to add the @c detached_t completion token as the /// default. template <typename InnerExecutor> struct executor_with_default : InnerExecutor { /// Specify @c detached_t as the default completion token type. typedef detached_t default_completion_token_type; /// Construct the adapted executor from the inner executor type. executor_with_default(const InnerExecutor& ex) BOOST_ASIO_NOEXCEPT : InnerExecutor(ex) { } /// Convert the specified executor to the inner executor type, then use /// that to construct the adapted executor. template <typename OtherExecutor> executor_with_default(const OtherExecutor& ex, typename enable_if< is_convertible<OtherExecutor, InnerExecutor>::value >::type* = 0) BOOST_ASIO_NOEXCEPT : InnerExecutor(ex) { } }; /// Type alias to adapt an I/O object to use @c detached_t as its /// default completion token type. #if defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) \ || defined(GENERATING_DOCUMENTATION) template <typename T> using as_default_on_t = typename T::template rebind_executor< executor_with_default<typename T::executor_type> >::other; #endif // defined(BOOST_ASIO_HAS_ALIAS_TEMPLATES) // || defined(GENERATING_DOCUMENTATION) /// Function helper to adapt an I/O object to use @c detached_t as its /// default completion token type. template <typename T> static typename decay<T>::type::template rebind_executor< executor_with_default<typename decay<T>::type::executor_type> >::other as_default_on(BOOST_ASIO_MOVE_ARG(T) object) { return typename decay<T>::type::template rebind_executor< executor_with_default<typename decay<T>::type::executor_type> >::other(BOOST_ASIO_MOVE_CAST(T)(object)); } }; /// 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 <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/detached.hpp> #endif // BOOST_ASIO_DETACHED_HPP system_context.hpp 0000644 00000005131 15125530236 0010347 0 ustar 00 // // system_context.hpp // ~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #include <boost/asio/detail/scheduler.hpp> #include <boost/asio/detail/thread_group.hpp> #include <boost/asio/execution.hpp> #include <boost/asio/execution_context.hpp> #include <boost/asio/detail/push_options.hpp> namespace boost { namespace asio { template <typename Blocking, typename Relationship, typename Allocator> class basic_system_executor; /// The executor context for the system executor. class system_context : public execution_context { public: /// The executor type associated with the context. typedef basic_system_executor< execution::blocking_t::possibly_t, execution::relationship_t::fork_t, std::allocator<void> > 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: template <typename, typename, typename> friend class basic_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_; // The number of threads in the pool. std::size_t num_threads_; }; } // namespace asio } // namespace boost #include <boost/asio/detail/pop_options.hpp> #include <boost/asio/impl/system_context.hpp> #if defined(BOOST_ASIO_HEADER_ONLY) # include <boost/asio/impl/system_context.ipp> #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // BOOST_ASIO_SYSTEM_CONTEXT_HPP basic_socket_streambuf.hpp 0000644 00000052321 15125530236 0011763 0 ustar 00 // // basic_socket_streambuf.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, 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 <boost/asio/detail/config.hpp> #if !defined(BOOST_ASIO_NO_IOSTREAM) #include <streambuf> #include <vector> #include <boost/asio/basic_socket.hpp> #include <boost/asio/basic_stream_socket.hpp> #include <boost/asio/detail/buffer_sequence_adapter.hpp> #include <boost/asio/detail/memory.hpp> #include <boost/asio/detail/throw_error.hpp> #include <boost/asio/io_context.hpp> #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) # include <boost/asio/detail/deadline_timer_service.hpp> #else // defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) // && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) # include <boost/asio/steady_timer.hpp> #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 <boost/asio/detail/variadic_templates.hpp> // A macro that should expand to: // template <typename T1, ..., typename Tn> // 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 <BOOST_ASIO_VARIADIC_TPARAMS(n)> \ 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 <boost/asio/detail/push_options.hpp> 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<io_context> 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<char> get_buffer_; std::vector<char> 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 <typename Protocol, #if defined(BOOST_ASIO_HAS_BOOST_DATE_TIME) \ && defined(BOOST_ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM) typename Clock = boost::posix_time::ptime, typename WaitTraits = time_traits<Clock> > #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<Clock> > #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 <typename Protocol, typename Clock = chrono::steady_clock, typename WaitTraits = wait_traits<Clock> > #else // defined(GENERATING_DOCUMENTATION) template <typename Protocol, typename Clock, typename WaitTraits> #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<Protocol> #else // defined(BOOST_ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION) public basic_socket<Protocol> #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<Clock, WaitTraits> 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<Protocol>(*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<protocol_type> s) : detail::socket_streambuf_io_context(0), basic_socket<Protocol>(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<Protocol>(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 <typename T1, ..., typename TN> basic_socket_streambuf* connect(T1 t1, ..., TN tn); #elif defined(BOOST_ASIO_HAS_VARIADIC_TEMPLATES) template <typename... T> 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<Protocol>& 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<mutable_buffer, mutable_buffer> 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<std::size_t>(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<int>::max)()) msec = (std::numeric_limits<int>::max)(); else if (msec < 0) msec = 0; return static_cast<int>(msec); } template <typename EndpointSequence> void connect_to_endpoints(const EndpointSequence& endpoints) { this->connect_to_endpoints(endpoints.begin(), endpoints.end()); } template <typename EndpointIterator> 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 <boost/asio/detail/pop_options.hpp> #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
| ver. 1.6 |
Github
|
.
| PHP 8.2.30 | ??????????? ?????????: 0.6 |
proxy
|
phpinfo
|
???????????