From e08c51e10c950ebd5e0c14b8a9385981693d11f6 Mon Sep 17 00:00:00 2001 From: Andrew Resch Date: Sun, 19 Apr 2009 21:40:09 +0000 Subject: [PATCH] Update to asio 1.4.1 --- libtorrent/include/asio/basic_serial_port.hpp | 14 ++ libtorrent/include/asio/basic_socket.hpp | 14 ++ .../include/asio/basic_socket_streambuf.hpp | 3 +- libtorrent/include/asio/basic_streambuf.hpp | 176 ++++++++++++-- .../include/asio/buffered_read_stream.hpp | 6 + libtorrent/include/asio/buffered_stream.hpp | 6 + .../include/asio/buffered_write_stream.hpp | 6 + libtorrent/include/asio/buffers_iterator.hpp | 7 + .../include/asio/completion_condition.hpp | 31 ++- .../include/asio/detail/consuming_buffers.hpp | 39 ++- .../asio/detail/deadline_timer_service.hpp | 1 + .../include/asio/detail/descriptor_ops.hpp | 15 +- .../include/asio/detail/dev_poll_reactor.hpp | 12 + .../include/asio/detail/epoll_reactor.hpp | 11 + .../include/asio/detail/kqueue_reactor.hpp | 10 + .../include/asio/detail/null_thread.hpp | 5 +- .../asio/detail/pipe_select_interrupter.hpp | 3 +- .../asio/detail/posix_fd_set_adapter.hpp | 4 + .../include/asio/detail/posix_thread.hpp | 5 +- .../detail/reactive_descriptor_service.hpp | 1 + .../detail/reactive_serial_port_service.hpp | 1 + .../asio/detail/reactive_socket_service.hpp | 226 +++++++++--------- .../include/asio/detail/resolver_service.hpp | 2 +- .../asio/detail/select_interrupter.hpp | 3 + .../include/asio/detail/select_reactor.hpp | 10 + .../include/asio/detail/service_registry.hpp | 20 +- libtorrent/include/asio/detail/socket_ops.hpp | 85 ++++--- .../include/asio/detail/socket_types.hpp | 17 +- .../include/asio/detail/task_io_service.hpp | 31 ++- .../asio/detail/task_io_service_2lock.hpp | 31 ++- .../asio/detail/win_iocp_io_service.hpp | 7 +- .../asio/detail/win_iocp_io_service_fwd.hpp | 1 + libtorrent/include/asio/detail/win_thread.hpp | 114 ++++++--- .../include/asio/detail/wince_thread.hpp | 5 +- libtorrent/include/asio/impl/error_code.ipp | 1 + libtorrent/include/asio/impl/read.ipp | 67 ++++-- libtorrent/include/asio/impl/read_at.ipp | 50 +++- libtorrent/include/asio/impl/read_until.ipp | 87 +++---- libtorrent/include/asio/impl/write.ipp | 25 +- libtorrent/include/asio/impl/write_at.ipp | 25 +- libtorrent/include/asio/io_service.hpp | 1 + libtorrent/include/asio/ip/address_v4.hpp | 19 ++ libtorrent/include/asio/ip/address_v6.hpp | 17 +- libtorrent/include/asio/ip/basic_resolver.hpp | 13 +- .../include/asio/ip/detail/socket_option.hpp | 2 +- .../include/asio/ip/resolver_query_base.hpp | 8 +- .../include/asio/local/basic_endpoint.hpp | 2 +- .../include/asio/posix/basic_descriptor.hpp | 14 ++ libtorrent/include/asio/read.hpp | 110 +++++---- libtorrent/include/asio/read_at.hpp | 78 +++--- libtorrent/include/asio/read_until.hpp | 16 ++ .../ssl/detail/openssl_context_service.hpp | 2 +- .../include/asio/ssl/detail/openssl_init.hpp | 7 + .../asio/ssl/detail/openssl_operation.hpp | 4 + .../ssl/detail/openssl_stream_service.hpp | 8 +- libtorrent/include/asio/ssl/stream.hpp | 13 + libtorrent/include/asio/thread.hpp | 2 +- libtorrent/include/asio/version.hpp | 2 +- .../include/asio/windows/basic_handle.hpp | 14 ++ libtorrent/include/asio/write.hpp | 116 ++++----- libtorrent/include/asio/write_at.hpp | 70 +++--- 61 files changed, 1141 insertions(+), 554 deletions(-) diff --git a/libtorrent/include/asio/basic_serial_port.hpp b/libtorrent/include/asio/basic_serial_port.hpp index ffe2b0213..681205963 100644 --- a/libtorrent/include/asio/basic_serial_port.hpp +++ b/libtorrent/include/asio/basic_serial_port.hpp @@ -142,6 +142,20 @@ public: return *this; } + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since a basic_serial_port cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } + /// Open the serial port using the specified device name. /** * This function opens the serial port for the specified device name. diff --git a/libtorrent/include/asio/basic_socket.hpp b/libtorrent/include/asio/basic_socket.hpp index f494c1725..eb9e34d15 100644 --- a/libtorrent/include/asio/basic_socket.hpp +++ b/libtorrent/include/asio/basic_socket.hpp @@ -149,6 +149,20 @@ public: return *this; } + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since a basic_socket cannot contain any further layers, it simply + * returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } + /// Open the socket using the specified protocol. /** * This function opens the socket so that it will use the specified protocol. diff --git a/libtorrent/include/asio/basic_socket_streambuf.hpp b/libtorrent/include/asio/basic_socket_streambuf.hpp index 0bcd3b7a9..5f301ee34 100644 --- a/libtorrent/include/asio/basic_socket_streambuf.hpp +++ b/libtorrent/include/asio/basic_socket_streambuf.hpp @@ -247,7 +247,8 @@ private: setp(put_buffer_.begin(), put_buffer_.end()); } - void resolve_and_connect(const typename Protocol::resolver_query& query, + template + void resolve_and_connect(const ResolverQuery& query, asio::error_code& ec) { typedef typename Protocol::resolver resolver_type; diff --git a/libtorrent/include/asio/basic_streambuf.hpp b/libtorrent/include/asio/basic_streambuf.hpp index 41649cc43..599cb702c 100644 --- a/libtorrent/include/asio/basic_streambuf.hpp +++ b/libtorrent/include/asio/basic_streambuf.hpp @@ -19,6 +19,7 @@ #include "asio/detail/push_options.hpp" #include +#include #include #include #include @@ -32,6 +33,73 @@ namespace asio { /// Automatically resizable buffer class based on std::streambuf. +/** + * The @c basic_streambuf class is derived from @c std::streambuf to associate + * the streambuf's input and output sequences with one or more character + * arrays. These character arrays are internal to the @c basic_streambuf + * object, but direct access to the array elements is provided to permit them + * to be used efficiently with I/O operations. Characters written to the output + * sequence of a @c basic_streambuf object are appended to the input sequence + * of the same object. + * + * The @c basic_streambuf class's public interface is intended to permit the + * following implementation strategies: + * + * @li A single contiguous character array, which is reallocated as necessary + * to accommodate changes in the size of the character sequence. This is the + * implementation approach currently used in Asio. + * + * @li A sequence of one or more character arrays, where each array is of the + * same size. Additional character array objects are appended to the sequence + * to accommodate changes in the size of the character sequence. + * + * @li A sequence of one or more character arrays of varying sizes. Additional + * character array objects are appended to the sequence to accommodate changes + * in the size of the character sequence. + * + * The constructor for basic_streambuf accepts a @c size_t argument specifying + * the maximum of the sum of the sizes of the input sequence and output + * sequence. During the lifetime of the @c basic_streambuf object, the following + * invariant holds: + * @code size() <= max_size()@endcode + * Any member function that would, if successful, cause the invariant to be + * violated shall throw an exception of class @c std::length_error. + * + * The constructor for @c basic_streambuf takes an Allocator argument. A copy + * of this argument is used for any memory allocation performed, by the + * constructor and by all member functions, during the lifetime of each @c + * basic_streambuf object. + * + * @par Examples + * Writing directly from an streambuf to a socket: + * @code + * asio::streambuf b; + * std::ostream os(&b); + * os << "Hello, World!\n"; + * + * // try sending some data in input sequence + * size_t n = sock.send(b.data()); + * + * b.consume(n); // sent data is removed from input sequence + * @endcode + * + * Reading from a socket directly into a streambuf: + * @code + * asio::streambuf b; + * + * // reserve 512 bytes in output sequence + * asio::streambuf::const_buffers_type bufs = b.prepare(512); + * + * size_t n = sock.receive(bufs); + * + * // received data is "committed" from output sequence to input sequence + * b.commit(n); + * + * std::istream is(&b); + * std::string s; + * is >> s; + * @endcode + */ template > class basic_streambuf : public std::streambuf, @@ -39,17 +107,21 @@ class basic_streambuf { public: #if defined(GENERATING_DOCUMENTATION) - /// The type used to represent the get area as a list of buffers. + /// The type used to represent the input sequence as a list of buffers. typedef implementation_defined const_buffers_type; - /// The type used to represent the put area as a list of buffers. + /// The type used to represent the output sequence as a list of buffers. typedef implementation_defined mutable_buffers_type; #else typedef asio::const_buffers_1 const_buffers_type; typedef asio::mutable_buffers_1 mutable_buffers_type; #endif - /// Construct a buffer with a specified maximum size. + /// Construct a basic_streambuf object. + /** + * Constructs a streambuf with the specified maximum size. The initial size + * of the streambuf's input sequence is 0. + */ explicit basic_streambuf( std::size_t max_size = (std::numeric_limits::max)(), const Allocator& allocator = Allocator()) @@ -62,42 +134,100 @@ public: setp(&buffer_[0], &buffer_[0] + pend); } - /// Return the size of the get area in characters. + /// Get the size of the input sequence. + /** + * @returns The size of the input sequence. The value is equal to that + * calculated for @c s in the following code: + * @code + * size_t s = 0; + * const_buffers_type bufs = data(); + * const_buffers_type::const_iterator i = bufs.begin(); + * while (i != bufs.end()) + * { + * const_buffer buf(*i++); + * s += buffer_size(buf); + * } + * @endcode + */ std::size_t size() const { return pptr() - gptr(); } - /// Return the maximum size of the buffer. + /// Get the maximum size of the basic_streambuf. + /** + * @returns The allowed maximum of the sum of the sizes of the input sequence + * and output sequence. + */ std::size_t max_size() const { return max_size_; } - /// Get a list of buffers that represents the get area. + /// Get a list of buffers that represents the input sequence. + /** + * @returns An object of type @c const_buffers_type that satisfies + * ConstBufferSequence requirements, representing all character arrays in the + * input sequence. + * + * @note The returned object is invalidated by any @c basic_streambuf member + * function that modifies the input sequence or output sequence. + */ const_buffers_type data() const { return asio::buffer(asio::const_buffer(gptr(), (pptr() - gptr()) * sizeof(char_type))); } - /// Get a list of buffers that represents the put area, with the given size. - mutable_buffers_type prepare(std::size_t size) + /// Get a list of buffers that represents the output sequence, with the given + /// size. + /** + * Ensures that the output sequence can accommodate @c n characters, + * reallocating character array objects as necessary. + * + * @returns An object of type @c mutable_buffers_type that satisfies + * MutableBufferSequence requirements, representing character array objects + * at the start of the output sequence such that the sum of the buffer sizes + * is @c n. + * + * @throws std::length_error If size() + n > max_size(). + * + * @note The returned object is invalidated by any @c basic_streambuf member + * function that modifies the input sequence or output sequence. + */ + mutable_buffers_type prepare(std::size_t n) { - reserve(size); + reserve(n); return asio::buffer(asio::mutable_buffer( - pptr(), size * sizeof(char_type))); + pptr(), n * sizeof(char_type))); } - /// Move the start of the put area by the specified number of characters. + /// Move characters from the output sequence to the input sequence. + /** + * Appends @c n characters from the start of the output sequence to the input + * sequence. The beginning of the output sequence is advanced by @c n + * characters. + * + * Requires a preceding call prepare(x) where x >= n, and + * no intervening operations that modify the input or output sequence. + * + * @throws std::length_error If @c n is greater than the size of the output + * sequence. + */ void commit(std::size_t n) { if (pptr() + n > epptr()) n = epptr() - pptr(); pbump(static_cast(n)); + setg(eback(), gptr(), pptr()); } - /// Move the start of the get area by the specified number of characters. + /// Remove characters from the input sequence. + /** + * Removes @c n characters from the beginning of the input sequence. + * + * @throws std::length_error If n > size(). + */ void consume(std::size_t n) { if (gptr() + n > pptr()) @@ -108,6 +238,10 @@ public: protected: enum { buffer_delta = 128 }; + /// Override std::streambuf behaviour. + /** + * Behaves according to the specification of @c std::streambuf::underflow(). + */ int_type underflow() { if (gptr() < pptr()) @@ -121,6 +255,13 @@ protected: } } + /// Override std::streambuf behaviour. + /** + * Behaves according to the specification of @c std::streambuf::overflow(), + * with the specialisation that @c std::length_error is thrown if appending + * the character to the input sequence would require the condition + * size() > max_size() to be true. + */ int_type overflow(int_type c) { if (!traits_type::eq_int_type(c, traits_type::eof())) @@ -150,7 +291,6 @@ protected: { // Get current stream positions as offsets. std::size_t gnext = gptr() - &buffer_[0]; - std::size_t gend = egptr() - &buffer_[0]; std::size_t pnext = pptr() - &buffer_[0]; std::size_t pend = epptr() - &buffer_[0]; @@ -163,9 +303,8 @@ protected: // Shift existing contents of get area to start of buffer. if (gnext > 0) { - std::rotate(&buffer_[0], &buffer_[0] + gnext, &buffer_[0] + pend); - gend -= gnext; pnext -= gnext; + std::memmove(&buffer_[0], &buffer_[0] + gnext, pnext); } // Ensure buffer is large enough to hold at least the specified size. @@ -173,7 +312,8 @@ protected: { if (n <= max_size_ && pnext <= max_size_ - n) { - buffer_.resize((std::max)(pnext + n, 1)); + pend = pnext + n; + buffer_.resize((std::max)(pend, 1)); } else { @@ -182,8 +322,8 @@ protected: } // Update stream positions. - setg(&buffer_[0], &buffer_[0], &buffer_[0] + gend); - setp(&buffer_[0] + pnext, &buffer_[0] + pnext + n); + setg(&buffer_[0], &buffer_[0], &buffer_[0] + pnext); + setp(&buffer_[0] + pnext, &buffer_[0] + pend); } private: diff --git a/libtorrent/include/asio/buffered_read_stream.hpp b/libtorrent/include/asio/buffered_read_stream.hpp index 673cce38d..f88d53cef 100644 --- a/libtorrent/include/asio/buffered_read_stream.hpp +++ b/libtorrent/include/asio/buffered_read_stream.hpp @@ -93,6 +93,12 @@ public: return next_layer_.lowest_layer(); } + /// Get a const reference to the lowest layer. + const lowest_layer_type& lowest_layer() const + { + return next_layer_.lowest_layer(); + } + /// (Deprecated: use get_io_service().) Get the io_service associated with /// the object. asio::io_service& io_service() diff --git a/libtorrent/include/asio/buffered_stream.hpp b/libtorrent/include/asio/buffered_stream.hpp index a02dc88c1..1d7ea9df0 100644 --- a/libtorrent/include/asio/buffered_stream.hpp +++ b/libtorrent/include/asio/buffered_stream.hpp @@ -83,6 +83,12 @@ public: return stream_impl_.lowest_layer(); } + /// Get a const reference to the lowest layer. + const lowest_layer_type& lowest_layer() const + { + return stream_impl_.lowest_layer(); + } + /// (Deprecated: use get_io_service().) Get the io_service associated with /// the object. asio::io_service& io_service() diff --git a/libtorrent/include/asio/buffered_write_stream.hpp b/libtorrent/include/asio/buffered_write_stream.hpp index 0ebd3454e..90c36081f 100644 --- a/libtorrent/include/asio/buffered_write_stream.hpp +++ b/libtorrent/include/asio/buffered_write_stream.hpp @@ -94,6 +94,12 @@ public: return next_layer_.lowest_layer(); } + /// Get a const reference to the lowest layer. + const lowest_layer_type& lowest_layer() const + { + return next_layer_.lowest_layer(); + } + /// (Deprecated: use get_io_service().) Get the io_service associated with /// the object. asio::io_service& io_service() diff --git a/libtorrent/include/asio/buffers_iterator.hpp b/libtorrent/include/asio/buffers_iterator.hpp index cc13bb5e2..48a7d5a98 100644 --- a/libtorrent/include/asio/buffers_iterator.hpp +++ b/libtorrent/include/asio/buffers_iterator.hpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -100,6 +101,9 @@ public: /// Construct an iterator representing the beginning of the buffers' data. static buffers_iterator begin(const BufferSequence& buffers) +#if BOOST_WORKAROUND(__GNUC__, == 4) && BOOST_WORKAROUND(__GNUC_MINOR__, == 3) + __attribute__ ((noinline)) +#endif { buffers_iterator new_iter; new_iter.begin_ = buffers.begin(); @@ -117,6 +121,9 @@ public: /// Construct an iterator representing the end of the buffers' data. static buffers_iterator end(const BufferSequence& buffers) +#if BOOST_WORKAROUND(__GNUC__, == 4) && BOOST_WORKAROUND(__GNUC_MINOR__, == 3) + __attribute__ ((noinline)) +#endif { buffers_iterator new_iter; new_iter.begin_ = buffers.begin(); diff --git a/libtorrent/include/asio/completion_condition.hpp b/libtorrent/include/asio/completion_condition.hpp index b4d59089a..3f712e356 100644 --- a/libtorrent/include/asio/completion_condition.hpp +++ b/libtorrent/include/asio/completion_condition.hpp @@ -26,22 +26,40 @@ namespace asio { namespace detail { +// The default maximum number of bytes to transfer in a single operation. +enum { default_max_transfer_size = 65536 }; + +// Adapt result of old-style completion conditions (which had a bool result +// where true indicated that the operation was complete). +inline std::size_t adapt_completion_condition_result(bool result) +{ + return result ? 0 : default_max_transfer_size; +} + +// Adapt result of current completion conditions (which have a size_t result +// where 0 means the operation is complete, and otherwise the result is the +// maximum number of bytes to transfer on the next underlying operation). +inline std::size_t adapt_completion_condition_result(std::size_t result) +{ + return result; +} + class transfer_all_t { public: - typedef bool result_type; + typedef std::size_t result_type; template - bool operator()(const Error& err, std::size_t) + std::size_t operator()(const Error& err, std::size_t) { - return !!err; + return !!err ? 0 : default_max_transfer_size; } }; class transfer_at_least_t { public: - typedef bool result_type; + typedef std::size_t result_type; explicit transfer_at_least_t(std::size_t minimum) : minimum_(minimum) @@ -49,9 +67,10 @@ public: } template - bool operator()(const Error& err, std::size_t bytes_transferred) + std::size_t operator()(const Error& err, std::size_t bytes_transferred) { - return !!err || bytes_transferred >= minimum_; + return (!!err || bytes_transferred >= minimum_) + ? 0 : default_max_transfer_size; } private: diff --git a/libtorrent/include/asio/detail/consuming_buffers.hpp b/libtorrent/include/asio/detail/consuming_buffers.hpp index 8e88e361d..bdc8fc927 100644 --- a/libtorrent/include/asio/detail/consuming_buffers.hpp +++ b/libtorrent/include/asio/detail/consuming_buffers.hpp @@ -20,11 +20,13 @@ #include "asio/detail/push_options.hpp" #include #include +#include #include #include #include "asio/detail/pop_options.hpp" #include "asio/buffer.hpp" +#include "asio/completion_condition.hpp" namespace asio { namespace detail { @@ -46,33 +48,33 @@ public: // Construct with a buffer for the first entry and an iterator // range for the remaining entries. consuming_buffers_iterator(bool at_end, const Buffer& first, - Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder) - : at_end_(at_end), + Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder, + std::size_t max_size) + : at_end_(max_size > 0 ? at_end : true), first_(buffer(first, max_size)), begin_remainder_(begin_remainder), end_remainder_(end_remainder), - offset_(0) + offset_(0), + max_size_(max_size) { } private: friend class boost::iterator_core_access; - enum { max_size = 65536 }; - void increment() { if (!at_end_) { if (begin_remainder_ == end_remainder_ - || offset_ + buffer_size(first_) >= max_size) + || offset_ + buffer_size(first_) >= max_size_) { at_end_ = true; } else { offset_ += buffer_size(first_); - first_ = buffer(*begin_remainder_++, max_size - offset_); + first_ = buffer(*begin_remainder_++, max_size_ - offset_); } } } @@ -99,6 +101,7 @@ private: Buffer_Iterator begin_remainder_; Buffer_Iterator end_remainder_; std::size_t offset_; + std::size_t max_size_; }; // A proxy for a sub-range in a list of buffers. @@ -118,7 +121,8 @@ public: : buffers_(buffers), at_end_(buffers_.begin() == buffers_.end()), first_(*buffers_.begin()), - begin_remainder_(buffers_.begin()) + begin_remainder_(buffers_.begin()), + max_size_((std::numeric_limits::max)()) { if (!at_end_) ++begin_remainder_; @@ -129,7 +133,8 @@ public: : buffers_(other.buffers_), at_end_(other.at_end_), first_(other.first_), - begin_remainder_(buffers_.begin()) + begin_remainder_(buffers_.begin()), + max_size_(other.max_size_) { typename Buffers::const_iterator first = other.buffers_.begin(); typename Buffers::const_iterator second = other.begin_remainder_; @@ -146,13 +151,15 @@ public: typename Buffers::const_iterator first = other.buffers_.begin(); typename Buffers::const_iterator second = other.begin_remainder_; std::advance(begin_remainder_, std::distance(first, second)); + max_size_ = other.max_size_; return *this; } // Get a forward-only iterator to the first element. const_iterator begin() const { - return const_iterator(at_end_, first_, begin_remainder_, buffers_.end()); + return const_iterator(at_end_, first_, + begin_remainder_, buffers_.end(), max_size_); } // Get a forward-only iterator for one past the last element. @@ -161,6 +168,12 @@ public: return const_iterator(); } + // Set the maximum size for a single transfer. + void set_max_size(std::size_t max_size) + { + max_size_ = max_size; + } + // Consume the specified number of bytes from the buffers. void consume(std::size_t size) { @@ -197,6 +210,7 @@ private: bool at_end_; Buffer first_; typename Buffers::const_iterator begin_remainder_; + std::size_t max_size_; }; // Specialisation for null_buffers to ensure that the null_buffers type is @@ -211,6 +225,11 @@ public: // No-op. } + void set_max_size(std::size_t) + { + // No-op. + } + void consume(std::size_t) { // No-op. diff --git a/libtorrent/include/asio/detail/deadline_timer_service.hpp b/libtorrent/include/asio/detail/deadline_timer_service.hpp index 6f30d7546..b4a660fe0 100644 --- a/libtorrent/include/asio/detail/deadline_timer_service.hpp +++ b/libtorrent/include/asio/detail/deadline_timer_service.hpp @@ -63,6 +63,7 @@ public: deadline_timer_service >(io_service), scheduler_(asio::use_service(io_service)) { + scheduler_.init_task(); scheduler_.add_timer_queue(timer_queue_); } diff --git a/libtorrent/include/asio/detail/descriptor_ops.hpp b/libtorrent/include/asio/detail/descriptor_ops.hpp index 6de34f621..e886b27f4 100644 --- a/libtorrent/include/asio/detail/descriptor_ops.hpp +++ b/libtorrent/include/asio/detail/descriptor_ops.hpp @@ -58,17 +58,28 @@ inline int close(int d, asio::error_code& ec) return error_wrapper(::close(d), ec); } +inline void init_buf_iov_base(void*& base, void* addr) +{ + base = addr; +} + +template +inline void init_buf_iov_base(T& base, void* addr) +{ + base = static_cast(addr); +} + typedef iovec buf; inline void init_buf(buf& b, void* data, size_t size) { - b.iov_base = data; + init_buf_iov_base(b.iov_base, data); b.iov_len = size; } inline void init_buf(buf& b, const void* data, size_t size) { - b.iov_base = const_cast(data); + init_buf_iov_base(b.iov_base, const_cast(data)); b.iov_len = size; } diff --git a/libtorrent/include/asio/detail/dev_poll_reactor.hpp b/libtorrent/include/asio/detail/dev_poll_reactor.hpp index 4eb387eb1..3edc3699c 100644 --- a/libtorrent/include/asio/detail/dev_poll_reactor.hpp +++ b/libtorrent/include/asio/detail/dev_poll_reactor.hpp @@ -122,6 +122,17 @@ public: timer_queues_.clear(); } + // Initialise the task, but only if the reactor is not in its own thread. + void init_task() + { + if (!Own_Thread) + { + typedef task_io_service > + task_io_service_type; + use_service(this->get_io_service()).init_task(); + } + } + // Register a socket with the reactor. Returns 0 on success, system error // code on failure. int register_descriptor(socket_type, per_descriptor_data&) @@ -421,6 +432,7 @@ private: more_writes = write_op_queue_.perform_operation(descriptor, ec); else more_writes = write_op_queue_.has_operation(descriptor); + if ((events[i].events & (POLLERR | POLLHUP)) != 0 && (events[i].events & ~(POLLERR | POLLHUP)) == 0 && !more_except && !more_reads && !more_writes) diff --git a/libtorrent/include/asio/detail/epoll_reactor.hpp b/libtorrent/include/asio/detail/epoll_reactor.hpp index 07bd7e1b6..a5d173483 100644 --- a/libtorrent/include/asio/detail/epoll_reactor.hpp +++ b/libtorrent/include/asio/detail/epoll_reactor.hpp @@ -123,6 +123,16 @@ public: timer_queues_.clear(); } + // Initialise the task, but only if the reactor is not in its own thread. + void init_task() + { + if (!Own_Thread) + { + typedef task_io_service > task_io_service_type; + use_service(this->get_io_service()).init_task(); + } + } + // Register a socket with the reactor. Returns 0 on success, system error // code on failure. int register_descriptor(socket_type descriptor, @@ -495,6 +505,7 @@ private: more_writes = write_op_queue_.perform_operation(descriptor, ec); else more_writes = write_op_queue_.has_operation(descriptor); + if ((events[i].events & (EPOLLERR | EPOLLHUP)) != 0 && (events[i].events & ~(EPOLLERR | EPOLLHUP)) == 0 && !more_except && !more_reads && !more_writes) diff --git a/libtorrent/include/asio/detail/kqueue_reactor.hpp b/libtorrent/include/asio/detail/kqueue_reactor.hpp index 1d0d21aba..5996b6ce7 100644 --- a/libtorrent/include/asio/detail/kqueue_reactor.hpp +++ b/libtorrent/include/asio/detail/kqueue_reactor.hpp @@ -131,6 +131,16 @@ public: timer_queues_.clear(); } + // Initialise the task, but only if the reactor is not in its own thread. + void init_task() + { + if (!Own_Thread) + { + typedef task_io_service > task_io_service_type; + use_service(this->get_io_service()).init_task(); + } + } + // Register a socket with the reactor. Returns 0 on success, system error // code on failure. int register_descriptor(socket_type, per_descriptor_data& descriptor_data) diff --git a/libtorrent/include/asio/detail/null_thread.hpp b/libtorrent/include/asio/detail/null_thread.hpp index f08b7b378..f91ca53e0 100644 --- a/libtorrent/include/asio/detail/null_thread.hpp +++ b/libtorrent/include/asio/detail/null_thread.hpp @@ -38,12 +38,9 @@ class null_thread : private noncopyable { public: - // The purpose of the thread. - enum purpose { internal, external }; - // Constructor. template - null_thread(Function f, purpose = internal) + null_thread(Function f) { asio::system_error e( asio::error::operation_not_supported, "thread"); diff --git a/libtorrent/include/asio/detail/pipe_select_interrupter.hpp b/libtorrent/include/asio/detail/pipe_select_interrupter.hpp index e0a224e33..e62d0c7b7 100644 --- a/libtorrent/include/asio/detail/pipe_select_interrupter.hpp +++ b/libtorrent/include/asio/detail/pipe_select_interrupter.hpp @@ -71,7 +71,8 @@ public: void interrupt() { char byte = 0; - ::write(write_descriptor_, &byte, 1); + int result = ::write(write_descriptor_, &byte, 1); + (void)result; } // Reset the select interrupt. Returns true if the call was interrupted. diff --git a/libtorrent/include/asio/detail/posix_fd_set_adapter.hpp b/libtorrent/include/asio/detail/posix_fd_set_adapter.hpp index 5519b9abc..443774347 100644 --- a/libtorrent/include/asio/detail/posix_fd_set_adapter.hpp +++ b/libtorrent/include/asio/detail/posix_fd_set_adapter.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/socket_types.hpp" #if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) diff --git a/libtorrent/include/asio/detail/posix_thread.hpp b/libtorrent/include/asio/detail/posix_thread.hpp index fe5f82905..892ffe076 100644 --- a/libtorrent/include/asio/detail/posix_thread.hpp +++ b/libtorrent/include/asio/detail/posix_thread.hpp @@ -42,12 +42,9 @@ class posix_thread : private noncopyable { public: - // The purpose of the thread. - enum purpose { internal, external }; - // Constructor. template - posix_thread(Function f, purpose = internal) + posix_thread(Function f) : joined_(false) { std::auto_ptr arg(new func(f)); diff --git a/libtorrent/include/asio/detail/reactive_descriptor_service.hpp b/libtorrent/include/asio/detail/reactive_descriptor_service.hpp index 12a0c36b4..10263ea08 100644 --- a/libtorrent/include/asio/detail/reactive_descriptor_service.hpp +++ b/libtorrent/include/asio/detail/reactive_descriptor_service.hpp @@ -81,6 +81,7 @@ public: reactive_descriptor_service >(io_service), reactor_(asio::use_service(io_service)) { + reactor_.init_task(); } // Destroy all user-defined handler objects owned by the service. diff --git a/libtorrent/include/asio/detail/reactive_serial_port_service.hpp b/libtorrent/include/asio/detail/reactive_serial_port_service.hpp index 5db94a2dd..2fcf8c755 100644 --- a/libtorrent/include/asio/detail/reactive_serial_port_service.hpp +++ b/libtorrent/include/asio/detail/reactive_serial_port_service.hpp @@ -119,6 +119,7 @@ public: ios.c_cflag |= CS8; #endif ios.c_iflag |= IGNPAR; + ios.c_cflag |= CREAD | CLOCAL; descriptor_ops::clear_error(ec); s = descriptor_ops::error_wrapper(::tcsetattr(fd, TCSANOW, &ios), ec); } diff --git a/libtorrent/include/asio/detail/reactive_socket_service.hpp b/libtorrent/include/asio/detail/reactive_socket_service.hpp index c7aedf88e..7c4c7efff 100644 --- a/libtorrent/include/asio/detail/reactive_socket_service.hpp +++ b/libtorrent/include/asio/detail/reactive_socket_service.hpp @@ -73,10 +73,21 @@ public: enum { - user_set_non_blocking = 1, // The user wants a non-blocking socket. - internal_non_blocking = 2, // The socket has been set non-blocking. - enable_connection_aborted = 4, // User wants connection_aborted errors. - user_set_linger = 8 // The user set the linger option. + // The user wants a non-blocking socket. + user_set_non_blocking = 1, + + // The implementation wants a non-blocking socket (in order to be able to + // perform asynchronous read and write operations). + internal_non_blocking = 2, + + // Helper "flag" used to determine whether the socket is non-blocking. + non_blocking = user_set_non_blocking | internal_non_blocking, + + // User wants connection_aborted errors, which are disabled by default. + enable_connection_aborted = 4, + + // The user set the linger option. Needs to be checked when closing. + user_set_linger = 8 }; // Flags indicating the current state of the socket. @@ -98,6 +109,7 @@ public: reactive_socket_service >(io_service), reactor_(asio::use_service(io_service)) { + reactor_.init_task(); } // Destroy all user-defined handler objects owned by the service. @@ -119,12 +131,12 @@ public: { reactor_.close_descriptor(impl.socket_, impl.reactor_data_); - if (impl.flags_ & implementation_type::internal_non_blocking) + if (impl.flags_ & implementation_type::non_blocking) { ioctl_arg_type non_blocking = 0; asio::error_code ignored_ec; socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec); - impl.flags_ &= ~implementation_type::internal_non_blocking; + impl.flags_ &= ~implementation_type::non_blocking; } if (impl.flags_ & implementation_type::user_set_linger) @@ -213,12 +225,12 @@ public: { reactor_.close_descriptor(impl.socket_, impl.reactor_data_); - if (impl.flags_ & implementation_type::internal_non_blocking) + if (impl.flags_ & implementation_type::non_blocking) { ioctl_arg_type non_blocking = 0; asio::error_code ignored_ec; socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec); - impl.flags_ &= ~implementation_type::internal_non_blocking; + impl.flags_ &= ~implementation_type::non_blocking; } if (socket_ops::close(impl.socket_, ec) == socket_error_retval) @@ -432,11 +444,35 @@ public: if (command.name() == static_cast(FIONBIO)) { + // Flags are manipulated in a temporary variable so that the socket + // implementation is not updated unless the ioctl operation succeeds. + unsigned char new_flags = impl.flags_; if (command.get()) - impl.flags_ |= implementation_type::user_set_non_blocking; + new_flags |= implementation_type::user_set_non_blocking; else - impl.flags_ &= ~implementation_type::user_set_non_blocking; - ec = asio::error_code(); + new_flags &= ~implementation_type::user_set_non_blocking; + + // Perform ioctl on socket if the non-blocking state has changed. + if (!(impl.flags_ & implementation_type::non_blocking) + && (new_flags & implementation_type::non_blocking)) + { + ioctl_arg_type non_blocking = 1; + socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec); + } + else if ((impl.flags_ & implementation_type::non_blocking) + && !(new_flags & implementation_type::non_blocking)) + { + ioctl_arg_type non_blocking = 0; + socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec); + } + else + { + ec = asio::error_code(); + } + + // Update socket implementation's flags only if successful. + if (!ec) + impl.flags_ = new_flags; } else { @@ -529,18 +565,6 @@ public: return 0; } - // Make socket non-blocking if user wants non-blocking. - if (impl.flags_ & implementation_type::user_set_non_blocking) - { - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - ioctl_arg_type non_blocking = 1; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - return 0; - impl.flags_ |= implementation_type::internal_non_blocking; - } - } - // Send the data. for (;;) { @@ -683,12 +707,15 @@ public: // Make socket non-blocking. if (!(impl.flags_ & implementation_type::internal_non_blocking)) { - ioctl_arg_type non_blocking = 1; - asio::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + if (!(impl.flags_ & implementation_type::non_blocking)) { - this->get_io_service().post(bind_handler(handler, ec, 0)); - return; + ioctl_arg_type non_blocking = 1; + asio::error_code ec; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + { + this->get_io_service().post(bind_handler(handler, ec, 0)); + return; + } } impl.flags_ |= implementation_type::internal_non_blocking; } @@ -772,18 +799,6 @@ public: asio::buffer_size(buffer)); } - // Make socket non-blocking if user wants non-blocking. - if (impl.flags_ & implementation_type::user_set_non_blocking) - { - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - ioctl_arg_type non_blocking = 1; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - return 0; - impl.flags_ |= implementation_type::internal_non_blocking; - } - } - // Send the data. for (;;) { @@ -911,12 +926,15 @@ public: // Make socket non-blocking. if (!(impl.flags_ & implementation_type::internal_non_blocking)) { - ioctl_arg_type non_blocking = 1; - asio::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + if (!(impl.flags_ & implementation_type::non_blocking)) { - this->get_io_service().post(bind_handler(handler, ec, 0)); - return; + ioctl_arg_type non_blocking = 1; + asio::error_code ec; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + { + this->get_io_service().post(bind_handler(handler, ec, 0)); + return; + } } impl.flags_ |= implementation_type::internal_non_blocking; } @@ -980,18 +998,6 @@ public: return 0; } - // Make socket non-blocking if user wants non-blocking. - if (impl.flags_ & implementation_type::user_set_non_blocking) - { - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - ioctl_arg_type non_blocking = 1; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - return 0; - impl.flags_ |= implementation_type::internal_non_blocking; - } - } - // Receive some data. for (;;) { @@ -1147,12 +1153,15 @@ public: // Make socket non-blocking. if (!(impl.flags_ & implementation_type::internal_non_blocking)) { - ioctl_arg_type non_blocking = 1; - asio::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + if (!(impl.flags_ & implementation_type::non_blocking)) { - this->get_io_service().post(bind_handler(handler, ec, 0)); - return; + ioctl_arg_type non_blocking = 1; + asio::error_code ec; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + { + this->get_io_service().post(bind_handler(handler, ec, 0)); + return; + } } impl.flags_ |= implementation_type::internal_non_blocking; } @@ -1224,18 +1233,6 @@ public: asio::buffer_size(buffer)); } - // Make socket non-blocking if user wants non-blocking. - if (impl.flags_ & implementation_type::user_set_non_blocking) - { - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - ioctl_arg_type non_blocking = 1; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - return 0; - impl.flags_ |= implementation_type::internal_non_blocking; - } - } - // Receive some data. for (;;) { @@ -1384,12 +1381,15 @@ public: // Make socket non-blocking. if (!(impl.flags_ & implementation_type::internal_non_blocking)) { - ioctl_arg_type non_blocking = 1; - asio::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + if (!(impl.flags_ & implementation_type::non_blocking)) { - this->get_io_service().post(bind_handler(handler, ec, 0)); - return; + ioctl_arg_type non_blocking = 1; + asio::error_code ec; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + { + this->get_io_service().post(bind_handler(handler, ec, 0)); + return; + } } impl.flags_ |= implementation_type::internal_non_blocking; } @@ -1449,18 +1449,6 @@ public: return ec; } - // Make socket non-blocking if user wants non-blocking. - if (impl.flags_ & implementation_type::user_set_non_blocking) - { - if (!(impl.flags_ & implementation_type::internal_non_blocking)) - { - ioctl_arg_type non_blocking = 1; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - return ec; - impl.flags_ |= implementation_type::internal_non_blocking; - } - } - // Accept a socket. for (;;) { @@ -1622,12 +1610,15 @@ public: // Make socket non-blocking. if (!(impl.flags_ & implementation_type::internal_non_blocking)) { - ioctl_arg_type non_blocking = 1; - asio::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + if (!(impl.flags_ & implementation_type::non_blocking)) { - this->get_io_service().post(bind_handler(handler, ec)); - return; + ioctl_arg_type non_blocking = 1; + asio::error_code ec; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + { + this->get_io_service().post(bind_handler(handler, ec)); + return; + } } impl.flags_ |= implementation_type::internal_non_blocking; } @@ -1651,18 +1642,30 @@ public: return ec; } - if (impl.flags_ & implementation_type::internal_non_blocking) - { - // Mark the socket as blocking while we perform the connect. - ioctl_arg_type non_blocking = 0; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) - return ec; - impl.flags_ &= ~implementation_type::internal_non_blocking; - } - // Perform the connect operation. socket_ops::connect(impl.socket_, peer_endpoint.data(), peer_endpoint.size(), ec); + if (ec != asio::error::in_progress + && ec != asio::error::would_block) + { + // The connect operation finished immediately. + return ec; + } + + // Wait for socket to become ready. + if (socket_ops::poll_connect(impl.socket_, ec) < 0) + return ec; + + // Get the error code from the connect operation. + int connect_error = 0; + size_t connect_error_len = sizeof(connect_error); + if (socket_ops::getsockopt(impl.socket_, SOL_SOCKET, SO_ERROR, + &connect_error, &connect_error_len, ec) == socket_error_retval) + return ec; + + // Return the result of the connect operation. + ec = asio::error_code(connect_error, + asio::error::get_system_category()); return ec; } @@ -1730,12 +1733,15 @@ public: // Make socket non-blocking. if (!(impl.flags_ & implementation_type::internal_non_blocking)) { - ioctl_arg_type non_blocking = 1; - asio::error_code ec; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + if (!(impl.flags_ & implementation_type::non_blocking)) { - this->get_io_service().post(bind_handler(handler, ec)); - return; + ioctl_arg_type non_blocking = 1; + asio::error_code ec; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + { + this->get_io_service().post(bind_handler(handler, ec)); + return; + } } impl.flags_ |= implementation_type::internal_non_blocking; } diff --git a/libtorrent/include/asio/detail/resolver_service.hpp b/libtorrent/include/asio/detail/resolver_service.hpp index 172a8fc6d..e9a4a5eff 100644 --- a/libtorrent/include/asio/detail/resolver_service.hpp +++ b/libtorrent/include/asio/detail/resolver_service.hpp @@ -329,7 +329,7 @@ private: void start_work_thread() { asio::detail::mutex::scoped_lock lock(mutex_); - if (work_thread_ == 0) + if (!work_thread_) { work_thread_.reset(new asio::detail::thread( work_io_service_runner(*work_io_service_))); diff --git a/libtorrent/include/asio/detail/select_interrupter.hpp b/libtorrent/include/asio/detail/select_interrupter.hpp index 4277e4758..db5e6c760 100644 --- a/libtorrent/include/asio/detail/select_interrupter.hpp +++ b/libtorrent/include/asio/detail/select_interrupter.hpp @@ -21,6 +21,7 @@ #include #include "asio/detail/pop_options.hpp" +#include "asio/detail/eventfd_select_interrupter.hpp" #include "asio/detail/pipe_select_interrupter.hpp" #include "asio/detail/socket_select_interrupter.hpp" @@ -29,6 +30,8 @@ namespace detail { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef socket_select_interrupter select_interrupter; +#elif defined(ASIO_HAS_EVENTFD) +typedef eventfd_select_interrupter select_interrupter; #else typedef pipe_select_interrupter select_interrupter; #endif diff --git a/libtorrent/include/asio/detail/select_reactor.hpp b/libtorrent/include/asio/detail/select_reactor.hpp index 78a364ee0..9c86c253a 100644 --- a/libtorrent/include/asio/detail/select_reactor.hpp +++ b/libtorrent/include/asio/detail/select_reactor.hpp @@ -110,6 +110,16 @@ public: timer_queues_.clear(); } + // Initialise the task, but only if the reactor is not in its own thread. + void init_task() + { + if (!Own_Thread) + { + typedef task_io_service > task_io_service_type; + use_service(this->get_io_service()).init_task(); + } + } + // Register a socket with the reactor. Returns 0 on success, system error // code on failure. int register_descriptor(socket_type, per_descriptor_data&) diff --git a/libtorrent/include/asio/detail/service_registry.hpp b/libtorrent/include/asio/detail/service_registry.hpp index f517cbbf1..a4c2ecbe1 100644 --- a/libtorrent/include/asio/detail/service_registry.hpp +++ b/libtorrent/include/asio/detail/service_registry.hpp @@ -36,6 +36,21 @@ namespace asio { namespace detail { +#if defined(__GNUC__) +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma GCC visibility push (default) +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +#endif // defined(__GNUC__) + +template +class typeid_wrapper {}; + +#if defined(__GNUC__) +# if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +# pragma GCC visibility pop +# endif // (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4) +#endif // defined(__GNUC__) + class service_registry : private noncopyable { @@ -168,7 +183,7 @@ private: void init_service_id(asio::io_service::service& service, const asio::detail::service_id& /*id*/) { - service.type_info_ = &typeid(Service); + service.type_info_ = &typeid(typeid_wrapper); service.id_ = 0; } #endif // !defined(ASIO_NO_TYPEID) @@ -188,7 +203,8 @@ private: const asio::io_service::service& service, const asio::detail::service_id& /*id*/) { - return service.type_info_ != 0 && *service.type_info_ == typeid(Service); + return service.type_info_ != 0 + && *service.type_info_ == typeid(typeid_wrapper); } #endif // !defined(ASIO_NO_TYPEID) diff --git a/libtorrent/include/asio/detail/socket_ops.hpp b/libtorrent/include/asio/detail/socket_ops.hpp index 231bc61c5..1f00b4ce4 100644 --- a/libtorrent/include/asio/detail/socket_ops.hpp +++ b/libtorrent/include/asio/detail/socket_ops.hpp @@ -102,7 +102,7 @@ inline socket_type accept(socket_type s, socket_addr_type* addr, } #endif -#if defined(BOOST_WINDOWS) && defined(UNDER_CE) +#if defined(BOOST_WINDOWS) clear_error(ec); #endif @@ -122,7 +122,7 @@ inline int bind(socket_type s, const socket_addr_type* addr, clear_error(ec); int result = error_wrapper(call_bind( &msghdr::msg_namelen, s, addr, addrlen), ec); -#if defined(BOOST_WINDOWS) && defined(UNDER_CE) +#if defined(BOOST_WINDOWS) if (result == 0) clear_error(ec); #endif @@ -134,10 +134,8 @@ inline int close(socket_type s, asio::error_code& ec) clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 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); @@ -148,7 +146,7 @@ inline int shutdown(socket_type s, int what, asio::error_code& ec) { clear_error(ec); int result = error_wrapper(::shutdown(s, what), ec); -#if defined(BOOST_WINDOWS) && defined(UNDER_CE) +#if defined(BOOST_WINDOWS) if (result == 0) clear_error(ec); #endif @@ -168,7 +166,7 @@ inline int connect(socket_type s, const socket_addr_type* addr, clear_error(ec); int result = error_wrapper(call_connect( &msghdr::msg_namelen, s, addr, addrlen), ec); -#if defined(BOOST_WINDOWS) && defined(UNDER_CE) +#if defined(BOOST_WINDOWS) if (result == 0) clear_error(ec); #endif @@ -195,13 +193,24 @@ inline int listen(socket_type s, int backlog, asio::error_code& ec) { clear_error(ec); int result = error_wrapper(::listen(s, backlog), ec); -#if defined(BOOST_WINDOWS) && defined(UNDER_CE) +#if defined(BOOST_WINDOWS) if (result == 0) clear_error(ec); #endif return result; } +inline void init_buf_iov_base(void*& base, void* addr) +{ + base = addr; +} + +template +inline void init_buf_iov_base(T& base, void* addr) +{ + base = static_cast(addr); +} + #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) typedef WSABUF buf; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -214,7 +223,7 @@ inline void init_buf(buf& b, void* data, size_t size) b.buf = static_cast(data); b.len = static_cast(size); #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - b.iov_base = data; + init_buf_iov_base(b.iov_base, data); b.iov_len = size; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } @@ -225,7 +234,7 @@ inline void init_buf(buf& b, const void* data, size_t size) b.buf = static_cast(const_cast(data)); b.len = static_cast(size); #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - b.iov_base = const_cast(data); + init_buf_iov_base(b.iov_base, const_cast(data)); b.iov_len = size; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } @@ -265,9 +274,7 @@ 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 = msghdr(); @@ -293,9 +300,7 @@ inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags, *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 = msghdr(); @@ -322,9 +327,7 @@ 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 = msghdr(); @@ -351,9 +354,7 @@ inline int sendto(socket_type s, const buf* bufs, size_t count, int flags, 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 = msghdr(); @@ -388,9 +389,7 @@ 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__) @@ -452,7 +451,7 @@ inline int setsockopt(socket_type s, int level, int optname, clear_error(ec); int result = error_wrapper(call_setsockopt(&msghdr::msg_namelen, s, level, optname, optval, optlen), ec); -# if defined(BOOST_WINDOWS) && defined(UNDER_CE) +# if defined(BOOST_WINDOWS) if (result == 0) clear_error(ec); # endif @@ -525,10 +524,8 @@ 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); @@ -566,7 +563,7 @@ inline int getpeername(socket_type s, socket_addr_type* addr, clear_error(ec); int result = error_wrapper(call_getpeername( &msghdr::msg_namelen, s, addr, addrlen), ec); -#if defined(BOOST_WINDOWS) && defined(UNDER_CE) +#if defined(BOOST_WINDOWS) if (result == 0) clear_error(ec); #endif @@ -589,7 +586,7 @@ inline int getsockname(socket_type s, socket_addr_type* addr, clear_error(ec); int result = error_wrapper(call_getsockname( &msghdr::msg_namelen, s, addr, addrlen), ec); -#if defined(BOOST_WINDOWS) && defined(UNDER_CE) +#if defined(BOOST_WINDOWS) if (result == 0) clear_error(ec); #endif @@ -602,10 +599,8 @@ inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg, clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) 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); @@ -647,7 +642,7 @@ inline int select(int nfds, fd_set* readfds, fd_set* writefds, #else int result = error_wrapper(::select(nfds, readfds, writefds, exceptfds, timeout), ec); -# if defined(BOOST_WINDOWS) && defined(UNDER_CE) +# if defined(BOOST_WINDOWS) if (result >= 0) clear_error(ec); # endif @@ -663,10 +658,8 @@ inline int poll_read(socket_type s, asio::error_code& ec) FD_SET(s, &fds); clear_error(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; @@ -686,10 +679,32 @@ inline int poll_write(socket_type s, asio::error_code& ec) FD_SET(s, &fds); clear_error(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; + fds.events = POLLOUT; + fds.revents = 0; + clear_error(ec); + return error_wrapper(::poll(&fds, 1, -1), ec); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) +} + +inline int poll_connect(socket_type s, asio::error_code& ec) +{ +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + FD_SET write_fds; + FD_ZERO(&write_fds); + FD_SET(s, &write_fds); + FD_SET except_fds; + FD_ZERO(&except_fds); + FD_SET(s, &except_fds); + clear_error(ec); + int result = error_wrapper(::select(s, 0, &write_fds, &except_fds, 0), ec); + if (result >= 0) + clear_error(ec); return result; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) pollfd fds; @@ -837,10 +852,8 @@ 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__) @@ -869,7 +882,7 @@ inline int gethostname(char* name, int namelen, asio::error_code& ec) { clear_error(ec); int result = error_wrapper(::gethostname(name, namelen), ec); -#if defined(BOOST_WINDOWS) && defined(UNDER_CE) +#if defined(BOOST_WINDOWS) if (result == 0) clear_error(ec); #endif @@ -912,9 +925,7 @@ 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__) @@ -963,9 +974,7 @@ 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__) diff --git a/libtorrent/include/asio/detail/socket_types.hpp b/libtorrent/include/asio/detail/socket_types.hpp index b2acb6931..f58374322 100644 --- a/libtorrent/include/asio/detail/socket_types.hpp +++ b/libtorrent/include/asio/detail/socket_types.hpp @@ -28,11 +28,15 @@ # endif // defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_) # 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=0x0501 (i.e. Windows XP target)") +# pragma message( \ + "Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. For example:\n"\ + "- add -D_WIN32_WINNT=0x0501 to the compiler command line; or\n"\ + "- add _WIN32_WINNT=0x0501 to your project's Preprocessor Definitions.\n"\ + "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=0x0501 (i.e. Windows XP target) +# warning Please define _WIN32_WINNT or _WIN32_WINDOWS appropriately. +# warning For example, add -D_WIN32_WINNT=0x0501 to the compiler command line. +# warning Assuming _WIN32_WINNT=0x0501 (i.e. Windows XP target). # endif // defined(_MSC_VER) || defined(__BORLANDC__) # define _WIN32_WINNT 0x0501 # endif // !defined(_WIN32_WINNT) && !defined(_WIN32_WINDOWS) @@ -187,7 +191,12 @@ 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; +# if defined(IOV_MAX) const int max_iov_len = IOV_MAX; +# else +// POSIX platforms are not required to define IOV_MAX. +const int max_iov_len = 16; +# endif #endif const int custom_socket_option_level = 0xA5100000; const int enable_connection_aborted_option = 1; diff --git a/libtorrent/include/asio/detail/task_io_service.hpp b/libtorrent/include/asio/detail/task_io_service.hpp index beba1f251..2b89c55b5 100644 --- a/libtorrent/include/asio/detail/task_io_service.hpp +++ b/libtorrent/include/asio/detail/task_io_service.hpp @@ -44,14 +44,13 @@ public: task_io_service(asio::io_service& io_service) : asio::detail::service_base >(io_service), mutex_(), - task_(use_service(io_service)), + task_(0), task_interrupted_(true), outstanding_work_(0), stopped_(false), shutdown_(false), first_idle_thread_(0) { - handler_queue_.push(&task_handler_); } void init(size_t /*concurrency_hint*/) @@ -74,8 +73,20 @@ public: h->destroy(); } - // Reset handler queue to initial state. - handler_queue_.push(&task_handler_); + // Reset to initial state. + task_ = 0; + } + + // Initialise the task, if required. + void init_task() + { + asio::detail::mutex::scoped_lock lock(mutex_); + if (!shutdown_ && !task_) + { + task_ = &use_service(this->get_io_service()); + handler_queue_.push(&task_handler_); + interrupt_one_idle_thread(lock); + } } // Run the event loop until interrupted or no more work. @@ -194,10 +205,10 @@ public: // Wake up a thread to execute the handler. if (!interrupt_one_idle_thread(lock)) { - if (!task_interrupted_) + if (!task_interrupted_ && task_) { task_interrupted_ = true; - task_.interrupt(); + task_->interrupt(); } } } @@ -246,7 +257,7 @@ private: // Run the task. May throw an exception. Only block if the handler // queue is empty and we have an idle_thread_info object, otherwise // we want to return as soon as possible. - task_.run(!more_handlers && !polling); + task_->run(!more_handlers && !polling); } else { @@ -285,10 +296,10 @@ private: { stopped_ = true; interrupt_all_idle_threads(lock); - if (!task_interrupted_) + if (!task_interrupted_ && task_) { task_interrupted_ = true; - task_.interrupt(); + task_->interrupt(); } } @@ -376,7 +387,7 @@ private: asio::detail::mutex mutex_; // The task to be run by this service. - Task& task_; + Task* task_; // Handler object to represent the position of the task in the queue. class task_handler diff --git a/libtorrent/include/asio/detail/task_io_service_2lock.hpp b/libtorrent/include/asio/detail/task_io_service_2lock.hpp index 9b0221bbb..f040e6599 100644 --- a/libtorrent/include/asio/detail/task_io_service_2lock.hpp +++ b/libtorrent/include/asio/detail/task_io_service_2lock.hpp @@ -49,7 +49,7 @@ public: : asio::detail::service_base >(io_service), front_mutex_(), back_mutex_(), - task_(use_service(io_service)), + task_(&use_service(io_service)), outstanding_work_(0), front_stopped_(false), back_stopped_(false), @@ -57,7 +57,6 @@ public: back_first_idle_thread_(0), back_task_thread_(0) { - handler_queue_.push(&task_handler_); } void init(size_t /*concurrency_hint*/) @@ -76,8 +75,20 @@ public: if (h != &task_handler_) h->destroy(); - // Reset handler queue to initial state. - handler_queue_.push(&task_handler_); + // Reset to initial state. + task_ = 0; + } + + // Initialise the task, if required. + void init_task() + { + asio::detail::mutex::scoped_lock back_lock(back_mutex_); + if (!back_shutdown_ && !task_) + { + task_ = &use_service(this->get_io_service()); + handler_queue_.push(&task_handler_); + interrupt_one_idle_thread(back_lock); + } } // Run the event loop until interrupted or no more work. @@ -286,7 +297,7 @@ private: // queue is empty and we're not polling, otherwise we want to return // as soon as possible. task_has_run = true; - task_.run(!more_handlers && !polling); + task_->run(!more_handlers && !polling); } else { @@ -341,10 +352,10 @@ private: idle_thread->next = 0; idle_thread->wakeup_event.signal(back_lock); } - else if (back_task_thread_) + else if (back_task_thread_ && task_) { back_task_thread_ = 0; - task_.interrupt(); + task_->interrupt(); } } @@ -360,10 +371,10 @@ private: idle_thread->wakeup_event.signal(back_lock); } - if (back_task_thread_) + if (back_task_thread_ && task_) { back_task_thread_ = 0; - task_.interrupt(); + task_->interrupt(); } } @@ -414,7 +425,7 @@ private: asio::detail::mutex back_mutex_; // The task to be run by this service. - Task& task_; + Task* task_; // Handler object to represent the position of the task in the queue. class task_handler diff --git a/libtorrent/include/asio/detail/win_iocp_io_service.hpp b/libtorrent/include/asio/detail/win_iocp_io_service.hpp index 7f6d631c0..f649a30c6 100644 --- a/libtorrent/include/asio/detail/win_iocp_io_service.hpp +++ b/libtorrent/include/asio/detail/win_iocp_io_service.hpp @@ -148,6 +148,11 @@ public: timer_queues_.clear(); } + // Initialise the task. Nothing to do here. + void init_task() + { + } + // Register a handle with the IO completion port. asio::error_code register_handle( HANDLE handle, asio::error_code& ec) @@ -530,7 +535,7 @@ private: // Wake up next thread that is blocked on GetQueuedCompletionStatus. if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) { - DWORD last_error = ::GetLastError(); + last_error = ::GetLastError(); ec = asio::error_code(last_error, asio::error::get_system_category()); return 0; 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 a40c6a871..85aba21a7 100644 --- a/libtorrent/include/asio/detail/win_iocp_io_service_fwd.hpp +++ b/libtorrent/include/asio/detail/win_iocp_io_service_fwd.hpp @@ -36,6 +36,7 @@ namespace asio { namespace detail { class win_iocp_io_service; +class win_iocp_overlapped_ptr; } // namespace detail } // namespace asio diff --git a/libtorrent/include/asio/detail/win_thread.hpp b/libtorrent/include/asio/detail/win_thread.hpp index 17d912565..d26826843 100644 --- a/libtorrent/include/asio/detail/win_thread.hpp +++ b/libtorrent/include/asio/detail/win_thread.hpp @@ -39,45 +39,67 @@ namespace detail { unsigned int __stdcall win_thread_function(void* arg); -class win_thread - : private noncopyable +#if (WINVER < 0x0500) +void __stdcall apc_function(ULONG data); +#else +void __stdcall apc_function(ULONG_PTR data); +#endif + +template +class win_thread_base { public: - // The purpose of the thread. - enum purpose { internal, external }; + static bool terminate_threads() + { + return ::InterlockedExchangeAdd(&terminate_threads_, 0) != 0; + } + static void set_terminate_threads(bool b) + { + ::InterlockedExchange(&terminate_threads_, b ? 1 : 0); + } + +private: + static long terminate_threads_; +}; + +template +long win_thread_base::terminate_threads_ = 0; + +class win_thread + : private noncopyable, + public win_thread_base +{ +public: // Constructor. template - win_thread(Function f, purpose p = internal) + win_thread(Function f) : exit_event_(0) { std::auto_ptr arg(new func(f)); ::HANDLE entry_event = 0; - if (p == internal) + arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0); + if (!entry_event) { - arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0); - if (!entry_event) - { - DWORD last_error = ::GetLastError(); - asio::system_error e( - asio::error_code(last_error, - asio::error::get_system_category()), - "thread.entry_event"); - boost::throw_exception(e); - } + DWORD last_error = ::GetLastError(); + asio::system_error e( + asio::error_code(last_error, + asio::error::get_system_category()), + "thread.entry_event"); + boost::throw_exception(e); + } - arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0); - if (!exit_event_) - { - DWORD last_error = ::GetLastError(); - ::CloseHandle(entry_event); - asio::system_error e( - asio::error_code(last_error, - asio::error::get_system_category()), - "thread.exit_event"); - boost::throw_exception(e); - } + arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0); + if (!exit_event_) + { + DWORD last_error = ::GetLastError(); + ::CloseHandle(entry_event); + asio::system_error e( + asio::error_code(last_error, + asio::error::get_system_category()), + "thread.exit_event"); + boost::throw_exception(e); } unsigned int thread_id = 0; @@ -117,14 +139,15 @@ public: // Wait for the thread to exit. void join() { - if (exit_event_) + ::WaitForSingleObject(exit_event_, INFINITE); + ::CloseHandle(exit_event_); + if (terminate_threads()) { - ::WaitForSingleObject(exit_event_, INFINITE); - ::CloseHandle(exit_event_); ::TerminateThread(thread_, 0); } else { + ::QueueUserAPC(apc_function, thread_, 0); ::WaitForSingleObject(thread_, INFINITE); } } @@ -132,6 +155,12 @@ public: private: friend unsigned int __stdcall win_thread_function(void* arg); +#if (WINVER < 0x0500) + friend void __stdcall apc_function(ULONG); +#else + friend void __stdcall apc_function(ULONG_PTR); +#endif + class func_base { public: @@ -169,21 +198,30 @@ inline unsigned int __stdcall win_thread_function(void* arg) std::auto_ptr func( static_cast(arg)); - if (func->entry_event_) - ::SetEvent(func->entry_event_); + ::SetEvent(func->entry_event_); func->run(); - if (HANDLE exit_event = func->exit_event_) - { - func.reset(); - ::SetEvent(exit_event); - ::Sleep(INFINITE); - } + // Signal that the thread has finished its work, but rather than returning go + // to sleep to put the thread into a well known state. If the thread is being + // joined during global object destruction then it may be killed using + // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx + // call will be interrupted using QueueUserAPC and the thread will shut down + // cleanly. + HANDLE exit_event = func->exit_event_; + func.reset(); + ::SetEvent(exit_event); + ::SleepEx(INFINITE, TRUE); return 0; } +#if (WINVER < 0x0500) +inline void __stdcall apc_function(ULONG) {} +#else +inline void __stdcall apc_function(ULONG_PTR) {} +#endif + } // namespace detail } // namespace asio diff --git a/libtorrent/include/asio/detail/wince_thread.hpp b/libtorrent/include/asio/detail/wince_thread.hpp index 5a558b9ef..d0b4a9f51 100644 --- a/libtorrent/include/asio/detail/wince_thread.hpp +++ b/libtorrent/include/asio/detail/wince_thread.hpp @@ -42,12 +42,9 @@ class wince_thread : private noncopyable { public: - // The purpose of the thread. - enum purpose { internal, external }; - // Constructor. template - wince_thread(Function f, purpose = internal) + wince_thread(Function f) { std::auto_ptr arg(new func(f)); DWORD thread_id = 0; diff --git a/libtorrent/include/asio/impl/error_code.ipp b/libtorrent/include/asio/impl/error_code.ipp index fa0520a9f..865600d7b 100644 --- a/libtorrent/include/asio/impl/error_code.ipp +++ b/libtorrent/include/asio/impl/error_code.ipp @@ -83,6 +83,7 @@ inline std::string error_code::message() const if (category() != error::get_system_category()) return "asio error"; #if defined(__sun) || defined(__QNX__) + using namespace std; return strerror(value_); #elif defined(__MACH__) && defined(__APPLE__) \ || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) \ diff --git a/libtorrent/include/asio/impl/read.ipp b/libtorrent/include/asio/impl/read.ipp index b3d573905..1f1fa6fc6 100644 --- a/libtorrent/include/asio/impl/read.ipp +++ b/libtorrent/include/asio/impl/read.ipp @@ -37,18 +37,20 @@ template tmp(buffers); std::size_t total_transferred = 0; + tmp.set_max_size(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { std::size_t bytes_transferred = s.read_some(tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; - if (completion_condition(ec, total_transferred)) - return total_transferred; + tmp.set_max_size(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); } - ec = asio::error_code(); return total_transferred; } @@ -78,18 +80,23 @@ std::size_t read(SyncReadStream& s, asio::basic_streambuf& b, CompletionCondition completion_condition, asio::error_code& ec) { + ec = asio::error_code(); std::size_t total_transferred = 0; - for (;;) + std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + std::size_t bytes_available = std::min(512, + std::min(max_size, b.max_size() - b.size())); + while (bytes_available > 0) { - std::size_t bytes_available = - std::min(512, b.max_size() - b.size()); std::size_t bytes_transferred = s.read_some(b.prepare(bytes_available), ec); b.commit(bytes_transferred); total_transferred += bytes_transferred; - if (b.size() == b.max_size() - || completion_condition(ec, total_transferred)) - return total_transferred; + max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + bytes_available = std::min(512, + std::min(max_size, b.max_size() - b.size())); } + return total_transferred; } template @@ -139,8 +146,9 @@ namespace detail { total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); - if (completion_condition_(ec, total_transferred_) - || buffers_.begin() == buffers_.end()) + buffers_.set_max_size(detail::adapt_completion_condition_result( + completion_condition_(ec, total_transferred_))); + if (buffers_.begin() == buffers_.end()) { handler_(ec, total_transferred_); } @@ -197,6 +205,18 @@ inline void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, { asio::detail::consuming_buffers< mutable_buffer, MutableBufferSequence> tmp(buffers); + + asio::error_code ec; + std::size_t total_transferred = 0; + tmp.set_max_size(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); + if (tmp.begin() == tmp.end()) + { + s.get_io_service().post(detail::bind_handler( + handler, ec, total_transferred)); + return; + } + s.async_read_some(tmp, detail::read_handler( @@ -234,15 +254,17 @@ namespace detail { total_transferred_ += bytes_transferred; streambuf_.commit(bytes_transferred); - if (streambuf_.size() == streambuf_.max_size() - || completion_condition_(ec, total_transferred_)) + std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition_(ec, total_transferred_)); + std::size_t bytes_available = std::min(512, + std::min(max_size, + streambuf_.max_size() - streambuf_.size())); + if (bytes_available == 0) { handler_(ec, total_transferred_); } else { - std::size_t bytes_available = - std::min(512, streambuf_.max_size() - streambuf_.size()); stream_.async_read_some(streambuf_.prepare(bytes_available), *this); } } @@ -292,8 +314,19 @@ inline void async_read(AsyncReadStream& s, asio::basic_streambuf& b, CompletionCondition completion_condition, ReadHandler handler) { - std::size_t bytes_available = - std::min(512, b.max_size() - b.size()); + asio::error_code ec; + std::size_t total_transferred = 0; + std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + std::size_t bytes_available = std::min(512, + std::min(max_size, b.max_size() - b.size())); + if (bytes_available == 0) + { + s.get_io_service().post(detail::bind_handler( + handler, ec, total_transferred)); + return; + } + s.async_read_some(b.prepare(bytes_available), detail::read_streambuf_handler( diff --git a/libtorrent/include/asio/impl/read_at.ipp b/libtorrent/include/asio/impl/read_at.ipp index 2412487b5..403ff31ac 100644 --- a/libtorrent/include/asio/impl/read_at.ipp +++ b/libtorrent/include/asio/impl/read_at.ipp @@ -38,19 +38,21 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, boost::uint64_t offset, const MutableBufferSequence& buffers, CompletionCondition completion_condition, asio::error_code& ec) { + ec = asio::error_code(); asio::detail::consuming_buffers< mutable_buffer, MutableBufferSequence> tmp(buffers); std::size_t total_transferred = 0; + tmp.set_max_size(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { std::size_t bytes_transferred = d.read_some_at( offset + total_transferred, tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; - if (completion_condition(ec, total_transferred)) - return total_transferred; + tmp.set_max_size(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); } - ec = asio::error_code(); return total_transferred; } @@ -151,8 +153,9 @@ namespace detail { total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); - if (completion_condition_(ec, total_transferred_) - || buffers_.begin() == buffers_.end()) + buffers_.set_max_size(detail::adapt_completion_condition_result( + completion_condition_(ec, total_transferred_))); + if (buffers_.begin() == buffers_.end()) { handler_(ec, total_transferred_); } @@ -214,6 +217,18 @@ inline void async_read_at(AsyncRandomAccessReadDevice& d, { asio::detail::consuming_buffers< mutable_buffer, MutableBufferSequence> tmp(buffers); + + asio::error_code ec; + std::size_t total_transferred = 0; + tmp.set_max_size(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); + if (tmp.begin() == tmp.end()) + { + d.get_io_service().post(detail::bind_handler( + handler, ec, total_transferred)); + return; + } + d.async_read_some_at(offset, tmp, detail::read_at_handler( @@ -253,15 +268,17 @@ namespace detail { total_transferred_ += bytes_transferred; streambuf_.commit(bytes_transferred); - if (streambuf_.size() == streambuf_.max_size() - || completion_condition_(ec, total_transferred_)) + std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition_(ec, total_transferred_)); + std::size_t bytes_available = std::min(512, + std::min(max_size, + streambuf_.max_size() - streambuf_.size())); + if (bytes_available == 0) { handler_(ec, total_transferred_); } else { - std::size_t bytes_available = - std::min(512, streambuf_.max_size() - streambuf_.size()); stream_.async_read_some_at(offset_ + total_transferred_, streambuf_.prepare(bytes_available), *this); } @@ -313,8 +330,19 @@ inline void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, asio::basic_streambuf& b, CompletionCondition completion_condition, ReadHandler handler) { - std::size_t bytes_available = - std::min(512, b.max_size() - b.size()); + asio::error_code ec; + std::size_t total_transferred = 0; + std::size_t max_size = detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred)); + std::size_t bytes_available = std::min(512, + std::min(max_size, b.max_size() - b.size())); + if (bytes_available == 0) + { + d.get_io_service().post(detail::bind_handler( + handler, ec, total_transferred)); + return; + } + d.async_read_some_at(offset, b.prepare(bytes_available), detail::read_at_streambuf_handler( diff --git a/libtorrent/include/asio/impl/read_until.ipp b/libtorrent/include/asio/impl/read_until.ipp index b88b14194..3ed7dbe7c 100644 --- a/libtorrent/include/asio/impl/read_until.ipp +++ b/libtorrent/include/asio/impl/read_until.ipp @@ -277,19 +277,16 @@ std::size_t read_until(SyncReadStream& s, // Look for a match. std::pair result = match_condition(start, end); - if (result.first != end) + if (result.second) { - if (result.second) - { - // Full match. We're done. - ec = asio::error_code(); - return result.first - begin; - } - else - { - // Partial match. Next search needs to start from beginning of match. - next_search_start = result.first - begin; - } + // Full match. We're done. + ec = asio::error_code(); + return result.first - begin; + } + else if (result.first != end) + { + // Partial match. Next search needs to start from beginning of match. + next_search_start = result.first - begin; } else { @@ -448,7 +445,7 @@ void async_read_until(AsyncReadStream& s, // Found a match. We're done. asio::error_code ec; std::size_t bytes = iter - begin + 1; - s.io_service().post(detail::bind_handler(handler, ec, bytes)); + s.get_io_service().post(detail::bind_handler(handler, ec, bytes)); return; } @@ -456,7 +453,7 @@ void async_read_until(AsyncReadStream& s, if (b.size() == b.max_size()) { asio::error_code ec(error::not_found); - s.io_service().post(detail::bind_handler(handler, ec, 0)); + s.get_io_service().post(detail::bind_handler(handler, ec, 0)); return; } @@ -537,8 +534,8 @@ namespace detail if (streambuf_.size() == streambuf_.max_size()) { std::size_t bytes = 0; - asio::error_code ec(error::not_found); - handler_(ec, bytes); + asio::error_code ec2(error::not_found); + handler_(ec2, bytes); return; } @@ -609,7 +606,7 @@ void async_read_until(AsyncReadStream& s, // Full match. We're done. asio::error_code ec; std::size_t bytes = result.first - begin + delim.length(); - s.io_service().post(detail::bind_handler(handler, ec, bytes)); + s.get_io_service().post(detail::bind_handler(handler, ec, bytes)); return; } else @@ -628,7 +625,7 @@ void async_read_until(AsyncReadStream& s, if (b.size() == b.max_size()) { asio::error_code ec(error::not_found); - s.io_service().post(detail::bind_handler(handler, ec, 0)); + s.get_io_service().post(detail::bind_handler(handler, ec, 0)); return; } @@ -782,7 +779,7 @@ void async_read_until(AsyncReadStream& s, // Full match. We're done. asio::error_code ec; std::size_t bytes = match_results[0].second - begin; - s.io_service().post(detail::bind_handler(handler, ec, bytes)); + s.get_io_service().post(detail::bind_handler(handler, ec, bytes)); return; } else @@ -801,7 +798,7 @@ void async_read_until(AsyncReadStream& s, if (b.size() == b.max_size()) { asio::error_code ec(error::not_found); - s.io_service().post(detail::bind_handler(handler, ec, 0)); + s.get_io_service().post(detail::bind_handler(handler, ec, 0)); return; } @@ -857,20 +854,17 @@ namespace detail // Look for a match. std::pair result = match_condition_(start, end); - if (result.first != end) + if (result.second) { - if (result.second) - { - // Full match. We're done. - std::size_t bytes = result.first - begin; - handler_(ec, bytes); - return; - } - else - { - // Partial match. Next search needs to start from beginning of match. - next_search_start_ = result.first - begin; - } + // Full match. We're done. + std::size_t bytes = result.first - begin; + handler_(ec, bytes); + return; + } + else if (result.first != end) + { + // Partial match. Next search needs to start from beginning of match. + next_search_start_ = result.first - begin; } else { @@ -950,21 +944,18 @@ void async_read_until(AsyncReadStream& s, // Look for a match. std::size_t next_search_start; std::pair result = match_condition(begin, end); - if (result.first != end) + if (result.second) { - if (result.second) - { - // Full match. We're done. - asio::error_code ec; - std::size_t bytes = result.first - begin; - s.io_service().post(detail::bind_handler(handler, ec, bytes)); - return; - } - else - { - // Partial match. Next search needs to start from beginning of match. - next_search_start = result.first - begin; - } + // Full match. We're done. + asio::error_code ec; + std::size_t bytes = result.first - begin; + s.get_io_service().post(detail::bind_handler(handler, ec, bytes)); + return; + } + else if (result.first != end) + { + // Partial match. Next search needs to start from beginning of match. + next_search_start = result.first - begin; } else { @@ -976,7 +967,7 @@ void async_read_until(AsyncReadStream& s, if (b.size() == b.max_size()) { asio::error_code ec(error::not_found); - s.io_service().post(detail::bind_handler(handler, ec, 0)); + s.get_io_service().post(detail::bind_handler(handler, ec, 0)); return; } diff --git a/libtorrent/include/asio/impl/write.ipp b/libtorrent/include/asio/impl/write.ipp index 43bc2972a..b9305a08a 100644 --- a/libtorrent/include/asio/impl/write.ipp +++ b/libtorrent/include/asio/impl/write.ipp @@ -32,18 +32,20 @@ template tmp(buffers); std::size_t total_transferred = 0; + tmp.set_max_size(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { std::size_t bytes_transferred = s.write_some(tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; - if (completion_condition(ec, total_transferred)) - return total_transferred; + tmp.set_max_size(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); } - ec = asio::error_code(); return total_transferred; } @@ -125,8 +127,9 @@ namespace detail { total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); - if (completion_condition_(ec, total_transferred_) - || buffers_.begin() == buffers_.end()) + buffers_.set_max_size(detail::adapt_completion_condition_result( + completion_condition_(ec, total_transferred_))); + if (buffers_.begin() == buffers_.end()) { handler_(ec, total_transferred_); } @@ -183,6 +186,18 @@ inline void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, { asio::detail::consuming_buffers< const_buffer, ConstBufferSequence> tmp(buffers); + + asio::error_code ec; + std::size_t total_transferred = 0; + tmp.set_max_size(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); + if (tmp.begin() == tmp.end()) + { + s.get_io_service().post(detail::bind_handler( + handler, ec, total_transferred)); + return; + } + s.async_write_some(tmp, detail::write_handler( diff --git a/libtorrent/include/asio/impl/write_at.ipp b/libtorrent/include/asio/impl/write_at.ipp index c6fa3078c..4c8c70d59 100644 --- a/libtorrent/include/asio/impl/write_at.ipp +++ b/libtorrent/include/asio/impl/write_at.ipp @@ -33,19 +33,21 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, const ConstBufferSequence& buffers, CompletionCondition completion_condition, asio::error_code& ec) { + ec = asio::error_code(); asio::detail::consuming_buffers< const_buffer, ConstBufferSequence> tmp(buffers); std::size_t total_transferred = 0; + tmp.set_max_size(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); while (tmp.begin() != tmp.end()) { std::size_t bytes_transferred = d.write_some_at( offset + total_transferred, tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; - if (completion_condition(ec, total_transferred)) - return total_transferred; + tmp.set_max_size(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); } - ec = asio::error_code(); return total_transferred; } @@ -135,8 +137,9 @@ namespace detail { total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); - if (completion_condition_(ec, total_transferred_) - || buffers_.begin() == buffers_.end()) + buffers_.set_max_size(detail::adapt_completion_condition_result( + completion_condition_(ec, total_transferred_))); + if (buffers_.begin() == buffers_.end()) { handler_(ec, total_transferred_); } @@ -196,6 +199,18 @@ inline void async_write_at(AsyncRandomAccessWriteDevice& d, { asio::detail::consuming_buffers< const_buffer, ConstBufferSequence> tmp(buffers); + + asio::error_code ec; + std::size_t total_transferred = 0; + tmp.set_max_size(detail::adapt_completion_condition_result( + completion_condition(ec, total_transferred))); + if (tmp.begin() == tmp.end()) + { + d.get_io_service().post(detail::bind_handler( + handler, ec, total_transferred)); + return; + } + d.async_write_some_at(offset, tmp, detail::write_at_handler( diff --git a/libtorrent/include/asio/io_service.hpp b/libtorrent/include/asio/io_service.hpp index b6a34fdc4..ad37aee14 100644 --- a/libtorrent/include/asio/io_service.hpp +++ b/libtorrent/include/asio/io_service.hpp @@ -134,6 +134,7 @@ private: // The type of the platform-specific implementation. #if defined(ASIO_HAS_IOCP) typedef detail::win_iocp_io_service impl_type; + friend class detail::win_iocp_overlapped_ptr; #elif defined(ASIO_HAS_EPOLL) typedef detail::task_io_service > impl_type; #elif defined(ASIO_HAS_KQUEUE) diff --git a/libtorrent/include/asio/ip/address_v4.hpp b/libtorrent/include/asio/ip/address_v4.hpp index cda2a11c0..05f38596f 100644 --- a/libtorrent/include/asio/ip/address_v4.hpp +++ b/libtorrent/include/asio/ip/address_v4.hpp @@ -18,7 +18,9 @@ #include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp" +#include #include +#include #include #include #include "asio/detail/pop_options.hpp" @@ -55,6 +57,15 @@ public: /// Construct an address from raw bytes. explicit address_v4(const bytes_type& bytes) { +#if UCHAR_MAX > 0xFF + if (bytes[0] > 0xFF || bytes[1] > 0xFF + || bytes[2] > 0xFF || bytes[3] > 0xFF) + { + std::out_of_range ex("address_v4 from bytes_type"); + boost::throw_exception(ex); + } +#endif // UCHAR_MAX > 0xFF + using namespace std; // For memcpy. memcpy(&addr_.s_addr, bytes.elems, 4); } @@ -62,6 +73,14 @@ public: /// Construct an address from a unsigned long in host byte order. explicit address_v4(unsigned long addr) { +#if ULONG_MAX > 0xFFFFFFFF + if (addr > 0xFFFFFFFF) + { + std::out_of_range ex("address_v4 from unsigned long"); + boost::throw_exception(ex); + } +#endif // ULONG_MAX > 0xFFFFFFFF + addr_.s_addr = asio::detail::socket_ops::host_to_network_long(addr); } diff --git a/libtorrent/include/asio/ip/address_v6.hpp b/libtorrent/include/asio/ip/address_v6.hpp index c317fe487..789ec09a9 100644 --- a/libtorrent/include/asio/ip/address_v6.hpp +++ b/libtorrent/include/asio/ip/address_v6.hpp @@ -62,6 +62,17 @@ public: explicit address_v6(const bytes_type& bytes, unsigned long scope_id = 0) : scope_id_(scope_id) { +#if UCHAR_MAX > 0xFF + for (std::size_t i = 0; i < bytes.size(); ++i) + { + if (bytes[i] > 0xFF) + { + std::out_of_range ex("address_v6 from bytes_type"); + boost::throw_exception(ex); + } + } +#endif // UCHAR_MAX > 0xFF + using namespace std; // For memcpy. memcpy(addr_.s6_addr, bytes.elems, 16); } @@ -165,7 +176,11 @@ public: address_v4 to_v4() const { if (!is_v4_mapped() && !is_v4_compatible()) - throw std::bad_cast(); + { + std::bad_cast ex; + boost::throw_exception(ex); + } + address_v4::bytes_type v4_bytes = { { addr_.s6_addr[12], addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] } }; return address_v4(v4_bytes); diff --git a/libtorrent/include/asio/ip/basic_resolver.hpp b/libtorrent/include/asio/ip/basic_resolver.hpp index d5593778d..154c2ad0a 100644 --- a/libtorrent/include/asio/ip/basic_resolver.hpp +++ b/libtorrent/include/asio/ip/basic_resolver.hpp @@ -75,7 +75,7 @@ public: return this->service.cancel(this->implementation); } - /// Resolve a query to a list of entries. + /// Perform forward resolution of a query to a list of entries. /** * This function is used to resolve a query into a list of endpoint entries. * @@ -99,7 +99,7 @@ public: return i; } - /// Resolve a query to a list of entries. + /// Perform forward resolution of a query to a list of entries. /** * This function is used to resolve a query into a list of endpoint entries. * @@ -121,7 +121,7 @@ public: return this->service.resolve(this->implementation, q, ec); } - /// Asynchronously resolve a query to a list of entries. + /// Asynchronously perform forward resolution of a query to a list of entries. /** * This function is used to asynchronously resolve a query into a list of * endpoint entries. @@ -153,7 +153,7 @@ public: return this->service.async_resolve(this->implementation, q, handler); } - /// Resolve an endpoint to a list of entries. + /// Perform reverse resolution of an endpoint to a list of entries. /** * This function is used to resolve an endpoint into a list of endpoint * entries. @@ -179,7 +179,7 @@ public: return i; } - /// Resolve an endpoint to a list of entries. + /// Perform reverse resolution of an endpoint to a list of entries. /** * This function is used to resolve an endpoint into a list of endpoint * entries. @@ -203,7 +203,8 @@ public: return this->service.resolve(this->implementation, e, ec); } - /// Asynchronously resolve an endpoint to a list of entries. + /// Asynchronously perform reverse resolution of an endpoint to a list of + /// entries. /** * This function is used to asynchronously resolve an endpoint into a list of * endpoint entries. diff --git a/libtorrent/include/asio/ip/detail/socket_option.hpp b/libtorrent/include/asio/ip/detail/socket_option.hpp index a3496fd56..912a1dc57 100644 --- a/libtorrent/include/asio/ip/detail/socket_option.hpp +++ b/libtorrent/include/asio/ip/detail/socket_option.hpp @@ -40,7 +40,7 @@ public: #if defined(__sun) || defined(__osf__) typedef unsigned char ipv4_value_type; typedef unsigned char ipv6_value_type; -#elif defined(_AIX) || defined(__hpux) +#elif defined(_AIX) || defined(__hpux) || defined(__QNXNTO__) typedef unsigned char ipv4_value_type; typedef unsigned int ipv6_value_type; #else diff --git a/libtorrent/include/asio/ip/resolver_query_base.hpp b/libtorrent/include/asio/ip/resolver_query_base.hpp index 16f846642..c6addb10c 100644 --- a/libtorrent/include/asio/ip/resolver_query_base.hpp +++ b/libtorrent/include/asio/ip/resolver_query_base.hpp @@ -69,17 +69,19 @@ public: # else BOOST_STATIC_CONSTANT(int, numeric_service = 0); # endif -# if defined(AI_V4MAPPED) + // Note: QNX Neutrino 6.3 defines AI_V4MAPPED, AI_ALL and AI_ADDRCONFIG but + // does not implement them. Therefore they are specifically excluded here. +# if defined(AI_V4MAPPED) && !defined(__QNXNTO__) BOOST_STATIC_CONSTANT(int, v4_mapped = AI_V4MAPPED); # else BOOST_STATIC_CONSTANT(int, v4_mapped = 0); # endif -# if defined(AI_ALL) +# if defined(AI_ALL) && !defined(__QNXNTO__) BOOST_STATIC_CONSTANT(int, all_matching = AI_ALL); # else BOOST_STATIC_CONSTANT(int, all_matching = 0); # endif -# if defined(AI_ADDRCONFIG) +# if defined(AI_ADDRCONFIG) && !defined(__QNXNTO__) BOOST_STATIC_CONSTANT(int, address_configured = AI_ADDRCONFIG); # else BOOST_STATIC_CONSTANT(int, address_configured = 0); diff --git a/libtorrent/include/asio/local/basic_endpoint.hpp b/libtorrent/include/asio/local/basic_endpoint.hpp index 75dd092e3..4ab652b44 100644 --- a/libtorrent/include/asio/local/basic_endpoint.hpp +++ b/libtorrent/include/asio/local/basic_endpoint.hpp @@ -148,7 +148,7 @@ public: - offsetof(asio::detail::sockaddr_un_type, sun_path); // The path returned by the operating system may be NUL-terminated. - if (path_length_ > 0 && data_.local.sun_path[path_length_] == 0) + if (path_length_ > 0 && data_.local.sun_path[path_length_ - 1] == 0) --path_length_; } } diff --git a/libtorrent/include/asio/posix/basic_descriptor.hpp b/libtorrent/include/asio/posix/basic_descriptor.hpp index 241a3e315..c440c04ff 100644 --- a/libtorrent/include/asio/posix/basic_descriptor.hpp +++ b/libtorrent/include/asio/posix/basic_descriptor.hpp @@ -99,6 +99,20 @@ public: return *this; } + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since a basic_descriptor cannot contain any further layers, it + * simply returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } + /// Assign an existing native descriptor to the descriptor. /* * This function opens the descriptor to hold an existing native descriptor. diff --git a/libtorrent/include/asio/read.hpp b/libtorrent/include/asio/read.hpp index 7c0b82247..ddbe5d4c9 100644 --- a/libtorrent/include/asio/read.hpp +++ b/libtorrent/include/asio/read.hpp @@ -45,7 +45,7 @@ namespace asio { * * @li An error occurred. * - * This operation is implemented in terms of one or more calls to the stream's + * This operation is implemented in terms of zero or more calls to the stream's * read_some function. * * @param s The stream from which the data is to be read. The type must support @@ -84,7 +84,7 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers); * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the stream's + * This operation is implemented in terms of zero or more calls to the stream's * read_some function. * * @param s The stream from which the data is to be read. The type must support @@ -97,15 +97,16 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers); * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: - * @code bool completion_condition( - * const asio::error_code& error, // Result of latest read_some - * // operation. + * @code std::size_t completion_condition( + * // Result of latest read_some operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * // Number of bytes transferred so far. + * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the read operation is complete. False - * indicates that further calls to the stream's read_some function are required. + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's read_some function. * * @returns The number of bytes transferred. * @@ -134,7 +135,7 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the stream's + * This operation is implemented in terms of zero or more calls to the stream's * read_some function. * * @param s The stream from which the data is to be read. The type must support @@ -147,15 +148,16 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: - * @code bool completion_condition( - * const asio::error_code& error, // Result of latest read_some - * // operation. + * @code std::size_t completion_condition( + * // Result of latest read_some operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * // Number of bytes transferred so far. + * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the read operation is complete. False - * indicates that further calls to the stream's read_some function are required. + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's read_some function. * * @param ec Set to indicate what error occurred, if any. * @@ -174,7 +176,7 @@ std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, * * @li An error occurred. * - * This operation is implemented in terms of one or more calls to the stream's + * This operation is implemented in terms of zero or more calls to the stream's * read_some function. * * @param s The stream from which the data is to be read. The type must support @@ -201,7 +203,7 @@ std::size_t read(SyncReadStream& s, basic_streambuf& b); * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the stream's + * This operation is implemented in terms of zero or more calls to the stream's * read_some function. * * @param s The stream from which the data is to be read. The type must support @@ -212,15 +214,16 @@ std::size_t read(SyncReadStream& s, basic_streambuf& b); * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: - * @code bool completion_condition( - * const asio::error_code& error, // Result of latest read_some - * // operation. + * @code std::size_t completion_condition( + * // Result of latest read_some operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * // Number of bytes transferred so far. + * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the read operation is complete. False - * indicates that further calls to the stream's read_some function are required. + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's read_some function. * * @returns The number of bytes transferred. * @@ -238,7 +241,7 @@ std::size_t read(SyncReadStream& s, basic_streambuf& b, * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the stream's + * This operation is implemented in terms of zero or more calls to the stream's * read_some function. * * @param s The stream from which the data is to be read. The type must support @@ -249,15 +252,16 @@ std::size_t read(SyncReadStream& s, basic_streambuf& b, * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: - * @code bool completion_condition( - * const asio::error_code& error, // Result of latest read_some - * // operation. + * @code std::size_t completion_condition( + * // Result of latest read_some operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * // Number of bytes transferred so far. + * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the read operation is complete. False - * indicates that further calls to the stream's read_some function are required. + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's read_some function. * * @param ec Set to indicate what error occurred, if any. * @@ -291,7 +295,7 @@ std::size_t read(SyncReadStream& s, basic_streambuf& b, * * @li An error occurred. * - * This operation is implemented in terms of one or more calls to the stream's + * This operation is implemented in terms of zero or more calls to the stream's * async_read_some function. * * @param s The stream from which the data is to be read. The type must support @@ -365,16 +369,16 @@ void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: - * @code bool completion_condition( - * const asio::error_code& error, // Result of latest read_some - * // operation. + * @code std::size_t completion_condition( + * // Result of latest async_read_some operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * // Number of bytes transferred so far. + * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the read operation is complete. False - * indicates that further calls to the stream's async_read_some function are - * required. + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's async_read_some function. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of the @@ -418,7 +422,7 @@ void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, * * @li An error occurred. * - * This operation is implemented in terms of one or more calls to the stream's + * This operation is implemented in terms of zero or more calls to the stream's * async_read_some function. * * @param s The stream from which the data is to be read. The type must support @@ -465,7 +469,7 @@ void async_read(AsyncReadStream& s, basic_streambuf& b, * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the stream's + * This operation is implemented in terms of zero or more calls to the stream's * async_read_some function. * * @param s The stream from which the data is to be read. The type must support @@ -478,16 +482,16 @@ void async_read(AsyncReadStream& s, basic_streambuf& b, * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: - * @code bool completion_condition( - * const asio::error_code& error, // Result of latest read_some - * // operation. + * @code std::size_t completion_condition( + * // Result of latest async_read_some operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * // Number of bytes transferred so far. + * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the read operation is complete. False - * indicates that further calls to the stream's async_read_some function are - * required. + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the stream's async_read_some function. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of the diff --git a/libtorrent/include/asio/read_at.hpp b/libtorrent/include/asio/read_at.hpp index bcc247a0f..5c4339c48 100644 --- a/libtorrent/include/asio/read_at.hpp +++ b/libtorrent/include/asio/read_at.hpp @@ -48,7 +48,7 @@ namespace asio { * * @li An error occurred. * - * This operation is implemented in terms of one or more calls to the device's + * This operation is implemented in terms of zero or more calls to the device's * read_some_at function. * * @param d The device from which the data is to be read. The type must support @@ -92,7 +92,7 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the device's + * This operation is implemented in terms of zero or more calls to the device's * read_some_at function. * * @param d The device from which the data is to be read. The type must support @@ -107,16 +107,16 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: - * @code bool completion_condition( + * @code std::size_t completion_condition( * // Result of latest read_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the read operation is complete. False - * indicates that further calls to the device's read_some_at function are - * required. + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the device's read_some_at function. * * @returns The number of bytes transferred. * @@ -148,7 +148,7 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the device's + * This operation is implemented in terms of zero or more calls to the device's * read_some_at function. * * @param d The device from which the data is to be read. The type must support @@ -163,16 +163,16 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: - * @code bool completion_condition( - * const asio::error_code& error, // Result of latest read_some_at - * // operation. + * @code std::size_t completion_condition( + * // Result of latest read_some_at operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * // Number of bytes transferred so far. + * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the read operation is complete. False - * indicates that further calls to the device's read_some_at function are - * required. + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the device's read_some_at function. * * @param ec Set to indicate what error occurred, if any. * @@ -194,7 +194,7 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, * * @li An error occurred. * - * This operation is implemented in terms of one or more calls to the device's + * This operation is implemented in terms of zero or more calls to the device's * read_some_at function. * * @param d The device from which the data is to be read. The type must support @@ -226,7 +226,7 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the device's + * This operation is implemented in terms of zero or more calls to the device's * read_some_at function. * * @param d The device from which the data is to be read. The type must support @@ -239,16 +239,16 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: - * @code bool completion_condition( + * @code std::size_t completion_condition( * // Result of latest read_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the read operation is complete. False - * indicates that further calls to the device's read_some_at function are - * required. + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the device's read_some_at function. * * @returns The number of bytes transferred. * @@ -269,7 +269,7 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the device's + * This operation is implemented in terms of zero or more calls to the device's * read_some_at function. * * @param d The device from which the data is to be read. The type must support @@ -282,16 +282,16 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: - * @code bool completion_condition( + * @code std::size_t completion_condition( * // Result of latest read_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the read operation is complete. False - * indicates that further calls to the device's read_some_at function are - * required. + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the device's read_some_at function. * * @param ec Set to indicate what error occurred, if any. * @@ -326,7 +326,7 @@ std::size_t read_at(SyncRandomAccessReadDevice& d, * * @li An error occurred. * - * This operation is implemented in terms of one or more calls to the device's + * This operation is implemented in terms of zero or more calls to the device's * async_read_some_at function. * * @param d The device from which the data is to be read. The type must support @@ -404,16 +404,16 @@ void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: - * @code bool completion_condition( - * // Result of latest read_some_at operation. + * @code std::size_t completion_condition( + * // Result of latest async_read_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the read operation is complete. False - * indicates that further calls to the device's async_read_some_at function are - * required. + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the device's async_read_some_at function. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of the @@ -458,7 +458,7 @@ void async_read_at(AsyncRandomAccessReadDevice& d, * * @li An error occurred. * - * This operation is implemented in terms of one or more calls to the device's + * This operation is implemented in terms of zero or more calls to the device's * async_read_some_at function. * * @param d The device from which the data is to be read. The type must support @@ -508,7 +508,7 @@ void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the device's + * This operation is implemented in terms of zero or more calls to the device's * async_read_some_at function. * * @param d The device from which the data is to be read. The type must support @@ -523,16 +523,16 @@ void async_read_at(AsyncRandomAccessReadDevice& d, boost::uint64_t offset, * @param completion_condition The function object to be called to determine * whether the read operation is complete. The signature of the function object * must be: - * @code bool completion_condition( - * // Result of latest read_some_at operation. + * @code std::size_t completion_condition( + * // Result of latest async_read_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the read operation is complete. False - * indicates that further calls to the device's async_read_some_at function are - * required. + * A return value of 0 indicates that the read operation is complete. A non-zero + * return value indicates the maximum number of bytes to be read on the next + * call to the device's async_read_some_at function. * * @param handler The handler to be called when the read operation completes. * Copies will be made of the handler as required. The function signature of the diff --git a/libtorrent/include/asio/read_until.hpp b/libtorrent/include/asio/read_until.hpp index 69922e266..33a6a0cc9 100644 --- a/libtorrent/include/asio/read_until.hpp +++ b/libtorrent/include/asio/read_until.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "asio/detail/pop_options.hpp" @@ -34,6 +35,20 @@ namespace asio { namespace detail { +#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x610)) + template + struct has_result_type + { + template struct inner + { + struct big { char a[100]; }; + static big helper(U, ...); + static char helper(U, typename U::result_type* = 0); + }; + static const T& ref(); + enum { value = (sizeof((inner::helper)((ref)())) == 1) }; + }; +#else // BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x610)) template struct has_result_type { @@ -43,6 +58,7 @@ namespace detail static const T& ref(); enum { value = (sizeof((helper)((ref)())) == 1) }; }; +#endif // BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x610)) } // namespace detail /// Type trait used to determine whether a type can be used as a match condition diff --git a/libtorrent/include/asio/ssl/detail/openssl_context_service.hpp b/libtorrent/include/asio/ssl/detail/openssl_context_service.hpp index 5a90d5a2f..3e4e05a93 100644 --- a/libtorrent/include/asio/ssl/detail/openssl_context_service.hpp +++ b/libtorrent/include/asio/ssl/detail/openssl_context_service.hpp @@ -308,9 +308,9 @@ public: ::BIO_free(bio); int result = ::SSL_CTX_set_tmp_dh(impl, dh); + ::DH_free(dh); if (result != 1) { - ::DH_free(dh); ec = asio::error::invalid_argument; return ec; } diff --git a/libtorrent/include/asio/ssl/detail/openssl_init.hpp b/libtorrent/include/asio/ssl/detail/openssl_init.hpp index 07d7e6674..0b2cf7939 100644 --- a/libtorrent/include/asio/ssl/detail/openssl_init.hpp +++ b/libtorrent/include/asio/ssl/detail/openssl_init.hpp @@ -21,6 +21,7 @@ #include "asio/detail/push_options.hpp" #include #include +#include #include #include "asio/detail/pop_options.hpp" @@ -86,11 +87,15 @@ private: private: static unsigned long openssl_id_func() { +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + return ::GetCurrentThreadId(); +#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) void* id = instance()->thread_id_; if (id == 0) instance()->thread_id_ = id = &id; // Ugh. BOOST_ASSERT(sizeof(unsigned long) >= sizeof(void*)); return reinterpret_cast(id); +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } static void openssl_locking_func(int mode, int n, @@ -105,8 +110,10 @@ private: // Mutexes to be used in locking callbacks. std::vector > mutexes_; +#if !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) // The thread identifiers to be used by openssl. asio::detail::tss_ptr thread_id_; +#endif // !defined(BOOST_WINDOWS) && !defined(__CYGWIN__) }; public: diff --git a/libtorrent/include/asio/ssl/detail/openssl_operation.hpp b/libtorrent/include/asio/ssl/detail/openssl_operation.hpp index c8603ac1e..c8db9514e 100644 --- a/libtorrent/include/asio/ssl/detail/openssl_operation.hpp +++ b/libtorrent/include/asio/ssl/detail/openssl_operation.hpp @@ -158,6 +158,10 @@ public: 0; int sys_error_code = ERR_get_error(); + if (error_code == SSL_ERROR_SSL) + return handler_(asio::error_code( + error_code, asio::error::get_ssl_category()), rc); + bool is_read_needed = (error_code == SSL_ERROR_WANT_READ); bool is_write_needed = (error_code == SSL_ERROR_WANT_WRITE || ::BIO_ctrl_pending( ssl_bio_ )); diff --git a/libtorrent/include/asio/ssl/detail/openssl_stream_service.hpp b/libtorrent/include/asio/ssl/detail/openssl_stream_service.hpp index 710c935cf..3bf939f0a 100644 --- a/libtorrent/include/asio/ssl/detail/openssl_stream_service.hpp +++ b/libtorrent/include/asio/ssl/detail/openssl_stream_service.hpp @@ -336,7 +336,7 @@ public: buffer_size = max_buffer_size; boost::function send_func = - boost::bind(&::SSL_write, boost::arg<1>(), + boost::bind(boost::type(), &::SSL_write, boost::arg<1>(), asio::buffer_cast(*buffers.begin()), static_cast(buffer_size)); openssl_operation op( @@ -372,7 +372,7 @@ public: buffer_size = max_buffer_size; boost::function send_func = - boost::bind(&::SSL_write, boost::arg<1>(), + boost::bind(boost::type(), &::SSL_write, boost::arg<1>(), asio::buffer_cast(*buffers.begin()), static_cast(buffer_size)); @@ -410,7 +410,7 @@ public: buffer_size = max_buffer_size; boost::function recv_func = - boost::bind(&::SSL_read, boost::arg<1>(), + boost::bind(boost::type(), &::SSL_read, boost::arg<1>(), asio::buffer_cast(*buffers.begin()), static_cast(buffer_size)); openssl_operation op(recv_func, @@ -446,7 +446,7 @@ public: buffer_size = max_buffer_size; boost::function recv_func = - boost::bind(&::SSL_read, boost::arg<1>(), + boost::bind(boost::type(), &::SSL_read, boost::arg<1>(), asio::buffer_cast(*buffers.begin()), static_cast(buffer_size)); diff --git a/libtorrent/include/asio/ssl/stream.hpp b/libtorrent/include/asio/ssl/stream.hpp index 77ced5bfe..c3a069f27 100644 --- a/libtorrent/include/asio/ssl/stream.hpp +++ b/libtorrent/include/asio/ssl/stream.hpp @@ -149,6 +149,19 @@ public: return next_layer_.lowest_layer(); } + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * stream layers. + * + * @return A const reference to the lowest layer in the stack of stream + * layers. Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return next_layer_.lowest_layer(); + } + /// Get the underlying implementation in the native type. /** * This function may be used to obtain the underlying implementation of the diff --git a/libtorrent/include/asio/thread.hpp b/libtorrent/include/asio/thread.hpp index b0f786c6b..7cc8cdf0b 100644 --- a/libtorrent/include/asio/thread.hpp +++ b/libtorrent/include/asio/thread.hpp @@ -58,7 +58,7 @@ public: */ template explicit thread(Function f) - : impl_(f, asio::detail::thread::external) + : impl_(f) { } diff --git a/libtorrent/include/asio/version.hpp b/libtorrent/include/asio/version.hpp index df2fa9f84..6a107ba5b 100644 --- a/libtorrent/include/asio/version.hpp +++ b/libtorrent/include/asio/version.hpp @@ -18,6 +18,6 @@ // ASIO_VERSION % 100 is the sub-minor version // ASIO_VERSION / 100 % 1000 is the minor version // ASIO_VERSION / 100000 is the major version -#define ASIO_VERSION 100100 // 1.1.0 +#define ASIO_VERSION 100401 // 1.4.1 #endif // ASIO_VERSION_HPP diff --git a/libtorrent/include/asio/windows/basic_handle.hpp b/libtorrent/include/asio/windows/basic_handle.hpp index f436436b7..3762f1d45 100644 --- a/libtorrent/include/asio/windows/basic_handle.hpp +++ b/libtorrent/include/asio/windows/basic_handle.hpp @@ -94,6 +94,20 @@ public: return *this; } + /// Get a const reference to the lowest layer. + /** + * This function returns a const reference to the lowest layer in a stack of + * layers. Since a basic_handle cannot contain any further layers, it simply + * returns a reference to itself. + * + * @return A const reference to the lowest layer in the stack of layers. + * Ownership is not transferred to the caller. + */ + const lowest_layer_type& lowest_layer() const + { + return *this; + } + /// Assign an existing native handle to the handle. /* * This function opens the handle to hold an existing native handle. diff --git a/libtorrent/include/asio/write.hpp b/libtorrent/include/asio/write.hpp index b1965880b..2c8e75b51 100644 --- a/libtorrent/include/asio/write.hpp +++ b/libtorrent/include/asio/write.hpp @@ -44,7 +44,7 @@ namespace asio { * * @li An error occurred. * - * This operation is implemented in terms of one or more calls to the stream's + * This operation is implemented in terms of zero or more calls to the stream's * write_some function. * * @param s The stream to which the data is to be written. The type must support @@ -83,7 +83,7 @@ std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers); * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the stream's + * This operation is implemented in terms of zero or more calls to the stream's * write_some function. * * @param s The stream to which the data is to be written. The type must support @@ -96,16 +96,16 @@ std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers); * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: - * @code bool completion_condition( - * const asio::error_code& error, // Result of latest write_some - * // operation. + * @code std::size_t completion_condition( + * // Result of latest write_some operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * // Number of bytes transferred so far. + * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the write operation is complete. False - * indicates that further calls to the stream's write_some function are - * required. + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's write_some function. * * @returns The number of bytes transferred. * @@ -134,7 +134,7 @@ std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the stream's + * This operation is implemented in terms of zero or more calls to the stream's * write_some function. * * @param s The stream to which the data is to be written. The type must support @@ -147,16 +147,16 @@ std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: - * @code bool completion_condition( - * const asio::error_code& error, // Result of latest write_some - * // operation. + * @code std::size_t completion_condition( + * // Result of latest write_some operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * // Number of bytes transferred so far. + * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the write operation is complete. False - * indicates that further calls to the stream's write_some function are - * required. + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's write_some function. * * @param ec Set to indicate what error occurred, if any. * @@ -177,7 +177,7 @@ std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, * * @li An error occurred. * - * This operation is implemented in terms of one or more calls to the stream's + * This operation is implemented in terms of zero or more calls to the stream's * write_some function. * * @param s The stream to which the data is to be written. The type must support @@ -206,7 +206,7 @@ std::size_t write(SyncWriteStream& s, basic_streambuf& b); * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the stream's + * This operation is implemented in terms of zero or more calls to the stream's * write_some function. * * @param s The stream to which the data is to be written. The type must support @@ -217,16 +217,16 @@ std::size_t write(SyncWriteStream& s, basic_streambuf& b); * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: - * @code bool completion_condition( - * const asio::error_code& error, // Result of latest write_some - * // operation. + * @code std::size_t completion_condition( + * // Result of latest write_some operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * // Number of bytes transferred so far. + * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the write operation is complete. False - * indicates that further calls to the stream's write_some function are - * required. + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's write_some function. * * @returns The number of bytes transferred. * @@ -246,7 +246,7 @@ std::size_t write(SyncWriteStream& s, basic_streambuf& b, * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the stream's + * This operation is implemented in terms of zero or more calls to the stream's * write_some function. * * @param s The stream to which the data is to be written. The type must support @@ -257,16 +257,16 @@ std::size_t write(SyncWriteStream& s, basic_streambuf& b, * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: - * @code bool completion_condition( - * const asio::error_code& error, // Result of latest write_some - * // operation. + * @code std::size_t completion_condition( + * // Result of latest write_some operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * // Number of bytes transferred so far. + * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the write operation is complete. False - * indicates that further calls to the stream's write_some function are - * required. + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's write_some function. * * @param ec Set to indicate what error occurred, if any. * @@ -300,7 +300,7 @@ std::size_t write(SyncWriteStream& s, basic_streambuf& b, * * @li An error occurred. * - * This operation is implemented in terms of one or more calls to the stream's + * This operation is implemented in terms of zero or more calls to the stream's * async_write_some function. * * @param s The stream to which the data is to be written. The type must support @@ -354,7 +354,7 @@ void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the stream's + * This operation is implemented in terms of zero or more calls to the stream's * async_write_some function. * * @param s The stream to which the data is to be written. The type must support @@ -368,16 +368,16 @@ void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: - * @code bool completion_condition( - * const asio::error_code& error, // Result of latest write_some - * // operation. + * @code std::size_t completion_condition( + * // Result of latest async_write_some operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * // Number of bytes transferred so far. + * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the write operation is complete. False - * indicates that further calls to the stream's async_write_some function are - * required. + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's async_write_some function. * * @param handler The handler to be called when the write operation completes. * Copies will be made of the handler as required. The function signature of the @@ -422,7 +422,7 @@ void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, * * @li An error occurred. * - * This operation is implemented in terms of one or more calls to the stream's + * This operation is implemented in terms of zero or more calls to the stream's * async_write_some function. * * @param s The stream to which the data is to be written. The type must support @@ -464,7 +464,7 @@ void async_write(AsyncWriteStream& s, basic_streambuf& b, * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the stream's + * This operation is implemented in terms of zero or more calls to the stream's * async_write_some function. * * @param s The stream to which the data is to be written. The type must support @@ -477,16 +477,16 @@ void async_write(AsyncWriteStream& s, basic_streambuf& b, * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: - * @code bool completion_condition( - * const asio::error_code& error, // Result of latest write_some - * // operation. + * @code std::size_t completion_condition( + * // Result of latest async_write_some operation. + * const asio::error_code& error, * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * // Number of bytes transferred so far. + * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the write operation is complete. False - * indicates that further calls to the stream's async_write_some function are - * required. + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the stream's async_write_some function. * * @param handler The handler to be called when the write operation completes. * Copies will be made of the handler as required. The function signature of the diff --git a/libtorrent/include/asio/write_at.hpp b/libtorrent/include/asio/write_at.hpp index a17733fff..a72061371 100644 --- a/libtorrent/include/asio/write_at.hpp +++ b/libtorrent/include/asio/write_at.hpp @@ -46,7 +46,7 @@ namespace asio { * * @li An error occurred. * - * This operation is implemented in terms of one or more calls to the device's + * This operation is implemented in terms of zero or more calls to the device's * write_some_at function. * * @param d The device to which the data is to be written. The type must support @@ -89,7 +89,7 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the device's + * This operation is implemented in terms of zero or more calls to the device's * write_some_at function. * * @param d The device to which the data is to be written. The type must support @@ -104,16 +104,16 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: - * @code bool completion_condition( + * @code std::size_t completion_condition( * // Result of latest write_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the write operation is complete. False - * indicates that further calls to the device's write_some_at function are - * required. + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the device's write_some_at function. * * @returns The number of bytes transferred. * @@ -144,7 +144,7 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the device's + * This operation is implemented in terms of zero or more calls to the device's * write_some_at function. * * @param d The device to which the data is to be written. The type must support @@ -159,16 +159,16 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: - * @code bool completion_condition( + * @code std::size_t completion_condition( * // Result of latest write_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the write operation is complete. False - * indicates that further calls to the device's write_some_at function are - * required. + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the device's write_some_at function. * * @param ec Set to indicate what error occurred, if any. * @@ -191,7 +191,7 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, * * @li An error occurred. * - * This operation is implemented in terms of one or more calls to the device's + * This operation is implemented in terms of zero or more calls to the device's * write_some_at function. * * @param d The device to which the data is to be written. The type must support @@ -224,7 +224,7 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the device's + * This operation is implemented in terms of zero or more calls to the device's * write_some_at function. * * @param d The device to which the data is to be written. The type must support @@ -237,16 +237,16 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: - * @code bool completion_condition( + * @code std::size_t completion_condition( * // Result of latest write_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the write operation is complete. False - * indicates that further calls to the device's write_some_at function are - * required. + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the device's write_some_at function. * * @returns The number of bytes transferred. * @@ -267,7 +267,7 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the device's + * This operation is implemented in terms of zero or more calls to the device's * write_some_at function. * * @param d The device to which the data is to be written. The type must support @@ -280,16 +280,16 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: - * @code bool completion_condition( + * @code std::size_t completion_condition( * // Result of latest write_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the write operation is complete. False - * indicates that further calls to the device's write_some_at function are - * required. + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the device's write_some_at function. * * @param ec Set to indicate what error occurred, if any. * @@ -324,7 +324,7 @@ std::size_t write_at(SyncRandomAccessWriteDevice& d, boost::uint64_t offset, * * @li An error occurred. * - * This operation is implemented in terms of one or more calls to the device's + * This operation is implemented in terms of zero or more calls to the device's * async_write_some_at function. * * @param d The device to which the data is to be written. The type must support @@ -380,7 +380,7 @@ void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the device's + * This operation is implemented in terms of zero or more calls to the device's * async_write_some_at function. * * @param d The device to which the data is to be written. The type must support @@ -396,16 +396,16 @@ void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: - * @code bool completion_condition( - * // Result of latest write_some_at operation. + * @code std::size_t completion_condition( + * // Result of latest async_write_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the write operation is complete. False - * indicates that further calls to the device's async_write_some_at function are - * required. + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the device's async_write_some_at function. * * @param handler The handler to be called when the write operation completes. * Copies will be made of the handler as required. The function signature of the @@ -451,7 +451,7 @@ void async_write_at(AsyncRandomAccessWriteDevice& d, * * @li An error occurred. * - * This operation is implemented in terms of one or more calls to the device's + * This operation is implemented in terms of zero or more calls to the device's * async_write_some_at function. * * @param d The device to which the data is to be written. The type must support @@ -496,7 +496,7 @@ void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, * * @li The completion_condition function object returns true. * - * This operation is implemented in terms of one or more calls to the device's + * This operation is implemented in terms of zero or more calls to the device's * async_write_some_at function. * * @param d The device to which the data is to be written. The type must support @@ -511,16 +511,16 @@ void async_write_at(AsyncRandomAccessWriteDevice& d, boost::uint64_t offset, * @param completion_condition The function object to be called to determine * whether the write operation is complete. The signature of the function object * must be: - * @code bool completion_condition( + * @code std::size_t completion_condition( * // Result of latest async_write_some_at operation. * const asio::error_code& error, * * // Number of bytes transferred so far. * std::size_t bytes_transferred * ); @endcode - * A return value of true indicates that the write operation is complete. False - * indicates that further calls to the device's async_write_some_at function are - * required. + * A return value of 0 indicates that the write operation is complete. A + * non-zero return value indicates the maximum number of bytes to be written on + * the next call to the device's async_write_some_at function. * * @param handler The handler to be called when the write operation completes. * Copies will be made of the handler as required. The function signature of the