diff --git a/libtorrent/include/libtorrent/asio/basic_socket.hpp b/libtorrent/include/libtorrent/asio/basic_socket.hpp index b0dc52e48..2b2521b69 100644 --- a/libtorrent/include/libtorrent/asio/basic_socket.hpp +++ b/libtorrent/include/libtorrent/asio/basic_socket.hpp @@ -238,6 +238,9 @@ public: * with the asio::error::operation_aborted error. * * @throws asio::system_error Thrown on failure. + * + * @note For portable behaviour with respect to graceful closure of a + * connected socket, call shutdown() before closing the socket. */ void close() { @@ -265,6 +268,9 @@ public: * // An error occurred. * } * @endcode + * + * @note For portable behaviour with respect to graceful closure of a + * connected socket, call shutdown() before closing the socket. */ asio::error_code close(asio::error_code& ec) { diff --git a/libtorrent/include/libtorrent/asio/buffer.hpp b/libtorrent/include/libtorrent/asio/buffer.hpp index 7e5dc76c8..9fe76178c 100644 --- a/libtorrent/include/libtorrent/asio/buffer.hpp +++ b/libtorrent/include/libtorrent/asio/buffer.hpp @@ -542,9 +542,10 @@ inline const_buffers_1 buffer(const PodType (&data)[N], ? N * sizeof(PodType) : max_size_in_bytes)); } -#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) \ + || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) -// Borland C++ thinks the overloads: +// Borland C++ and Sun Studio think the overloads: // // unspecified buffer(boost::array& array ...); // @@ -610,6 +611,7 @@ buffer(boost::array& data, std::size_t max_size_in_bytes) } #else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) + // || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) /// Create a new modifiable buffer that represents the given POD array. template @@ -650,6 +652,7 @@ inline const_buffers_1 buffer(boost::array& data, } #endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) + // || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) /// Create a new non-modifiable buffer that represents the given POD array. template diff --git a/libtorrent/include/libtorrent/asio/detail/null_event.hpp b/libtorrent/include/libtorrent/asio/detail/null_event.hpp index df522ce0f..99bcbc6a4 100644 --- a/libtorrent/include/libtorrent/asio/detail/null_event.hpp +++ b/libtorrent/include/libtorrent/asio/detail/null_event.hpp @@ -43,17 +43,20 @@ public: } // Signal the event. - void signal() + template + void signal(Lock&) { } // Reset the event. - void clear() + template + void clear(Lock&) { } // Wait for the event to become signalled. - void wait() + template + void wait(Lock&) { } }; diff --git a/libtorrent/include/libtorrent/asio/detail/posix_event.hpp b/libtorrent/include/libtorrent/asio/detail/posix_event.hpp index 408c23bb9..1197ac3f1 100644 --- a/libtorrent/include/libtorrent/asio/detail/posix_event.hpp +++ b/libtorrent/include/libtorrent/asio/detail/posix_event.hpp @@ -24,6 +24,7 @@ #if defined(BOOST_HAS_PTHREADS) #include "asio/detail/push_options.hpp" +#include #include #include #include "asio/detail/pop_options.hpp" @@ -42,7 +43,7 @@ public: posix_event() : signalled_(false) { - int error = ::pthread_mutex_init(&mutex_, 0); + int error = ::pthread_cond_init(&cond_, 0); if (error != 0) { asio::system_error e( @@ -50,53 +51,43 @@ public: "event"); boost::throw_exception(e); } - - error = ::pthread_cond_init(&cond_, 0); - if (error != 0) - { - ::pthread_mutex_destroy(&mutex_); - asio::system_error e( - asio::error_code(error, asio::native_ecat), - "event"); - boost::throw_exception(e); - } } // Destructor. ~posix_event() { ::pthread_cond_destroy(&cond_); - ::pthread_mutex_destroy(&mutex_); } // Signal the event. - void signal() + template + void signal(Lock& lock) { - ::pthread_mutex_lock(&mutex_); // Ignore EINVAL and EDEADLK. + BOOST_ASSERT(lock.locked()); + (void)lock; signalled_ = true; ::pthread_cond_signal(&cond_); // Ignore EINVAL. - ::pthread_mutex_unlock(&mutex_); // Ignore EINVAL and EPERM. } // Reset the event. - void clear() + template + void clear(Lock& lock) { - ::pthread_mutex_lock(&mutex_); // Ignore EINVAL and EDEADLK. + BOOST_ASSERT(lock.locked()); + (void)lock; signalled_ = false; - ::pthread_mutex_unlock(&mutex_); // Ignore EINVAL and EPERM. } // Wait for the event to become signalled. - void wait() + template + void wait(Lock& lock) { - ::pthread_mutex_lock(&mutex_); // Ignore EINVAL and EDEADLK. + BOOST_ASSERT(lock.locked()); while (!signalled_) - ::pthread_cond_wait(&cond_, &mutex_); // Ignore EINVAL. - ::pthread_mutex_unlock(&mutex_); // Ignore EINVAL and EPERM. + ::pthread_cond_wait(&cond_, &lock.mutex().mutex_); // Ignore EINVAL. } private: - ::pthread_mutex_t mutex_; ::pthread_cond_t cond_; bool signalled_; }; diff --git a/libtorrent/include/libtorrent/asio/detail/posix_mutex.hpp b/libtorrent/include/libtorrent/asio/detail/posix_mutex.hpp index 154089f3c..224722bb4 100644 --- a/libtorrent/include/libtorrent/asio/detail/posix_mutex.hpp +++ b/libtorrent/include/libtorrent/asio/detail/posix_mutex.hpp @@ -35,6 +35,8 @@ namespace asio { namespace detail { +class posix_event; + class posix_mutex : private noncopyable { @@ -87,6 +89,7 @@ public: } private: + friend class posix_event; ::pthread_mutex_t mutex_; }; diff --git a/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp b/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp index d5b8e4fc8..e4b4dfa7c 100644 --- a/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp +++ b/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp @@ -86,7 +86,7 @@ public: }; // The maximum number of buffers to support in a single operation. - enum { max_buffers = 16 }; + enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; // Constructor. reactive_socket_service(asio::io_service& io_service) diff --git a/libtorrent/include/libtorrent/asio/detail/scoped_lock.hpp b/libtorrent/include/libtorrent/asio/detail/scoped_lock.hpp index 64c77cbab..57f8cb8f6 100644 --- a/libtorrent/include/libtorrent/asio/detail/scoped_lock.hpp +++ b/libtorrent/include/libtorrent/asio/detail/scoped_lock.hpp @@ -63,6 +63,18 @@ public: } } + // Test whether the lock is held. + bool locked() const + { + return locked_; + } + + // Get the underlying mutex. + Mutex& mutex() + { + return mutex_; + } + private: // The underlying mutex. Mutex& mutex_; diff --git a/libtorrent/include/libtorrent/asio/detail/service_registry.hpp b/libtorrent/include/libtorrent/asio/detail/service_registry.hpp index bd1c3ea5b..3a9e9f620 100644 --- a/libtorrent/include/libtorrent/asio/detail/service_registry.hpp +++ b/libtorrent/include/libtorrent/asio/detail/service_registry.hpp @@ -166,7 +166,8 @@ private: } // Check if a service matches the given id. - bool service_id_matches(const asio::io_service::service& service, + static bool service_id_matches( + const asio::io_service::service& service, const asio::io_service::id& id) { return service.id_ == &id; @@ -174,7 +175,8 @@ private: // Check if a service matches the given id. template - bool service_id_matches(const asio::io_service::service& service, + static bool service_id_matches( + const asio::io_service::service& service, const asio::detail::service_id& /*id*/) { return service.type_info_ != 0 && *service.type_info_ == typeid(Service); diff --git a/libtorrent/include/libtorrent/asio/detail/socket_option.hpp b/libtorrent/include/libtorrent/asio/detail/socket_option.hpp index ee867e6b2..1a03936ab 100644 --- a/libtorrent/include/libtorrent/asio/detail/socket_option.hpp +++ b/libtorrent/include/libtorrent/asio/detail/socket_option.hpp @@ -110,8 +110,19 @@ public: template void resize(const Protocol&, std::size_t s) { - if (s != sizeof(value_)) + // On some platforms (e.g. Windows Vista), the getsockopt function will + // return the size of a boolean socket option as one byte, even though a + // four byte integer was passed in. + switch (s) + { + case sizeof(char): + value_ = *reinterpret_cast(&value_) ? 1 : 0; + break; + case sizeof(value_): + break; + default: throw std::length_error("boolean socket option resize"); + } } private: diff --git a/libtorrent/include/libtorrent/asio/detail/socket_types.hpp b/libtorrent/include/libtorrent/asio/detail/socket_types.hpp index 49d1c7fc2..02c3a78d5 100644 --- a/libtorrent/include/libtorrent/asio/detail/socket_types.hpp +++ b/libtorrent/include/libtorrent/asio/detail/socket_types.hpp @@ -98,6 +98,7 @@ # include # include # include +# include # if defined(__sun) # include # include @@ -141,6 +142,11 @@ const int shutdown_both = SD_BOTH; const int message_peek = MSG_PEEK; const int message_out_of_band = MSG_OOB; const int message_do_not_route = MSG_DONTROUTE; +# if defined (_WIN32_WINNT) +const int max_iov_len = 64; +# else +const int max_iov_len = 16; +# endif #else typedef int socket_type; const int invalid_socket = -1; @@ -166,6 +172,7 @@ const int shutdown_both = SHUT_RDWR; const int message_peek = MSG_PEEK; const int message_out_of_band = MSG_OOB; const int message_do_not_route = MSG_DONTROUTE; +const int max_iov_len = IOV_MAX; #endif const int custom_socket_option_level = 0xA5100000; const int enable_connection_aborted_option = 1; diff --git a/libtorrent/include/libtorrent/asio/detail/strand_service.hpp b/libtorrent/include/libtorrent/asio/detail/strand_service.hpp index f10289090..d987cb98d 100644 --- a/libtorrent/include/libtorrent/asio/detail/strand_service.hpp +++ b/libtorrent/include/libtorrent/asio/detail/strand_service.hpp @@ -239,6 +239,7 @@ public: #else BOOST_ASSERT(size <= strand_impl::handler_storage_type::size); #endif + (void)size; return impl_->handler_storage_.address(); } @@ -415,14 +416,14 @@ public: } else { - asio::detail::mutex::scoped_lock lock(impl->mutex_); - // 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(handler); handler_ptr ptr(raw_ptr, handler); + asio::detail::mutex::scoped_lock lock(impl->mutex_); + if (impl->current_handler_ == 0) { // This handler now has the lock, so can be dispatched immediately. @@ -455,14 +456,14 @@ public: template void post(implementation_type& impl, Handler handler) { - asio::detail::mutex::scoped_lock lock(impl->mutex_); - // 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(handler); handler_ptr ptr(raw_ptr, handler); + asio::detail::mutex::scoped_lock lock(impl->mutex_); + if (impl->current_handler_ == 0) { // This handler now has the lock, so can be dispatched immediately. diff --git a/libtorrent/include/libtorrent/asio/detail/task_io_service.hpp b/libtorrent/include/libtorrent/asio/detail/task_io_service.hpp index 07df1c18a..802d7ea95 100644 --- a/libtorrent/include/libtorrent/asio/detail/task_io_service.hpp +++ b/libtorrent/include/libtorrent/asio/detail/task_io_service.hpp @@ -40,6 +40,7 @@ public: : asio::detail::service_base >(io_service), mutex_(), task_(use_service(io_service)), + task_interrupted_(true), outstanding_work_(0), handler_queue_(&task_handler_), handler_queue_end_(&task_handler_), @@ -80,8 +81,7 @@ public: typename call_stack::context ctx(this); idle_thread_info this_idle_thread; - this_idle_thread.prev = &this_idle_thread; - this_idle_thread.next = &this_idle_thread; + this_idle_thread.next = 0; asio::detail::mutex::scoped_lock lock(mutex_); @@ -98,8 +98,7 @@ public: typename call_stack::context ctx(this); idle_thread_info this_idle_thread; - this_idle_thread.prev = &this_idle_thread; - this_idle_thread.next = &this_idle_thread; + this_idle_thread.next = 0; asio::detail::mutex::scoped_lock lock(mutex_); @@ -134,7 +133,7 @@ public: void stop() { asio::detail::mutex::scoped_lock lock(mutex_); - stop_all_threads(); + stop_all_threads(lock); } // Reset in preparation for a subsequent run invocation. @@ -156,7 +155,7 @@ public: { asio::detail::mutex::scoped_lock lock(mutex_); if (--outstanding_work_ == 0) - stop_all_threads(); + stop_all_threads(lock); } // Request invocation of the given handler. @@ -201,9 +200,14 @@ public: ++outstanding_work_; // Wake up a thread to execute the handler. - if (!interrupt_one_idle_thread()) - if (task_handler_.next_ == 0 && handler_queue_end_ != &task_handler_) + if (!interrupt_one_idle_thread(lock)) + { + if (!task_interrupted_) + { + task_interrupted_ = true; task_.interrupt(); + } + } } private: @@ -214,7 +218,7 @@ private: { if (outstanding_work_ == 0 && !stopped_) { - stop_all_threads(); + stop_all_threads(lock); ec = asio::error_code(); return 0; } @@ -230,11 +234,14 @@ private: handler_queue_ = h->next_; if (handler_queue_ == 0) handler_queue_end_ = 0; - bool more_handlers = (handler_queue_ != 0); - lock.unlock(); + h->next_ = 0; if (h == &task_handler_) { + bool more_handlers = (handler_queue_ != 0); + 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) { @@ -252,6 +259,7 @@ private: } else { + lock.unlock(); handler_cleanup c(lock, *this); // Invoke the handler. May throw an exception. @@ -264,31 +272,10 @@ private: else if (this_idle_thread) { // Nothing to run right now, so just wait for work to do. - if (first_idle_thread_) - { - this_idle_thread->next = first_idle_thread_; - this_idle_thread->prev = first_idle_thread_->prev; - first_idle_thread_->prev->next = this_idle_thread; - first_idle_thread_->prev = this_idle_thread; - } + this_idle_thread->next = first_idle_thread_; first_idle_thread_ = this_idle_thread; - this_idle_thread->wakeup_event.clear(); - lock.unlock(); - this_idle_thread->wakeup_event.wait(); - lock.lock(); - if (this_idle_thread->next == this_idle_thread) - { - first_idle_thread_ = 0; - } - else - { - if (first_idle_thread_ == this_idle_thread) - first_idle_thread_ = this_idle_thread->next; - this_idle_thread->next->prev = this_idle_thread->prev; - this_idle_thread->prev->next = this_idle_thread->next; - this_idle_thread->next = this_idle_thread; - this_idle_thread->prev = this_idle_thread; - } + this_idle_thread->wakeup_event.clear(lock); + this_idle_thread->wakeup_event.wait(lock); } else { @@ -302,39 +289,44 @@ private: } // Stop the task and all idle threads. - void stop_all_threads() + void stop_all_threads( + asio::detail::mutex::scoped_lock& lock) { stopped_ = true; - interrupt_all_idle_threads(); - if (task_handler_.next_ == 0 && handler_queue_end_ != &task_handler_) + interrupt_all_idle_threads(lock); + if (!task_interrupted_) + { + task_interrupted_ = true; task_.interrupt(); + } } // Interrupt a single idle thread. Returns true if a thread was interrupted, // false if no running thread could be found to interrupt. - bool interrupt_one_idle_thread() + bool interrupt_one_idle_thread( + asio::detail::mutex::scoped_lock& lock) { if (first_idle_thread_) { - first_idle_thread_->wakeup_event.signal(); - first_idle_thread_ = first_idle_thread_->next; + idle_thread_info* idle_thread = first_idle_thread_; + first_idle_thread_ = idle_thread->next; + idle_thread->next = 0; + idle_thread->wakeup_event.signal(lock); return true; } return false; } // Interrupt all idle threads. - void interrupt_all_idle_threads() + void interrupt_all_idle_threads( + asio::detail::mutex::scoped_lock& lock) { - if (first_idle_thread_) + while (first_idle_thread_) { - first_idle_thread_->wakeup_event.signal(); - idle_thread_info* current_idle_thread = first_idle_thread_->next; - while (current_idle_thread != first_idle_thread_) - { - current_idle_thread->wakeup_event.signal(); - current_idle_thread = current_idle_thread->next; - } + idle_thread_info* idle_thread = first_idle_thread_; + first_idle_thread_ = idle_thread->next; + idle_thread->next = 0; + idle_thread->wakeup_event.signal(lock); } } @@ -440,6 +432,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_) { @@ -478,7 +471,7 @@ private: { lock_.lock(); if (--task_io_service_.outstanding_work_ == 0) - task_io_service_.stop_all_threads(); + task_io_service_.stop_all_threads(lock_); } private: @@ -503,6 +496,9 @@ private: } } task_handler_; + // Whether the task has been interrupted. + bool task_interrupted_; + // The count of unfinished work. int outstanding_work_; @@ -522,7 +518,6 @@ private: struct idle_thread_info { event wakeup_event; - idle_thread_info* prev; idle_thread_info* next; }; diff --git a/libtorrent/include/libtorrent/asio/detail/win_event.hpp b/libtorrent/include/libtorrent/asio/detail/win_event.hpp index 8de9383da..68f55ff13 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_event.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_event.hpp @@ -28,6 +28,7 @@ #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" +#include #include #include "asio/detail/pop_options.hpp" @@ -59,21 +60,31 @@ public: } // Signal the event. - void signal() + template + void signal(Lock& lock) { + BOOST_ASSERT(lock.locked()); + (void)lock; ::SetEvent(event_); } // Reset the event. - void clear() + template + void clear(Lock& lock) { + BOOST_ASSERT(lock.locked()); + (void)lock; ::ResetEvent(event_); } // Wait for the event to become signalled. - void wait() + template + void wait(Lock& lock) { + BOOST_ASSERT(lock.locked()); + lock.unlock(); ::WaitForSingleObject(event_, INFINITE); + lock.lock(); } private: diff --git a/libtorrent/include/libtorrent/asio/detail/win_iocp_socket_service.hpp b/libtorrent/include/libtorrent/asio/detail/win_iocp_socket_service.hpp index d0078978a..dcef56576 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_iocp_socket_service.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_iocp_socket_service.hpp @@ -137,7 +137,7 @@ public: enum { enable_connection_aborted = 1, // User wants connection_aborted errors. - user_set_linger = 2, // The user set the linger option. + close_might_block = 2, // User set linger option for blocking close. user_set_non_blocking = 4 // The user wants a non-blocking socket. }; @@ -170,7 +170,7 @@ public: typedef detail::select_reactor reactor_type; // The maximum number of buffers to support in a single operation. - enum { max_buffers = 16 }; + enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; // Constructor. win_iocp_socket_service(asio::io_service& io_service) @@ -192,7 +192,7 @@ public: while (impl) { asio::error_code ignored_ec; - close(*impl, ignored_ec); + close_for_destruction(*impl); impl = impl->next_; } } @@ -217,34 +217,7 @@ public: // Destroy a socket implementation. void destroy(implementation_type& impl) { - if (impl.socket_ != invalid_socket) - { - // Check if the reactor was created, in which case we need to close the - // socket on the reactor as well to cancel any operations that might be - // running there. - reactor_type* reactor = static_cast( - interlocked_compare_exchange_pointer( - reinterpret_cast(&reactor_), 0, 0)); - if (reactor) - reactor->close_descriptor(impl.socket_); - - if (impl.flags_ & implementation_type::user_set_linger) - { - ::linger opt; - opt.l_onoff = 0; - opt.l_linger = 0; - asio::error_code ignored_ec; - socket_ops::setsockopt(impl.socket_, - SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec); - } - - asio::error_code ignored_ec; - socket_ops::close(impl.socket_, ignored_ec); - impl.socket_ = invalid_socket; - impl.flags_ = 0; - impl.cancel_token_.reset(); - impl.safe_cancellation_thread_id_ = 0; - } + close_for_destruction(impl); // Remove implementation from linked list of all implementations. asio::detail::mutex::scoped_lock lock(mutex_); @@ -353,6 +326,24 @@ public: { ec = asio::error::bad_descriptor; } + else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( + ::GetModuleHandle("KERNEL32"), "CancelIoEx")) + { + // The version of Windows supports cancellation from any thread. + typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); + cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr; + socket_type sock = impl.socket_; + HANDLE sock_as_handle = reinterpret_cast(sock); + if (!cancel_io_ex(sock_as_handle, 0)) + { + DWORD last_error = ::GetLastError(); + ec = asio::error_code(last_error, asio::native_ecat); + } + else + { + ec = asio::error_code(); + } + } else if (impl.safe_cancellation_thread_id_ == 0) { // No operations have been started, so there's nothing to cancel. @@ -475,7 +466,12 @@ public: if (option.level(impl.protocol_) == SOL_SOCKET && option.name(impl.protocol_) == SO_LINGER) { - impl.flags_ |= implementation_type::user_set_linger; + const ::linger* linger_option = + reinterpret_cast(option.data(impl.protocol_)); + if (linger_option->l_onoff != 0 && linger_option->l_linger != 0) + impl.flags_ |= implementation_type::close_might_block; + else + impl.flags_ &= ~implementation_type::close_might_block; } socket_ops::setsockopt(impl.socket_, @@ -1950,6 +1946,43 @@ public: } private: + // Helper function to close a socket when the associated object is being + // destroyed. + void close_for_destruction(implementation_type& impl) + { + if (is_open(impl)) + { + // Check if the reactor was created, in which case we need to close the + // socket on the reactor as well to cancel any operations that might be + // running there. + reactor_type* reactor = static_cast( + interlocked_compare_exchange_pointer( + reinterpret_cast(&reactor_), 0, 0)); + if (reactor) + reactor->close_descriptor(impl.socket_); + + // The socket destructor must not block. If the user has changed the + // linger option to block in the foreground, we will change it back to the + // default so that the closure is performed in the background. + if (impl.flags_ & implementation_type::close_might_block) + { + ::linger opt; + opt.l_onoff = 0; + opt.l_linger = 0; + asio::error_code ignored_ec; + socket_ops::setsockopt(impl.socket_, + SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec); + } + + asio::error_code ignored_ec; + socket_ops::close(impl.socket_, ignored_ec); + impl.socket_ = invalid_socket; + impl.flags_ = 0; + impl.cancel_token_.reset(); + impl.safe_cancellation_thread_id_ = 0; + } + } + // Helper function to emulate InterlockedCompareExchangePointer functionality // for: // - very old Platform SDKs; and diff --git a/libtorrent/include/libtorrent/asio/detail/wrapped_handler.hpp b/libtorrent/include/libtorrent/asio/detail/wrapped_handler.hpp index f757fd3dc..913a795dc 100644 --- a/libtorrent/include/libtorrent/asio/detail/wrapped_handler.hpp +++ b/libtorrent/include/libtorrent/asio/detail/wrapped_handler.hpp @@ -17,6 +17,10 @@ #include "asio/detail/push_options.hpp" +#include "asio/detail/push_options.hpp" +#include +#include "asio/detail/pop_options.hpp" + #include "asio/detail/bind_handler.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" @@ -30,7 +34,9 @@ class wrapped_handler public: typedef void result_type; - wrapped_handler(Dispatcher& dispatcher, Handler handler) + wrapped_handler( + typename boost::add_reference::type dispatcher, + Handler handler) : dispatcher_(dispatcher), handler_(handler) { @@ -117,7 +123,7 @@ public: } //private: - Dispatcher& dispatcher_; + Dispatcher dispatcher_; Handler handler_; }; @@ -171,9 +177,9 @@ inline void asio_handler_invoke(const Function& function, function, this_handler->handler_)); } -template +template inline void asio_handler_invoke(const Function& function, - rewrapped_handler* this_handler) + rewrapped_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, &this_handler->context_); diff --git a/libtorrent/include/libtorrent/asio/impl/io_service.ipp b/libtorrent/include/libtorrent/asio/impl/io_service.ipp index e973619d1..f51d3697d 100644 --- a/libtorrent/include/libtorrent/asio/impl/io_service.ipp +++ b/libtorrent/include/libtorrent/asio/impl/io_service.ipp @@ -128,11 +128,11 @@ template #if defined(GENERATING_DOCUMENTATION) unspecified #else -inline detail::wrapped_handler +inline detail::wrapped_handler #endif io_service::wrap(Handler handler) { - return detail::wrapped_handler(*this, handler); + return detail::wrapped_handler(*this, handler); } inline io_service::work::work(asio::io_service& io_service) diff --git a/libtorrent/include/libtorrent/asio/io_service.hpp b/libtorrent/include/libtorrent/asio/io_service.hpp index b694545db..2101e56c4 100644 --- a/libtorrent/include/libtorrent/asio/io_service.hpp +++ b/libtorrent/include/libtorrent/asio/io_service.hpp @@ -320,7 +320,7 @@ public: #if defined(GENERATING_DOCUMENTATION) unspecified #else - detail::wrapped_handler + detail::wrapped_handler #endif wrap(Handler handler); diff --git a/libtorrent/include/libtorrent/asio/ip/basic_endpoint.hpp b/libtorrent/include/libtorrent/asio/ip/basic_endpoint.hpp index 3ca91dc03..499d82631 100644 --- a/libtorrent/include/libtorrent/asio/ip/basic_endpoint.hpp +++ b/libtorrent/include/libtorrent/asio/ip/basic_endpoint.hpp @@ -172,7 +172,7 @@ public: /// The protocol associated with the endpoint. protocol_type protocol() const { - if (is_v4()) + if (is_v4(data_)) return InternetProtocol::v4(); return InternetProtocol::v6(); } @@ -192,7 +192,7 @@ public: /// Get the underlying size of the endpoint in the native type. size_type size() const { - if (is_v4()) + if (is_v4(data_)) return sizeof(asio::detail::sockaddr_in4_type); else return sizeof(asio::detail::sockaddr_in6_type); @@ -218,7 +218,7 @@ public: /// the host's byte order. unsigned short port() const { - if (is_v4()) + if (is_v4(data_)) { return asio::detail::socket_ops::network_to_host_short( reinterpret_cast( @@ -236,7 +236,7 @@ public: /// the host's byte order. void port(unsigned short port_num) { - if (is_v4()) + if (is_v4(data_)) { reinterpret_cast(data_).sin_port = asio::detail::socket_ops::host_to_network_short(port_num); @@ -252,7 +252,7 @@ public: asio::ip::address address() const { using namespace std; // For memcpy. - if (is_v4()) + if (is_v4(data_)) { const asio::detail::sockaddr_in4_type& data = reinterpret_cast( @@ -306,15 +306,27 @@ public: private: // Helper function to determine whether the endpoint is IPv4. - bool is_v4() const - { #if defined(_AIX) - return data_.__ss_family == AF_INET; -#else - return data_.ss_family == AF_INET; -#endif + template struct is_v4_helper {}; + + template + static bool is_v4(const T& ss, is_v4_helper* = 0) + { + return ss.ss_family == AF_INET; } + template + static bool is_v4(const T& ss, is_v4_helper* = 0) + { + return ss.__ss_family == AF_INET; + } +#else + static bool is_v4(const asio::detail::sockaddr_storage_type& ss) + { + return ss.ss_family == AF_INET; + } +#endif + // The underlying IP socket address. asio::detail::sockaddr_storage_type data_; };