// // detail/reactive_descriptor_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP #define BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) #include #if !defined(BOOST_ASIO_WINDOWS) \ && !defined(BOOST_ASIO_WINDOWS_RUNTIME) \ && !defined(__CYGWIN__) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace asio { namespace detail { class reactive_descriptor_service : public service_base { public: // The native type of a descriptor. typedef int native_handle_type; // The implementation type of the descriptor. class implementation_type : private boost::asio::detail::noncopyable { public: // Default constructor. implementation_type() : descriptor_(-1), state_(0) { } private: // Only this service will have access to the internal values. friend class reactive_descriptor_service; // The native descriptor representation. int descriptor_; // The current state of the descriptor. descriptor_ops::state_type state_; // Per-descriptor data used by the reactor. reactor::per_descriptor_data reactor_data_; }; // Constructor. BOOST_ASIO_DECL reactive_descriptor_service( boost::asio::io_context& io_context); // Destroy all user-defined handler objects owned by the service. BOOST_ASIO_DECL void shutdown(); // Construct a new descriptor implementation. BOOST_ASIO_DECL void construct(implementation_type& impl); // Move-construct a new descriptor implementation. BOOST_ASIO_DECL void move_construct(implementation_type& impl, implementation_type& other_impl); // Move-assign from another descriptor implementation. BOOST_ASIO_DECL void move_assign(implementation_type& impl, reactive_descriptor_service& other_service, implementation_type& other_impl); // Destroy a descriptor implementation. BOOST_ASIO_DECL void destroy(implementation_type& impl); // Assign a native descriptor to a descriptor implementation. BOOST_ASIO_DECL boost::system::error_code assign(implementation_type& impl, const native_handle_type& native_descriptor, boost::system::error_code& ec); // Determine whether the descriptor is open. bool is_open(const implementation_type& impl) const { return impl.descriptor_ != -1; } // Destroy a descriptor implementation. BOOST_ASIO_DECL boost::system::error_code close(implementation_type& impl, boost::system::error_code& ec); // Get the native descriptor representation. native_handle_type native_handle(const implementation_type& impl) const { return impl.descriptor_; } // Release ownership of the native descriptor representation. BOOST_ASIO_DECL native_handle_type release(implementation_type& impl); // Cancel all operations associated with the descriptor. BOOST_ASIO_DECL boost::system::error_code cancel(implementation_type& impl, boost::system::error_code& ec); // Perform an IO control command on the descriptor. template boost::system::error_code io_control(implementation_type& impl, IO_Control_Command& command, boost::system::error_code& ec) { descriptor_ops::ioctl(impl.descriptor_, impl.state_, command.name(), static_cast(command.data()), ec); return ec; } // Gets the non-blocking mode of the descriptor. bool non_blocking(const implementation_type& impl) const { return (impl.state_ & descriptor_ops::user_set_non_blocking) != 0; } // Sets the non-blocking mode of the descriptor. boost::system::error_code non_blocking(implementation_type& impl, bool mode, boost::system::error_code& ec) { descriptor_ops::set_user_non_blocking( impl.descriptor_, impl.state_, mode, ec); return ec; } // Gets the non-blocking mode of the native descriptor implementation. bool native_non_blocking(const implementation_type& impl) const { return (impl.state_ & descriptor_ops::internal_non_blocking) != 0; } // Sets the non-blocking mode of the native descriptor implementation. boost::system::error_code native_non_blocking(implementation_type& impl, bool mode, boost::system::error_code& ec) { descriptor_ops::set_internal_non_blocking( impl.descriptor_, impl.state_, mode, ec); return ec; } // Wait for the descriptor to become ready to read, ready to write, or to have // pending error conditions. boost::system::error_code wait(implementation_type& impl, posix::descriptor_base::wait_type w, boost::system::error_code& ec) { switch (w) { case posix::descriptor_base::wait_read: descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec); break; case posix::descriptor_base::wait_write: descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec); break; case posix::descriptor_base::wait_error: descriptor_ops::poll_error(impl.descriptor_, impl.state_, ec); break; default: ec = boost::asio::error::invalid_argument; break; } return ec; } // Asynchronously wait for the descriptor to become ready to read, ready to // write, or to have pending error conditions. template void async_wait(implementation_type& impl, posix::descriptor_base::wait_type w, Handler& handler) { bool is_continuation = boost_asio_handler_cont_helpers::is_continuation(handler); // Allocate and construct an operation to wrap the handler. typedef reactive_wait_op op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", &impl, impl.descriptor_, "async_wait")); int op_type; switch (w) { case posix::descriptor_base::wait_read: op_type = reactor::read_op; break; case posix::descriptor_base::wait_write: op_type = reactor::write_op; break; case posix::descriptor_base::wait_error: op_type = reactor::except_op; break; default: p.p->ec_ = boost::asio::error::invalid_argument; reactor_.post_immediate_completion(p.p, is_continuation); p.v = p.p = 0; return; } start_op(impl, op_type, p.p, is_continuation, false, false); p.v = p.p = 0; } // Write some data to the descriptor. template size_t write_some(implementation_type& impl, const ConstBufferSequence& buffers, boost::system::error_code& ec) { buffer_sequence_adapter bufs(buffers); return descriptor_ops::sync_write(impl.descriptor_, impl.state_, bufs.buffers(), bufs.count(), bufs.all_empty(), ec); } // Wait until data can be written without blocking. size_t write_some(implementation_type& impl, const null_buffers&, boost::system::error_code& ec) { // Wait for descriptor to become ready. descriptor_ops::poll_write(impl.descriptor_, impl.state_, ec); return 0; } // Start an asynchronous write. The data being sent must be valid for the // lifetime of the asynchronous operation. template void async_write_some(implementation_type& impl, const ConstBufferSequence& buffers, Handler& handler) { bool is_continuation = boost_asio_handler_cont_helpers::is_continuation(handler); // Allocate and construct an operation to wrap the handler. typedef descriptor_write_op op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.descriptor_, buffers, handler); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", &impl, impl.descriptor_, "async_write_some")); start_op(impl, reactor::write_op, p.p, is_continuation, true, buffer_sequence_adapter::all_empty(buffers)); p.v = p.p = 0; } // Start an asynchronous wait until data can be written without blocking. template void async_write_some(implementation_type& impl, const null_buffers&, Handler& handler) { bool is_continuation = boost_asio_handler_cont_helpers::is_continuation(handler); // Allocate and construct an operation to wrap the handler. typedef reactive_null_buffers_op op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", &impl, impl.descriptor_, "async_write_some(null_buffers)")); start_op(impl, reactor::write_op, p.p, is_continuation, false, false); p.v = p.p = 0; } // Read some data from the stream. Returns the number of bytes read. template size_t read_some(implementation_type& impl, const MutableBufferSequence& buffers, boost::system::error_code& ec) { buffer_sequence_adapter bufs(buffers); return descriptor_ops::sync_read(impl.descriptor_, impl.state_, bufs.buffers(), bufs.count(), bufs.all_empty(), ec); } // Wait until data can be read without blocking. size_t read_some(implementation_type& impl, const null_buffers&, boost::system::error_code& ec) { // Wait for descriptor to become ready. descriptor_ops::poll_read(impl.descriptor_, impl.state_, ec); return 0; } // Start an asynchronous read. The buffer for the data being read must be // valid for the lifetime of the asynchronous operation. template void async_read_some(implementation_type& impl, const MutableBufferSequence& buffers, Handler& handler) { bool is_continuation = boost_asio_handler_cont_helpers::is_continuation(handler); // Allocate and construct an operation to wrap the handler. typedef descriptor_read_op op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(impl.descriptor_, buffers, handler); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", &impl, impl.descriptor_, "async_read_some")); start_op(impl, reactor::read_op, p.p, is_continuation, true, buffer_sequence_adapter::all_empty(buffers)); p.v = p.p = 0; } // Wait until data can be read without blocking. template void async_read_some(implementation_type& impl, const null_buffers&, Handler& handler) { bool is_continuation = boost_asio_handler_cont_helpers::is_continuation(handler); // Allocate and construct an operation to wrap the handler. typedef reactive_null_buffers_op op; typename op::ptr p = { boost::asio::detail::addressof(handler), op::ptr::allocate(handler), 0 }; p.p = new (p.v) op(handler); BOOST_ASIO_HANDLER_CREATION((reactor_.context(), *p.p, "descriptor", &impl, impl.descriptor_, "async_read_some(null_buffers)")); start_op(impl, reactor::read_op, p.p, is_continuation, false, false); p.v = p.p = 0; } private: // Start the asynchronous operation. BOOST_ASIO_DECL void start_op(implementation_type& impl, int op_type, reactor_op* op, bool is_continuation, bool is_non_blocking, bool noop); // The selector that performs event demultiplexing for the service. reactor& reactor_; }; } // namespace detail } // namespace asio } // namespace boost #include #if defined(BOOST_ASIO_HEADER_ONLY) # include #endif // defined(BOOST_ASIO_HEADER_ONLY) #endif // !defined(BOOST_ASIO_WINDOWS) // && !defined(BOOST_ASIO_WINDOWS_RUNTIME) // && !defined(__CYGWIN__) #endif // BOOST_ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP