From ffa20660469b043b1b35563d1563bf810315ac45 Mon Sep 17 00:00:00 2001 From: Marcos Pinto Date: Fri, 23 Nov 2007 23:36:34 +0000 Subject: [PATCH] asio sync --- libtorrent/include/asio.hpp | 74 -- libtorrent/include/asio/COPYING | 4 + libtorrent/include/asio/LICENSE_1_0.txt | 23 + .../include/asio/basic_datagram_socket.hpp | 4 +- libtorrent/include/asio/basic_io_object.hpp | 18 +- libtorrent/include/asio/basic_resolver.hpp | 252 +++++++ libtorrent/include/asio/basic_socket.hpp | 3 +- libtorrent/include/asio/buffer.hpp | 7 +- .../include/asio/buffered_read_stream.hpp | 17 +- libtorrent/include/asio/buffered_stream.hpp | 11 +- .../include/asio/buffered_write_stream.hpp | 17 +- .../include/asio/datagram_socket_service.hpp | 3 + .../include/asio/deadline_timer_service.hpp | 6 +- .../asio/detail/deadline_timer_service.hpp | 2 +- .../include/asio/detail/dev_poll_reactor.hpp | 647 ++++++++++++++++++ .../asio/detail/dev_poll_reactor_fwd.hpp | 40 ++ .../include/asio/detail/epoll_reactor.hpp | 70 +- .../include/asio/detail/handler_queue.hpp | 219 ++++++ .../include/asio/detail/kqueue_reactor.hpp | 20 +- .../asio/detail/pipe_select_interrupter.hpp | 10 + .../include/asio/detail/posix_event.hpp | 3 +- .../asio/detail/posix_fd_set_adapter.hpp | 2 +- .../include/asio/detail/posix_mutex.hpp | 9 +- .../include/asio/detail/posix_thread.hpp | 3 +- .../include/asio/detail/posix_tss_ptr.hpp | 3 +- .../asio/detail/reactive_socket_service.hpp | 70 +- .../include/asio/detail/resolver_service.hpp | 4 +- libtorrent/include/asio/detail/socket_ops.hpp | 377 +++++++--- .../asio/detail/socket_select_interrupter.hpp | 2 +- .../include/asio/detail/socket_types.hpp | 12 +- .../include/asio/detail/strand_service.hpp | 12 +- .../include/asio/detail/task_io_service.hpp | 160 +---- libtorrent/include/asio/detail/thread.hpp | 10 +- .../include/asio/detail/timer_queue.hpp | 25 +- libtorrent/include/asio/detail/win_event.hpp | 2 +- .../asio/detail/win_iocp_io_service.hpp | 231 ++++++- .../asio/detail/win_iocp_io_service_fwd.hpp | 2 + .../asio/detail/win_iocp_socket_service.hpp | 104 +-- .../detail/win_local_free_on_block_exit.hpp | 59 ++ libtorrent/include/asio/detail/win_mutex.hpp | 6 +- libtorrent/include/asio/detail/win_thread.hpp | 6 +- .../include/asio/detail/win_tss_ptr.hpp | 10 +- .../include/asio/detail/wince_thread.hpp | 124 ++++ .../include/asio/detail/winsock_init.hpp | 3 +- libtorrent/include/asio/error.hpp | 22 +- libtorrent/include/asio/error_code.hpp | 21 +- libtorrent/include/asio/error_handler.hpp | 120 ++++ libtorrent/include/asio/impl/error_code.ipp | 8 +- libtorrent/include/asio/impl/io_service.ipp | 11 + libtorrent/include/asio/io_service.hpp | 23 +- libtorrent/include/asio/ip/address_v4.hpp | 7 +- libtorrent/include/asio/ip/address_v6.hpp | 9 +- libtorrent/include/asio/ip/basic_endpoint.hpp | 56 +- .../asio/ip/basic_resolver_iterator.hpp | 4 +- .../include/asio/ip/detail/socket_option.hpp | 104 ++- libtorrent/include/asio/ip/multicast.hpp | 2 +- libtorrent/include/asio/placeholders.hpp | 6 +- libtorrent/include/asio/resolver_service.hpp | 126 ++++ .../include/asio/socket_acceptor_service.hpp | 3 + .../asio/ssl/detail/openssl_operation.hpp | 2 +- .../ssl/detail/openssl_stream_service.hpp | 16 +- libtorrent/include/asio/ssl/stream.hpp | 20 +- libtorrent/include/asio/strand.hpp | 18 +- .../include/asio/stream_socket_service.hpp | 3 + libtorrent/include/asio/system_exception.hpp | 198 ++++++ 65 files changed, 2886 insertions(+), 579 deletions(-) delete mode 100644 libtorrent/include/asio.hpp create mode 100644 libtorrent/include/asio/COPYING create mode 100644 libtorrent/include/asio/LICENSE_1_0.txt create mode 100644 libtorrent/include/asio/basic_resolver.hpp create mode 100644 libtorrent/include/asio/detail/dev_poll_reactor.hpp create mode 100644 libtorrent/include/asio/detail/dev_poll_reactor_fwd.hpp create mode 100644 libtorrent/include/asio/detail/handler_queue.hpp create mode 100644 libtorrent/include/asio/detail/win_local_free_on_block_exit.hpp create mode 100644 libtorrent/include/asio/detail/wince_thread.hpp create mode 100644 libtorrent/include/asio/error_handler.hpp create mode 100644 libtorrent/include/asio/resolver_service.hpp create mode 100644 libtorrent/include/asio/system_exception.hpp diff --git a/libtorrent/include/asio.hpp b/libtorrent/include/asio.hpp deleted file mode 100644 index ae6455bdb..000000000 --- a/libtorrent/include/asio.hpp +++ /dev/null @@ -1,74 +0,0 @@ -// -// asio.hpp -// ~~~~~~~~ -// -// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) -// -// Distributed under the Boost 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_HPP -#define ASIO_HPP - -#if defined(_MSC_VER) && (_MSC_VER >= 1200) -# pragma once -#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) - -#include "asio/basic_datagram_socket.hpp" -#include "asio/basic_deadline_timer.hpp" -#include "asio/basic_io_object.hpp" -#include "asio/basic_socket_acceptor.hpp" -#include "asio/basic_socket_iostream.hpp" -#include "asio/basic_socket_streambuf.hpp" -#include "asio/basic_stream_socket.hpp" -#include "asio/basic_streambuf.hpp" -#include "asio/buffer.hpp" -#include "asio/buffered_read_stream_fwd.hpp" -#include "asio/buffered_read_stream.hpp" -#include "asio/buffered_stream_fwd.hpp" -#include "asio/buffered_stream.hpp" -#include "asio/buffered_write_stream_fwd.hpp" -#include "asio/buffered_write_stream.hpp" -#include "asio/completion_condition.hpp" -#include "asio/datagram_socket_service.hpp" -#include "asio/deadline_timer_service.hpp" -#include "asio/deadline_timer.hpp" -#include "asio/error.hpp" -#include "asio/error_code.hpp" -#include "asio/handler_alloc_hook.hpp" -#include "asio/handler_invoke_hook.hpp" -#include "asio/io_service.hpp" -#include "asio/ip/address.hpp" -#include "asio/ip/address_v4.hpp" -#include "asio/ip/address_v6.hpp" -#include "asio/ip/basic_endpoint.hpp" -#include "asio/ip/basic_resolver.hpp" -#include "asio/ip/basic_resolver_entry.hpp" -#include "asio/ip/basic_resolver_iterator.hpp" -#include "asio/ip/basic_resolver_query.hpp" -#include "asio/ip/host_name.hpp" -#include "asio/ip/multicast.hpp" -#include "asio/ip/resolver_query_base.hpp" -#include "asio/ip/resolver_service.hpp" -#include "asio/ip/tcp.hpp" -#include "asio/ip/udp.hpp" -#include "asio/ip/unicast.hpp" -#include "asio/ip/v6_only.hpp" -#include "asio/is_read_buffered.hpp" -#include "asio/is_write_buffered.hpp" -#include "asio/placeholders.hpp" -#include "asio/read.hpp" -#include "asio/read_until.hpp" -#include "asio/socket_acceptor_service.hpp" -#include "asio/socket_base.hpp" -#include "asio/strand.hpp" -#include "asio/stream_socket_service.hpp" -#include "asio/streambuf.hpp" -#include "asio/system_error.hpp" -#include "asio/thread.hpp" -#include "asio/time_traits.hpp" -#include "asio/version.hpp" -#include "asio/write.hpp" - -#endif // ASIO_HPP diff --git a/libtorrent/include/asio/COPYING b/libtorrent/include/asio/COPYING new file mode 100644 index 000000000..b68879a1a --- /dev/null +++ b/libtorrent/include/asio/COPYING @@ -0,0 +1,4 @@ +Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) + +Distributed under the Boost Software License, Version 1.0. (See accompanying +file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/asio/LICENSE_1_0.txt b/libtorrent/include/asio/LICENSE_1_0.txt new file mode 100644 index 000000000..36b7cd93c --- /dev/null +++ b/libtorrent/include/asio/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/libtorrent/include/asio/basic_datagram_socket.hpp b/libtorrent/include/asio/basic_datagram_socket.hpp index 1a521628f..64d4d7244 100644 --- a/libtorrent/include/asio/basic_datagram_socket.hpp +++ b/libtorrent/include/asio/basic_datagram_socket.hpp @@ -732,8 +732,8 @@ public: * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( - * const asio::system_error& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes received. + * const asio::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. Invocation diff --git a/libtorrent/include/asio/basic_io_object.hpp b/libtorrent/include/asio/basic_io_object.hpp index 9291ff5da..5b1f94b8e 100644 --- a/libtorrent/include/asio/basic_io_object.hpp +++ b/libtorrent/include/asio/basic_io_object.hpp @@ -34,7 +34,8 @@ public: /// The underlying implementation type of I/O object. typedef typename service_type::implementation_type implementation_type; - /// Get the io_service associated with the object. + /// (Deprecated: use get_io_service().) Get the io_service associated with + /// the object. /** * This function may be used to obtain the io_service object that the I/O * object uses to dispatch handlers for asynchronous operations. @@ -44,7 +45,20 @@ public: */ asio::io_service& io_service() { - return service.io_service(); + return service.get_io_service(); + } + + /// Get the io_service associated with the object. + /** + * This function may be used to obtain the io_service object that the I/O + * object uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_service object that the I/O object will use + * to dispatch handlers. Ownership is not transferred to the caller. + */ + asio::io_service& get_io_service() + { + return service.get_io_service(); } protected: diff --git a/libtorrent/include/asio/basic_resolver.hpp b/libtorrent/include/asio/basic_resolver.hpp new file mode 100644 index 000000000..5df89d545 --- /dev/null +++ b/libtorrent/include/asio/basic_resolver.hpp @@ -0,0 +1,252 @@ +// +// basic_resolver.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost 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_BASIC_RESOLVER_HPP +#define ASIO_BASIC_RESOLVER_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/basic_io_object.hpp" +#include "asio/error.hpp" +#include "asio/error_handler.hpp" +#include "asio/resolver_service.hpp" + +namespace asio { + +/// 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. + * + * @par Concepts: + * Async_Object, Error_Source. + */ +template > +class basic_resolver + : public basic_io_object +{ +public: + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// The query type. + typedef typename Protocol::resolver_query query; + + /// The iterator type. + typedef typename Protocol::resolver_iterator iterator; + + /// The type used for reporting errors. + typedef asio::error error_type; + + /// Constructor. + /** + * This constructor creates a basic_resolver. + * + * @param io_service The io_service object that the resolver will use to + * dispatch handlers for any asynchronous operations performed on the timer. + */ + explicit basic_resolver(asio::io_service& io_service) + : basic_io_object(io_service) + { + } + + /// 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 asio::error::operation_aborted error code. + */ + void cancel() + { + return this->service.cancel(this->implementation); + } + + /// Resolve 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 forward-only iterator that can be used to traverse the list + * of endpoint entries. + * + * @throws asio::error Thrown on failure. + * + * @note A default constructed iterator represents the end of the list. + * + * @note A successful call to this function is guaranteed to return at least + * one entry. + */ + iterator resolve(const query& q) + { + return this->service.resolve(this->implementation, q, throw_error()); + } + + /// Resolve 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 forward-only iterator that can be used to traverse the list + * of endpoint entries. Returns a default constructed iterator if an error + * occurs. + * + * @param error_handler A handler to be called when the operation completes, + * to indicate whether or not an error has occurred. Copies will be made of + * the handler as required. The function signature of the handler must be: + * @code void error_handler( + * const asio::error& error // Result of operation. + * ); @endcode + * + * @note A default constructed iterator represents the end of the list. + * + * @note A successful call to this function is guaranteed to return at least + * one entry. + */ + template + iterator resolve(const query& q, Error_Handler error_handler) + { + return this->service.resolve(this->implementation, q, error_handler); + } + + /// Asynchronously resolve 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 asio::error& error, // Result of operation. + * resolver::iterator iterator // Forward-only iterator that can be used to + * // traverse the list of endpoint entries. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @note A default constructed iterator represents the end of the list. + * + * @note A successful resolve operation is guaranteed to pass at least one + * entry to the handler. + */ + template + void async_resolve(const query& q, Handler handler) + { + return this->service.async_resolve(this->implementation, q, handler); + } + + /// Resolve 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 forward-only iterator that can be used to traverse the list + * of endpoint entries. + * + * @throws asio::error Thrown on failure. + * + * @note A default constructed iterator represents the end of the list. + * + * @note A successful call to this function is guaranteed to return at least + * one entry. + */ + iterator resolve(const endpoint_type& e) + { + return this->service.resolve(this->implementation, e, throw_error()); + } + + /// Resolve 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 forward-only iterator that can be used to traverse the list + * of endpoint entries. Returns a default constructed iterator if an error + * occurs. + * + * @param error_handler A handler to be called when the operation completes, + * to indicate whether or not an error has occurred. Copies will be made of + * the handler as required. The function signature of the handler must be: + * @code void error_handler( + * const asio::error& error // Result of operation. + * ); @endcode + * + * @note A default constructed iterator represents the end of the list. + * + * @note A successful call to this function is guaranteed to return at least + * one entry. + */ + template + iterator resolve(const endpoint_type& e, Error_Handler error_handler) + { + return this->service.resolve(this->implementation, e, error_handler); + } + + /// Asynchronously resolve 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 asio::error& error, // Result of operation. + * resolver::iterator iterator // Forward-only iterator that can be used to + * // traverse the list of endpoint entries. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @note A default constructed iterator represents the end of the list. + * + * @note A successful resolve operation is guaranteed to pass at least one + * entry to the handler. + */ + template + void async_resolve(const endpoint_type& e, Handler handler) + { + return this->service.async_resolve(this->implementation, e, handler); + } +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_BASIC_RESOLVER_HPP diff --git a/libtorrent/include/asio/basic_socket.hpp b/libtorrent/include/asio/basic_socket.hpp index 2b2521b69..fbacf940d 100644 --- a/libtorrent/include/asio/basic_socket.hpp +++ b/libtorrent/include/asio/basic_socket.hpp @@ -564,7 +564,8 @@ public: if (this->service.open(this->implementation, peer_endpoint.protocol(), ec)) { - this->io_service().post(asio::detail::bind_handler(handler, ec)); + this->get_io_service().post( + asio::detail::bind_handler(handler, ec)); return; } } diff --git a/libtorrent/include/asio/buffer.hpp b/libtorrent/include/asio/buffer.hpp index 9fe76178c..881bc1176 100644 --- a/libtorrent/include/asio/buffer.hpp +++ b/libtorrent/include/asio/buffer.hpp @@ -27,7 +27,7 @@ #include "asio/detail/pop_options.hpp" #if defined(BOOST_MSVC) -# if defined(_HAS_ITERATOR_DEBUGGING) +# if defined(_HAS_ITERATOR_DEBUGGING) && (_HAS_ITERATOR_DEBUGGING != 0) # if !defined(ASIO_DISABLE_BUFFER_DEBUGGING) # define ASIO_ENABLE_BUFFER_DEBUGGING # endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING) @@ -390,6 +390,11 @@ public: { } + ~buffer_debug_check() + { + iter_ = Iterator(); + } + void operator()() { *iter_; diff --git a/libtorrent/include/asio/buffered_read_stream.hpp b/libtorrent/include/asio/buffered_read_stream.hpp index 5cf5d688e..bd9169b8f 100644 --- a/libtorrent/include/asio/buffered_read_stream.hpp +++ b/libtorrent/include/asio/buffered_read_stream.hpp @@ -93,10 +93,17 @@ public: return next_layer_.lowest_layer(); } - /// Get the io_service associated with the object. + /// (Deprecated: use get_io_service().) Get the io_service associated with + /// the object. asio::io_service& io_service() { - return next_layer_.io_service(); + return next_layer_.get_io_service(); + } + + /// Get the io_service associated with the object. + asio::io_service& get_io_service() + { + return next_layer_.get_io_service(); } /// Close the stream. @@ -207,7 +214,7 @@ public: buffer( storage_.data() + previous_size, storage_.size() - previous_size), - fill_handler(io_service(), + fill_handler(get_io_service(), storage_, previous_size, handler)); } @@ -295,12 +302,12 @@ public: if (storage_.empty()) { async_fill(read_some_handler( - io_service(), storage_, buffers, handler)); + get_io_service(), storage_, buffers, handler)); } else { std::size_t length = copy(buffers); - io_service().post(detail::bind_handler( + get_io_service().post(detail::bind_handler( handler, asio::error_code(), length)); } } diff --git a/libtorrent/include/asio/buffered_stream.hpp b/libtorrent/include/asio/buffered_stream.hpp index b6901a6d4..57959059e 100644 --- a/libtorrent/include/asio/buffered_stream.hpp +++ b/libtorrent/include/asio/buffered_stream.hpp @@ -83,10 +83,17 @@ public: return stream_impl_.lowest_layer(); } - /// Get the io_service associated with the object. + /// (Deprecated: use get_io_service().) Get the io_service associated with + /// the object. asio::io_service& io_service() { - return stream_impl_.io_service(); + return stream_impl_.get_io_service(); + } + + /// Get the io_service associated with the object. + asio::io_service& get_io_service() + { + return stream_impl_.get_io_service(); } /// Close the stream. diff --git a/libtorrent/include/asio/buffered_write_stream.hpp b/libtorrent/include/asio/buffered_write_stream.hpp index ffe3a2ee7..d06787091 100644 --- a/libtorrent/include/asio/buffered_write_stream.hpp +++ b/libtorrent/include/asio/buffered_write_stream.hpp @@ -94,10 +94,17 @@ public: return next_layer_.lowest_layer(); } - /// Get the io_service associated with the object. + /// (Deprecated: use get_io_service().) Get the io_service associated with + /// the object. asio::io_service& io_service() { - return next_layer_.io_service(); + return next_layer_.get_io_service(); + } + + /// Get the io_service associated with the object. + asio::io_service& get_io_service() + { + return next_layer_.get_io_service(); } /// Close the stream. @@ -165,7 +172,7 @@ public: void async_flush(WriteHandler handler) { async_write(next_layer_, buffer(storage_.data(), storage_.size()), - flush_handler(io_service(), storage_, handler)); + flush_handler(get_io_service(), storage_, handler)); } /// Write the given data to the stream. Returns the number of bytes written. @@ -253,12 +260,12 @@ public: if (storage_.size() == storage_.capacity()) { async_flush(write_some_handler( - io_service(), storage_, buffers, handler)); + get_io_service(), storage_, buffers, handler)); } else { std::size_t bytes_copied = copy(buffers); - io_service().post(detail::bind_handler( + get_io_service().post(detail::bind_handler( handler, asio::error_code(), bytes_copied)); } } diff --git a/libtorrent/include/asio/datagram_socket_service.hpp b/libtorrent/include/asio/datagram_socket_service.hpp index 1f858de61..69de5f2cc 100644 --- a/libtorrent/include/asio/datagram_socket_service.hpp +++ b/libtorrent/include/asio/datagram_socket_service.hpp @@ -64,6 +64,9 @@ private: #elif defined(ASIO_HAS_KQUEUE) typedef detail::reactive_socket_service< Protocol, detail::kqueue_reactor > service_impl_type; +#elif defined(ASIO_HAS_DEV_POLL) + typedef detail::reactive_socket_service< + Protocol, detail::dev_poll_reactor > service_impl_type; #else typedef detail::reactive_socket_service< Protocol, detail::select_reactor > service_impl_type; diff --git a/libtorrent/include/asio/deadline_timer_service.hpp b/libtorrent/include/asio/deadline_timer_service.hpp index 17b97350b..e1d1bc97e 100644 --- a/libtorrent/include/asio/deadline_timer_service.hpp +++ b/libtorrent/include/asio/deadline_timer_service.hpp @@ -29,6 +29,7 @@ #include "asio/detail/kqueue_reactor.hpp" #include "asio/detail/select_reactor.hpp" #include "asio/detail/service_base.hpp" +#include "asio/detail/win_iocp_io_service.hpp" namespace asio { @@ -62,13 +63,16 @@ private: // The type of the platform-specific implementation. #if defined(ASIO_HAS_IOCP) typedef detail::deadline_timer_service< - traits_type, detail::select_reactor > service_impl_type; + traits_type, detail::win_iocp_io_service> service_impl_type; #elif defined(ASIO_HAS_EPOLL) typedef detail::deadline_timer_service< traits_type, detail::epoll_reactor > service_impl_type; #elif defined(ASIO_HAS_KQUEUE) typedef detail::deadline_timer_service< traits_type, detail::kqueue_reactor > service_impl_type; +#elif defined(ASIO_HAS_DEV_POLL) + typedef detail::deadline_timer_service< + traits_type, detail::dev_poll_reactor > service_impl_type; #else typedef detail::deadline_timer_service< traits_type, detail::select_reactor > service_impl_type; diff --git a/libtorrent/include/asio/detail/deadline_timer_service.hpp b/libtorrent/include/asio/detail/deadline_timer_service.hpp index c22c5a7b7..06b90b5eb 100644 --- a/libtorrent/include/asio/detail/deadline_timer_service.hpp +++ b/libtorrent/include/asio/detail/deadline_timer_service.hpp @@ -180,7 +180,7 @@ public: { impl.might_have_pending_waits = true; scheduler_.schedule_timer(timer_queue_, impl.expiry, - wait_handler(this->io_service(), handler), &impl); + wait_handler(this->get_io_service(), handler), &impl); } private: diff --git a/libtorrent/include/asio/detail/dev_poll_reactor.hpp b/libtorrent/include/asio/detail/dev_poll_reactor.hpp new file mode 100644 index 000000000..15babcdb9 --- /dev/null +++ b/libtorrent/include/asio/detail/dev_poll_reactor.hpp @@ -0,0 +1,647 @@ +// +// dev_poll_reactor.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost 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_DEV_POLL_REACTOR_HPP +#define ASIO_DETAIL_DEV_POLL_REACTOR_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/dev_poll_reactor_fwd.hpp" + +#if defined(ASIO_HAS_DEV_POLL) + +#include "asio/detail/push_options.hpp" +#include +#include +#include +#include +#include +#include +#include "asio/detail/pop_options.hpp" + +#include "asio/error.hpp" +#include "asio/io_service.hpp" +#include "asio/system_error.hpp" +#include "asio/detail/bind_handler.hpp" +#include "asio/detail/hash_map.hpp" +#include "asio/detail/mutex.hpp" +#include "asio/detail/task_io_service.hpp" +#include "asio/detail/thread.hpp" +#include "asio/detail/reactor_op_queue.hpp" +#include "asio/detail/select_interrupter.hpp" +#include "asio/detail/service_base.hpp" +#include "asio/detail/signal_blocker.hpp" +#include "asio/detail/socket_types.hpp" +#include "asio/detail/timer_queue.hpp" + +namespace asio { +namespace detail { + +template +class dev_poll_reactor + : public asio::detail::service_base > +{ +public: + // Constructor. + dev_poll_reactor(asio::io_service& io_service) + : asio::detail::service_base< + dev_poll_reactor >(io_service), + mutex_(), + dev_poll_fd_(do_dev_poll_create()), + wait_in_progress_(false), + interrupter_(), + read_op_queue_(), + write_op_queue_(), + except_op_queue_(), + pending_cancellations_(), + stop_thread_(false), + thread_(0), + shutdown_(false) + { + // Start the reactor's internal thread only if needed. + if (Own_Thread) + { + asio::detail::signal_blocker sb; + thread_ = new asio::detail::thread( + bind_handler(&dev_poll_reactor::call_run_thread, this)); + } + + // Add the interrupter's descriptor to /dev/poll. + ::pollfd ev = { 0 }; + ev.fd = interrupter_.read_descriptor(); + ev.events = POLLIN | POLLERR; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); + } + + // Destructor. + ~dev_poll_reactor() + { + shutdown_service(); + ::close(dev_poll_fd_); + } + + // Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + asio::detail::mutex::scoped_lock lock(mutex_); + shutdown_ = true; + stop_thread_ = true; + lock.unlock(); + + if (thread_) + { + interrupter_.interrupt(); + thread_->join(); + delete thread_; + thread_ = 0; + } + + read_op_queue_.destroy_operations(); + write_op_queue_.destroy_operations(); + except_op_queue_.destroy_operations(); + + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + timer_queues_[i]->destroy_timers(); + timer_queues_.clear(); + } + + // Register a socket with the reactor. Returns 0 on success, system error + // code on failure. + int register_descriptor(socket_type descriptor) + { + return 0; + } + + // Start a new read operation. The handler object will be invoked when the + // given descriptor is ready to be read, or an error has occurred. + template + void start_read_op(socket_type descriptor, Handler handler) + { + asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + return; + + if (!read_op_queue_.has_operation(descriptor)) + if (handler(asio::error_code())) + return; + + if (read_op_queue_.enqueue_operation(descriptor, handler)) + { + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLIN | POLLERR | POLLHUP; + if (write_op_queue_.has_operation(descriptor)) + ev.events |= POLLOUT; + if (except_op_queue_.has_operation(descriptor)) + ev.events |= POLLPRI; + interrupter_.interrupt(); + } + } + + // Start a new write operation. The handler object will be invoked when the + // given descriptor is ready to be written, or an error has occurred. + template + void start_write_op(socket_type descriptor, Handler handler) + { + asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + return; + + if (!write_op_queue_.has_operation(descriptor)) + if (handler(asio::error_code())) + return; + + if (write_op_queue_.enqueue_operation(descriptor, handler)) + { + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLOUT | POLLERR | POLLHUP; + if (read_op_queue_.has_operation(descriptor)) + ev.events |= POLLIN; + if (except_op_queue_.has_operation(descriptor)) + ev.events |= POLLPRI; + interrupter_.interrupt(); + } + } + + // Start a new exception operation. The handler object will be invoked when + // the given descriptor has exception information, or an error has occurred. + template + void start_except_op(socket_type descriptor, Handler handler) + { + asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + return; + + if (except_op_queue_.enqueue_operation(descriptor, handler)) + { + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLPRI | POLLERR | POLLHUP; + if (read_op_queue_.has_operation(descriptor)) + ev.events |= POLLIN; + if (write_op_queue_.has_operation(descriptor)) + ev.events |= POLLOUT; + interrupter_.interrupt(); + } + } + + // Start new write and exception operations. The handler object will be + // invoked when the given descriptor is ready for writing or has exception + // information available, or an error has occurred. + template + void start_write_and_except_ops(socket_type descriptor, Handler handler) + { + asio::detail::mutex::scoped_lock lock(mutex_); + + if (shutdown_) + return; + + bool need_mod = write_op_queue_.enqueue_operation(descriptor, handler); + need_mod = except_op_queue_.enqueue_operation(descriptor, handler) + && need_mod; + if (need_mod) + { + ::pollfd& ev = add_pending_event_change(descriptor); + ev.events = POLLOUT | POLLPRI | POLLERR | POLLHUP; + if (read_op_queue_.has_operation(descriptor)) + ev.events |= POLLIN; + interrupter_.interrupt(); + } + } + + // Cancel all operations associated with the given descriptor. The + // handlers associated with the descriptor will be invoked with the + // operation_aborted error. + void cancel_ops(socket_type descriptor) + { + asio::detail::mutex::scoped_lock lock(mutex_); + cancel_ops_unlocked(descriptor); + } + + // Enqueue cancellation of all operations associated with the given + // descriptor. The handlers associated with the descriptor will be invoked + // with the operation_aborted error. This function does not acquire the + // dev_poll_reactor's mutex, and so should only be used from within a reactor + // handler. + void enqueue_cancel_ops_unlocked(socket_type descriptor) + { + pending_cancellations_.push_back(descriptor); + } + + // Cancel any operations that are running against the descriptor and remove + // its registration from the reactor. + void close_descriptor(socket_type descriptor) + { + 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); + } + + // Add a new timer queue to the reactor. + template + void add_timer_queue(timer_queue& timer_queue) + { + asio::detail::mutex::scoped_lock lock(mutex_); + timer_queues_.push_back(&timer_queue); + } + + // Remove a timer queue from the reactor. + template + void remove_timer_queue(timer_queue& timer_queue) + { + asio::detail::mutex::scoped_lock lock(mutex_); + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + if (timer_queues_[i] == &timer_queue) + { + timer_queues_.erase(timer_queues_.begin() + i); + return; + } + } + } + + // Schedule a timer in the given timer queue to expire at the specified + // absolute time. The handler object will be invoked when the timer expires. + template + void schedule_timer(timer_queue& timer_queue, + const typename Time_Traits::time_type& time, Handler handler, void* token) + { + asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_) + if (timer_queue.enqueue_timer(time, handler, token)) + interrupter_.interrupt(); + } + + // Cancel the timer associated with the given token. Returns the number of + // handlers that have been posted or dispatched. + template + std::size_t cancel_timer(timer_queue& timer_queue, void* token) + { + asio::detail::mutex::scoped_lock lock(mutex_); + std::size_t n = timer_queue.cancel_timer(token); + if (n > 0) + interrupter_.interrupt(); + return n; + } + +private: + friend class task_io_service >; + + // Run /dev/poll once until interrupted or events are ready to be dispatched. + void run(bool block) + { + asio::detail::mutex::scoped_lock lock(mutex_); + + // Dispatch any operation cancellations that were made while the select + // loop was not running. + read_op_queue_.dispatch_cancellations(); + write_op_queue_.dispatch_cancellations(); + except_op_queue_.dispatch_cancellations(); + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + timer_queues_[i]->dispatch_cancellations(); + + // Check if the thread is supposed to stop. + if (stop_thread_) + { + cleanup_operations_and_timers(lock); + return; + } + + // We can return immediately if there's no work to do and the reactor is + // not supposed to block. + if (!block && read_op_queue_.empty() && write_op_queue_.empty() + && except_op_queue_.empty() && all_timer_queues_are_empty()) + { + cleanup_operations_and_timers(lock); + return; + } + + // Write the pending event registration changes to the /dev/poll descriptor. + std::size_t events_size = sizeof(::pollfd) * pending_event_changes_.size(); + errno = 0; + int result = ::write(dev_poll_fd_, + &pending_event_changes_[0], events_size); + if (result != static_cast(events_size)) + { + for (std::size_t i = 0; i < pending_event_changes_.size(); ++i) + { + int descriptor = pending_event_changes_[i].fd; + asio::error_code ec = asio::error_code( + errno, asio::error::get_system_category()); + read_op_queue_.dispatch_all_operations(descriptor, ec); + write_op_queue_.dispatch_all_operations(descriptor, ec); + except_op_queue_.dispatch_all_operations(descriptor, ec); + } + } + pending_event_changes_.clear(); + pending_event_change_index_.clear(); + + int timeout = block ? get_timeout() : 0; + wait_in_progress_ = true; + lock.unlock(); + + // Block on the /dev/poll descriptor. + ::pollfd events[128] = { { 0 } }; + ::dvpoll dp = { 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(); + wait_in_progress_ = false; + + // Block signals while dispatching operations. + asio::detail::signal_blocker sb; + + // 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; + asio::error_code ec; + + // 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 = except_op_queue_.dispatch_operation(descriptor, ec); + else + more_except = except_op_queue_.has_operation(descriptor); + + if (events[i].events & (POLLIN | POLLERR | POLLHUP)) + more_reads = read_op_queue_.dispatch_operation(descriptor, ec); + else + more_reads = read_op_queue_.has_operation(descriptor); + + if (events[i].events & (POLLOUT | POLLERR | POLLHUP)) + more_writes = write_op_queue_.dispatch_operation(descriptor, ec); + else + more_writes = write_op_queue_.has_operation(descriptor); + + if ((events[i].events == POLLHUP) + && !more_except && !more_reads && !more_writes) + { + // If we have only an POLLHUP event and no operations associated + // with the descriptor then we need to delete the descriptor from + // /dev/poll. The poll operation might produce POLLHUP events even + // if they are not specifically requested, so if we do not remove the + // descriptor we can end up in a tight polling loop. + ::pollfd ev = { 0 }; + ev.fd = descriptor; + ev.events = POLLREMOVE; + ev.revents = 0; + ::write(dev_poll_fd_, &ev, sizeof(ev)); + } + else + { + ::pollfd ev = { 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)) + { + ec = asio::error_code(errno, + asio::error::get_system_category()); + read_op_queue_.dispatch_all_operations(descriptor, ec); + write_op_queue_.dispatch_all_operations(descriptor, ec); + except_op_queue_.dispatch_all_operations(descriptor, ec); + } + } + } + } + read_op_queue_.dispatch_cancellations(); + write_op_queue_.dispatch_cancellations(); + except_op_queue_.dispatch_cancellations(); + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + timer_queues_[i]->dispatch_timers(); + timer_queues_[i]->dispatch_cancellations(); + } + + // Issue any pending cancellations. + for (size_t i = 0; i < pending_cancellations_.size(); ++i) + cancel_ops_unlocked(pending_cancellations_[i]); + pending_cancellations_.clear(); + + cleanup_operations_and_timers(lock); + } + + // Run the select loop in the thread. + void run_thread() + { + asio::detail::mutex::scoped_lock lock(mutex_); + while (!stop_thread_) + { + lock.unlock(); + run(true); + lock.lock(); + } + } + + // Entry point for the select loop thread. + static void call_run_thread(dev_poll_reactor* reactor) + { + reactor->run_thread(); + } + + // Interrupt the select loop. + void interrupt() + { + interrupter_.interrupt(); + } + + // Create the /dev/poll file descriptor. Throws an exception if the descriptor + // cannot be created. + static int do_dev_poll_create() + { + int fd = ::open("/dev/poll", O_RDWR); + if (fd == -1) + { + boost::throw_exception( + asio::system_error( + asio::error_code(errno, + asio::error::get_system_category()), + "/dev/poll")); + } + return fd; + } + + // Check if all timer queues are empty. + bool all_timer_queues_are_empty() const + { + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + if (!timer_queues_[i]->empty()) + return false; + return true; + } + + // 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. + int get_timeout() + { + if (all_timer_queues_are_empty()) + return -1; + + // 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. + boost::posix_time::time_duration minimum_wait_duration + = boost::posix_time::minutes(5); + + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + boost::posix_time::time_duration wait_duration + = timer_queues_[i]->wait_duration(); + if (wait_duration < minimum_wait_duration) + minimum_wait_duration = wait_duration; + } + + if (minimum_wait_duration > boost::posix_time::time_duration()) + { + int milliseconds = minimum_wait_duration.total_milliseconds(); + return milliseconds > 0 ? milliseconds : 1; + } + else + { + return 0; + } + } + + // 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. + void cancel_ops_unlocked(socket_type descriptor) + { + bool interrupt = read_op_queue_.cancel_operations(descriptor); + interrupt = write_op_queue_.cancel_operations(descriptor) || interrupt; + interrupt = except_op_queue_.cancel_operations(descriptor) || interrupt; + if (interrupt) + interrupter_.interrupt(); + } + + // Clean up operations and timers. We must not hold the lock since the + // destructors may make calls back into this reactor. We make a copy of the + // vector of timer queues since the original may be modified while the lock + // is not held. + void cleanup_operations_and_timers( + asio::detail::mutex::scoped_lock& lock) + { + timer_queues_for_cleanup_ = timer_queues_; + lock.unlock(); + read_op_queue_.cleanup_operations(); + write_op_queue_.cleanup_operations(); + except_op_queue_.cleanup_operations(); + for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i) + timer_queues_for_cleanup_[i]->cleanup_timers(); + } + + // Add a pending event entry for the given descriptor. + ::pollfd& add_pending_event_change(int descriptor) + { + hash_map::iterator iter + = pending_event_change_index_.find(descriptor); + if (iter == pending_event_change_index_.end()) + { + std::size_t index = pending_event_changes_.size(); + pending_event_changes_.reserve(pending_event_changes_.size() + 1); + pending_event_change_index_.insert(std::make_pair(descriptor, index)); + pending_event_changes_.push_back(::pollfd()); + pending_event_changes_[index].fd = descriptor; + pending_event_changes_[index].revents = 0; + return pending_event_changes_[index]; + } + else + { + return pending_event_changes_[iter->second]; + } + } + + // Mutex to protect access to internal data. + asio::detail::mutex mutex_; + + // The /dev/poll file descriptor. + int dev_poll_fd_; + + // Vector of /dev/poll events waiting to be written to the descriptor. + std::vector< ::pollfd> pending_event_changes_; + + // Hash map to associate a descriptor with a pending event change index. + hash_map pending_event_change_index_; + + // Whether the DP_POLL operation is currently in progress + bool wait_in_progress_; + + // The interrupter is used to break a blocking DP_POLL operation. + select_interrupter interrupter_; + + // The queue of read operations. + reactor_op_queue read_op_queue_; + + // The queue of write operations. + reactor_op_queue write_op_queue_; + + // The queue of except operations. + reactor_op_queue except_op_queue_; + + // The timer queues. + std::vector timer_queues_; + + // A copy of the timer queues, used when cleaning up timers. The copy is + // stored as a class data member to avoid unnecessary memory allocation. + std::vector timer_queues_for_cleanup_; + + // The descriptors that are pending cancellation. + std::vector pending_cancellations_; + + // Does the reactor loop thread need to stop. + bool stop_thread_; + + // The thread that is running the reactor loop. + asio::detail::thread* thread_; + + // Whether the service has been shut down. + bool shutdown_; +}; + +} // namespace detail +} // namespace asio + +#endif // defined(ASIO_HAS_DEV_POLL) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_DEV_POLL_REACTOR_HPP diff --git a/libtorrent/include/asio/detail/dev_poll_reactor_fwd.hpp b/libtorrent/include/asio/detail/dev_poll_reactor_fwd.hpp new file mode 100644 index 000000000..230a6fd12 --- /dev/null +++ b/libtorrent/include/asio/detail/dev_poll_reactor_fwd.hpp @@ -0,0 +1,40 @@ +// +// dev_poll_reactor_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost 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_DEV_POLL_REACTOR_FWD_HPP +#define ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +#if !defined(ASIO_DISABLE_DEV_POLL) +#if defined(__sun) // This service is only supported on Solaris. + +// Define this to indicate that /dev/poll is supported on the target platform. +#define ASIO_HAS_DEV_POLL 1 + +namespace asio { +namespace detail { + +template +class dev_poll_reactor; + +} // namespace detail +} // namespace asio + +#endif // defined(__sun) +#endif // !defined(ASIO_DISABLE_DEV_POLL) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_DEV_POLL_REACTOR_FWD_HPP diff --git a/libtorrent/include/asio/detail/epoll_reactor.hpp b/libtorrent/include/asio/detail/epoll_reactor.hpp index e260c5194..93d39a23c 100644 --- a/libtorrent/include/asio/detail/epoll_reactor.hpp +++ b/libtorrent/include/asio/detail/epoll_reactor.hpp @@ -155,10 +155,12 @@ public: ev.data.fd = descriptor; int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); + if (result != 0 && errno == ENOENT) + result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); if (result != 0) { asio::error_code ec(errno, - asio::error::system_category); + asio::error::get_system_category()); read_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -189,10 +191,12 @@ public: ev.data.fd = descriptor; int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); + if (result != 0 && errno == ENOENT) + result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); if (result != 0) { asio::error_code ec(errno, - asio::error::system_category); + asio::error::get_system_category()); write_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -219,10 +223,12 @@ public: ev.data.fd = descriptor; int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); + if (result != 0 && errno == ENOENT) + result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); if (result != 0) { asio::error_code ec(errno, - asio::error::system_category); + asio::error::get_system_category()); except_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -251,10 +257,12 @@ public: ev.data.fd = descriptor; int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); + if (result != 0 && errno == ENOENT) + result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); if (result != 0) { asio::error_code ec(errno, - asio::error::system_category); + asio::error::get_system_category()); write_op_queue_.dispatch_all_operations(descriptor, ec); except_op_queue_.dispatch_all_operations(descriptor, ec); } @@ -419,23 +427,40 @@ private: else more_writes = write_op_queue_.has_operation(descriptor); - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLERR | EPOLLHUP; - if (more_reads) - ev.events |= EPOLLIN; - if (more_writes) - ev.events |= EPOLLOUT; - if (more_except) - ev.events |= EPOLLPRI; - ev.data.fd = descriptor; - int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); - if (result != 0) + if ((events[i].events == EPOLLHUP) + && !more_except && !more_reads && !more_writes) { - ec = asio::error_code(errno, - asio::error::system_category); - read_op_queue_.dispatch_all_operations(descriptor, ec); - write_op_queue_.dispatch_all_operations(descriptor, ec); - except_op_queue_.dispatch_all_operations(descriptor, ec); + // If we have only an EPOLLHUP event and no operations associated + // with the descriptor then we need to delete the descriptor from + // epoll. The epoll_wait system call will produce EPOLLHUP events + // even if they are not specifically requested, so if we do not + // remove the descriptor we can end up in a tight loop of repeated + // calls to epoll_wait. + epoll_event ev = { 0, { 0 } }; + epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev); + } + else + { + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLERR | EPOLLHUP; + if (more_reads) + ev.events |= EPOLLIN; + if (more_writes) + ev.events |= EPOLLOUT; + if (more_except) + ev.events |= EPOLLPRI; + ev.data.fd = descriptor; + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); + if (result != 0 && errno == ENOENT) + result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); + if (result != 0) + { + ec = asio::error_code(errno, + asio::error::get_system_category()); + read_op_queue_.dispatch_all_operations(descriptor, ec); + write_op_queue_.dispatch_all_operations(descriptor, ec); + except_op_queue_.dispatch_all_operations(descriptor, ec); + } } } } @@ -493,7 +518,7 @@ private: boost::throw_exception( asio::system_error( asio::error_code(errno, - asio::error::system_category), + asio::error::get_system_category()), "epoll")); } return fd; @@ -531,7 +556,8 @@ private: if (minimum_wait_duration > boost::posix_time::time_duration()) { - return minimum_wait_duration.total_milliseconds(); + int milliseconds = minimum_wait_duration.total_milliseconds(); + return milliseconds > 0 ? milliseconds : 1; } else { diff --git a/libtorrent/include/asio/detail/handler_queue.hpp b/libtorrent/include/asio/detail/handler_queue.hpp new file mode 100644 index 000000000..cd9870279 --- /dev/null +++ b/libtorrent/include/asio/detail/handler_queue.hpp @@ -0,0 +1,219 @@ +// +// handler_queue.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost 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_HANDLER_QUEUE_HPP +#define ASIO_DETAIL_HANDLER_QUEUE_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/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/noncopyable.hpp" + +namespace asio { +namespace detail { + +class handler_queue + : private noncopyable +{ +public: + // Base class for handlers in the queue. + class handler + : private noncopyable + { + public: + void invoke() + { + invoke_func_(this); + } + + void destroy() + { + destroy_func_(this); + } + + protected: + typedef void (*invoke_func_type)(handler*); + typedef void (*destroy_func_type)(handler*); + + handler(invoke_func_type invoke_func, + destroy_func_type destroy_func) + : next_(0), + invoke_func_(invoke_func), + destroy_func_(destroy_func) + { + } + + ~handler() + { + } + + private: + friend class handler_queue; + handler* next_; + invoke_func_type invoke_func_; + destroy_func_type destroy_func_; + }; + + // Smart point to manager handler lifetimes. + class scoped_ptr + : private noncopyable + { + public: + explicit scoped_ptr(handler* h) + : handler_(h) + { + } + + ~scoped_ptr() + { + if (handler_) + handler_->destroy(); + } + + handler* get() const + { + return handler_; + } + + handler* release() + { + handler* tmp = handler_; + handler_ = 0; + return tmp; + } + + private: + handler* handler_; + }; + + // Constructor. + handler_queue() + : front_(0), + back_(0) + { + } + + // Wrap a handler to be pushed into the queue. + template + static handler* wrap(Handler h) + { + // Allocate and construct an object to wrap the handler. + typedef handler_wrapper value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(h); + handler_ptr ptr(raw_ptr, h); + return ptr.release(); + } + + // Get the handler at the front of the queue. + handler* front() + { + return front_; + } + + // Pop a handler from the front of the queue. + void pop() + { + if (front_) + { + handler* tmp = front_; + front_ = front_->next_; + if (front_ == 0) + back_ = 0; + tmp->next_= 0; + } + } + + // Push a handler on to the back of the queue. + void push(handler* h) + { + h->next_ = 0; + if (back_) + { + back_->next_ = h; + back_ = h; + } + else + { + front_ = back_ = h; + } + } + + // Whether the queue is empty. + bool empty() const + { + return front_ == 0; + } + +private: + // Template wrapper for handlers. + template + class handler_wrapper + : public handler + { + public: + handler_wrapper(Handler h) + : handler( + &handler_wrapper::do_call, + &handler_wrapper::do_destroy), + handler_(h) + { + } + + static void do_call(handler* base) + { + // Take ownership of the handler object. + typedef handler_wrapper this_type; + this_type* h(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(h->handler_, h); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. + Handler handler(h->handler_); + + // Free the memory associated with the handler. + ptr.reset(); + + // Make the upcall. + asio_handler_invoke_helpers::invoke(handler, &handler); + } + + static void do_destroy(handler* base) + { + // Take ownership of the handler object. + typedef handler_wrapper this_type; + this_type* h(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(h->handler_, h); + } + + private: + Handler handler_; + }; + + // The front of the queue. + handler* front_; + + // The back of the queue. + handler* back_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_HANDLER_QUEUE_HPP diff --git a/libtorrent/include/asio/detail/kqueue_reactor.hpp b/libtorrent/include/asio/detail/kqueue_reactor.hpp index 5fffc6788..896ff5403 100644 --- a/libtorrent/include/asio/detail/kqueue_reactor.hpp +++ b/libtorrent/include/asio/detail/kqueue_reactor.hpp @@ -151,7 +151,7 @@ public: if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { asio::error_code ec(errno, - asio::error::system_category); + asio::error::get_system_category()); read_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -178,7 +178,7 @@ public: if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { asio::error_code ec(errno, - asio::error::system_category); + asio::error::get_system_category()); write_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -204,7 +204,7 @@ public: if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { asio::error_code ec(errno, - asio::error::system_category); + asio::error::get_system_category()); except_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -228,7 +228,7 @@ public: if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { asio::error_code ec(errno, - asio::error::system_category); + asio::error::get_system_category()); write_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -243,7 +243,7 @@ public: if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { asio::error_code ec(errno, - asio::error::system_category); + asio::error::get_system_category()); except_op_queue_.dispatch_all_operations(descriptor, ec); write_op_queue_.dispatch_all_operations(descriptor, ec); } @@ -397,7 +397,7 @@ private: if (events[i].flags & EV_ERROR) { asio::error_code error( - events[i].data, asio::error::system_category); + events[i].data, asio::error::get_system_category()); except_op_queue_.dispatch_all_operations(descriptor, error); read_op_queue_.dispatch_all_operations(descriptor, error); } @@ -428,7 +428,7 @@ private: if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { asio::error_code error(errno, - asio::error::system_category); + asio::error::get_system_category()); except_op_queue_.dispatch_all_operations(descriptor, error); read_op_queue_.dispatch_all_operations(descriptor, error); } @@ -440,7 +440,7 @@ private: if (events[i].flags & EV_ERROR) { asio::error_code error( - events[i].data, asio::error::system_category); + events[i].data, asio::error::get_system_category()); write_op_queue_.dispatch_all_operations(descriptor, error); } else @@ -458,7 +458,7 @@ private: if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { asio::error_code error(errno, - asio::error::system_category); + asio::error::get_system_category()); write_op_queue_.dispatch_all_operations(descriptor, error); } } @@ -515,7 +515,7 @@ private: boost::throw_exception( asio::system_error( asio::error_code(errno, - asio::error::system_category), + asio::error::get_system_category()), "kqueue")); } return fd; diff --git a/libtorrent/include/asio/detail/pipe_select_interrupter.hpp b/libtorrent/include/asio/detail/pipe_select_interrupter.hpp index e203669cb..c0ac2aab1 100644 --- a/libtorrent/include/asio/detail/pipe_select_interrupter.hpp +++ b/libtorrent/include/asio/detail/pipe_select_interrupter.hpp @@ -19,6 +19,7 @@ #include "asio/detail/push_options.hpp" #include +#include #include "asio/detail/pop_options.hpp" #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) @@ -27,6 +28,8 @@ #include #include "asio/detail/pop_options.hpp" +#include "asio/error.hpp" +#include "asio/system_error.hpp" #include "asio/detail/socket_types.hpp" namespace asio { @@ -46,6 +49,13 @@ public: write_descriptor_ = pipe_fds[1]; ::fcntl(write_descriptor_, F_SETFL, O_NONBLOCK); } + else + { + asio::error_code ec(errno, + asio::error::get_system_category()); + asio::system_error e(ec, "pipe_select_interrupter"); + boost::throw_exception(e); + } } // Destructor. diff --git a/libtorrent/include/asio/detail/posix_event.hpp b/libtorrent/include/asio/detail/posix_event.hpp index b48586f15..305ed873b 100644 --- a/libtorrent/include/asio/detail/posix_event.hpp +++ b/libtorrent/include/asio/detail/posix_event.hpp @@ -48,7 +48,8 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, + asio::error::get_system_category()), "event"); boost::throw_exception(e); } diff --git a/libtorrent/include/asio/detail/posix_fd_set_adapter.hpp b/libtorrent/include/asio/detail/posix_fd_set_adapter.hpp index ae5bf6642..c43904f4d 100644 --- a/libtorrent/include/asio/detail/posix_fd_set_adapter.hpp +++ b/libtorrent/include/asio/detail/posix_fd_set_adapter.hpp @@ -58,7 +58,7 @@ public: } private: - fd_set fd_set_; + mutable fd_set fd_set_; socket_type max_descriptor_; }; diff --git a/libtorrent/include/asio/detail/posix_mutex.hpp b/libtorrent/include/asio/detail/posix_mutex.hpp index 6067880fb..c2a01d0b0 100644 --- a/libtorrent/include/asio/detail/posix_mutex.hpp +++ b/libtorrent/include/asio/detail/posix_mutex.hpp @@ -51,7 +51,8 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, + asio::error::get_system_category()), "mutex"); boost::throw_exception(e); } @@ -70,7 +71,8 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, + asio::error::get_system_category()), "mutex"); boost::throw_exception(e); } @@ -83,7 +85,8 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, + asio::error::get_system_category()), "mutex"); boost::throw_exception(e); } diff --git a/libtorrent/include/asio/detail/posix_thread.hpp b/libtorrent/include/asio/detail/posix_thread.hpp index 6e5815426..a4a3da23c 100644 --- a/libtorrent/include/asio/detail/posix_thread.hpp +++ b/libtorrent/include/asio/detail/posix_thread.hpp @@ -53,7 +53,8 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, + asio::error::get_system_category()), "thread"); boost::throw_exception(e); } diff --git a/libtorrent/include/asio/detail/posix_tss_ptr.hpp b/libtorrent/include/asio/detail/posix_tss_ptr.hpp index dda329c40..1becb8dc4 100644 --- a/libtorrent/include/asio/detail/posix_tss_ptr.hpp +++ b/libtorrent/include/asio/detail/posix_tss_ptr.hpp @@ -47,7 +47,8 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, + asio::error::get_system_category()), "tss"); boost::throw_exception(e); } diff --git a/libtorrent/include/asio/detail/reactive_socket_service.hpp b/libtorrent/include/asio/detail/reactive_socket_service.hpp index 9c0075821..df70f8863 100644 --- a/libtorrent/include/asio/detail/reactive_socket_service.hpp +++ b/libtorrent/include/asio/detail/reactive_socket_service.hpp @@ -157,7 +157,8 @@ public: if (int err = reactor_.register_descriptor(sock.get())) { - ec = asio::error_code(err, asio::error::system_category); + ec = asio::error_code(err, + asio::error::get_system_category()); return ec; } @@ -181,7 +182,8 @@ public: if (int err = reactor_.register_descriptor(native_socket)) { - ec = asio::error_code(err, asio::error::system_category); + ec = asio::error_code(err, + asio::error::get_system_category()); return ec; } @@ -450,7 +452,7 @@ public: } endpoint_type endpoint; - socket_addr_len_type addr_len = endpoint.capacity(); + 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); @@ -468,7 +470,7 @@ public: } endpoint_type endpoint; - socket_addr_len_type addr_len = endpoint.capacity(); + std::size_t addr_len = endpoint.capacity(); if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec)) return endpoint_type(); endpoint.resize(addr_len); @@ -624,7 +626,7 @@ public: { if (!is_open(impl)) { - this->io_service().post(bind_handler(handler, + this->get_io_service().post(bind_handler(handler, asio::error::bad_descriptor, 0)); } else @@ -645,7 +647,7 @@ public: // A request to receive 0 bytes on a stream socket is a no-op. if (total_buffer_size == 0) { - this->io_service().post(bind_handler(handler, + this->get_io_service().post(bind_handler(handler, asio::error_code(), 0)); return; } @@ -658,7 +660,7 @@ public: asio::error_code ec; if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) { - this->io_service().post(bind_handler(handler, ec, 0)); + this->get_io_service().post(bind_handler(handler, ec, 0)); return; } impl.flags_ |= implementation_type::internal_non_blocking; @@ -666,7 +668,7 @@ public: reactor_.start_write_op(impl.socket_, send_handler( - impl.socket_, this->io_service(), buffers, flags, handler)); + impl.socket_, this->get_io_service(), buffers, flags, handler)); } } @@ -804,7 +806,7 @@ public: { if (!is_open(impl)) { - this->io_service().post(bind_handler(handler, + this->get_io_service().post(bind_handler(handler, asio::error::bad_descriptor, 0)); } else @@ -816,7 +818,7 @@ public: asio::error_code ec; if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) { - this->io_service().post(bind_handler(handler, ec, 0)); + this->get_io_service().post(bind_handler(handler, ec, 0)); return; } impl.flags_ |= implementation_type::internal_non_blocking; @@ -824,7 +826,7 @@ public: reactor_.start_write_op(impl.socket_, send_to_handler( - impl.socket_, this->io_service(), buffers, + impl.socket_, this->get_io_service(), buffers, destination, flags, handler)); } } @@ -975,7 +977,7 @@ public: { if (!is_open(impl)) { - this->io_service().post(bind_handler(handler, + this->get_io_service().post(bind_handler(handler, asio::error::bad_descriptor, 0)); } else @@ -996,7 +998,7 @@ public: // A request to receive 0 bytes on a stream socket is a no-op. if (total_buffer_size == 0) { - this->io_service().post(bind_handler(handler, + this->get_io_service().post(bind_handler(handler, asio::error_code(), 0)); return; } @@ -1009,7 +1011,7 @@ public: asio::error_code ec; if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) { - this->io_service().post(bind_handler(handler, ec, 0)); + this->get_io_service().post(bind_handler(handler, ec, 0)); return; } impl.flags_ |= implementation_type::internal_non_blocking; @@ -1019,13 +1021,13 @@ public: { reactor_.start_except_op(impl.socket_, receive_handler( - impl.socket_, this->io_service(), buffers, flags, handler)); + impl.socket_, this->get_io_service(), buffers, flags, handler)); } else { reactor_.start_read_op(impl.socket_, receive_handler( - impl.socket_, this->io_service(), buffers, flags, handler)); + impl.socket_, this->get_io_service(), buffers, flags, handler)); } } } @@ -1073,7 +1075,7 @@ public: for (;;) { // Try to complete the operation without blocking. - socket_addr_len_type addr_len = sender_endpoint.capacity(); + std::size_t addr_len = sender_endpoint.capacity(); int bytes_recvd = socket_ops::recvfrom(impl.socket_, bufs, i, flags, sender_endpoint.data(), &addr_len, ec); @@ -1144,7 +1146,7 @@ public: } // Receive some data. - socket_addr_len_type addr_len = sender_endpoint_.capacity(); + std::size_t addr_len = sender_endpoint_.capacity(); asio::error_code ec; int bytes = socket_ops::recvfrom(socket_, bufs, i, flags_, sender_endpoint_.data(), &addr_len, ec); @@ -1181,7 +1183,7 @@ public: { if (!is_open(impl)) { - this->io_service().post(bind_handler(handler, + this->get_io_service().post(bind_handler(handler, asio::error::bad_descriptor, 0)); } else @@ -1193,7 +1195,7 @@ public: asio::error_code ec; if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) { - this->io_service().post(bind_handler(handler, ec, 0)); + this->get_io_service().post(bind_handler(handler, ec, 0)); return; } impl.flags_ |= implementation_type::internal_non_blocking; @@ -1201,7 +1203,7 @@ public: reactor_.start_read_op(impl.socket_, receive_from_handler( - impl.socket_, this->io_service(), buffers, + impl.socket_, this->get_io_service(), buffers, sender_endpoint, flags, handler)); } } @@ -1242,7 +1244,7 @@ public: // Try to complete the operation without blocking. asio::error_code ec; socket_holder new_socket; - socket_addr_len_type addr_len = 0; + std::size_t addr_len = 0; if (peer_endpoint) { addr_len = peer_endpoint->capacity(); @@ -1327,7 +1329,7 @@ public: // Accept the waiting connection. asio::error_code ec; socket_holder new_socket; - socket_addr_len_type addr_len = 0; + std::size_t addr_len = 0; if (peer_endpoint_) { addr_len = peer_endpoint_->capacity(); @@ -1384,12 +1386,12 @@ public: { if (!is_open(impl)) { - this->io_service().post(bind_handler(handler, + this->get_io_service().post(bind_handler(handler, asio::error::bad_descriptor)); } else if (peer.is_open()) { - this->io_service().post(bind_handler(handler, + this->get_io_service().post(bind_handler(handler, asio::error::already_open)); } else @@ -1401,7 +1403,7 @@ public: asio::error_code ec; if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) { - this->io_service().post(bind_handler(handler, ec)); + this->get_io_service().post(bind_handler(handler, ec)); return; } impl.flags_ |= implementation_type::internal_non_blocking; @@ -1409,7 +1411,7 @@ public: reactor_.start_read_op(impl.socket_, accept_handler( - impl.socket_, this->io_service(), + impl.socket_, this->get_io_service(), peer, impl.protocol_, peer_endpoint, (impl.flags_ & implementation_type::enable_connection_aborted) != 0, handler)); @@ -1489,7 +1491,7 @@ public: if (connect_error) { ec = asio::error_code(connect_error, - asio::error::system_category); + asio::error::get_system_category()); io_service_.post(bind_handler(handler_, ec)); return true; } @@ -1515,7 +1517,7 @@ public: { if (!is_open(impl)) { - this->io_service().post(bind_handler(handler, + this->get_io_service().post(bind_handler(handler, asio::error::bad_descriptor)); return; } @@ -1527,7 +1529,7 @@ public: asio::error_code ec; if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) { - this->io_service().post(bind_handler(handler, ec)); + this->get_io_service().post(bind_handler(handler, ec)); return; } impl.flags_ |= implementation_type::internal_non_blocking; @@ -1541,7 +1543,7 @@ public: { // The connect operation has finished successfully so we need to post the // handler immediately. - this->io_service().post(bind_handler(handler, + this->get_io_service().post(bind_handler(handler, asio::error_code())); } else if (ec == asio::error::in_progress @@ -1551,13 +1553,13 @@ public: // until the socket becomes writeable. boost::shared_ptr completed(new bool(false)); reactor_.start_write_and_except_ops(impl.socket_, - connect_handler( - impl.socket_, completed, this->io_service(), reactor_, handler)); + connect_handler(impl.socket_, completed, + this->get_io_service(), reactor_, handler)); } else { // The connect operation has failed, so post the handler immediately. - this->io_service().post(bind_handler(handler, ec)); + this->get_io_service().post(bind_handler(handler, ec)); } } diff --git a/libtorrent/include/asio/detail/resolver_service.hpp b/libtorrent/include/asio/detail/resolver_service.hpp index c820b75f3..dab6340a5 100644 --- a/libtorrent/include/asio/detail/resolver_service.hpp +++ b/libtorrent/include/asio/detail/resolver_service.hpp @@ -213,7 +213,7 @@ public: start_work_thread(); work_io_service_->post( resolve_query_handler( - impl, query, this->io_service(), handler)); + impl, query, this->get_io_service(), handler)); } } @@ -309,7 +309,7 @@ public: start_work_thread(); work_io_service_->post( resolve_endpoint_handler( - impl, endpoint, this->io_service(), handler)); + impl, endpoint, this->get_io_service(), handler)); } } diff --git a/libtorrent/include/asio/detail/socket_ops.hpp b/libtorrent/include/asio/detail/socket_ops.hpp index 98f3b0f64..ee0b4b582 100644 --- a/libtorrent/include/asio/detail/socket_ops.hpp +++ b/libtorrent/include/asio/detail/socket_ops.hpp @@ -26,9 +26,6 @@ #include #include #include -#if defined(__MACH__) && defined(__APPLE__) -# include -#endif // defined(__MACH__) && defined(__APPLE__) #include "asio/detail/pop_options.hpp" #include "asio/error.hpp" @@ -38,12 +35,24 @@ namespace asio { namespace detail { namespace socket_ops { +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +struct msghdr { int msg_namelen; }; +#endif // defined(BOOST_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) + inline void clear_error(asio::error_code& ec) { - errno = 0; #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) WSASetLastError(0); -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +#else + errno = 0; +#endif ec = asio::error_code(); } @@ -53,22 +62,36 @@ inline ReturnType error_wrapper(ReturnType return_value, { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) ec = asio::error_code(WSAGetLastError(), - asio::error::system_category); + asio::error::get_system_category()); #else - ec = asio::error_code(errno, asio::error::system_category); + ec = asio::error_code(errno, + asio::error::get_system_category()); #endif return return_value; } +template +inline socket_type call_accept(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; + socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0); + if (addrlen) + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + inline socket_type accept(socket_type s, socket_addr_type* addr, - socket_addr_len_type* addrlen, asio::error_code& ec) + std::size_t* addrlen, asio::error_code& ec) { clear_error(ec); -#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) - socket_type new_s = error_wrapper(::accept(s, addr, addrlen), ec); + + socket_type new_s = error_wrapper(call_accept( + &msghdr::msg_namelen, s, addr, addrlen), ec); if (new_s == invalid_socket) return new_s; +#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) int optval = 1; int result = error_wrapper(::setsockopt(new_s, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); @@ -77,25 +100,45 @@ inline socket_type accept(socket_type s, socket_addr_type* addr, ::close(new_s); return invalid_socket; } +#endif + +#if defined(BOOST_WINDOWS) && defined(UNDER_CE) + clear_error(ec); +#endif return new_s; -#else - return error_wrapper(::accept(s, addr, addrlen), ec); -#endif +} + +template +inline int call_bind(SockLenType msghdr::*, + socket_type s, const socket_addr_type* addr, std::size_t addrlen) +{ + return ::bind(s, addr, (SockLenType)addrlen); } inline int bind(socket_type s, const socket_addr_type* addr, - socket_addr_len_type addrlen, asio::error_code& ec) + std::size_t addrlen, asio::error_code& ec) { clear_error(ec); - return error_wrapper(::bind(s, addr, addrlen), ec); + int result = error_wrapper(call_bind( + &msghdr::msg_namelen, s, addr, addrlen), ec); +#if defined(BOOST_WINDOWS) && defined(UNDER_CE) + if (result == 0) + clear_error(ec); +#endif + return result; } inline int close(socket_type s, asio::error_code& ec) { clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - return error_wrapper(::closesocket(s), ec); + int result = error_wrapper(::closesocket(s), ec); +# if defined(UNDER_CE) + if (result == 0) + clear_error(ec); +# endif + return result; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) return error_wrapper(::close(s), ec); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -104,20 +147,43 @@ inline int close(socket_type s, asio::error_code& ec) inline int shutdown(socket_type s, int what, asio::error_code& ec) { clear_error(ec); - return error_wrapper(::shutdown(s, what), ec); + int result = error_wrapper(::shutdown(s, what), ec); +#if defined(BOOST_WINDOWS) && defined(UNDER_CE) + if (result == 0) + clear_error(ec); +#endif + return result; +} + +template +inline int call_connect(SockLenType msghdr::*, + socket_type s, const socket_addr_type* addr, std::size_t addrlen) +{ + return ::connect(s, addr, (SockLenType)addrlen); } inline int connect(socket_type s, const socket_addr_type* addr, - socket_addr_len_type addrlen, asio::error_code& ec) + std::size_t addrlen, asio::error_code& ec) { clear_error(ec); - return error_wrapper(::connect(s, addr, addrlen), ec); + int result = error_wrapper(call_connect( + &msghdr::msg_namelen, s, addr, addrlen), ec); +#if defined(BOOST_WINDOWS) && defined(UNDER_CE) + if (result == 0) + clear_error(ec); +#endif + return result; } inline int listen(socket_type s, int backlog, asio::error_code& ec) { clear_error(ec); - return error_wrapper(::listen(s, backlog), ec); + int result = error_wrapper(::listen(s, backlog), ec); +#if defined(BOOST_WINDOWS) && defined(UNDER_CE) + if (result == 0) + clear_error(ec); +#endif + return result; } #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -148,6 +214,28 @@ inline void init_buf(buf& b, const void* data, size_t size) #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } +inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr) +{ + name = addr; +} + +inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr) +{ + name = const_cast(addr); +} + +template +inline void init_msghdr_msg_name(T& name, socket_addr_type* addr) +{ + name = reinterpret_cast(addr); +} + +template +inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr) +{ + name = reinterpret_cast(const_cast(addr)); +} + inline int recv(socket_type s, buf* bufs, size_t count, int flags, asio::error_code& ec) { @@ -161,22 +249,20 @@ inline int recv(socket_type s, buf* bufs, size_t count, int flags, recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec); if (result != 0) return -1; +# if defined(UNDER_CE) + clear_error(ec); +# endif return bytes_transferred; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg; - msg.msg_name = 0; - msg.msg_namelen = 0; + msghdr msg = msghdr(); msg.msg_iov = bufs; msg.msg_iovlen = count; - msg.msg_control = 0; - msg.msg_controllen = 0; - msg.msg_flags = 0; return error_wrapper(::recvmsg(s, &msg, flags), ec); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags, - socket_addr_type* addr, socket_addr_len_type* addrlen, + socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec) { clear_error(ec); @@ -185,25 +271,22 @@ inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags, DWORD recv_buf_count = static_cast(count); DWORD bytes_transferred = 0; DWORD recv_flags = flags; + int tmp_addrlen = (int)*addrlen; int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count, - &bytes_transferred, &recv_flags, addr, addrlen, 0, 0), ec); + &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec); + *addrlen = (std::size_t)tmp_addrlen; if (result != 0) return -1; +# if defined(UNDER_CE) + clear_error(ec); +# endif return bytes_transferred; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg; -#if defined(__MACH__) && defined(__APPLE__) \ - && (MAC_OS_X_VERSION_MAX_ALLOWED < 1040) - msg.msg_name = reinterpret_cast(addr); -#else - msg.msg_name = addr; -#endif + msghdr msg = msghdr(); + init_msghdr_msg_name(msg.msg_name, addr); msg.msg_namelen = *addrlen; msg.msg_iov = bufs; msg.msg_iovlen = count; - msg.msg_control = 0; - msg.msg_controllen = 0; - msg.msg_flags = 0; int result = error_wrapper(::recvmsg(s, &msg, flags), ec); *addrlen = msg.msg_namelen; return result; @@ -223,16 +306,14 @@ inline int send(socket_type s, const buf* bufs, size_t count, int flags, send_buf_count, &bytes_transferred, send_flags, 0, 0), ec); if (result != 0) return -1; +# if defined(UNDER_CE) + clear_error(ec); +# endif return bytes_transferred; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg; - msg.msg_name = 0; - msg.msg_namelen = 0; + msghdr msg = msghdr(); msg.msg_iov = const_cast(bufs); msg.msg_iovlen = count; - msg.msg_control = 0; - msg.msg_controllen = 0; - msg.msg_flags = 0; #if defined(__linux__) flags |= MSG_NOSIGNAL; #endif // defined(__linux__) @@ -241,7 +322,7 @@ inline int send(socket_type s, const buf* bufs, size_t count, int flags, } inline int sendto(socket_type s, const buf* bufs, size_t count, int flags, - const socket_addr_type* addr, socket_addr_len_type addrlen, + const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec) { clear_error(ec); @@ -250,24 +331,20 @@ inline int sendto(socket_type s, const buf* bufs, size_t count, int flags, DWORD send_buf_count = static_cast(count); DWORD bytes_transferred = 0; int result = error_wrapper(::WSASendTo(s, const_cast(bufs), - send_buf_count, &bytes_transferred, flags, addr, addrlen, 0, 0), ec); + send_buf_count, &bytes_transferred, flags, addr, + static_cast(addrlen), 0, 0), ec); if (result != 0) return -1; +# if defined(UNDER_CE) + clear_error(ec); +# endif return bytes_transferred; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg; -#if defined(__MACH__) && defined(__APPLE__) \ - && (MAC_OS_X_VERSION_MAX_ALLOWED < 1040) - msg.msg_name = reinterpret_cast(const_cast(addr)); -#else - msg.msg_name = const_cast(addr); -#endif + msghdr msg = msghdr(); + init_msghdr_msg_name(msg.msg_name, addr); msg.msg_namelen = addrlen; msg.msg_iov = const_cast(bufs); msg.msg_iovlen = count; - msg.msg_control = 0; - msg.msg_controllen = 0; - msg.msg_flags = 0; #if defined(__linux__) flags |= MSG_NOSIGNAL; #endif // defined(__linux__) @@ -295,6 +372,10 @@ inline socket_type socket(int af, int type, int protocol, reinterpret_cast(&optval), sizeof(optval)); } +# if defined(UNDER_CE) + clear_error(ec); +# endif + return s; #elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) socket_type s = error_wrapper(::socket(af, type, protocol), ec); @@ -316,8 +397,17 @@ inline socket_type socket(int af, int type, int protocol, #endif } +template +inline int call_setsockopt(SockLenType msghdr::*, + socket_type s, int level, int optname, + const void* optval, std::size_t optlen) +{ + return ::setsockopt(s, level, optname, + (const char*)optval, (SockLenType)optlen); +} + inline int setsockopt(socket_type s, int level, int optname, - const void* optval, size_t optlen, asio::error_code& ec) + const void* optval, std::size_t optlen, asio::error_code& ec) { if (level == custom_socket_option_level && optname == always_fail_option) { @@ -342,15 +432,27 @@ inline int setsockopt(socket_type s, int level, int optname, } ec = asio::error::fault; return -1; -#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) +#else // defined(__BORLANDC__) clear_error(ec); - return error_wrapper(::setsockopt(s, level, optname, - reinterpret_cast(optval), static_cast(optlen)), ec); -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - clear_error(ec); - return error_wrapper(::setsockopt(s, level, optname, optval, - static_cast(optlen)), ec); -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); +# if defined(BOOST_WINDOWS) && defined(UNDER_CE) + if (result == 0) + clear_error(ec); +# endif + return result; +#endif // defined(__BORLANDC__) +} + +template +inline int call_getsockopt(SockLenType msghdr::*, + socket_type s, int level, int optname, + void* optval, std::size_t* optlen) +{ + SockLenType tmp_optlen = (SockLenType)*optlen; + int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen); + *optlen = (std::size_t)tmp_optlen; + return result; } inline int getsockopt(socket_type s, int level, int optname, void* optval, @@ -394,10 +496,8 @@ inline int getsockopt(socket_type s, int level, int optname, void* optval, return -1; #elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) clear_error(ec); - int tmp_optlen = static_cast(*optlen); - int result = error_wrapper(::getsockopt(s, level, optname, - reinterpret_cast(optval), &tmp_optlen), ec); - *optlen = static_cast(tmp_optlen); + int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) { @@ -409,13 +509,15 @@ inline int getsockopt(socket_type s, int level, int optname, void* optval, *static_cast(optval) = 1; clear_error(ec); } +# if defined(UNDER_CE) + if (result == 0) + clear_error(ec); +# endif return result; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) clear_error(ec); - socklen_t tmp_optlen = static_cast(*optlen); - int result = error_wrapper(::getsockopt(s, level, optname, - optval, &tmp_optlen), ec); - *optlen = static_cast(tmp_optlen); + int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); #if defined(__linux__) if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int) && (optname == SO_SNDBUF || optname == SO_RCVBUF)) @@ -432,18 +534,50 @@ inline int getsockopt(socket_type s, int level, int optname, void* optval, #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } +template +inline int call_getpeername(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = (SockLenType)*addrlen; + int result = ::getpeername(s, addr, &tmp_addrlen); + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + inline int getpeername(socket_type s, socket_addr_type* addr, - socket_addr_len_type* addrlen, asio::error_code& ec) + std::size_t* addrlen, asio::error_code& ec) { clear_error(ec); - return error_wrapper(::getpeername(s, addr, addrlen), ec); + int result = error_wrapper(call_getpeername( + &msghdr::msg_namelen, s, addr, addrlen), ec); +#if defined(BOOST_WINDOWS) && defined(UNDER_CE) + if (result == 0) + clear_error(ec); +#endif + return result; +} + +template +inline int call_getsockname(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = (SockLenType)*addrlen; + int result = ::getsockname(s, addr, &tmp_addrlen); + *addrlen = (std::size_t)tmp_addrlen; + return result; } inline int getsockname(socket_type s, socket_addr_type* addr, - socket_addr_len_type* addrlen, asio::error_code& ec) + std::size_t* addrlen, asio::error_code& ec) { clear_error(ec); - return error_wrapper(::getsockname(s, addr, addrlen), ec); + int result = error_wrapper(call_getsockname( + &msghdr::msg_namelen, s, addr, addrlen), ec); +#if defined(BOOST_WINDOWS) && defined(UNDER_CE) + if (result == 0) + clear_error(ec); +#endif + return result; } inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg, @@ -451,7 +585,12 @@ inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg, { clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - return error_wrapper(::ioctlsocket(s, cmd, arg), ec); + int result = error_wrapper(::ioctlsocket(s, cmd, arg), ec); +# if defined(UNDER_CE) + if (result == 0) + clear_error(ec); +# endif + return result; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) return error_wrapper(::ioctl(s, cmd, arg), ec); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -482,8 +621,22 @@ inline int select(int nfds, fd_set* readfds, fd_set* writefds, && timeout->tv_usec > 0 && timeout->tv_usec < 1000) timeout->tv_usec = 1000; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - return error_wrapper(::select(nfds, readfds, + +#if defined(__hpux) && defined(__HP_aCC) + timespec ts; + ts.tv_sec = timeout ? timeout->tv_sec : 0; + ts.tv_nsec = timeout ? timeout->tv_usec * 1000 : 0; + return error_wrapper(::pselect(nfds, readfds, + writefds, exceptfds, timeout ? &ts : 0, 0), ec); +#else + int result = error_wrapper(::select(nfds, readfds, writefds, exceptfds, timeout), ec); +# if defined(BOOST_WINDOWS) && defined(UNDER_CE) + if (result >= 0) + clear_error(ec); +# endif + return result; +#endif } inline int poll_read(socket_type s, asio::error_code& ec) @@ -493,7 +646,12 @@ inline int poll_read(socket_type s, asio::error_code& ec) FD_ZERO(&fds); FD_SET(s, &fds); clear_error(ec); - return error_wrapper(::select(s, &fds, 0, 0, 0), ec); + int result = error_wrapper(::select(s, &fds, 0, 0, 0), ec); +# if defined(UNDER_CE) + if (result >= 0) + clear_error(ec); +# endif + return result; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) pollfd fds; fds.fd = s; @@ -511,7 +669,12 @@ inline int poll_write(socket_type s, asio::error_code& ec) FD_ZERO(&fds); FD_SET(s, &fds); clear_error(ec); - return error_wrapper(::select(s, 0, &fds, 0, 0), ec); + int result = error_wrapper(::select(s, 0, &fds, 0, 0), ec); +# if defined(UNDER_CE) + if (result >= 0) + clear_error(ec); +# endif + return result; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) pollfd fds; fds.fd = s; @@ -559,9 +722,17 @@ inline const char* inet_ntop(int af, const void* src, char* dest, size_t length, } DWORD string_length = static_cast(length); +#if defined(BOOST_NO_ANSI_APIS) + LPWSTR string_buffer = (LPWSTR)_alloca(length * sizeof(WCHAR)); + int result = error_wrapper(::WSAAddressToStringW( + reinterpret_cast(&address), + address_length, 0, string_buffer, &string_length), ec); + ::WideCharToMultiByte(CP_ACP, 0, string_buffer, -1, dest, length, 0, 0); +#else int result = error_wrapper(::WSAAddressToStringA( reinterpret_cast(&address), address_length, 0, dest, &string_length), ec); +#endif // Windows may set error code on success. if (result != socket_error_retval) @@ -605,10 +776,20 @@ inline int inet_pton(int af, const char* src, void* dest, sockaddr_storage_type address; int address_length = sizeof(sockaddr_storage_type); +#if defined(BOOST_NO_ANSI_APIS) + int num_wide_chars = strlen(src) + 1; + LPWSTR wide_buffer = (LPWSTR)_alloca(num_wide_chars * sizeof(WCHAR)); + ::MultiByteToWideChar(CP_ACP, 0, src, -1, wide_buffer, num_wide_chars); + int result = error_wrapper(::WSAStringToAddressW( + wide_buffer, af, 0, + reinterpret_cast(&address), + &address_length), ec); +#else int result = error_wrapper(::WSAStringToAddressA( const_cast(src), af, 0, reinterpret_cast(&address), &address_length), ec); +#endif if (af == AF_INET) { @@ -642,6 +823,11 @@ inline int inet_pton(int af, const char* src, void* dest, if (result == socket_error_retval && !ec) ec = asio::error::invalid_argument; +#if defined(UNDER_CE) + if (result != socket_error_retval) + clear_error(ec); +#endif + return result == socket_error_retval ? -1 : 1; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) int result = error_wrapper(::inet_pton(af, src, dest), ec); @@ -668,7 +854,12 @@ inline int inet_pton(int af, const char* src, void* dest, inline int gethostname(char* name, int namelen, asio::error_code& ec) { clear_error(ec); - return error_wrapper(::gethostname(name, namelen), ec); + int result = error_wrapper(::gethostname(name, namelen), ec); +#if defined(BOOST_WINDOWS) && defined(UNDER_CE) + if (result == 0) + clear_error(ec); +#endif + return result; } #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \ @@ -707,6 +898,9 @@ inline hostent* gethostbyaddr(const char* addr, int length, int af, hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec); if (!retval) return 0; +# if defined(UNDER_CE) + clear_error(ec); +# endif *result = *retval; return retval; #elif defined(__sun) || defined(__QNX__) @@ -755,6 +949,9 @@ inline hostent* gethostbyname(const char* name, int af, struct hostent* result, hostent* retval = error_wrapper(::gethostbyname(name), ec); if (!retval) return 0; +# if defined(UNDER_CE) + clear_error(ec); +# endif *result = *retval; return result; #elif defined(__sun) || defined(__QNX__) @@ -1373,7 +1570,7 @@ inline int getaddrinfo_emulation(const char* host, const char* service, } inline asio::error_code getnameinfo_emulation( - const socket_addr_type* sa, socket_addr_len_type salen, char* host, + const socket_addr_type* sa, std::size_t salen, char* host, std::size_t hostlen, char* serv, std::size_t servlen, int flags, asio::error_code& ec) { @@ -1526,10 +1723,10 @@ inline asio::error_code translate_addrinfo_error(int error) default: // Possibly the non-portable EAI_SYSTEM. #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) return asio::error_code( - WSAGetLastError(), asio::error::system_category); + WSAGetLastError(), asio::error::get_system_category()); #else return asio::error_code( - errno, asio::error::system_category); + errno, asio::error::get_system_category()); #endif } } @@ -1540,7 +1737,7 @@ inline asio::error_code getaddrinfo(const char* host, { clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) // Building for Windows XP, Windows Server 2003, or later. int error = ::getaddrinfo(host, service, hints, result); return ec = translate_addrinfo_error(error); @@ -1571,7 +1768,7 @@ inline asio::error_code getaddrinfo(const char* host, inline void freeaddrinfo(addrinfo_type* ai) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) // Building for Windows XP, Windows Server 2003, or later. ::freeaddrinfo(ai); # else @@ -1595,11 +1792,11 @@ inline void freeaddrinfo(addrinfo_type* ai) } inline asio::error_code getnameinfo(const socket_addr_type* addr, - socket_addr_len_type addrlen, char* host, std::size_t hostlen, + std::size_t addrlen, char* host, std::size_t hostlen, char* serv, std::size_t servlen, int flags, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) || defined(UNDER_CE) // Building for Windows XP, Windows Server 2003, or later. clear_error(ec); int error = ::getnameinfo(addr, addrlen, host, static_cast(hostlen), @@ -1608,7 +1805,7 @@ inline asio::error_code getnameinfo(const socket_addr_type* addr, # else // Building for Windows 2000 or earlier. typedef int (WSAAPI *gni_t)(const socket_addr_type*, - socket_addr_len_type, char*, std::size_t, char*, std::size_t, int); + int, char*, std::size_t, char*, std::size_t, int); if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) { if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo")) diff --git a/libtorrent/include/asio/detail/socket_select_interrupter.hpp b/libtorrent/include/asio/detail/socket_select_interrupter.hpp index ba62b12d6..988f92e8e 100644 --- a/libtorrent/include/asio/detail/socket_select_interrupter.hpp +++ b/libtorrent/include/asio/detail/socket_select_interrupter.hpp @@ -52,7 +52,7 @@ public: using namespace std; // For memset. sockaddr_in4_type addr; - socket_addr_len_type addr_len = sizeof(addr); + std::size_t addr_len = sizeof(addr); memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); diff --git a/libtorrent/include/asio/detail/socket_types.hpp b/libtorrent/include/asio/detail/socket_types.hpp index 02c3a78d5..e2b68910c 100644 --- a/libtorrent/include/asio/detail/socket_types.hpp +++ b/libtorrent/include/asio/detail/socket_types.hpp @@ -29,12 +29,12 @@ # if !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) # if defined(_MSC_VER) || defined(__BORLANDC__) # pragma message("Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately") -# pragma message("Assuming _WIN32_WINNT=0x0500 (i.e. Windows 2000 target)") +# pragma message("Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target)") # else // defined(_MSC_VER) || defined(__BORLANDC__) # warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately -# warning Assuming _WIN32_WINNT=0x0500 (i.e. Windows 2000 target) +# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target) # endif // defined(_MSC_VER) || defined(__BORLANDC__) -# define _WIN32_WINNT 0x0500 +# define _WIN32_WINNT 0x0501 # endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) # if defined(_MSC_VER) # if defined(_WIN32) && !defined(WIN32) @@ -80,7 +80,9 @@ # undef ASIO_WSPIAPI_H_DEFINED # endif // defined(ASIO_WSPIAPI_H_DEFINED) # if !defined(ASIO_NO_DEFAULT_LINKED_LIBS) -# if defined(_MSC_VER) || defined(__BORLANDC__) +# if defined(UNDER_CE) +# pragma comment(lib, "ws2.lib") +# elif defined(_MSC_VER) || defined(__BORLANDC__) # pragma comment(lib, "ws2_32.lib") # pragma comment(lib, "mswsock.lib") # endif // defined(_MSC_VER) || defined(__BORLANDC__) @@ -116,7 +118,6 @@ 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 int socket_addr_len_type; typedef in_addr in4_addr_type; typedef ip_mreq in4_mreq_type; typedef sockaddr_in sockaddr_in4_type; @@ -154,7 +155,6 @@ const int socket_error_retval = -1; const int max_addr_v4_str_len = INET_ADDRSTRLEN; const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE; typedef sockaddr socket_addr_type; -typedef socklen_t socket_addr_len_type; typedef in_addr in4_addr_type; typedef ip_mreq in4_mreq_type; typedef sockaddr_in sockaddr_in4_type; diff --git a/libtorrent/include/asio/detail/strand_service.hpp b/libtorrent/include/asio/detail/strand_service.hpp index d987cb98d..598b79dcc 100644 --- a/libtorrent/include/asio/detail/strand_service.hpp +++ b/libtorrent/include/asio/detail/strand_service.hpp @@ -135,9 +135,9 @@ public: handler_base* last_waiter_; // Storage for posted handlers. - typedef boost::aligned_storage<64> handler_storage_type; + typedef boost::aligned_storage<128> handler_storage_type; #if defined(__BORLANDC__) - boost::aligned_storage<64> handler_storage_; + boost::aligned_storage<128> handler_storage_; #else handler_storage_type handler_storage_; #endif @@ -235,7 +235,7 @@ public: void* do_handler_allocate(std::size_t size) { #if defined(__BORLANDC__) - BOOST_ASSERT(size <= boost::aligned_storage<64>::size); + BOOST_ASSERT(size <= boost::aligned_storage<128>::size); #else BOOST_ASSERT(size <= strand_impl::handler_storage_type::size); #endif @@ -276,7 +276,7 @@ public: if (impl_->first_waiter_ == 0) impl_->last_waiter_ = 0; lock.unlock(); - service_impl_.io_service().post( + service_impl_.get_io_service().post( invoke_current_handler(service_impl_, impl_)); } } @@ -429,7 +429,7 @@ public: // This handler now has the lock, so can be dispatched immediately. impl->current_handler_ = ptr.get(); lock.unlock(); - this->io_service().dispatch(invoke_current_handler(*this, impl)); + this->get_io_service().dispatch(invoke_current_handler(*this, impl)); ptr.release(); } else @@ -469,7 +469,7 @@ public: // This handler now has the lock, so can be dispatched immediately. impl->current_handler_ = ptr.get(); lock.unlock(); - this->io_service().post(invoke_current_handler(*this, impl)); + this->get_io_service().post(invoke_current_handler(*this, impl)); ptr.release(); } else diff --git a/libtorrent/include/asio/detail/task_io_service.hpp b/libtorrent/include/asio/detail/task_io_service.hpp index 802d7ea95..ffadb620b 100644 --- a/libtorrent/include/asio/detail/task_io_service.hpp +++ b/libtorrent/include/asio/detail/task_io_service.hpp @@ -23,6 +23,7 @@ #include "asio/detail/event.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_queue.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/service_base.hpp" #include "asio/detail/task_io_service_fwd.hpp" @@ -42,12 +43,11 @@ public: task_(use_service(io_service)), task_interrupted_(true), outstanding_work_(0), - handler_queue_(&task_handler_), - handler_queue_end_(&task_handler_), stopped_(false), shutdown_(false), first_idle_thread_(0) { + handler_queue_.push(&task_handler_); } void init(size_t /*concurrency_hint*/) @@ -62,17 +62,16 @@ public: lock.unlock(); // Destroy handler objects. - while (handler_queue_) + while (!handler_queue_.empty()) { - handler_base* h = handler_queue_; - handler_queue_ = h->next_; + handler_queue::handler* h = handler_queue_.front(); + handler_queue_.pop(); if (h != &task_handler_) h->destroy(); } // Reset handler queue to initial state. - handler_queue_ = &task_handler_; - handler_queue_end_ = &task_handler_; + handler_queue_.push(&task_handler_); } // Run the event loop until interrupted or no more work. @@ -173,10 +172,7 @@ public: void post(Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef handler_wrapper value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); + handler_queue::scoped_ptr ptr(handler_queue::wrap(handler)); asio::detail::mutex::scoped_lock lock(mutex_); @@ -185,15 +181,7 @@ public: return; // Add the handler to the end of the queue. - if (handler_queue_end_) - { - handler_queue_end_->next_ = ptr.get(); - handler_queue_end_ = ptr.get(); - } - else - { - handler_queue_ = handler_queue_end_ = ptr.get(); - } + handler_queue_.push(ptr.get()); ptr.release(); // An undelivered handler is treated as unfinished work. @@ -227,29 +215,28 @@ private: bool task_has_run = false; while (!stopped_) { - if (handler_queue_) + if (!handler_queue_.empty()) { // Prepare to execute first handler from queue. - handler_base* h = handler_queue_; - handler_queue_ = h->next_; - if (handler_queue_ == 0) - handler_queue_end_ = 0; - h->next_ = 0; + handler_queue::handler* h = handler_queue_.front(); + handler_queue_.pop(); if (h == &task_handler_) { - bool more_handlers = (handler_queue_ != 0); + bool more_handlers = (!handler_queue_.empty()); task_interrupted_ = more_handlers || polling; - lock.unlock(); // If the task has already run and we're polling then we're done. if (task_has_run && polling) { + task_interrupted_ = true; + handler_queue_.push(&task_handler_); ec = asio::error_code(); return 0; } task_has_run = true; - + + lock.unlock(); task_cleanup c(lock, *this); // Run the task. May throw an exception. Only block if the handler @@ -263,7 +250,7 @@ private: handler_cleanup c(lock, *this); // Invoke the handler. May throw an exception. - h->call(); // call() deletes the handler object + h->invoke(); // invoke() deletes the handler object ec = asio::error_code(); return 1; @@ -330,94 +317,9 @@ private: } } + // Helper class to perform task-related operations on block exit. class task_cleanup; friend class task_cleanup; - - // The base class for all handler wrappers. A function pointer is used - // instead of virtual functions to avoid the associated overhead. - class handler_base - { - public: - typedef void (*call_func_type)(handler_base*); - typedef void (*destroy_func_type)(handler_base*); - - handler_base(call_func_type call_func, destroy_func_type destroy_func) - : next_(0), - call_func_(call_func), - destroy_func_(destroy_func) - { - } - - void call() - { - call_func_(this); - } - - void destroy() - { - destroy_func_(this); - } - - protected: - // Prevent deletion through this type. - ~handler_base() - { - } - - private: - friend class task_io_service; - friend class task_cleanup; - handler_base* next_; - call_func_type call_func_; - destroy_func_type destroy_func_; - }; - - // Template wrapper for handlers. - template - class handler_wrapper - : public handler_base - { - public: - handler_wrapper(Handler handler) - : handler_base(&handler_wrapper::do_call, - &handler_wrapper::do_destroy), - handler_(handler) - { - } - - static void do_call(handler_base* base) - { - // Take ownership of the handler object. - typedef handler_wrapper this_type; - this_type* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(h->handler_, h); - - // Make a copy of the handler so that the memory can be deallocated before - // the upcall is made. - Handler handler(h->handler_); - - // Free the memory associated with the handler. - ptr.reset(); - - // Make the upcall. - asio_handler_invoke_helpers::invoke(handler, &handler); - } - - static void do_destroy(handler_base* base) - { - // Take ownership of the handler object. - typedef handler_wrapper this_type; - this_type* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(h->handler_, h); - } - - private: - Handler handler_; - }; - - // Helper class to perform task-related operations on block exit. class task_cleanup { public: @@ -433,20 +335,7 @@ private: // Reinsert the task at the end of the handler queue. lock_.lock(); task_io_service_.task_interrupted_ = true; - task_io_service_.task_handler_.next_ = 0; - if (task_io_service_.handler_queue_end_) - { - task_io_service_.handler_queue_end_->next_ - = &task_io_service_.task_handler_; - task_io_service_.handler_queue_end_ - = &task_io_service_.task_handler_; - } - else - { - task_io_service_.handler_queue_ - = task_io_service_.handler_queue_end_ - = &task_io_service_.task_handler_; - } + task_io_service_.handler_queue_.push(&task_io_service_.task_handler_); } private: @@ -487,11 +376,11 @@ private: // Handler object to represent the position of the task in the queue. class task_handler - : public handler_base + : public handler_queue::handler { public: task_handler() - : handler_base(0, 0) + : handler_queue::handler(0, 0) { } } task_handler_; @@ -502,11 +391,8 @@ private: // The count of unfinished work. int outstanding_work_; - // The start of a linked list of handlers that are ready to be delivered. - handler_base* handler_queue_; - - // The end of a linked list of handlers that are ready to be delivered. - handler_base* handler_queue_end_; + // The queue of handlers that are ready to be delivered. + handler_queue handler_queue_; // Flag to indicate that the dispatcher has been stopped. bool stopped_; diff --git a/libtorrent/include/asio/detail/thread.hpp b/libtorrent/include/asio/detail/thread.hpp index b334c38af..520477e37 100644 --- a/libtorrent/include/asio/detail/thread.hpp +++ b/libtorrent/include/asio/detail/thread.hpp @@ -24,7 +24,11 @@ #if !defined(BOOST_HAS_THREADS) # include "asio/detail/null_thread.hpp" #elif defined(BOOST_WINDOWS) -# include "asio/detail/win_thread.hpp" +# if defined(UNDER_CE) +# include "asio/detail/wince_thread.hpp" +# else +# include "asio/detail/win_thread.hpp" +# endif #elif defined(BOOST_HAS_PTHREADS) # include "asio/detail/posix_thread.hpp" #else @@ -37,7 +41,11 @@ namespace detail { #if !defined(BOOST_HAS_THREADS) typedef null_thread thread; #elif defined(BOOST_WINDOWS) +# if defined(UNDER_CE) +typedef wince_thread thread; +# else typedef win_thread thread; +# endif #elif defined(BOOST_HAS_PTHREADS) typedef posix_thread thread; #endif diff --git a/libtorrent/include/asio/detail/timer_queue.hpp b/libtorrent/include/asio/detail/timer_queue.hpp index 7735e87cf..472cc3759 100644 --- a/libtorrent/include/asio/detail/timer_queue.hpp +++ b/libtorrent/include/asio/detail/timer_queue.hpp @@ -162,13 +162,7 @@ public: // Destroy timers that are waiting to be cleaned up. virtual void cleanup_timers() { - while (cleanup_timers_) - { - timer_base* next_timer = cleanup_timers_->next_; - cleanup_timers_->next_ = 0; - cleanup_timers_->destroy(); - cleanup_timers_ = next_timer; - } + destroy_timer_list(cleanup_timers_); } // Destroy all timers. @@ -181,11 +175,12 @@ public: timer_base* t = i->second; typename hash_map::iterator old_i = i++; timers_.erase(old_i); - t->destroy(); + destroy_timer_list(t); } heap_.clear(); timers_.clear(); - cleanup_timers(); + destroy_timer_list(cancelled_timers_); + destroy_timer_list(cleanup_timers_); } private: @@ -367,6 +362,18 @@ private: } } + // Destroy all timers in a linked list. + void destroy_timer_list(timer_base*& t) + { + while (t) + { + timer_base* next = t->next_; + t->next_ = 0; + t->destroy(); + t = next; + } + } + // A hash of timer token to linked lists of timers. hash_map timers_; diff --git a/libtorrent/include/asio/detail/win_event.hpp b/libtorrent/include/asio/detail/win_event.hpp index c73ed56ea..ff97fbedc 100644 --- a/libtorrent/include/asio/detail/win_event.hpp +++ b/libtorrent/include/asio/detail/win_event.hpp @@ -49,7 +49,7 @@ public: DWORD last_error = ::GetLastError(); asio::system_error e( asio::error_code(last_error, - asio::error::system_category), + asio::error::get_system_category()), "event"); boost::throw_exception(e); } diff --git a/libtorrent/include/asio/detail/win_iocp_io_service.hpp b/libtorrent/include/asio/detail/win_iocp_io_service.hpp index 61eeb1745..46e651653 100644 --- a/libtorrent/include/asio/detail/win_iocp_io_service.hpp +++ b/libtorrent/include/asio/detail/win_iocp_io_service.hpp @@ -33,7 +33,9 @@ #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/service_base.hpp" #include "asio/detail/socket_types.hpp" +#include "asio/detail/timer_queue.hpp" #include "asio/detail/win_iocp_operation.hpp" +#include "asio/detail/mutex.hpp" namespace asio { namespace detail { @@ -51,7 +53,9 @@ public: iocp_(), outstanding_work_(0), stopped_(0), - shutdown_(0) + shutdown_(0), + timer_thread_(0), + timer_interrupt_issued_(false) { } @@ -64,7 +68,7 @@ public: DWORD last_error = ::GetLastError(); asio::system_error e( asio::error_code(last_error, - asio::error::system_category), + asio::error::get_system_category()), "iocp"); boost::throw_exception(e); } @@ -93,6 +97,10 @@ public: if (overlapped) static_cast(overlapped)->destroy(); } + + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + timer_queues_[i]->destroy_timers(); + timer_queues_.clear(); } // Register a handle with the IO completion port. @@ -175,7 +183,7 @@ public: DWORD last_error = ::GetLastError(); asio::system_error e( asio::error_code(last_error, - asio::error::system_category), + asio::error::get_system_category()), "pqcs"); boost::throw_exception(e); } @@ -231,7 +239,7 @@ public: DWORD last_error = ::GetLastError(); asio::system_error e( asio::error_code(last_error, - asio::error::system_category), + asio::error::get_system_category()), "pqcs"); boost::throw_exception(e); } @@ -251,20 +259,102 @@ public: DWORD last_error = ::GetLastError(); asio::system_error e( asio::error_code(last_error, - asio::error::system_category), + asio::error::get_system_category()), "pqcs"); boost::throw_exception(e); } } + // Add a new timer queue to the service. + template + void add_timer_queue(timer_queue& timer_queue) + { + asio::detail::mutex::scoped_lock lock(timer_mutex_); + timer_queues_.push_back(&timer_queue); + } + + // Remove a timer queue from the service. + template + void remove_timer_queue(timer_queue& timer_queue) + { + asio::detail::mutex::scoped_lock lock(timer_mutex_); + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + if (timer_queues_[i] == &timer_queue) + { + timer_queues_.erase(timer_queues_.begin() + i); + return; + } + } + } + + // Schedule a timer in the given timer queue to expire at the specified + // absolute time. The handler object will be invoked when the timer expires. + template + void schedule_timer(timer_queue& timer_queue, + const typename Time_Traits::time_type& time, Handler handler, void* token) + { + // If the service has been shut down we silently discard the timer. + if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) + return; + + asio::detail::mutex::scoped_lock lock(timer_mutex_); + if (timer_queue.enqueue_timer(time, handler, token)) + { + if (!timer_interrupt_issued_) + { + timer_interrupt_issued_ = true; + lock.unlock(); + ::PostQueuedCompletionStatus(iocp_.handle, + 0, steal_timer_dispatching, 0); + } + } + } + + // Cancel the timer associated with the given token. Returns the number of + // handlers that have been posted or dispatched. + template + std::size_t cancel_timer(timer_queue& timer_queue, void* token) + { + // If the service has been shut down we silently ignore the cancellation. + if (::InterlockedExchangeAdd(&shutdown_, 0) != 0) + return 0; + + asio::detail::mutex::scoped_lock lock(timer_mutex_); + std::size_t n = timer_queue.cancel_timer(token); + if (n > 0 && !timer_interrupt_issued_) + { + timer_interrupt_issued_ = true; + lock.unlock(); + ::PostQueuedCompletionStatus(iocp_.handle, + 0, steal_timer_dispatching, 0); + } + return n; + } + private: // 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). size_t do_one(bool block, asio::error_code& ec) { + long this_thread_id = static_cast(::GetCurrentThreadId()); + for (;;) { + // Try to acquire responsibility for dispatching timers. + bool dispatching_timers = (::InterlockedCompareExchange( + &timer_thread_, this_thread_id, 0) == 0); + + // Calculate timeout for GetQueuedCompletionStatus call. + DWORD timeout = max_timeout; + if (dispatching_timers) + { + asio::detail::mutex::scoped_lock lock(timer_mutex_); + timer_interrupt_issued_ = false; + timeout = get_timeout(); + } + // Get the next operation from the queue. DWORD bytes_transferred = 0; #if (WINVER < 0x0500) @@ -275,18 +365,47 @@ private: LPOVERLAPPED overlapped = 0; ::SetLastError(0); BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, - &completion_key, &overlapped, block ? 1000 : 0); + &completion_key, &overlapped, block ? timeout : 0); DWORD last_error = ::GetLastError(); + // Dispatch any pending timers. + if (dispatching_timers) + { + asio::detail::mutex::scoped_lock lock(timer_mutex_); + timer_queues_copy_ = timer_queues_; + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + timer_queues_[i]->dispatch_timers(); + timer_queues_[i]->dispatch_cancellations(); + timer_queues_[i]->cleanup_timers(); + } + } + if (!ok && overlapped == 0) { if (block && last_error == WAIT_TIMEOUT) + { + // Relinquish responsibility for dispatching timers. + if (dispatching_timers) + { + ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id); + } + continue; + } + + // Transfer responsibility for dispatching timers to another thread. + if (dispatching_timers && ::InterlockedCompareExchange( + &timer_thread_, 0, this_thread_id) == this_thread_id) + { + ::PostQueuedCompletionStatus(iocp_.handle, + 0, transfer_timer_dispatching, 0); + } + ec = asio::error_code(); return 0; } - - if (overlapped) + else if (overlapped) { // We may have been passed a last_error value in the completion_key. if (last_error == 0) @@ -294,6 +413,14 @@ private: last_error = completion_key; } + // Transfer responsibility for dispatching timers to another thread. + if (dispatching_timers && ::InterlockedCompareExchange( + &timer_thread_, 0, this_thread_id) == this_thread_id) + { + ::PostQueuedCompletionStatus(iocp_.handle, + 0, transfer_timer_dispatching, 0); + } + // Ensure that the io_service does not exit due to running out of work // while we make the upcall. auto_work work(*this); @@ -305,18 +432,34 @@ private: ec = asio::error_code(); return 1; } + else if (completion_key == transfer_timer_dispatching) + { + // Woken up to try to acquire responsibility for dispatching timers. + ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id); + } + else if (completion_key == steal_timer_dispatching) + { + // Woken up to steal responsibility for dispatching timers. + ::InterlockedExchange(&timer_thread_, 0); + } else { // The stopped_ flag is always checked to ensure that any leftover // interrupts from a previous run invocation are ignored. if (::InterlockedExchangeAdd(&stopped_, 0) != 0) { + // Relinquish responsibility for dispatching timers. + if (dispatching_timers) + { + ::InterlockedCompareExchange(&timer_thread_, 0, this_thread_id); + } + // Wake up next thread that is blocked on GetQueuedCompletionStatus. if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, - asio::error::system_category); + asio::error::get_system_category()); return 0; } @@ -327,6 +470,45 @@ private: } } + // Check if all timer queues are empty. + bool all_timer_queues_are_empty() const + { + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + if (!timer_queues_[i]->empty()) + return false; + return true; + } + + // Get the timeout value for the GetQueuedCompletionStatus call. The timeout + // value is returned as a number of milliseconds. We will wait no longer than + // 1000 milliseconds. + DWORD get_timeout() + { + if (all_timer_queues_are_empty()) + return max_timeout; + + boost::posix_time::time_duration minimum_wait_duration + = boost::posix_time::milliseconds(max_timeout); + + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + boost::posix_time::time_duration wait_duration + = timer_queues_[i]->wait_duration(); + if (wait_duration < minimum_wait_duration) + minimum_wait_duration = wait_duration; + } + + if (minimum_wait_duration > boost::posix_time::time_duration()) + { + int milliseconds = minimum_wait_duration.total_milliseconds(); + return static_cast(milliseconds > 0 ? milliseconds : 1); + } + else + { + return 0; + } + } + struct auto_work { auto_work(win_iocp_io_service& io_service) @@ -416,6 +598,37 @@ private: // Flag to indicate whether the service has been shut down. long shutdown_; + + enum + { + // Maximum GetQueuedCompletionStatus timeout, in milliseconds. + max_timeout = 1000, + + // Completion key value to indicate that responsibility for dispatching + // timers is being cooperatively transferred from one thread to another. + transfer_timer_dispatching = 1, + + // Completion key value to indicate that responsibility for dispatching + // timers should be stolen from another thread. + steal_timer_dispatching = 2 + }; + + // The thread that's currently in charge of dispatching timers. + long timer_thread_; + + // Mutex for protecting access to the timer queues. + mutex timer_mutex_; + + // Whether a thread has been interrupted to process a new timeout. + bool timer_interrupt_issued_; + + // The timer queues. + std::vector timer_queues_; + + // A copy of the timer queues, used when dispatching, cancelling and cleaning + // up timers. The copy is stored as a class data member to avoid unnecessary + // memory allocation. + std::vector timer_queues_copy_; }; } // namespace detail diff --git a/libtorrent/include/asio/detail/win_iocp_io_service_fwd.hpp b/libtorrent/include/asio/detail/win_iocp_io_service_fwd.hpp index 26eacae2a..b3d1dec34 100644 --- a/libtorrent/include/asio/detail/win_iocp_io_service_fwd.hpp +++ b/libtorrent/include/asio/detail/win_iocp_io_service_fwd.hpp @@ -27,6 +27,7 @@ #if !defined(ASIO_DISABLE_IOCP) #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) +#if !defined(UNDER_CE) // Define this to indicate that IOCP is supported on the target platform. #define ASIO_HAS_IOCP 1 @@ -39,6 +40,7 @@ class win_iocp_io_service; } // namespace detail } // namespace asio +#endif // !defined(UNDER_CE) #endif // defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400) #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #endif // !defined(ASIO_DISABLE_IOCP) diff --git a/libtorrent/include/asio/detail/win_iocp_socket_service.hpp b/libtorrent/include/asio/detail/win_iocp_socket_service.hpp index 17d1d5887..cb3640638 100644 --- a/libtorrent/include/asio/detail/win_iocp_socket_service.hpp +++ b/libtorrent/include/asio/detail/win_iocp_socket_service.hpp @@ -327,7 +327,7 @@ public: ec = asio::error::bad_descriptor; } else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( - ::GetModuleHandle("KERNEL32"), "CancelIoEx")) + ::GetModuleHandleA("KERNEL32"), "CancelIoEx")) { // The version of Windows supports cancellation from any thread. typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); @@ -338,7 +338,7 @@ public: { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, - asio::error::system_category); + asio::error::get_system_category()); } else { @@ -360,7 +360,7 @@ public: { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, - asio::error::system_category); + asio::error::get_system_category()); } else { @@ -561,7 +561,7 @@ public: } endpoint_type endpoint; - socket_addr_len_type addr_len = endpoint.capacity(); + 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); @@ -600,7 +600,7 @@ public: else { endpoint_type endpoint; - socket_addr_len_type addr_len = endpoint.capacity(); + std::size_t addr_len = endpoint.capacity(); if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec)) return endpoint_type(); endpoint.resize(addr_len); @@ -667,7 +667,7 @@ public: else if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; ec = asio::error_code(last_error, - asio::error::system_category); + asio::error::get_system_category()); return 0; } @@ -719,7 +719,7 @@ public: // Map non-portable errors to their portable counterparts. asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); if (ec.value() == ERROR_NETNAME_DELETED) { if (handler_op->cancel_token_.expired()) @@ -767,7 +767,7 @@ public: { if (!is_open(impl)) { - this->io_service().post(bind_handler(handler, + this->get_io_service().post(bind_handler(handler, asio::error::bad_descriptor, 0)); return; } @@ -783,7 +783,7 @@ public: typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); handler_ptr ptr(raw_ptr, - this->io_service(), impl.cancel_token_, buffers, handler); + this->get_io_service(), impl.cancel_token_, buffers, handler); // Copy buffers into WSABUF array. ::WSABUF bufs[max_buffers]; @@ -803,7 +803,7 @@ public: // A request to receive 0 bytes on a stream socket is a no-op. if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) { - asio::io_service::work work(this->io_service()); + asio::io_service::work work(this->get_io_service()); ptr.reset(); asio::error_code error; iocp_service_.post(bind_handler(handler, error, 0)); @@ -819,10 +819,10 @@ public: // Check if the operation completed immediately. if (result != 0 && last_error != WSA_IO_PENDING) { - asio::io_service::work work(this->io_service()); + asio::io_service::work work(this->get_io_service()); ptr.reset(); asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else @@ -867,7 +867,7 @@ public: if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; ec = asio::error_code(last_error, - asio::error::system_category); + asio::error::get_system_category()); return 0; } @@ -917,7 +917,7 @@ public: // Map non-portable errors to their portable counterparts. asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); if (ec.value() == ERROR_PORT_UNREACHABLE) { ec = asio::error::connection_refused; @@ -958,7 +958,7 @@ public: { if (!is_open(impl)) { - this->io_service().post(bind_handler(handler, + this->get_io_service().post(bind_handler(handler, asio::error::bad_descriptor, 0)); return; } @@ -974,7 +974,7 @@ public: typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); handler_ptr ptr(raw_ptr, - this->io_service(), buffers, handler); + this->get_io_service(), buffers, handler); // Copy buffers into WSABUF array. ::WSABUF bufs[max_buffers]; @@ -998,10 +998,10 @@ public: // Check if the operation completed immediately. if (result != 0 && last_error != WSA_IO_PENDING) { - asio::io_service::work work(this->io_service()); + asio::io_service::work work(this->get_io_service()); ptr.reset(); asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else @@ -1056,7 +1056,7 @@ public: else if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; ec = asio::error_code(last_error, - asio::error::system_category); + asio::error::get_system_category()); return 0; } if (bytes_transferred == 0) @@ -1115,7 +1115,7 @@ public: // Map non-portable errors to their portable counterparts. asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); if (ec.value() == ERROR_NETNAME_DELETED) { if (handler_op->cancel_token_.expired()) @@ -1170,7 +1170,7 @@ public: { if (!is_open(impl)) { - this->io_service().post(bind_handler(handler, + this->get_io_service().post(bind_handler(handler, asio::error::bad_descriptor, 0)); return; } @@ -1186,7 +1186,7 @@ public: typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); handler_ptr ptr(raw_ptr, - this->io_service(), impl.cancel_token_, buffers, handler); + this->get_io_service(), impl.cancel_token_, buffers, handler); // Copy buffers into WSABUF array. ::WSABUF bufs[max_buffers]; @@ -1205,7 +1205,7 @@ public: // A request to receive 0 bytes on a stream socket is a no-op. if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) { - asio::io_service::work work(this->io_service()); + asio::io_service::work work(this->get_io_service()); ptr.reset(); asio::error_code error; iocp_service_.post(bind_handler(handler, error, 0)); @@ -1220,10 +1220,10 @@ public: DWORD last_error = ::WSAGetLastError(); if (result != 0 && last_error != WSA_IO_PENDING) { - asio::io_service::work work(this->io_service()); + asio::io_service::work work(this->get_io_service()); ptr.reset(); asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else @@ -1261,7 +1261,7 @@ public: // Receive some data. DWORD bytes_transferred = 0; DWORD recv_flags = flags; - int endpoint_size = sender_endpoint.capacity(); + int endpoint_size = static_cast(sender_endpoint.capacity()); int result = ::WSARecvFrom(impl.socket_, bufs, i, &bytes_transferred, &recv_flags, sender_endpoint.data(), &endpoint_size, 0, 0); if (result != 0) @@ -1270,7 +1270,7 @@ public: if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; ec = asio::error_code(last_error, - asio::error::system_category); + asio::error::get_system_category()); return 0; } if (bytes_transferred == 0) @@ -1279,7 +1279,7 @@ public: return 0; } - sender_endpoint.resize(endpoint_size); + sender_endpoint.resize(static_cast(endpoint_size)); ec = asio::error_code(); return bytes_transferred; @@ -1299,7 +1299,7 @@ public: &receive_from_operation< MutableBufferSequence, Handler>::destroy_impl), endpoint_(endpoint), - endpoint_size_(endpoint.capacity()), + endpoint_size_(static_cast(endpoint.capacity())), work_(io_service), buffers_(buffers), handler_(handler) @@ -1337,7 +1337,7 @@ public: // Map non-portable errors to their portable counterparts. asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); if (ec.value() == ERROR_PORT_UNREACHABLE) { ec = asio::error::connection_refused; @@ -1390,7 +1390,7 @@ public: { if (!is_open(impl)) { - this->io_service().post(bind_handler(handler, + this->get_io_service().post(bind_handler(handler, asio::error::bad_descriptor, 0)); return; } @@ -1406,7 +1406,7 @@ public: typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); handler_ptr ptr(raw_ptr, - this->io_service(), sender_endp, buffers, handler); + this->get_io_service(), sender_endp, buffers, handler); // Copy buffers into WSABUF array. ::WSABUF bufs[max_buffers]; @@ -1429,10 +1429,10 @@ public: DWORD last_error = ::WSAGetLastError(); if (result != 0 && last_error != WSA_IO_PENDING) { - asio::io_service::work work(this->io_service()); + asio::io_service::work work(this->get_io_service()); ptr.reset(); asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else @@ -1463,7 +1463,7 @@ public: { asio::error_code ec; socket_holder new_socket; - socket_addr_len_type addr_len = 0; + std::size_t addr_len = 0; if (peer_endpoint) { addr_len = peer_endpoint->capacity(); @@ -1517,7 +1517,7 @@ public: peer_(peer), protocol_(protocol), peer_endpoint_(peer_endpoint), - work_(io_service.io_service()), + work_(io_service.get_io_service()), enable_connection_aborted_(enable_connection_aborted), handler_(handler) { @@ -1618,7 +1618,8 @@ public: GetAcceptExSockaddrs(handler_op->output_buffer(), 0, handler_op->address_length(), handler_op->address_length(), &local_addr, &local_addr_length, &remote_addr, &remote_addr_length); - if (remote_addr_length > peer_endpoint.capacity()) + if (static_cast(remote_addr_length) + > peer_endpoint.capacity()) { last_error = WSAEINVAL; } @@ -1626,7 +1627,7 @@ public: { using namespace std; // For memcpy. memcpy(peer_endpoint.data(), remote_addr, remote_addr_length); - peer_endpoint.resize(remote_addr_length); + peer_endpoint.resize(static_cast(remote_addr_length)); } } @@ -1670,7 +1671,7 @@ public: // Call the handler. asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); asio_handler_invoke_helpers::invoke( detail::bind_handler(handler, ec), &handler); } @@ -1705,7 +1706,7 @@ public: // Check whether acceptor has been initialised. if (!is_open(impl)) { - this->io_service().post(bind_handler(handler, + this->get_io_service().post(bind_handler(handler, asio::error::bad_descriptor)); return; } @@ -1713,7 +1714,7 @@ public: // Check that peer socket has not already been opened. if (peer.is_open()) { - this->io_service().post(bind_handler(handler, + this->get_io_service().post(bind_handler(handler, asio::error::already_open)); return; } @@ -1730,7 +1731,7 @@ public: impl.protocol_.type(), impl.protocol_.protocol(), ec)); if (sock.get() == invalid_socket) { - this->io_service().post(bind_handler(handler, ec)); + this->get_io_service().post(bind_handler(handler, ec)); return; } @@ -1768,10 +1769,10 @@ public: } else { - asio::io_service::work work(this->io_service()); + asio::io_service::work work(this->get_io_service()); ptr.reset(); asio::error_code ec(last_error, - asio::error::system_category); + asio::error::get_system_category()); iocp_service_.post(bind_handler(handler, ec)); } } @@ -1848,7 +1849,7 @@ public: if (connect_error) { ec = asio::error_code(connect_error, - asio::error::system_category); + asio::error::get_system_category()); io_service_.post(bind_handler(handler_, ec)); return true; } @@ -1887,7 +1888,7 @@ public: { if (!is_open(impl)) { - this->io_service().post(bind_handler(handler, + this->get_io_service().post(bind_handler(handler, asio::error::bad_descriptor)); return; } @@ -1904,7 +1905,8 @@ public: reinterpret_cast(&reactor_), 0, 0)); if (!reactor) { - reactor = &(asio::use_service(this->io_service())); + reactor = &(asio::use_service( + this->get_io_service())); interlocked_exchange_pointer( reinterpret_cast(&reactor_), reactor); } @@ -1915,7 +1917,7 @@ public: asio::error_code ec; if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) { - this->io_service().post(bind_handler(handler, ec)); + this->get_io_service().post(bind_handler(handler, ec)); return; } @@ -1932,7 +1934,7 @@ public: // The connect operation has finished successfully so we need to post the // handler immediately. - this->io_service().post(bind_handler(handler, ec)); + this->get_io_service().post(bind_handler(handler, ec)); } else if (ec == asio::error::in_progress || ec == asio::error::would_block) @@ -1944,7 +1946,7 @@ public: connect_handler( impl.socket_, (impl.flags_ & implementation_type::user_set_non_blocking) != 0, - completed, this->io_service(), *reactor, handler)); + completed, this->get_io_service(), *reactor, handler)); } else { @@ -1957,7 +1959,7 @@ public: } // The connect operation has failed, so post the handler immediately. - this->io_service().post(bind_handler(handler, ec)); + this->get_io_service().post(bind_handler(handler, ec)); } } diff --git a/libtorrent/include/asio/detail/win_local_free_on_block_exit.hpp b/libtorrent/include/asio/detail/win_local_free_on_block_exit.hpp new file mode 100644 index 000000000..c909e1af3 --- /dev/null +++ b/libtorrent/include/asio/detail/win_local_free_on_block_exit.hpp @@ -0,0 +1,59 @@ +// +// win_local_free_on_block_exit.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost 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_WIN_LOCAL_FREE_ON_BLOCK_EXIT_HPP +#define ASIO_DETAIL_WIN_LOCAL_FREE_ON_BLOCK_EXIT_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" + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/socket_types.hpp" + +namespace asio { +namespace detail { + +class win_local_free_on_block_exit + : private noncopyable +{ +public: + // Constructor blocks all signals for the calling thread. + explicit win_local_free_on_block_exit(void* p) + : p_(p) + { + } + + // Destructor restores the previous signal mask. + ~win_local_free_on_block_exit() + { + ::LocalFree(p_); + } + +private: + void* p_; +}; + +} // namespace detail +} // namespace asio + +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_WIN_LOCAL_FREE_ON_BLOCK_EXIT_HPP diff --git a/libtorrent/include/asio/detail/win_mutex.hpp b/libtorrent/include/asio/detail/win_mutex.hpp index 4d1bc20c2..f937db69f 100644 --- a/libtorrent/include/asio/detail/win_mutex.hpp +++ b/libtorrent/include/asio/detail/win_mutex.hpp @@ -49,7 +49,8 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, + asio::error::get_system_category()), "mutex"); boost::throw_exception(e); } @@ -68,7 +69,8 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, + asio::error::get_system_category()), "mutex"); boost::throw_exception(e); } diff --git a/libtorrent/include/asio/detail/win_thread.hpp b/libtorrent/include/asio/detail/win_thread.hpp index c6bd61af5..4a80d15a3 100644 --- a/libtorrent/include/asio/detail/win_thread.hpp +++ b/libtorrent/include/asio/detail/win_thread.hpp @@ -21,7 +21,7 @@ #include #include "asio/detail/pop_options.hpp" -#if defined(BOOST_WINDOWS) +#if defined(BOOST_WINDOWS) && !defined(UNDER_CE) #include "asio/error.hpp" #include "asio/system_error.hpp" @@ -56,7 +56,7 @@ public: DWORD last_error = ::GetLastError(); asio::system_error e( asio::error_code(last_error, - asio::error::system_category), + asio::error::get_system_category()), "thread"); boost::throw_exception(e); } @@ -118,7 +118,7 @@ inline unsigned int __stdcall win_thread_function(void* arg) } // namespace detail } // namespace asio -#endif // defined(BOOST_WINDOWS) +#endif // defined(BOOST_WINDOWS) && !defined(UNDER_CE) #include "asio/detail/pop_options.hpp" diff --git a/libtorrent/include/asio/detail/win_tss_ptr.hpp b/libtorrent/include/asio/detail/win_tss_ptr.hpp index d84810d41..8f6eaf6cb 100644 --- a/libtorrent/include/asio/detail/win_tss_ptr.hpp +++ b/libtorrent/include/asio/detail/win_tss_ptr.hpp @@ -40,16 +40,22 @@ class win_tss_ptr : private noncopyable { public: +#if defined(UNDER_CE) + enum { out_of_indexes = 0xFFFFFFFF }; +#else + enum { out_of_indexes = TLS_OUT_OF_INDEXES }; +#endif + // Constructor. win_tss_ptr() { tss_key_ = ::TlsAlloc(); - if (tss_key_ == TLS_OUT_OF_INDEXES) + if (tss_key_ == out_of_indexes) { DWORD last_error = ::GetLastError(); asio::system_error e( asio::error_code(last_error, - asio::error::system_category), + asio::error::get_system_category()), "tss"); boost::throw_exception(e); } diff --git a/libtorrent/include/asio/detail/wince_thread.hpp b/libtorrent/include/asio/detail/wince_thread.hpp new file mode 100644 index 000000000..f65a36f0c --- /dev/null +++ b/libtorrent/include/asio/detail/wince_thread.hpp @@ -0,0 +1,124 @@ +// +// wince_thread.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost 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_WINCE_THREAD_HPP +#define ASIO_DETAIL_WINCE_THREAD_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" + +#if defined(BOOST_WINDOWS) && defined(UNDER_CE) + +#include "asio/error.hpp" +#include "asio/system_error.hpp" +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/socket_types.hpp" + +#include "asio/detail/push_options.hpp" +#include +#include +#include "asio/detail/pop_options.hpp" + +namespace asio { +namespace detail { + +DWORD WINAPI wince_thread_function(LPVOID arg); + +class wince_thread + : private noncopyable +{ +public: + // Constructor. + template + wince_thread(Function f) + { + std::auto_ptr arg(new func(f)); + DWORD thread_id = 0; + thread_ = ::CreateThread(0, 0, wince_thread_function, + arg.get(), 0, &thread_id); + if (!thread_) + { + DWORD last_error = ::GetLastError(); + asio::system_error e( + asio::error_code(last_error, + asio::error::get_system_category()), + "thread"); + boost::throw_exception(e); + } + arg.release(); + } + + // Destructor. + ~wince_thread() + { + ::CloseHandle(thread_); + } + + // Wait for the thread to exit. + void join() + { + ::WaitForSingleObject(thread_, INFINITE); + } + +private: + friend DWORD WINAPI wince_thread_function(LPVOID arg); + + class func_base + { + public: + virtual ~func_base() {} + virtual void run() = 0; + }; + + template + class func + : public func_base + { + public: + func(Function f) + : f_(f) + { + } + + virtual void run() + { + f_(); + } + + private: + Function f_; + }; + + ::HANDLE thread_; +}; + +inline DWORD WINAPI wince_thread_function(LPVOID arg) +{ + std::auto_ptr func( + static_cast(arg)); + func->run(); + return 0; +} + +} // namespace detail +} // namespace asio + +#endif // defined(BOOST_WINDOWS) && defined(UNDER_CE) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_WINCE_THREAD_HPP diff --git a/libtorrent/include/asio/detail/winsock_init.hpp b/libtorrent/include/asio/detail/winsock_init.hpp index 874d2b77b..65efb8852 100644 --- a/libtorrent/include/asio/detail/winsock_init.hpp +++ b/libtorrent/include/asio/detail/winsock_init.hpp @@ -28,6 +28,7 @@ #include #include "asio/detail/pop_options.hpp" +#include "asio/error.hpp" #include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" @@ -86,7 +87,7 @@ public: { asio::system_error e( asio::error_code(ref_->result(), - asio::error::system_category), + asio::error::get_system_category()), "winsock"); boost::throw_exception(e); } diff --git a/libtorrent/include/asio/error.hpp b/libtorrent/include/asio/error.hpp index a8316be2c..c65599c91 100644 --- a/libtorrent/include/asio/error.hpp +++ b/libtorrent/include/asio/error.hpp @@ -197,26 +197,40 @@ enum misc_errors not_found }; +enum ssl_errors +{ +}; + // boostify: error category definitions go here. inline asio::error_code make_error_code(basic_errors e) { - return asio::error_code(static_cast(e), system_category); + return asio::error_code( + static_cast(e), get_system_category()); } inline asio::error_code make_error_code(netdb_errors e) { - return asio::error_code(static_cast(e), netdb_category); + return asio::error_code( + static_cast(e), get_netdb_category()); } inline asio::error_code make_error_code(addrinfo_errors e) { - return asio::error_code(static_cast(e), addrinfo_category); + return asio::error_code( + static_cast(e), get_addrinfo_category()); } inline asio::error_code make_error_code(misc_errors e) { - return asio::error_code(static_cast(e), misc_category); + return asio::error_code( + static_cast(e), get_misc_category()); +} + +inline asio::error_code make_error_code(ssl_errors e) +{ + return asio::error_code( + static_cast(e), get_ssl_category()); } } // namespace error diff --git a/libtorrent/include/asio/error_code.hpp b/libtorrent/include/asio/error_code.hpp index 0941a8c00..989898ce5 100644 --- a/libtorrent/include/asio/error_code.hpp +++ b/libtorrent/include/asio/error_code.hpp @@ -41,10 +41,10 @@ namespace error system_category = ASIO_WIN_OR_POSIX(0, 0), /// Error codes from NetDB functions. - netdb_category = ASIO_WIN_OR_POSIX(system_category, 1), + netdb_category = ASIO_WIN_OR_POSIX(_system_category, 1), /// Error codes from getaddrinfo. - addrinfo_category = ASIO_WIN_OR_POSIX(system_category, 2), + addrinfo_category = ASIO_WIN_OR_POSIX(_system_category, 2), /// Miscellaneous error codes. misc_category = ASIO_WIN_OR_POSIX(3, 3), @@ -52,8 +52,19 @@ namespace error /// SSL error codes. ssl_category = ASIO_WIN_OR_POSIX(4, 4) }; + + // Category getters. + inline error_category get_system_category() { return system_category; } + inline error_category get_netdb_category() { return netdb_category; } + inline error_category get_addrinfo_category() { return addrinfo_category; } + inline error_category get_misc_category() { return misc_category; } + inline error_category get_ssl_category() { return ssl_category; } + } // namespace error +/// Bring error category type into the asio namespace. +typedef asio::error::error_category error_category; + /// Class to represent an error code value. class error_code { @@ -69,7 +80,7 @@ public: } /// Construct with specific error code and category. - error_code(value_type v, error::error_category c) + error_code(value_type v, error_category c) : value_(v), category_(c) { @@ -89,7 +100,7 @@ public: } /// Get the error category. - error::error_category category() const + error_category category() const { return category_; } @@ -135,7 +146,7 @@ private: value_type value_; // The category associated with the error code. - error::error_category category_; + error_category category_; }; } // namespace asio diff --git a/libtorrent/include/asio/error_handler.hpp b/libtorrent/include/asio/error_handler.hpp new file mode 100644 index 000000000..c315c8d5e --- /dev/null +++ b/libtorrent/include/asio/error_handler.hpp @@ -0,0 +1,120 @@ +// +// error_handler.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost 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_ERROR_HANDLER_HPP +#define ASIO_ERROR_HANDLER_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" + +namespace asio { + +namespace detail { + +class ignore_error_t +{ +public: + typedef void result_type; + + template + void operator()(const Error&) const + { + } +}; + +class throw_error_t +{ +public: + typedef void result_type; + + template + void operator()(const Error& err) const + { + if (err) + boost::throw_exception(err); + } +}; + +template +class assign_error_t +{ +public: + typedef void result_type; + + assign_error_t(Target& target) + : target_(&target) + { + } + + template + void operator()(const Error& err) const + { + *target_ = err; + } + +private: + Target* target_; +}; + +} // namespace detail + +/** + * @defgroup error_handler Error Handler Function Objects + * + * Function objects for custom error handling. + */ +/*@{*/ + +/// Return a function object that always ignores the error. +#if defined(GENERATING_DOCUMENTATION) +unspecified ignore_error(); +#else +inline detail::ignore_error_t ignore_error() +{ + return detail::ignore_error_t(); +} +#endif + +/// Return a function object that always throws the error. +#if defined(GENERATING_DOCUMENTATION) +unspecified throw_error(); +#else +inline detail::throw_error_t throw_error() +{ + return detail::throw_error_t(); +} +#endif + +/// Return a function object that assigns the error to a variable. +#if defined(GENERATING_DOCUMENTATION) +template +unspecified assign_error(Target& target); +#else +template +inline detail::assign_error_t assign_error(Target& target) +{ + return detail::assign_error_t(target); +} +#endif + +/*@}*/ + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_ERROR_HANDLER_HPP diff --git a/libtorrent/include/asio/impl/error_code.ipp b/libtorrent/include/asio/impl/error_code.ipp index f66b6fd94..9925cb484 100644 --- a/libtorrent/include/asio/impl/error_code.ipp +++ b/libtorrent/include/asio/impl/error_code.ipp @@ -35,11 +35,11 @@ inline std::string error_code::message() const return "Already open."; if (*this == error::not_found) return "Not found."; - if (category_ == error::ssl_category) + if (category_ == error::get_ssl_category()) return "SSL error."; #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) value_type value = value_; - if (category() != error::system_category && *this != error::eof) + if (category() != error::get_system_category() && *this != error::eof) return "asio error"; if (*this == error::eof) value = ERROR_HANDLE_EOF; @@ -78,13 +78,13 @@ inline std::string error_code::message() const return "Service not found."; if (*this == error::socket_type_not_supported) return "Socket type not supported."; - if (category() != error::system_category) + if (category() != error::get_system_category()) return "asio error"; #if defined(__sun) || defined(__QNX__) return strerror(value_); #elif defined(__MACH__) && defined(__APPLE__) \ || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) \ -|| defined(_AIX) +|| defined(_AIX) || defined(__hpux) || defined(__osf__) char buf[256] = ""; strerror_r(value_, buf, sizeof(buf)); return buf; diff --git a/libtorrent/include/asio/impl/io_service.ipp b/libtorrent/include/asio/impl/io_service.ipp index f51d3697d..8ebc2643c 100644 --- a/libtorrent/include/asio/impl/io_service.ipp +++ b/libtorrent/include/asio/impl/io_service.ipp @@ -21,6 +21,7 @@ #include #include "asio/detail/pop_options.hpp" +#include "asio/detail/dev_poll_reactor.hpp" #include "asio/detail/epoll_reactor.hpp" #include "asio/detail/kqueue_reactor.hpp" #include "asio/detail/select_reactor.hpp" @@ -157,6 +158,11 @@ inline asio::io_service& io_service::work::io_service() return io_service_; } +inline asio::io_service& io_service::work::get_io_service() +{ + return io_service_; +} + inline io_service::service::service(asio::io_service& owner) : owner_(owner), type_info_(0), @@ -173,6 +179,11 @@ inline asio::io_service& io_service::service::io_service() return owner_; } +inline asio::io_service& io_service::service::get_io_service() +{ + return owner_; +} + template inline Service& use_service(io_service& ios) { diff --git a/libtorrent/include/asio/io_service.hpp b/libtorrent/include/asio/io_service.hpp index 2101e56c4..984a63e18 100644 --- a/libtorrent/include/asio/io_service.hpp +++ b/libtorrent/include/asio/io_service.hpp @@ -26,6 +26,7 @@ #include "asio/detail/pop_options.hpp" #include "asio/error_code.hpp" +#include "asio/detail/dev_poll_reactor_fwd.hpp" #include "asio/detail/epoll_reactor_fwd.hpp" #include "asio/detail/kqueue_reactor_fwd.hpp" #include "asio/detail/noncopyable.hpp" @@ -39,6 +40,11 @@ namespace asio { +class io_service; +template Service& use_service(io_service& ios); +template void add_service(io_service& ios, Service* svc); +template bool has_service(io_service& ios); + /// Provides core I/O functionality. /** * The io_service class provides the core I/O functionality for users of the @@ -106,6 +112,8 @@ private: typedef detail::task_io_service > impl_type; #elif defined(ASIO_HAS_KQUEUE) typedef detail::task_io_service > impl_type; +#elif defined(ASIO_HAS_DEV_POLL) + typedef detail::task_io_service > impl_type; #else typedef detail::task_io_service > impl_type; #endif @@ -373,7 +381,8 @@ public: private: #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) detail::winsock_init<> init_; -#elif defined(__sun) || defined(__QNX__) +#elif defined(__sun) || defined(__QNX__) || defined(__hpux) || defined(_AIX) \ + || defined(__osf__) detail::signal_init<> init_; #endif @@ -421,9 +430,13 @@ public: */ ~work(); - /// Get the io_service associated with the work. + /// (Deprecated: use get_io_service().) Get the io_service associated with the + /// work. asio::io_service& io_service(); + /// Get the io_service associated with the work. + asio::io_service& get_io_service(); + private: // Prevent assignment. void operator=(const work& other); @@ -446,9 +459,13 @@ class io_service::service : private noncopyable { public: - /// Get the io_service object that owns the service. + /// (Deprecated: use get_io_service().) Get the io_service object that owns + /// the service. asio::io_service& io_service(); + /// Get the io_service object that owns the service. + asio::io_service& get_io_service(); + protected: /// Constructor. /** diff --git a/libtorrent/include/asio/ip/address_v4.hpp b/libtorrent/include/asio/ip/address_v4.hpp index ae3891c95..c7de56b7e 100644 --- a/libtorrent/include/asio/ip/address_v4.hpp +++ b/libtorrent/include/asio/ip/address_v4.hpp @@ -268,7 +268,12 @@ std::basic_ostream& operator<<( asio::error_code ec; std::string s = addr.to_string(ec); if (ec) - os.setstate(std::ios_base::failbit); + { + if (os.exceptions() & std::ios::failbit) + asio::detail::throw_error(ec); + else + os.setstate(std::ios_base::failbit); + } else for (std::string::iterator i = s.begin(); i != s.end(); ++i) os << os.widen(*i); diff --git a/libtorrent/include/asio/ip/address_v6.hpp b/libtorrent/include/asio/ip/address_v6.hpp index f732955fa..ce5eeb00b 100644 --- a/libtorrent/include/asio/ip/address_v6.hpp +++ b/libtorrent/include/asio/ip/address_v6.hpp @@ -300,7 +300,7 @@ public: { using namespace std; // For memcmp. int memcmp_result = memcmp(&a1.addr_, &a2.addr_, - sizeof(asio::detail::in6_addr_type)) < 0; + sizeof(asio::detail::in6_addr_type)); if (memcmp_result < 0) return true; if (memcmp_result > 0) @@ -386,7 +386,12 @@ std::basic_ostream& operator<<( asio::error_code ec; std::string s = addr.to_string(ec); if (ec) - os.setstate(std::ios_base::failbit); + { + if (os.exceptions() & std::ios::failbit) + asio::detail::throw_error(ec); + else + os.setstate(std::ios_base::failbit); + } else for (std::string::iterator i = s.begin(); i != s.end(); ++i) os << os.widen(*i); diff --git a/libtorrent/include/asio/ip/basic_endpoint.hpp b/libtorrent/include/asio/ip/basic_endpoint.hpp index 3d1316e22..643df48a7 100644 --- a/libtorrent/include/asio/ip/basic_endpoint.hpp +++ b/libtorrent/include/asio/ip/basic_endpoint.hpp @@ -61,14 +61,6 @@ public: typedef asio::detail::socket_addr_type data_type; #endif - /// The type for the size of the endpoint structure. This type is dependent on - /// the underlying implementation of the socket layer. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined size_type; -#else - typedef asio::detail::socket_addr_len_type size_type; -#endif - /// Default constructor. basic_endpoint() : data_() @@ -190,7 +182,7 @@ public: } /// Get the underlying size of the endpoint in the native type. - size_type size() const + std::size_t size() const { if (is_v4(data_)) return sizeof(asio::detail::sockaddr_in4_type); @@ -199,9 +191,9 @@ public: } /// Set the underlying size of the endpoint in the native type. - void resize(size_type size) + void resize(std::size_t size) { - if (size > size_type(sizeof(data_))) + if (size > sizeof(data_)) { asio::system_error e(asio::error::invalid_argument); boost::throw_exception(e); @@ -209,7 +201,7 @@ public: } /// Get the capacity of the endpoint in the native type. - size_type capacity() const + std::size_t capacity() const { return sizeof(data_); } @@ -349,11 +341,23 @@ std::ostream& operator<<(std::ostream& os, const basic_endpoint& endpoint) { const address& addr = endpoint.address(); - if (addr.is_v4()) - os << addr.to_string(); + asio::error_code ec; + std::string a = addr.to_string(ec); + if (ec) + { + if (os.exceptions() & std::ios::failbit) + asio::detail::throw_error(ec); + else + os.setstate(std::ios_base::failbit); + } else - os << '[' << addr.to_string() << ']'; - os << ':' << endpoint.port(); + { + if (addr.is_v4()) + os << a; + else + os << '[' << a << ']'; + os << ':' << endpoint.port(); + } return os; } #else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) @@ -363,11 +367,23 @@ std::basic_ostream& operator<<( const basic_endpoint& endpoint) { const address& addr = endpoint.address(); - if (addr.is_v4()) - os << addr.to_string(); + asio::error_code ec; + std::string a = addr.to_string(ec); + if (ec) + { + if (os.exceptions() & std::ios::failbit) + asio::detail::throw_error(ec); + else + os.setstate(std::ios_base::failbit); + } else - os << '[' << addr.to_string() << ']'; - os << ':' << endpoint.port(); + { + if (addr.is_v4()) + os << a; + else + os << '[' << a << ']'; + os << ':' << endpoint.port(); + } return os; } #endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) diff --git a/libtorrent/include/asio/ip/basic_resolver_iterator.hpp b/libtorrent/include/asio/ip/basic_resolver_iterator.hpp index 686e4446e..81c652ce8 100644 --- a/libtorrent/include/asio/ip/basic_resolver_iterator.hpp +++ b/libtorrent/include/asio/ip/basic_resolver_iterator.hpp @@ -80,9 +80,7 @@ public: { using namespace std; // For memcpy. typename InternetProtocol::endpoint endpoint; - endpoint.resize( - static_cast( - address_info->ai_addrlen)); + endpoint.resize(static_cast(address_info->ai_addrlen)); memcpy(endpoint.data(), address_info->ai_addr, address_info->ai_addrlen); iter.values_->push_back( diff --git a/libtorrent/include/asio/ip/detail/socket_option.hpp b/libtorrent/include/asio/ip/detail/socket_option.hpp index a86307077..1d43d6059 100644 --- a/libtorrent/include/asio/ip/detail/socket_option.hpp +++ b/libtorrent/include/asio/ip/detail/socket_option.hpp @@ -32,52 +32,60 @@ namespace ip { namespace detail { namespace socket_option { -// Helper template for implementing boolean-based options. +// Helper template for implementing multicast enable loopback options. template -class boolean +class multicast_enable_loopback { public: -#if defined(__sun) - typedef unsigned char value_type; +#if defined(__sun) || defined(__osf__) + typedef unsigned char ipv4_value_type; + typedef unsigned char ipv6_value_type; +#elif defined(_AIX) || defined(__hpux) + typedef unsigned char ipv4_value_type; + typedef unsigned int ipv6_value_type; #else - typedef int value_type; + typedef int ipv4_value_type; + typedef int ipv6_value_type; #endif // Default constructor. - boolean() - : value_(0) + multicast_enable_loopback() + : ipv4_value_(0), + ipv6_value_(0) { } // Construct with a specific option value. - explicit boolean(bool v) - : value_(v ? 1 : 0) + explicit multicast_enable_loopback(bool v) + : ipv4_value_(v ? 1 : 0), + ipv6_value_(v ? 1 : 0) { } // Set the value of the boolean. - boolean& operator=(bool v) + multicast_enable_loopback& operator=(bool v) { - value_ = v ? 1 : 0; + ipv4_value_ = v ? 1 : 0; + ipv6_value_ = v ? 1 : 0; return *this; } // Get the current value of the boolean. bool value() const { - return !!value_; + return !!ipv4_value_; } // Convert to bool. operator bool() const { - return !!value_; + return !!ipv4_value_; } // Test for false. bool operator!() const { - return !value_; + return !ipv4_value_; } // Get the level of the socket option. @@ -100,35 +108,58 @@ public: // Get the address of the boolean data. template - value_type* data(const Protocol&) + void* data(const Protocol& protocol) { - return &value_; + if (protocol.family() == PF_INET6) + return &ipv6_value_; + return &ipv4_value_; } // Get the address of the boolean data. template - const value_type* data(const Protocol&) const + const void* data(const Protocol& protocol) const { - return &value_; + if (protocol.family() == PF_INET6) + return &ipv6_value_; + return &ipv4_value_; } // Get the size of the boolean data. template - std::size_t size(const Protocol&) const + std::size_t size(const Protocol& protocol) const { - return sizeof(value_); + if (protocol.family() == PF_INET6) + return sizeof(ipv6_value_); + return sizeof(ipv4_value_); } // Set the size of the boolean data. template - void resize(const Protocol&, std::size_t s) + void resize(const Protocol& protocol, std::size_t s) { - if (s != sizeof(value_)) - throw std::length_error("boolean socket option resize"); + if (protocol.family() == PF_INET6) + { + if (s != sizeof(ipv6_value_)) + { + throw std::length_error( + "multicast_enable_loopback socket option resize"); + } + ipv4_value_ = ipv6_value_ ? 1 : 0; + } + else + { + if (s != sizeof(ipv4_value_)) + { + throw std::length_error( + "multicast_enable_loopback socket option resize"); + } + ipv6_value_ = ipv4_value_ ? 1 : 0; + } } private: - value_type value_; + ipv4_value_type ipv4_value_; + ipv6_value_type ipv6_value_; }; // Helper template for implementing unicast hops options. @@ -206,6 +237,10 @@ public: { if (s != sizeof(value_)) throw std::length_error("unicast hops socket option resize"); +#if defined(__hpux) + if (value_ < 0) + value_ = value_ & 0xFF; +#endif } private: @@ -217,6 +252,13 @@ template class multicast_hops { public: +#if defined(BOOST_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), @@ -229,7 +271,7 @@ public: { if (v < 0 || v > 255) throw std::out_of_range("multicast hops value out of range"); - ipv4_value_ = static_cast(v); + ipv4_value_ = (ipv4_value_type)v; ipv6_value_ = v; } @@ -238,7 +280,7 @@ public: { if (v < 0 || v > 255) throw std::out_of_range("multicast hops value out of range"); - ipv4_value_ = static_cast(v); + ipv4_value_ = (ipv4_value_type)v; ipv6_value_ = v; return *this; } @@ -307,7 +349,7 @@ public: else if (ipv6_value_ > 255) ipv4_value_ = 255; else - ipv4_value_ = static_cast(ipv6_value_); + ipv4_value_ = (ipv4_value_type)ipv6_value_; } else { @@ -318,8 +360,8 @@ public: } private: - unsigned char ipv4_value_; - int ipv6_value_; + ipv4_value_type ipv4_value_; + ipv6_value_type ipv6_value_; }; // Helper template for implementing ip_mreq-based options. @@ -477,7 +519,7 @@ public: } // Construct with IPv6 interface. - explicit network_interface(unsigned long ipv6_interface) + explicit network_interface(unsigned int ipv6_interface) { ipv4_value_.s_addr = asio::detail::socket_ops::host_to_network_long( @@ -523,7 +565,7 @@ public: private: asio::detail::in4_addr_type ipv4_value_; - unsigned long ipv6_value_; + unsigned int ipv6_value_; }; } // namespace socket_option diff --git a/libtorrent/include/asio/ip/multicast.hpp b/libtorrent/include/asio/ip/multicast.hpp index 0d90659ca..8b48687f1 100644 --- a/libtorrent/include/asio/ip/multicast.hpp +++ b/libtorrent/include/asio/ip/multicast.hpp @@ -167,7 +167,7 @@ typedef asio::ip::detail::socket_option::multicast_hops< #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined enable_loopback; #else -typedef asio::ip::detail::socket_option::boolean< +typedef asio::ip::detail::socket_option::multicast_enable_loopback< IPPROTO_IP, IP_MULTICAST_LOOP, IPPROTO_IPV6, IPV6_MULTICAST_LOOP> enable_loopback; #endif diff --git a/libtorrent/include/asio/placeholders.hpp b/libtorrent/include/asio/placeholders.hpp index 0c1b6b4a6..9309fc0b4 100644 --- a/libtorrent/include/asio/placeholders.hpp +++ b/libtorrent/include/asio/placeholders.hpp @@ -27,17 +27,17 @@ namespace placeholders { #if defined(GENERATING_DOCUMENTATION) -/// An argument placeholder, for use with @ref boost_bind, that corresponds to +/// 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 @ref boost_bind, that corresponds to +/// An argument placeholder, for use with boost::bind(), that corresponds to /// the bytes_transferred argument of a handler for asynchronous functions such /// as asio::basic_stream_socket::async_write_some or /// asio::async_write. unspecified bytes_transferred; -/// An argument placeholder, for use with @ref boost_bind, that corresponds to +/// An argument placeholder, for use with boost::bind(), that corresponds to /// the iterator argument of a handler for asynchronous functions such as /// asio::basic_resolver::resolve. unspecified iterator; diff --git a/libtorrent/include/asio/resolver_service.hpp b/libtorrent/include/asio/resolver_service.hpp new file mode 100644 index 000000000..bdd8dbfbd --- /dev/null +++ b/libtorrent/include/asio/resolver_service.hpp @@ -0,0 +1,126 @@ +// +// resolver_service.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost 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_RESOLVER_SERVICE_HPP +#define ASIO_RESOLVER_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/io_service.hpp" +#include "asio/detail/resolver_service.hpp" + +namespace asio { + +/// Default service implementation for a resolver. +template +class resolver_service + : public asio::io_service::service +{ +public: + /// The protocol type. + typedef Protocol protocol_type; + + /// The endpoint type. + typedef typename Protocol::endpoint endpoint_type; + + /// The query type. + typedef typename Protocol::resolver_query query_type; + + /// The iterator type. + typedef typename Protocol::resolver_iterator iterator_type; + +private: + // The type of the platform-specific implementation. + typedef detail::resolver_service service_impl_type; + +public: + /// The type of a resolver implementation. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined implementation_type; +#else + typedef typename service_impl_type::implementation_type implementation_type; +#endif + + /// Construct a new resolver service for the specified io_service. + explicit resolver_service(asio::io_service& io_service) + : asio::io_service::service(io_service), + service_impl_(asio::use_service(io_service)) + { + } + + /// Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + } + + /// Construct a new resolver implementation. + void construct(implementation_type& impl) + { + service_impl_.construct(impl); + } + + /// Destroy a resolver implementation. + void destroy(implementation_type& impl) + { + service_impl_.destroy(impl); + } + + /// Cancel pending asynchronous operations. + void cancel(implementation_type& impl) + { + service_impl_.cancel(impl); + } + + /// Resolve a query to a list of entries. + template + iterator_type resolve(implementation_type& impl, const query_type& query, + Error_Handler error_handler) + { + return service_impl_.resolve(impl, query, error_handler); + } + + /// Asynchronously resolve a query to a list of entries. + template + void async_resolve(implementation_type& impl, const query_type& query, + Handler handler) + { + service_impl_.async_resolve(impl, query, handler); + } + + /// Resolve an endpoint to a list of entries. + template + iterator_type resolve(implementation_type& impl, + const endpoint_type& endpoint, Error_Handler error_handler) + { + return service_impl_.resolve(impl, endpoint, error_handler); + } + + /// Asynchronously resolve an endpoint to a list of entries. + template + void async_resolve(implementation_type& impl, const endpoint_type& endpoint, + Handler handler) + { + return service_impl_.async_resolve(impl, endpoint, handler); + } + +private: + // The service that provides the platform-specific implementation. + service_impl_type& service_impl_; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_RESOLVER_SERVICE_HPP diff --git a/libtorrent/include/asio/socket_acceptor_service.hpp b/libtorrent/include/asio/socket_acceptor_service.hpp index 965bff39e..e80f8c1ca 100644 --- a/libtorrent/include/asio/socket_acceptor_service.hpp +++ b/libtorrent/include/asio/socket_acceptor_service.hpp @@ -60,6 +60,9 @@ private: #elif defined(ASIO_HAS_KQUEUE) typedef detail::reactive_socket_service< Protocol, detail::kqueue_reactor > service_impl_type; +#elif defined(ASIO_HAS_DEV_POLL) + typedef detail::reactive_socket_service< + Protocol, detail::dev_poll_reactor > service_impl_type; #else typedef detail::reactive_socket_service< Protocol, detail::select_reactor > service_impl_type; diff --git a/libtorrent/include/asio/ssl/detail/openssl_operation.hpp b/libtorrent/include/asio/ssl/detail/openssl_operation.hpp index 5fd3ebba4..c254aceb2 100755 --- a/libtorrent/include/asio/ssl/detail/openssl_operation.hpp +++ b/libtorrent/include/asio/ssl/detail/openssl_operation.hpp @@ -179,7 +179,7 @@ public: else { return handler_(asio::error_code( - error_code, asio::error::ssl_category), rc); + error_code, asio::error::get_ssl_category()), rc); } } diff --git a/libtorrent/include/asio/ssl/detail/openssl_stream_service.hpp b/libtorrent/include/asio/ssl/detail/openssl_stream_service.hpp index d90b588ef..3812deb80 100644 --- a/libtorrent/include/asio/ssl/detail/openssl_stream_service.hpp +++ b/libtorrent/include/asio/ssl/detail/openssl_stream_service.hpp @@ -238,7 +238,7 @@ public: typedef handshake_handler connect_handler; connect_handler* local_handler = - new connect_handler(handler, io_service()); + new connect_handler(handler, get_io_service()); openssl_operation* op = new openssl_operation ( @@ -259,7 +259,7 @@ public: ); local_handler->set_operation(op); - io_service().post(boost::bind(&openssl_operation::start, op)); + get_io_service().post(boost::bind(&openssl_operation::start, op)); } // Shut down SSL on the stream. @@ -294,7 +294,7 @@ public: typedef shutdown_handler disconnect_handler; disconnect_handler* local_handler = - new disconnect_handler(handler, io_service()); + new disconnect_handler(handler, get_io_service()); openssl_operation* op = new openssl_operation ( @@ -313,7 +313,7 @@ public: ); local_handler->set_operation(op); - io_service().post(boost::bind(&openssl_operation::start, op)); + get_io_service().post(boost::bind(&openssl_operation::start, op)); } // Write some data to the stream. @@ -354,7 +354,7 @@ public: { typedef io_handler send_handler; - send_handler* local_handler = new send_handler(handler, io_service()); + send_handler* local_handler = new send_handler(handler, get_io_service()); boost::function send_func = boost::bind(&::SSL_write, boost::arg<1>(), @@ -378,7 +378,7 @@ public: ); local_handler->set_operation(op); - io_service().post(boost::bind(&openssl_operation::start, op)); + get_io_service().post(boost::bind(&openssl_operation::start, op)); } // Read some data from the stream. @@ -419,7 +419,7 @@ public: { typedef io_handler recv_handler; - recv_handler* local_handler = new recv_handler(handler, io_service()); + recv_handler* local_handler = new recv_handler(handler, get_io_service()); boost::function recv_func = boost::bind(&::SSL_read, boost::arg<1>(), @@ -443,7 +443,7 @@ public: ); local_handler->set_operation(op); - io_service().post(boost::bind(&openssl_operation::start, op)); + get_io_service().post(boost::bind(&openssl_operation::start, op)); } // Peek at the incoming data on the stream. diff --git a/libtorrent/include/asio/ssl/stream.hpp b/libtorrent/include/asio/ssl/stream.hpp index a6af16101..9ee48fef1 100644 --- a/libtorrent/include/asio/ssl/stream.hpp +++ b/libtorrent/include/asio/ssl/stream.hpp @@ -85,7 +85,7 @@ public: template explicit stream(Arg& arg, basic_context& context) : next_layer_(arg), - service_(asio::use_service(next_layer_.io_service())), + service_(asio::use_service(next_layer_.get_io_service())), impl_(service_.null()) { service_.create(impl_, next_layer_, context); @@ -97,7 +97,8 @@ public: service_.destroy(impl_, next_layer_); } - /// Get the io_service associated with the object. + /// (Deprecated: use get_io_service().) Get the io_service associated with + /// the object. /** * This function may be used to obtain the io_service object that the stream * uses to dispatch handlers for asynchronous operations. @@ -107,7 +108,20 @@ public: */ asio::io_service& io_service() { - return next_layer_.io_service(); + return next_layer_.get_io_service(); + } + + /// Get the io_service associated with the object. + /** + * This function may be used to obtain the io_service object that the stream + * uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_service object that stream will use to + * dispatch handlers. Ownership is not transferred to the caller. + */ + asio::io_service& get_io_service() + { + return next_layer_.get_io_service(); } /// Get a reference to the next layer. diff --git a/libtorrent/include/asio/strand.hpp b/libtorrent/include/asio/strand.hpp index d0869d95d..ff76415a2 100644 --- a/libtorrent/include/asio/strand.hpp +++ b/libtorrent/include/asio/strand.hpp @@ -65,7 +65,8 @@ public: service_.destroy(impl_); } - /// Get the io_service associated with the strand. + /// (Deprecated: use get_io_service().) Get the io_service associated with + /// the strand. /** * This function may be used to obtain the io_service object that the strand * uses to dispatch handlers for asynchronous operations. @@ -75,7 +76,20 @@ public: */ asio::io_service& io_service() { - return service_.io_service(); + return service_.get_io_service(); + } + + /// Get the io_service associated with the strand. + /** + * This function may be used to obtain the io_service object that the strand + * uses to dispatch handlers for asynchronous operations. + * + * @return A reference to the io_service object that the strand will use to + * dispatch handlers. Ownership is not transferred to the caller. + */ + asio::io_service& get_io_service() + { + return service_.get_io_service(); } /// Request the strand to invoke the given handler. diff --git a/libtorrent/include/asio/stream_socket_service.hpp b/libtorrent/include/asio/stream_socket_service.hpp index d7915aaf4..7a04c6bf0 100644 --- a/libtorrent/include/asio/stream_socket_service.hpp +++ b/libtorrent/include/asio/stream_socket_service.hpp @@ -64,6 +64,9 @@ private: #elif defined(ASIO_HAS_KQUEUE) typedef detail::reactive_socket_service< Protocol, detail::kqueue_reactor > service_impl_type; +#elif defined(ASIO_HAS_DEV_POLL) + typedef detail::reactive_socket_service< + Protocol, detail::dev_poll_reactor > service_impl_type; #else typedef detail::reactive_socket_service< Protocol, detail::select_reactor > service_impl_type; diff --git a/libtorrent/include/asio/system_exception.hpp b/libtorrent/include/asio/system_exception.hpp new file mode 100644 index 000000000..599e22712 --- /dev/null +++ b/libtorrent/include/asio/system_exception.hpp @@ -0,0 +1,198 @@ +// +// error.hpp +// ~~~~~~~~~ +// +// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost 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_SYSTEM_EXCEPTION_HPP +#define ASIO_SYSTEM_EXCEPTION_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 +#include +#include +#include +#include +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +# include +#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +#include "asio/detail/pop_options.hpp" + +#include "asio/detail/win_local_free_on_block_exit.hpp" + +namespace asio { + +/// The system_exception class is used to represent system conditions that +/// prevent the library from operating correctly. +class system_exception + : public std::exception +{ +public: + /// Construct with a specific context and error code. + system_exception(const std::string& context, int code) + : context_(context), + code_(code) + { + } + + /// Copy constructor. + system_exception(const system_exception& e) + : std::exception(e), + context_(e.context_), + code_(e.code_) + { + } + + /// Destructor. + virtual ~system_exception() throw () + { + } + + /// Assignment operator. + system_exception& operator=(const system_exception& e) + { + context_ = e.context_; + code_ = e.code_; + what_.reset(); + return *this; + } + + /// Get a string representation of the exception. + virtual const char* what() const throw () + { +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + try + { + if (!what_) + { + char* msg = 0; + DWORD length = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, 0, code_, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msg, 0, 0); + detail::win_local_free_on_block_exit local_free_obj(msg); + if (length && msg[length - 1] == '\n') + msg[--length] = '\0'; + if (length && msg[length - 1] == '\r') + msg[--length] = '\0'; + if (length) + { + std::string tmp(context_); + tmp += ": "; + tmp += msg; + what_.reset(new std::string(tmp)); + } + else + { + return "asio system_exception"; + } + } + return what_->c_str(); + } + catch (std::exception&) + { + return "asio system_exception"; + } +#elif defined(__sun) || defined(__QNX__) + return strerror(code_); +#elif defined(__MACH__) && defined(__APPLE__) \ + || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) + try + { + char buf[256] = ""; + strerror_r(code_, buf, sizeof(buf)); + std::string tmp(context_); + tmp += ": "; + tmp += buf; + what_.reset(new std::string(tmp)); + return what_->c_str(); + } + catch (std::exception&) + { + return "asio system_exception"; + } +#else + try + { + char buf[256] = ""; + std::string tmp(context_); + tmp += ": "; + tmp += strerror_r(code_, buf, sizeof(buf)); + what_.reset(new std::string(tmp)); + return what_->c_str(); + } + catch (std::exception&) + { + return "asio system_exception"; + } +#endif + } + + /// Get the implementation-defined context associated with the exception. + const std::string& context() const + { + return context_; + } + + /// Get the implementation-defined code associated with the exception. + int code() const + { + return code_; + } + +private: + // The context associated with the error. + std::string context_; + + // The code associated with the error. + int code_; + + // The string representation of the error. + mutable boost::scoped_ptr what_; +}; + +/// Output the string associated with a system exception. +/** + * Used to output a human-readable string that is associated with a system + * exception. + * + * @param os The output stream to which the string will be written. + * + * @param e The exception to be written. + * + * @return The output stream. + * + * @relates asio::system_exception + */ +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +std::ostream& operator<<(std::ostream& os, const system_exception& e) +{ + os << e.what(); + return os; +} +#else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +template +Ostream& operator<<(Ostream& os, const system_exception& e) +{ + os << e.what(); + return os; +} +#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SYSTEM_EXCEPTION_HPP