diff --git a/asio/include/Makefile.am b/asio/include/Makefile.am index e7fa5707..e70c45be 100644 --- a/asio/include/Makefile.am +++ b/asio/include/Makefile.am @@ -26,6 +26,7 @@ nobase_include_HEADERS = \ asio/detail/consuming_buffers.hpp \ asio/detail/const_buffers_iterator.hpp \ asio/detail/deadline_timer_service.hpp \ + asio/detail/descriptor_ops.hpp \ asio/detail/dev_poll_reactor.hpp \ asio/detail/dev_poll_reactor_fwd.hpp \ asio/detail/epoll_reactor.hpp \ @@ -58,6 +59,7 @@ nobase_include_HEADERS = \ asio/detail/posix_tss_ptr.hpp \ asio/detail/push_options.hpp \ asio/detail/reactive_socket_service.hpp \ + asio/detail/reactive_descriptor_service.hpp \ asio/detail/reactor_op_queue.hpp \ asio/detail/resolver_service.hpp \ asio/detail/scoped_lock.hpp \ @@ -130,6 +132,11 @@ nobase_include_HEADERS = \ asio/local/datagram_protocol.hpp \ asio/local/stream_protocol.hpp \ asio/placeholders.hpp \ + asio/posix/basic_descriptor.hpp \ + asio/posix/basic_stream_descriptor.hpp \ + asio/posix/descriptor_base.hpp \ + asio/posix/stream_descriptor.hpp \ + asio/posix/stream_descriptor_service.hpp \ asio/read.hpp \ asio/read_until.hpp \ asio/socket_acceptor_service.hpp \ diff --git a/asio/include/asio.hpp b/asio/include/asio.hpp index 3b22b8b2..92a0b4b3 100644 --- a/asio/include/asio.hpp +++ b/asio/include/asio.hpp @@ -62,6 +62,11 @@ #include "asio/local/datagram_protocol.hpp" #include "asio/local/stream_protocol.hpp" #include "asio/placeholders.hpp" +#include "asio/posix/basic_descriptor.hpp" +#include "asio/posix/basic_stream_descriptor.hpp" +#include "asio/posix/descriptor_base.hpp" +#include "asio/posix/stream_descriptor.hpp" +#include "asio/posix/stream_descriptor_service.hpp" #include "asio/read.hpp" #include "asio/read_until.hpp" #include "asio/socket_acceptor_service.hpp" diff --git a/asio/include/asio/detail/descriptor_ops.hpp b/asio/include/asio/detail/descriptor_ops.hpp new file mode 100644 index 00000000..8a434d39 --- /dev/null +++ b/asio/include/asio/detail/descriptor_ops.hpp @@ -0,0 +1,119 @@ +// +// descriptor_ops.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_DESCRIPTOR_OPS_HPP +#define ASIO_DETAIL_DESCRIPTOR_OPS_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +#include "asio/detail/push_options.hpp" +#include +#include +#include "asio/detail/pop_options.hpp" + +#include "asio/error.hpp" +#include "asio/detail/socket_types.hpp" + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +namespace asio { +namespace detail { +namespace descriptor_ops { + +inline void clear_error(asio::error_code& ec) +{ + errno = 0; + ec = asio::error_code(); +} + +template +inline ReturnType error_wrapper(ReturnType return_value, + asio::error_code& ec) +{ + ec = asio::error_code(errno, + asio::error::get_system_category()); + return return_value; +} + +inline int close(int d, asio::error_code& ec) +{ + clear_error(ec); + return error_wrapper(::close(d), ec); +} + +typedef iovec buf; + +inline void init_buf(buf& b, void* data, size_t size) +{ + b.iov_base = data; + b.iov_len = size; +} + +inline void init_buf(buf& b, const void* data, size_t size) +{ + b.iov_base = const_cast(data); + b.iov_len = size; +} + +inline int readv(int d, buf* bufs, size_t count, asio::error_code& ec) +{ + clear_error(ec); + return error_wrapper(::readv(d, bufs, static_cast(count)), ec); +} + +inline int writev(int d, const buf* bufs, size_t count, + asio::error_code& ec) +{ + clear_error(ec); + return error_wrapper(::writev(d, bufs, static_cast(count)), ec); +} + +inline int ioctl(int d, long cmd, ioctl_arg_type* arg, + asio::error_code& ec) +{ + clear_error(ec); + return error_wrapper(::ioctl(d, cmd, arg), ec); +} + +inline int poll_read(int d, asio::error_code& ec) +{ + clear_error(ec); + pollfd fds; + fds.fd = d; + fds.events = POLLIN; + fds.revents = 0; + clear_error(ec); + return error_wrapper(::poll(&fds, 1, -1), ec); +} + +inline int poll_write(int d, asio::error_code& ec) +{ + clear_error(ec); + pollfd fds; + fds.fd = d; + fds.events = POLLOUT; + fds.revents = 0; + clear_error(ec); + return error_wrapper(::poll(&fds, 1, -1), ec); +} + +} // namespace descriptor_ops +} // namespace detail +} // namespace asio + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_DESCRIPTOR_OPS_HPP diff --git a/asio/include/asio/detail/reactive_descriptor_service.hpp b/asio/include/asio/detail/reactive_descriptor_service.hpp new file mode 100644 index 00000000..85fe1e22 --- /dev/null +++ b/asio/include/asio/detail/reactive_descriptor_service.hpp @@ -0,0 +1,682 @@ +// +// reactive_descriptor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP +#define ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +#include "asio/buffer.hpp" +#include "asio/error.hpp" +#include "asio/io_service.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/service_base.hpp" +#include "asio/detail/descriptor_ops.hpp" + +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +namespace asio { +namespace detail { + +template +class reactive_descriptor_service + : public asio::detail::service_base< + reactive_descriptor_service > +{ +public: + // The native type of a descriptor. + typedef int native_type; + + // The implementation type of the descriptor. + class implementation_type + : private asio::detail::noncopyable + { + public: + // Default constructor. + implementation_type() + : descriptor_(-1), + flags_(0) + { + } + + private: + // Only this service will have access to the internal values. + friend class reactive_descriptor_service; + + // The native descriptor representation. + int descriptor_; + + enum + { + user_set_non_blocking = 1, // The user wants a non-blocking descriptor. + internal_non_blocking = 2 // The descriptor has been set non-blocking. + }; + + // Flags indicating the current state of the descriptor. + unsigned char flags_; + }; + + // The maximum number of buffers to support in a single operation. + enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; + + // Constructor. + reactive_descriptor_service(asio::io_service& io_service) + : asio::detail::service_base< + reactive_descriptor_service >(io_service), + reactor_(asio::use_service(io_service)) + { + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + } + + // Construct a new descriptor implementation. + void construct(implementation_type& impl) + { + impl.descriptor_ = -1; + impl.flags_ = 0; + } + + // Destroy a descriptor implementation. + void destroy(implementation_type& impl) + { + if (impl.descriptor_ != -1) + { + reactor_.close_descriptor(impl.descriptor_); + + if (impl.flags_ & implementation_type::internal_non_blocking) + { + ioctl_arg_type non_blocking = 0; + asio::error_code ignored_ec; + descriptor_ops::ioctl(impl.descriptor_, + FIONBIO, &non_blocking, ignored_ec); + impl.flags_ &= ~implementation_type::internal_non_blocking; + } + + asio::error_code ignored_ec; + descriptor_ops::close(impl.descriptor_, ignored_ec); + + impl.descriptor_ = -1; + } + } + + // Assign a native descriptor to a descriptor implementation. + asio::error_code assign(implementation_type& impl, + const native_type& native_descriptor, asio::error_code& ec) + { + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } + + if (int err = reactor_.register_descriptor(native_descriptor)) + { + ec = asio::error_code(err, + asio::error::get_system_category()); + return ec; + } + + impl.descriptor_ = native_descriptor; + impl.flags_ = 0; + ec = asio::error_code(); + return ec; + } + + // Determine whether the descriptor is open. + bool is_open(const implementation_type& impl) const + { + return impl.descriptor_ != -1; + } + + // Destroy a descriptor implementation. + asio::error_code close(implementation_type& impl, + asio::error_code& ec) + { + if (is_open(impl)) + { + reactor_.close_descriptor(impl.descriptor_); + + if (impl.flags_ & implementation_type::internal_non_blocking) + { + ioctl_arg_type non_blocking = 0; + asio::error_code ignored_ec; + descriptor_ops::ioctl(impl.descriptor_, + FIONBIO, &non_blocking, ignored_ec); + impl.flags_ &= ~implementation_type::internal_non_blocking; + } + + if (descriptor_ops::close(impl.descriptor_, ec) == -1) + return ec; + + impl.descriptor_ = -1; + } + + ec = asio::error_code(); + return ec; + } + + // Get the native descriptor representation. + native_type native(implementation_type& impl) + { + return impl.descriptor_; + } + + // Cancel all operations associated with the descriptor. + asio::error_code cancel(implementation_type& impl, + asio::error_code& ec) + { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + reactor_.cancel_ops(impl.descriptor_); + ec = asio::error_code(); + return ec; + } + + // Perform an IO control command on the descriptor. + template + asio::error_code io_control(implementation_type& impl, + IO_Control_Command& command, asio::error_code& ec) + { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + if (command.name() == static_cast(FIONBIO)) + { + if (command.get()) + impl.flags_ |= implementation_type::user_set_non_blocking; + else + impl.flags_ &= ~implementation_type::user_set_non_blocking; + ec = asio::error_code(); + } + else + { + descriptor_ops::ioctl(impl.descriptor_, command.name(), + static_cast(command.data()), ec); + } + return ec; + } + + // Write some data to the descriptor. + template + size_t write_some(implementation_type& impl, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // Copy buffers into array. + descriptor_ops::buf bufs[max_buffers]; + typename ConstBufferSequence::const_iterator iter = buffers.begin(); + typename ConstBufferSequence::const_iterator end = buffers.end(); + size_t i = 0; + size_t total_buffer_size = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + asio::const_buffer buffer(*iter); + descriptor_ops::init_buf(bufs[i], + asio::buffer_cast(buffer), + asio::buffer_size(buffer)); + total_buffer_size += asio::buffer_size(buffer); + } + + // A request to read_some 0 bytes on a stream is a no-op. + if (total_buffer_size == 0) + { + ec = asio::error_code(); + return 0; + } + + // Make descriptor non-blocking if user wants non-blocking. + if (impl.flags_ & implementation_type::user_set_non_blocking) + { + if (!(impl.flags_ & implementation_type::internal_non_blocking)) + { + ioctl_arg_type non_blocking = 1; + if (descriptor_ops::ioctl(impl.descriptor_, + FIONBIO, &non_blocking, ec)) + return 0; + impl.flags_ |= implementation_type::internal_non_blocking; + } + } + + // Send the data. + for (;;) + { + // Try to complete the operation without blocking. + int bytes_sent = descriptor_ops::writev(impl.descriptor_, bufs, i, ec); + + // Check if operation succeeded. + if (bytes_sent >= 0) + return bytes_sent; + + // Operation failed. + if ((impl.flags_ & implementation_type::user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_write(impl.descriptor_, ec) < 0) + return 0; + } + } + + // Wait until data can be written without blocking. + size_t write_some(implementation_type& impl, + const null_buffers&, asio::error_code& ec) + { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // Wait for descriptor to become ready. + descriptor_ops::poll_write(impl.descriptor_, ec); + + return 0; + } + + template + class write_handler + { + public: + write_handler(int descriptor, asio::io_service& io_service, + const ConstBufferSequence& buffers, Handler handler) + : descriptor_(descriptor), + io_service_(io_service), + work_(io_service), + buffers_(buffers), + handler_(handler) + { + } + + bool operator()(const asio::error_code& result) + { + // Check whether the operation was successful. + if (result) + { + io_service_.post(bind_handler(handler_, result, 0)); + return true; + } + + // Copy buffers into array. + descriptor_ops::buf bufs[max_buffers]; + typename ConstBufferSequence::const_iterator iter = buffers_.begin(); + typename ConstBufferSequence::const_iterator end = buffers_.end(); + size_t i = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + asio::const_buffer buffer(*iter); + descriptor_ops::init_buf(bufs[i], + asio::buffer_cast(buffer), + asio::buffer_size(buffer)); + } + + // Write the data. + asio::error_code ec; + int bytes = descriptor_ops::writev(descriptor_, bufs, i, ec); + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + io_service_.post(bind_handler(handler_, ec, bytes < 0 ? 0 : bytes)); + return true; + } + + private: + int descriptor_; + asio::io_service& io_service_; + asio::io_service::work work_; + ConstBufferSequence buffers_; + Handler handler_; + }; + + // 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) + { + if (!is_open(impl)) + { + this->get_io_service().post(bind_handler(handler, + asio::error::bad_descriptor, 0)); + } + else + { + // Determine total size of buffers. + typename ConstBufferSequence::const_iterator iter = buffers.begin(); + typename ConstBufferSequence::const_iterator end = buffers.end(); + size_t i = 0; + size_t total_buffer_size = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + asio::const_buffer buffer(*iter); + total_buffer_size += asio::buffer_size(buffer); + } + + // A request to read_some 0 bytes on a stream is a no-op. + if (total_buffer_size == 0) + { + this->get_io_service().post(bind_handler(handler, + asio::error_code(), 0)); + return; + } + + // Make descriptor non-blocking. + if (!(impl.flags_ & implementation_type::internal_non_blocking)) + { + ioctl_arg_type non_blocking = 1; + asio::error_code ec; + if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec)) + { + this->get_io_service().post(bind_handler(handler, ec, 0)); + return; + } + impl.flags_ |= implementation_type::internal_non_blocking; + } + + reactor_.start_write_op(impl.descriptor_, + write_handler( + impl.descriptor_, this->get_io_service(), buffers, handler)); + } + } + + template + class null_buffers_handler + { + public: + null_buffers_handler(asio::io_service& io_service, Handler handler) + : work_(io_service), + handler_(handler) + { + } + + bool operator()(const asio::error_code& result) + { + work_.get_io_service().post(bind_handler(handler_, result, 0)); + return true; + } + + private: + asio::io_service::work work_; + Handler handler_; + }; + + // Start an asynchronous wait until data can be written without blocking. + template + void async_write_some(implementation_type& impl, + const null_buffers&, Handler handler) + { + if (!is_open(impl)) + { + this->get_io_service().post(bind_handler(handler, + asio::error::bad_descriptor, 0)); + } + else + { + reactor_.start_write_op(impl.descriptor_, + null_buffers_handler(this->get_io_service(), handler), + false); + } + } + + // Read some data from the stream. Returns the number of bytes read. + template + size_t read_some(implementation_type& impl, + const MutableBufferSequence& buffers, asio::error_code& ec) + { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // Copy buffers into array. + descriptor_ops::buf bufs[max_buffers]; + typename MutableBufferSequence::const_iterator iter = buffers.begin(); + typename MutableBufferSequence::const_iterator end = buffers.end(); + size_t i = 0; + size_t total_buffer_size = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + asio::mutable_buffer buffer(*iter); + descriptor_ops::init_buf(bufs[i], + asio::buffer_cast(buffer), + asio::buffer_size(buffer)); + total_buffer_size += asio::buffer_size(buffer); + } + + // A request to read_some 0 bytes on a stream is a no-op. + if (total_buffer_size == 0) + { + ec = asio::error_code(); + return 0; + } + + // Make descriptor non-blocking if user wants non-blocking. + if (impl.flags_ & implementation_type::user_set_non_blocking) + { + if (!(impl.flags_ & implementation_type::internal_non_blocking)) + { + ioctl_arg_type non_blocking = 1; + if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec)) + return 0; + impl.flags_ |= implementation_type::internal_non_blocking; + } + } + + // Read some data. + for (;;) + { + // Try to complete the operation without blocking. + int bytes_read = descriptor_ops::readv(impl.descriptor_, bufs, i, ec); + + // Check if operation succeeded. + if (bytes_read > 0) + return bytes_read; + + // Check for EOF. + if (bytes_read == 0) + { + ec = asio::error::eof; + return 0; + } + + // Operation failed. + if ((impl.flags_ & implementation_type::user_set_non_blocking) + || (ec != asio::error::would_block + && ec != asio::error::try_again)) + return 0; + + // Wait for descriptor to become ready. + if (descriptor_ops::poll_read(impl.descriptor_, ec) < 0) + return 0; + } + } + + // Wait until data can be read without blocking. + size_t read_some(implementation_type& impl, + const null_buffers& buffers, asio::error_code& ec) + { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + + // Wait for descriptor to become ready. + descriptor_ops::poll_read(impl.descriptor_, ec); + + return 0; + } + + template + class read_handler + { + public: + read_handler(int descriptor, asio::io_service& io_service, + const MutableBufferSequence& buffers, Handler handler) + : descriptor_(descriptor), + io_service_(io_service), + work_(io_service), + buffers_(buffers), + handler_(handler) + { + } + + bool operator()(const asio::error_code& result) + { + // Check whether the operation was successful. + if (result) + { + io_service_.post(bind_handler(handler_, result, 0)); + return true; + } + + // Copy buffers into array. + descriptor_ops::buf bufs[max_buffers]; + typename MutableBufferSequence::const_iterator iter = buffers_.begin(); + typename MutableBufferSequence::const_iterator end = buffers_.end(); + size_t i = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + asio::mutable_buffer buffer(*iter); + descriptor_ops::init_buf(bufs[i], + asio::buffer_cast(buffer), + asio::buffer_size(buffer)); + } + + // Read some data. + asio::error_code ec; + int bytes = descriptor_ops::readv(descriptor_, bufs, i, ec); + if (bytes == 0) + ec = asio::error::eof; + + // Check if we need to run the operation again. + if (ec == asio::error::would_block + || ec == asio::error::try_again) + return false; + + io_service_.post(bind_handler(handler_, ec, bytes < 0 ? 0 : bytes)); + return true; + } + + private: + int descriptor_; + asio::io_service& io_service_; + asio::io_service::work work_; + MutableBufferSequence buffers_; + Handler handler_; + }; + + // 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) + { + if (!is_open(impl)) + { + this->get_io_service().post(bind_handler(handler, + asio::error::bad_descriptor, 0)); + } + else + { + // Determine total size of buffers. + typename MutableBufferSequence::const_iterator iter = buffers.begin(); + typename MutableBufferSequence::const_iterator end = buffers.end(); + size_t i = 0; + size_t total_buffer_size = 0; + for (; iter != end && i < max_buffers; ++iter, ++i) + { + asio::mutable_buffer buffer(*iter); + total_buffer_size += asio::buffer_size(buffer); + } + + // A request to read_some 0 bytes on a stream is a no-op. + if (total_buffer_size == 0) + { + this->get_io_service().post(bind_handler(handler, + asio::error_code(), 0)); + return; + } + + // Make descriptor non-blocking. + if (!(impl.flags_ & implementation_type::internal_non_blocking)) + { + ioctl_arg_type non_blocking = 1; + asio::error_code ec; + if (descriptor_ops::ioctl(impl.descriptor_, FIONBIO, &non_blocking, ec)) + { + this->get_io_service().post(bind_handler(handler, ec, 0)); + return; + } + impl.flags_ |= implementation_type::internal_non_blocking; + } + + reactor_.start_read_op(impl.descriptor_, + read_handler( + impl.descriptor_, this->get_io_service(), buffers, handler)); + } + } + + // Wait until data can be read without blocking. + template + void async_read_some(implementation_type& impl, + const null_buffers&, Handler handler) + { + if (!is_open(impl)) + { + this->get_io_service().post(bind_handler(handler, + asio::error::bad_descriptor, 0)); + } + else + { + reactor_.start_read_op(impl.descriptor_, + null_buffers_handler(this->get_io_service(), handler), + false); + } + } + +private: + // The selector that performs event demultiplexing for the service. + Reactor& reactor_; +}; + +} // namespace detail +} // namespace asio + +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_REACTIVE_DESCRIPTOR_SERVICE_HPP diff --git a/asio/include/asio/posix/basic_descriptor.hpp b/asio/include/asio/posix/basic_descriptor.hpp new file mode 100644 index 00000000..a2b8ba9e --- /dev/null +++ b/asio/include/asio/posix/basic_descriptor.hpp @@ -0,0 +1,277 @@ +// +// basic_descriptor.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_POSIX_BASIC_DESCRIPTOR_HPP +#define ASIO_POSIX_BASIC_DESCRIPTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +#include "asio/detail/push_options.hpp" +#include +#include "asio/detail/pop_options.hpp" + +#include "asio/basic_io_object.hpp" +#include "asio/error.hpp" +#include "asio/posix/descriptor_base.hpp" +#include "asio/detail/throw_error.hpp" + +namespace asio { +namespace posix { + +/// Provides Windows descriptor functionality. +/** + * The posix::basic_descriptor class template provides the ability to wrap a + * Windows descriptor. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template +class basic_descriptor + : public basic_io_object, + public descriptor_base +{ +public: + /// The native representation of a descriptor. + typedef typename Descriptorservice::native_type native_type; + + /// A basic_descriptor is always the lowest layer. + typedef basic_descriptor lowest_layer_type; + + /// Construct a basic_descriptor without opening it. + /** + * This constructor creates a descriptor without opening it. + * + * @param io_service The io_service object that the descriptor will use to + * dispatch descriptorrs for any asynchronous operations performed on the descriptor. + */ + explicit basic_descriptor(asio::io_service& io_service) + : basic_io_object(io_service) + { + } + + /// Construct a basic_descriptor on an existing native descriptor. + /** + * This constructor creates a descriptor object to hold an existing native descriptor. + * + * @param io_service The io_service object that the descriptor will use to + * dispatch descriptorrs for any asynchronous operations performed on the descriptor. + * + * @param native_descriptor A native descriptor. + * + * @throws asio::system_error Thrown on failure. + */ + basic_descriptor(asio::io_service& io_service, + const native_type& native_descriptor) + : basic_io_object(io_service) + { + asio::error_code ec; + this->service.assign(this->implementation, native_descriptor, ec); + asio::detail::throw_error(ec); + } + + /// Get a reference to the lowest layer. + /** + * This function returns a reference to the lowest layer in a stack of + * layers. Since a basic_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; + } + + /// 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 asio::system_error Thrown on failure. + */ + void assign(const native_type& native_descriptor) + { + asio::error_code ec; + this->service.assign(this->implementation, native_descriptor, ec); + asio::detail::throw_error(ec); + } + + /// 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. + */ + asio::error_code assign(const native_type& native_descriptor, + asio::error_code& ec) + { + return this->service.assign(this->implementation, native_descriptor, ec); + } + + /// Determine whether the descriptor is open. + bool is_open() const + { + return this->service.is_open(this->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 + * asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. + */ + void close() + { + asio::error_code ec; + this->service.close(this->implementation, ec); + asio::detail::throw_error(ec); + } + + /// 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 + * asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + asio::error_code close(asio::error_code& ec) + { + return this->service.close(this->implementation, 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_type native() + { + return this->service.native(this->implementation); + } + + /// Cancel all asynchronous operations associated with the descriptor. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the descriptorrs for cancelled operations will be + * passed the asio::error::operation_aborted error. + * + * @throws asio::system_error Thrown on failure. + */ + void cancel() + { + asio::error_code ec; + this->service.cancel(this->implementation, ec); + asio::detail::throw_error(ec); + } + + /// Cancel all asynchronous operations associated with the descriptor. + /** + * This function causes all outstanding asynchronous read or write operations + * to finish immediately, and the descriptorrs for cancelled operations will be + * passed the asio::error::operation_aborted error. + * + * @param ec Set to indicate what error occurred, if any. + */ + asio::error_code cancel(asio::error_code& ec) + { + return this->service.cancel(this->implementation, 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 asio::system_error Thrown on failure. + * + * @sa IoControlCommand @n + * asio::posix::descriptor_base::bytes_readable @n + * asio::posix::descriptor_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * asio::posix::stream_descriptor descriptor(io_service); + * ... + * asio::posix::stream_descriptor::bytes_readable command; + * descriptor.io_control(command); + * std::size_t bytes_readable = command.get(); + * @endcode + */ + template + void io_control(IoControlCommand& command) + { + asio::error_code ec; + this->service.io_control(this->implementation, command, ec); + asio::detail::throw_error(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. + * + * @param ec Set to indicate what error occurred, if any. + * + * @sa IoControlCommand @n + * asio::posix::descriptor_base::bytes_readable @n + * asio::posix::descriptor_base::non_blocking_io + * + * @par Example + * Getting the number of bytes ready to read: + * @code + * asio::posix::stream_descriptor descriptor(io_service); + * ... + * asio::posix::stream_descriptor::bytes_readable command; + * asio::error_code ec; + * descriptor.io_control(command, ec); + * if (ec) + * { + * // An error occurred. + * } + * std::size_t bytes_readable = command.get(); + * @endcode + */ + template + asio::error_code io_control(IoControlCommand& command, + asio::error_code& ec) + { + return this->service.io_control(this->implementation, command, ec); + } + +protected: + /// Protected destructor to prevent deletion through this type. + ~basic_descriptor() + { + } +}; + +} // namespace posix +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_POSIX_BASIC_DESCRIPTOR_HPP diff --git a/asio/include/asio/posix/basic_stream_descriptor.hpp b/asio/include/asio/posix/basic_stream_descriptor.hpp new file mode 100644 index 00000000..b91c7778 --- /dev/null +++ b/asio/include/asio/posix/basic_stream_descriptor.hpp @@ -0,0 +1,300 @@ +// +// basic_stream_descriptor.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP +#define ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +#include "asio/detail/push_options.hpp" +#include +#include +#include "asio/detail/pop_options.hpp" + +#include "asio/error.hpp" +#include "asio/posix/basic_descriptor.hpp" +#include "asio/posix/stream_descriptor_service.hpp" +#include "asio/detail/throw_error.hpp" + +#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + +namespace asio { +namespace posix { + +/// Provides stream-oriented descriptor functionality. +/** + * The posix::basic_stream_descriptor class template provides asynchronous and + * blocking stream-oriented descriptor functionality. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + * + * @par Concepts: + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. + */ +template +class basic_stream_descriptor + : public basic_descriptor +{ +public: + /// The native representation of a descriptor. + typedef typename StreamDescriptorservice::native_type native_type; + + /// Construct a basic_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 io_service The io_service object that the stream descriptor will use to + * dispatch descriptorrs for any asynchronous operations performed on the descriptor. + */ + explicit basic_stream_descriptor(asio::io_service& io_service) + : basic_descriptor(io_service) + { + } + + /// Construct a basic_stream_descriptor on an existing native descriptor. + /** + * This constructor creates a stream descriptor object to hold an existing native + * descriptor. + * + * @param io_service The io_service object that the stream descriptor will use to + * dispatch descriptorrs for any asynchronous operations performed on the descriptor. + * + * @param native_descriptor The new underlying descriptor implementation. + * + * @throws asio::system_error Thrown on failure. + */ + basic_stream_descriptor(asio::io_service& io_service, + const native_type& native_descriptor) + : basic_descriptor(io_service, native_descriptor) + { + } + + /// 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 asio::system_error Thrown on failure. An error code of + * 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(asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on writing multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t write_some(const ConstBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->service.write_some(this->implementation, buffers, ec); + asio::detail::throw_error(ec); + return s; + } + + /// Write some data to the descriptor. + /** + * This function is used to write data to the stream descriptor. The function call + * will block until one or more bytes of the data has been written + * successfully, or until an error occurs. + * + * @param buffers One or more data buffers to be written to the descriptor. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes written. Returns 0 if an error occurred. + * + * @note The write_some operation may not transmit all of the data to the + * peer. Consider using the @ref write function if you need to ensure that + * all data is written before the blocking operation completes. + */ + template + std::size_t write_some(const ConstBufferSequence& buffers, + asio::error_code& ec) + { + return this->service.write_some(this->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 descriptorr is called. + * + * @param descriptorr The descriptorr to be called when the write operation completes. + * Copies will be made of the descriptorr as required. The function signature of + * the descriptorr must be: + * @code void descriptorr( + * const asio::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 descriptorr will not be invoked from within this function. Invocation + * of the descriptorr will be performed in a manner equivalent to using + * asio::io_service::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(asio::buffer(data, size), descriptorr); + * @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 + void async_write_some(const ConstBufferSequence& buffers, + WriteHandler descriptorr) + { + this->service.async_write_some(this->implementation, buffers, descriptorr); + } + + /// 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 asio::system_error Thrown on failure. An error code of + * 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(asio::buffer(data, size)); + * @endcode + * See the @ref buffer documentation for information on reading into multiple + * buffers in one go, and how to use it with arrays, boost::array or + * std::vector. + */ + template + std::size_t read_some(const MutableBufferSequence& buffers) + { + asio::error_code ec; + std::size_t s = this->service.read_some(this->implementation, buffers, ec); + asio::detail::throw_error(ec); + return s; + } + + /// Read some data from the descriptor. + /** + * This function is used to read data from the stream descriptor. The function + * call will block until one or more bytes of data has been read successfully, + * or until an error occurs. + * + * @param buffers One or more buffers into which the data will be read. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns The number of bytes read. Returns 0 if an error occurred. + * + * @note The read_some operation may not read all of the requested number of + * bytes. Consider using the @ref read function if you need to ensure that + * the requested amount of data is read before the blocking operation + * completes. + */ + template + std::size_t read_some(const MutableBufferSequence& buffers, + asio::error_code& ec) + { + return this->service.read_some(this->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 descriptorr is called. + * + * @param descriptorr The descriptorr to be called when the read operation completes. + * Copies will be made of the descriptorr as required. The function signature of + * the descriptorr must be: + * @code void descriptorr( + * const asio::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 descriptorr will not be invoked from within this function. Invocation + * of the descriptorr will be performed in a manner equivalent to using + * asio::io_service::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(asio::buffer(data, size), descriptorr); + * @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 + void async_read_some(const MutableBufferSequence& buffers, + ReadHandler descriptorr) + { + this->service.async_read_some(this->implementation, buffers, descriptorr); + } +}; + +} // namespace posix +} // namespace asio + +#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_POSIX_BASIC_STREAM_DESCRIPTOR_HPP diff --git a/asio/include/asio/posix/descriptor_base.hpp b/asio/include/asio/posix/descriptor_base.hpp new file mode 100644 index 00000000..6ea2738d --- /dev/null +++ b/asio/include/asio/posix/descriptor_base.hpp @@ -0,0 +1,93 @@ +// +// descriptor_base.hpp +// ~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_POSIX_DESCRIPTOR_BASE_HPP +#define ASIO_POSIX_DESCRIPTOR_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +#include "asio/detail/push_options.hpp" +#include +#include +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/io_control.hpp" +#include "asio/detail/socket_option.hpp" + +namespace asio { +namespace posix { + +/// The descriptor_base class is used as a base for the basic_stream_descriptor +/// class template so that we have a common place to define the associated +/// IO control commands. +class descriptor_base +{ +public: + /// IO control command to set the blocking mode of the descriptor. + /** + * Implements the FIONBIO IO control command. + * + * @par Example + * @code + * asio::posix::stream_descriptor descriptor(io_service); + * ... + * asio::descriptor_base::non_blocking_io command(true); + * descriptor.io_control(command); + * @endcode + * + * @par Concepts: + * IoControlCommand. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined non_blocking_io; +#else + typedef asio::detail::io_control::non_blocking_io non_blocking_io; +#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 + * asio::posix::stream_descriptor descriptor(io_service); + * ... + * 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 asio::detail::io_control::bytes_readable bytes_readable; +#endif + +protected: + /// Protected destructor to prevent deletion through this type. + ~descriptor_base() + { + } +}; + +} // namespace posix +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_POSIX_DESCRIPTOR_BASE_HPP diff --git a/asio/include/asio/posix/stream_descriptor.hpp b/asio/include/asio/posix/stream_descriptor.hpp new file mode 100644 index 00000000..cdfbd47c --- /dev/null +++ b/asio/include/asio/posix/stream_descriptor.hpp @@ -0,0 +1,37 @@ +// +// stream_descriptor.hpp +// ~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_POSIX_STREAM_DESCRIPTOR_HPP +#define ASIO_POSIX_STREAM_DESCRIPTOR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +#include "asio/posix/basic_stream_descriptor.hpp" + +#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + +namespace asio { +namespace posix { + +/// Typedef for the typical usage of a stream-oriented descriptor. +typedef basic_stream_descriptor<> stream_descriptor; + +} // namespace posix +} // namespace asio + +#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_POSIX_STREAM_DESCRIPTOR_HPP diff --git a/asio/include/asio/posix/stream_descriptor_service.hpp b/asio/include/asio/posix/stream_descriptor_service.hpp new file mode 100644 index 00000000..a74e22ee --- /dev/null +++ b/asio/include/asio/posix/stream_descriptor_service.hpp @@ -0,0 +1,198 @@ +// +// stream_descriptor_service.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2008 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP +#define ASIO_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +#include "asio/detail/push_options.hpp" +#include +#include +#include "asio/detail/pop_options.hpp" + +#include "asio/error.hpp" +#include "asio/io_service.hpp" +#include "asio/detail/epoll_reactor.hpp" +#include "asio/detail/kqueue_reactor.hpp" +#include "asio/detail/select_reactor.hpp" +#include "asio/detail/service_base.hpp" +#include "asio/detail/reactive_descriptor_service.hpp" + +#if !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) +# if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +# define ASIO_HAS_POSIX_STREAM_DESCRIPTOR 1 +# endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#endif // !defined(ASIO_DISABLE_POSIX_STREAM_DESCRIPTOR) + +#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + +namespace asio { +namespace posix { + +/// Default service implementation for a stream descriptor. +class stream_descriptor_service +#if defined(GENERATING_DOCUMENTATION) + : public asio::io_service::service +#else + : public asio::detail::service_base +#endif +{ +public: +#if defined(GENERATING_DOCUMENTATION) + /// The unique service identifier. + static asio::io_service::id id; +#endif + +private: + // The type of the platform-specific implementation. +#if defined(ASIO_HAS_EPOLL) + typedef detail::reactive_descriptor_service< + detail::epoll_reactor > service_impl_type; +#elif defined(ASIO_HAS_KQUEUE) + typedef detail::reactive_descriptor_service< + detail::kqueue_reactor > service_impl_type; +#elif defined(ASIO_HAS_DEV_POLL) + typedef detail::reactive_descriptor_service< + detail::dev_poll_reactor > service_impl_type; +#else + typedef detail::reactive_descriptor_service< + detail::select_reactor > service_impl_type; +#endif + +public: + /// The type of a stream descriptor implementation. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined implementation_type; +#else + typedef service_impl_type::implementation_type implementation_type; +#endif + + /// The native descriptor type. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined native_type; +#else + typedef service_impl_type::native_type native_type; +#endif + + /// Construct a new stream descriptor service for the specified io_service. + explicit stream_descriptor_service(asio::io_service& io_service) + : asio::detail::service_base(io_service), + service_impl_(asio::use_service(io_service)) + { + } + + /// Destroy all user-defined descriptorr objects owned by the service. + void shutdown_service() + { + } + + /// Construct a new stream descriptor implementation. + void construct(implementation_type& impl) + { + service_impl_.construct(impl); + } + + /// Destroy a stream descriptor implementation. + void destroy(implementation_type& impl) + { + service_impl_.destroy(impl); + } + + /// Assign an existing native descriptor to a stream descriptor. + asio::error_code assign(implementation_type& impl, + const native_type& native_descriptor, asio::error_code& ec) + { + return service_impl_.assign(impl, native_descriptor, ec); + } + + /// Determine whether the descriptor is open. + bool is_open(const implementation_type& impl) const + { + return service_impl_.is_open(impl); + } + + /// Close a stream descriptor implementation. + asio::error_code close(implementation_type& impl, + asio::error_code& ec) + { + return service_impl_.close(impl, ec); + } + + /// Get the native descriptor implementation. + native_type native(implementation_type& impl) + { + return service_impl_.native(impl); + } + + /// Cancel all asynchronous operations associated with the descriptor. + asio::error_code cancel(implementation_type& impl, + asio::error_code& ec) + { + return service_impl_.cancel(impl, ec); + } + + /// Perform an IO control command on the descriptor. + template + asio::error_code io_control(implementation_type& impl, + IoControlCommand& command, asio::error_code& ec) + { + return service_impl_.io_control(impl, command, ec); + } + + /// Write the given data to the stream. + template + std::size_t write_some(implementation_type& impl, + const ConstBufferSequence& buffers, asio::error_code& ec) + { + return service_impl_.write_some(impl, buffers, ec); + } + + /// Start an asynchronous write. + template + void async_write_some(implementation_type& impl, + const ConstBufferSequence& buffers, WriteHandler descriptorr) + { + service_impl_.async_write_some(impl, buffers, descriptorr); + } + + /// Read some data from the stream. + template + std::size_t read_some(implementation_type& impl, + const MutableBufferSequence& buffers, asio::error_code& ec) + { + return service_impl_.read_some(impl, buffers, ec); + } + + /// Start an asynchronous read. + template + void async_read_some(implementation_type& impl, + const MutableBufferSequence& buffers, ReadHandler descriptorr) + { + service_impl_.async_read_some(impl, buffers, descriptorr); + } + +private: + // The service that provides the platform-specific implementation. + service_impl_type& service_impl_; +}; + +} // namespace posix +} // namespace asio + +#endif // defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_POSIX_STREAM_DESCRIPTOR_SERVICE_HPP