diff --git a/libtorrent/include/libtorrent/alert_types.hpp b/libtorrent/include/libtorrent/alert_types.hpp index 7a5cb7fd3..878185e42 100644 --- a/libtorrent/include/libtorrent/alert_types.hpp +++ b/libtorrent/include/libtorrent/alert_types.hpp @@ -41,14 +41,24 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { - struct TORRENT_EXPORT tracker_alert: alert + struct TORRENT_EXPORT torrent_alert: alert + { + torrent_alert(torrent_handle const& h, alert::severity_t s + , std::string const& msg) + : alert(s, msg) + , handle(h) + {} + + torrent_handle handle; + }; + + struct TORRENT_EXPORT tracker_alert: torrent_alert { tracker_alert(torrent_handle const& h , int times , int status , std::string const& msg) - : alert(alert::warning, msg) - , handle(h) + : torrent_alert(h, alert::warning, msg) , times_in_row(times) , status_code(status) {} @@ -56,85 +66,75 @@ namespace libtorrent virtual std::auto_ptr clone() const { return std::auto_ptr(new tracker_alert(*this)); } - torrent_handle handle; int times_in_row; int status_code; }; - struct TORRENT_EXPORT tracker_warning_alert: alert + struct TORRENT_EXPORT tracker_warning_alert: torrent_alert { tracker_warning_alert(torrent_handle const& h , std::string const& msg) - : alert(alert::warning, msg) - , handle(h) + : torrent_alert(h, alert::warning, msg) {} virtual std::auto_ptr clone() const { return std::auto_ptr(new tracker_warning_alert(*this)); } - - torrent_handle handle; }; - struct TORRENT_EXPORT tracker_reply_alert: alert + struct TORRENT_EXPORT tracker_reply_alert: torrent_alert { tracker_reply_alert(torrent_handle const& h + , int np , std::string const& msg) - : alert(alert::info, msg) - , handle(h) + : torrent_alert(h, alert::info, msg) + , num_peers(np) {} + int num_peers; + virtual std::auto_ptr clone() const { return std::auto_ptr(new tracker_reply_alert(*this)); } - - torrent_handle handle; }; - struct TORRENT_EXPORT tracker_announce_alert: alert + struct TORRENT_EXPORT tracker_announce_alert: torrent_alert { tracker_announce_alert(torrent_handle const& h, std::string const& msg) - : alert(alert::info, msg) - , handle(h) + : torrent_alert(h, alert::info, msg) {} virtual std::auto_ptr clone() const { return std::auto_ptr(new tracker_announce_alert(*this)); } - - torrent_handle handle; }; - struct TORRENT_EXPORT hash_failed_alert: alert + struct TORRENT_EXPORT hash_failed_alert: torrent_alert { hash_failed_alert( torrent_handle const& h , int index , std::string const& msg) - : alert(alert::info, msg) - , handle(h) + : torrent_alert(h, alert::info, msg) , piece_index(index) { assert(index >= 0);} virtual std::auto_ptr clone() const { return std::auto_ptr(new hash_failed_alert(*this)); } - torrent_handle handle; int piece_index; }; - struct TORRENT_EXPORT peer_ban_alert: alert + struct TORRENT_EXPORT peer_ban_alert: torrent_alert { peer_ban_alert(tcp::endpoint const& pip, torrent_handle h, std::string const& msg) - : alert(alert::info, msg) + : torrent_alert(h, alert::info, msg) , ip(pip) - , handle(h) {} virtual std::auto_ptr clone() const { return std::auto_ptr(new peer_ban_alert(*this)); } tcp::endpoint ip; - torrent_handle handle; }; struct TORRENT_EXPORT peer_error_alert: alert @@ -152,25 +152,7 @@ namespace libtorrent peer_id pid; }; - struct TORRENT_EXPORT chat_message_alert: alert - { - chat_message_alert( - const torrent_handle& h - , const tcp::endpoint& sender - , const std::string& msg) - : alert(alert::critical, msg) - , handle(h) - , ip(sender) - {} - - virtual std::auto_ptr clone() const - { return std::auto_ptr(new chat_message_alert(*this)); } - - torrent_handle handle; - tcp::endpoint ip; - }; - - struct TORRENT_EXPORT invalid_request_alert: alert + struct TORRENT_EXPORT invalid_request_alert: torrent_alert { invalid_request_alert( peer_request const& r @@ -178,8 +160,7 @@ namespace libtorrent , tcp::endpoint const& sender , peer_id const& pid_ , std::string const& msg) - : alert(alert::debug, msg) - , handle(h) + : torrent_alert(h, alert::debug, msg) , ip(sender) , request(r) , pid(pid_) @@ -188,33 +169,30 @@ namespace libtorrent virtual std::auto_ptr clone() const { return std::auto_ptr(new invalid_request_alert(*this)); } - torrent_handle handle; tcp::endpoint ip; peer_request request; peer_id pid; }; - struct TORRENT_EXPORT torrent_finished_alert: alert + struct TORRENT_EXPORT torrent_finished_alert: torrent_alert { torrent_finished_alert( const torrent_handle& h , const std::string& msg) - : alert(alert::warning, msg) - , handle(h) + : torrent_alert(h, alert::warning, msg) {} virtual std::auto_ptr clone() const { return std::auto_ptr(new torrent_finished_alert(*this)); } - - torrent_handle handle; }; - struct TORRENT_EXPORT url_seed_alert: alert + struct TORRENT_EXPORT url_seed_alert: torrent_alert { url_seed_alert( - const std::string& url_ + torrent_handle const& h + , const std::string& url_ , const std::string& msg) - : alert(alert::warning, msg) + : torrent_alert(h, alert::warning, msg) , url(url_) {} @@ -224,49 +202,40 @@ namespace libtorrent std::string url; }; - struct TORRENT_EXPORT file_error_alert: alert + struct TORRENT_EXPORT file_error_alert: torrent_alert { file_error_alert( const torrent_handle& h , const std::string& msg) - : alert(alert::fatal, msg) - , handle(h) + : torrent_alert(h, alert::fatal, msg) {} virtual std::auto_ptr clone() const { return std::auto_ptr(new file_error_alert(*this)); } - - torrent_handle handle; }; - struct TORRENT_EXPORT metadata_failed_alert: alert + struct TORRENT_EXPORT metadata_failed_alert: torrent_alert { metadata_failed_alert( const torrent_handle& h , const std::string& msg) - : alert(alert::info, msg) - , handle(h) + : torrent_alert(h, alert::info, msg) {} virtual std::auto_ptr clone() const { return std::auto_ptr(new metadata_failed_alert(*this)); } - - torrent_handle handle; }; - struct TORRENT_EXPORT metadata_received_alert: alert + struct TORRENT_EXPORT metadata_received_alert: torrent_alert { metadata_received_alert( const torrent_handle& h , const std::string& msg) - : alert(alert::info, msg) - , handle(h) + : torrent_alert(h, alert::info, msg) {} virtual std::auto_ptr clone() const { return std::auto_ptr(new metadata_received_alert(*this)); } - - torrent_handle handle; }; struct TORRENT_EXPORT listen_failed_alert: alert @@ -280,18 +249,15 @@ namespace libtorrent { return std::auto_ptr(new listen_failed_alert(*this)); } }; - struct TORRENT_EXPORT fastresume_rejected_alert: alert + struct TORRENT_EXPORT fastresume_rejected_alert: torrent_alert { fastresume_rejected_alert(torrent_handle const& h , std::string const& msg) - : alert(alert::warning, msg) - , handle(h) + : torrent_alert(h, alert::warning, msg) {} virtual std::auto_ptr clone() const { return std::auto_ptr(new fastresume_rejected_alert(*this)); } - - torrent_handle handle; }; } diff --git a/libtorrent/include/libtorrent/allocate_resources.hpp b/libtorrent/include/libtorrent/allocate_resources.hpp index b859b6b47..3d8237914 100644 --- a/libtorrent/include/libtorrent/allocate_resources.hpp +++ b/libtorrent/include/libtorrent/allocate_resources.hpp @@ -41,6 +41,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/resource_request.hpp" #include "libtorrent/peer_id.hpp" #include "libtorrent/socket.hpp" +#include "libtorrent/session.hpp" namespace libtorrent { @@ -66,6 +67,11 @@ namespace libtorrent , std::map& connections , resource_request peer_connection::* res); + // Used for global limits. + void allocate_resources( + int resources + , std::vector& _sessions + , resource_request session::* res); } diff --git a/libtorrent/include/libtorrent/asio.hpp b/libtorrent/include/libtorrent/asio.hpp index 3bd10de70..dfad4a6d5 100644 --- a/libtorrent/include/libtorrent/asio.hpp +++ b/libtorrent/include/libtorrent/asio.hpp @@ -2,7 +2,7 @@ // asio.hpp // ~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -18,7 +18,6 @@ #include "asio/basic_datagram_socket.hpp" #include "asio/basic_deadline_timer.hpp" #include "asio/basic_io_object.hpp" -#include "asio/basic_resolver.hpp" #include "asio/basic_socket_acceptor.hpp" #include "asio/basic_socket_iostream.hpp" #include "asio/basic_socket_streambuf.hpp" @@ -35,8 +34,8 @@ #include "asio/datagram_socket_service.hpp" #include "asio/deadline_timer_service.hpp" #include "asio/deadline_timer.hpp" -#include "asio/error_handler.hpp" #include "asio/error.hpp" +#include "asio/error_code.hpp" #include "asio/handler_alloc_hook.hpp" #include "asio/handler_invoke_hook.hpp" #include "asio/io_service.hpp" @@ -44,26 +43,29 @@ #include "asio/ip/address_v4.hpp" #include "asio/ip/address_v6.hpp" #include "asio/ip/basic_endpoint.hpp" +#include "asio/ip/basic_resolver.hpp" #include "asio/ip/basic_resolver_entry.hpp" #include "asio/ip/basic_resolver_iterator.hpp" #include "asio/ip/basic_resolver_query.hpp" #include "asio/ip/host_name.hpp" #include "asio/ip/multicast.hpp" #include "asio/ip/resolver_query_base.hpp" +#include "asio/ip/resolver_service.hpp" #include "asio/ip/tcp.hpp" #include "asio/ip/udp.hpp" +#include "asio/ip/unicast.hpp" +#include "asio/ip/v6_only.hpp" #include "asio/is_read_buffered.hpp" #include "asio/is_write_buffered.hpp" #include "asio/placeholders.hpp" #include "asio/read.hpp" #include "asio/read_until.hpp" -#include "asio/resolver_service.hpp" #include "asio/socket_acceptor_service.hpp" #include "asio/socket_base.hpp" #include "asio/strand.hpp" #include "asio/stream_socket_service.hpp" #include "asio/streambuf.hpp" -#include "asio/system_exception.hpp" +#include "asio/system_error.hpp" #include "asio/thread.hpp" #include "asio/time_traits.hpp" #include "asio/write.hpp" diff --git a/libtorrent/include/libtorrent/asio/basic_datagram_socket.hpp b/libtorrent/include/libtorrent/asio/basic_datagram_socket.hpp index f555ae506..1a521628f 100644 --- a/libtorrent/include/libtorrent/asio/basic_datagram_socket.hpp +++ b/libtorrent/include/libtorrent/asio/basic_datagram_socket.hpp @@ -2,7 +2,7 @@ // basic_datagram_socket.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -24,7 +24,8 @@ #include "asio/basic_socket.hpp" #include "asio/datagram_socket_service.hpp" -#include "asio/error_handler.hpp" +#include "asio/error.hpp" +#include "asio/detail/throw_error.hpp" namespace asio { @@ -33,21 +34,18 @@ namespace asio { * The basic_datagram_socket class template provides asynchronous and blocking * datagram-oriented socket functionality. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. - * - * @par Concepts: - * Async_Object, Error_Source. */ template > + typename DatagramSocketService = datagram_socket_service > class basic_datagram_socket - : public basic_socket + : public basic_socket { public: /// The native representation of a socket. - typedef typename Service::native_type native_type; + typedef typename DatagramSocketService::native_type native_type; /// The protocol type. typedef Protocol protocol_type; @@ -65,7 +63,7 @@ public: * socket. */ explicit basic_datagram_socket(asio::io_service& io_service) - : basic_socket(io_service) + : basic_socket(io_service) { } @@ -79,11 +77,11 @@ public: * * @param protocol An object specifying protocol parameters to be used. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ basic_datagram_socket(asio::io_service& io_service, const protocol_type& protocol) - : basic_socket(io_service, protocol) + : basic_socket(io_service, protocol) { } @@ -101,11 +99,11 @@ public: * @param endpoint An endpoint on the local machine to which the datagram * socket will be bound. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ basic_datagram_socket(asio::io_service& io_service, const endpoint_type& endpoint) - : basic_socket(io_service, endpoint) + : basic_socket(io_service, endpoint) { } @@ -122,11 +120,12 @@ public: * * @param native_socket The new underlying socket implementation. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ basic_datagram_socket(asio::io_service& io_service, const protocol_type& protocol, const native_type& native_socket) - : basic_socket(io_service, protocol, native_socket) + : basic_socket( + io_service, protocol, native_socket) { } @@ -140,22 +139,25 @@ public: * * @returns The number of bytes sent. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * * @note The send operation can only be used with a connected socket. Use * the send_to function to send data on an unconnected datagram socket. * - * @par Example: + * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code socket.send(asio::buffer(data, size)); @endcode * See the @ref buffer documentation for information on sending multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - std::size_t send(const Const_Buffers& buffers) + template + std::size_t send(const ConstBufferSequence& buffers) { - return this->service.send(this->implementation, buffers, 0, throw_error()); + asio::error_code ec; + std::size_t s = this->service.send(this->implementation, buffers, 0, ec); + asio::detail::throw_error(ec); + return s; } /// Send some data on a connected socket. @@ -170,17 +172,20 @@ public: * * @returns The number of bytes sent. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * * @note The send operation can only be used with a connected socket. Use * the send_to function to send data on an unconnected datagram socket. */ - template - std::size_t send(const Const_Buffers& buffers, + template + std::size_t send(const ConstBufferSequence& buffers, socket_base::message_flags flags) { - return this->service.send(this->implementation, buffers, flags, - throw_error()); + asio::error_code ec; + std::size_t s = this->service.send( + this->implementation, buffers, flags, ec); + asio::detail::throw_error(ec); + return s; } /// Send some data on a connected socket. @@ -193,24 +198,18 @@ public: * * @param flags Flags specifying how the send call is to be made. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation. - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes sent. * * @note The send operation can only be used with a connected socket. Use * the send_to function to send data on an unconnected datagram socket. */ - template - std::size_t send(const Const_Buffers& buffers, - socket_base::message_flags flags, Error_Handler error_handler) + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) { - return this->service.send(this->implementation, buffers, flags, - error_handler); + return this->service.send(this->implementation, buffers, flags, ec); } /// Start an asynchronous send on a connected socket. @@ -228,8 +227,8 @@ public: * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( - * const asio::error& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes sent. + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation @@ -240,7 +239,7 @@ public: * Use the async_send_to function to send data on an unconnected datagram * socket. * - * @par Example: + * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code * socket.async_send(asio::buffer(data, size), handler); @@ -249,8 +248,8 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - void async_send(const Const_Buffers& buffers, Handler handler) + template + void async_send(const ConstBufferSequence& buffers, WriteHandler handler) { this->service.async_send(this->implementation, buffers, 0, handler); } @@ -272,8 +271,8 @@ public: * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( - * const asio::error& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes sent. + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation @@ -284,9 +283,9 @@ public: * Use the async_send_to function to send data on an unconnected datagram * socket. */ - template - void async_send(const Const_Buffers& buffers, - socket_base::message_flags flags, Handler handler) + template + void async_send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, WriteHandler handler) { this->service.async_send(this->implementation, buffers, flags, handler); } @@ -303,9 +302,9 @@ public: * * @returns The number of bytes sent. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @par Example: + * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code * asio::ip::udp::endpoint destination( @@ -316,12 +315,15 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - std::size_t send_to(const Const_Buffers& buffers, + template + std::size_t send_to(const ConstBufferSequence& buffers, const endpoint_type& destination) { - return this->service.send_to(this->implementation, buffers, destination, 0, - throw_error()); + asio::error_code ec; + std::size_t s = this->service.send_to( + this->implementation, buffers, destination, 0, ec); + asio::detail::throw_error(ec); + return s; } /// Send a datagram to the specified endpoint. @@ -338,14 +340,17 @@ public: * * @returns The number of bytes sent. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ - template - std::size_t send_to(const Const_Buffers& buffers, + template + std::size_t send_to(const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags) { - return this->service.send_to(this->implementation, buffers, destination, - flags, throw_error()); + asio::error_code ec; + std::size_t s = this->service.send_to( + this->implementation, buffers, destination, flags, ec); + asio::detail::throw_error(ec); + return s; } /// Send a datagram to the specified endpoint. @@ -360,22 +365,17 @@ public: * * @param flags Flags specifying how the send call is to be made. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation. - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes sent. */ - template - std::size_t send_to(const Const_Buffers& buffers, + template + std::size_t send_to(const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, - Error_Handler error_handler) + asio::error_code& ec) { - return this->service.send_to(this->implementation, buffers, destination, - flags, error_handler); + return this->service.send_to(this->implementation, + buffers, destination, flags, ec); } /// Start an asynchronous send. @@ -395,15 +395,15 @@ public: * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( - * const asio::error& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes sent. + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * - * @par Example: + * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code * asio::ip::udp::endpoint destination( @@ -415,9 +415,9 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - void async_send_to(const Const_Buffers& buffers, - const endpoint_type& destination, Handler handler) + template + void async_send_to(const ConstBufferSequence& buffers, + const endpoint_type& destination, WriteHandler handler) { this->service.async_send_to(this->implementation, buffers, destination, 0, handler); @@ -442,18 +442,18 @@ public: * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( - * const asio::error& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes sent. + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). */ - template - void async_send_to(const Const_Buffers& buffers, + template + void async_send_to(const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, - Handler handler) + WriteHandler handler) { this->service.async_send_to(this->implementation, buffers, destination, flags, handler); @@ -469,13 +469,13 @@ public: * * @returns The number of bytes received. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * * @note The receive operation can only be used with a connected socket. Use * the receive_from function to receive data on an unconnected datagram * socket. * - * @par Example: + * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code socket.receive(asio::buffer(data, size)); @endcode @@ -483,11 +483,14 @@ public: * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - std::size_t receive(const Mutable_Buffers& buffers) + template + std::size_t receive(const MutableBufferSequence& buffers) { - return this->service.receive(this->implementation, buffers, 0, - throw_error()); + asio::error_code ec; + std::size_t s = this->service.receive( + this->implementation, buffers, 0, ec); + asio::detail::throw_error(ec); + return s; } /// Receive some data on a connected socket. @@ -502,18 +505,21 @@ public: * * @returns The number of bytes received. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * * @note The receive operation can only be used with a connected socket. Use * the receive_from function to receive data on an unconnected datagram * socket. */ - template - std::size_t receive(const Mutable_Buffers& buffers, + template + std::size_t receive(const MutableBufferSequence& buffers, socket_base::message_flags flags) { - return this->service.receive(this->implementation, buffers, flags, - throw_error()); + asio::error_code ec; + std::size_t s = this->service.receive( + this->implementation, buffers, flags, ec); + asio::detail::throw_error(ec); + return s; } /// Receive some data on a connected socket. @@ -526,12 +532,7 @@ public: * * @param flags Flags specifying how the receive call is to be made. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation. - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes received. * @@ -539,12 +540,11 @@ public: * the receive_from function to receive data on an unconnected datagram * socket. */ - template - std::size_t receive(const Mutable_Buffers& buffers, - socket_base::message_flags flags, Error_Handler error_handler) + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) { - return this->service.receive(this->implementation, buffers, flags, - error_handler); + return this->service.receive(this->implementation, buffers, flags, ec); } /// Start an asynchronous receive on a connected socket. @@ -561,8 +561,8 @@ public: * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( - * const asio::error& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes received. + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation @@ -573,7 +573,7 @@ public: * Use the async_receive_from function to receive data on an unconnected * datagram socket. * - * @par Example: + * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code @@ -583,8 +583,8 @@ public: * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - void async_receive(const Mutable_Buffers& buffers, Handler handler) + template + void async_receive(const MutableBufferSequence& buffers, ReadHandler handler) { this->service.async_receive(this->implementation, buffers, 0, handler); } @@ -605,8 +605,8 @@ public: * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( - * const asio::error& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes received. + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation @@ -617,9 +617,9 @@ public: * Use the async_receive_from function to receive data on an unconnected * datagram socket. */ - template - void async_receive(const Mutable_Buffers& buffers, - socket_base::message_flags flags, Handler handler) + template + void async_receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, ReadHandler handler) { this->service.async_receive(this->implementation, buffers, flags, handler); } @@ -636,9 +636,9 @@ public: * * @returns The number of bytes received. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @par Example: + * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code @@ -650,12 +650,15 @@ public: * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - std::size_t receive_from(const Mutable_Buffers& buffers, + template + std::size_t receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint) { - return this->service.receive_from(this->implementation, buffers, - sender_endpoint, 0, throw_error()); + asio::error_code ec; + std::size_t s = this->service.receive_from( + this->implementation, buffers, sender_endpoint, 0, ec); + asio::detail::throw_error(ec); + return s; } /// Receive a datagram with the endpoint of the sender. @@ -672,14 +675,17 @@ public: * * @returns The number of bytes received. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ - template - std::size_t receive_from(const Mutable_Buffers& buffers, + template + std::size_t receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags) { - return this->service.receive_from(this->implementation, buffers, - sender_endpoint, flags, throw_error()); + asio::error_code ec; + std::size_t s = this->service.receive_from( + this->implementation, buffers, sender_endpoint, flags, ec); + asio::detail::throw_error(ec); + return s; } /// Receive a datagram with the endpoint of the sender. @@ -694,22 +700,17 @@ public: * * @param flags Flags specifying how the receive call is to be made. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation. - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes received. */ - template - std::size_t receive_from(const Mutable_Buffers& buffers, + template + std::size_t receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, - Error_Handler error_handler) + asio::error_code& ec) { return this->service.receive_from(this->implementation, buffers, - sender_endpoint, flags, error_handler); + sender_endpoint, flags, ec); } /// Start an asynchronous receive. @@ -731,15 +732,15 @@ public: * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( - * const asio::error& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes received. + * const asio::system_error& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * - * @par Example: + * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code socket.async_receive_from( @@ -748,9 +749,9 @@ public: * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - void async_receive_from(const Mutable_Buffers& buffers, - endpoint_type& sender_endpoint, Handler handler) + template + void async_receive_from(const MutableBufferSequence& buffers, + endpoint_type& sender_endpoint, ReadHandler handler) { this->service.async_receive_from(this->implementation, buffers, sender_endpoint, 0, handler); @@ -777,18 +778,18 @@ public: * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( - * const asio::error& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes received. + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). */ - template - void async_receive_from(const Mutable_Buffers& buffers, + template + void async_receive_from(const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, - Handler handler) + ReadHandler handler) { this->service.async_receive_from(this->implementation, buffers, sender_endpoint, flags, handler); diff --git a/libtorrent/include/libtorrent/asio/basic_deadline_timer.hpp b/libtorrent/include/libtorrent/asio/basic_deadline_timer.hpp index 7a2765a20..a630c67bc 100644 --- a/libtorrent/include/libtorrent/asio/basic_deadline_timer.hpp +++ b/libtorrent/include/libtorrent/asio/basic_deadline_timer.hpp @@ -2,7 +2,7 @@ // basic_deadline_timer.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -25,6 +25,7 @@ #include "asio/basic_io_object.hpp" #include "asio/deadline_timer_service.hpp" #include "asio/error.hpp" +#include "asio/detail/throw_error.hpp" namespace asio { @@ -35,16 +36,13 @@ namespace asio { * * Most applications will use the asio::deadline_timer typedef. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * - * @par Concepts: - * Async_Object, Error_Source. - * * @sa @ref deadline_timer_reset * - * @par Examples: + * @par Examples * Performing a blocking wait: * @code * // Construct a timer without setting an expiry time. @@ -60,7 +58,7 @@ namespace asio { * @par * Performing an asynchronous wait: * @code - * void handler(const asio::error& error) + * void handler(const asio::error_code& error) * { * if (!error) * { @@ -78,18 +76,15 @@ namespace asio { * timer.async_wait(handler); * @endcode */ -template , - typename Service = deadline_timer_service > +template , + typename TimerService = deadline_timer_service > class basic_deadline_timer - : public basic_io_object + : public basic_io_object { public: - /// The type used for reporting errors. - typedef asio::error error_type; - /// The time traits type. - typedef Time_Traits traits_type; + typedef TimeTraits traits_type; /// The time type. typedef typename traits_type::time_type time_type; @@ -107,7 +102,7 @@ public: * handlers for any asynchronous operations performed on the timer. */ explicit basic_deadline_timer(asio::io_service& io_service) - : basic_io_object(io_service) + : basic_io_object(io_service) { } @@ -123,9 +118,11 @@ public: */ basic_deadline_timer(asio::io_service& io_service, const time_type& expiry_time) - : basic_io_object(io_service) + : basic_io_object(io_service) { - this->service.expires_at(this->implementation, expiry_time); + asio::error_code ec; + this->service.expires_at(this->implementation, expiry_time, ec); + asio::detail::throw_error(ec); } /// Constructor to set a particular expiry time relative to now. @@ -140,9 +137,11 @@ public: */ basic_deadline_timer(asio::io_service& io_service, const duration_type& expiry_time) - : basic_io_object(io_service) + : basic_io_object(io_service) { - this->service.expires_from_now(this->implementation, expiry_time); + asio::error_code ec; + this->service.expires_from_now(this->implementation, expiry_time, ec); + asio::detail::throw_error(ec); } /// Cancel any asynchronous operations that are waiting on the timer. @@ -154,10 +153,32 @@ public: * Cancelling the timer does not change the expiry time. * * @return The number of asynchronous operations that were cancelled. + * + * @throws asio::system_error Thrown on failure. */ std::size_t cancel() { - return this->service.cancel(this->implementation); + asio::error_code ec; + std::size_t s = this->service.cancel(this->implementation, ec); + asio::detail::throw_error(ec); + return s; + } + + /// Cancel any asynchronous operations that are waiting on the timer. + /** + * This function forces the completion of any pending asynchronous wait + * operations against the timer. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * Cancelling the timer does not change the expiry time. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. + */ + std::size_t cancel(asio::error_code& ec) + { + return this->service.cancel(this->implementation, ec); } /// Get the timer's expiry time as an absolute time. @@ -182,10 +203,37 @@ public: * @param expiry_time The expiry time to be used for the timer. * * @return The number of asynchronous operations that were cancelled. + * + * @throws asio::system_error Thrown on failure. */ std::size_t expires_at(const time_type& expiry_time) { - return this->service.expires_at(this->implementation, expiry_time); + asio::error_code ec; + std::size_t s = this->service.expires_at( + this->implementation, expiry_time, ec); + asio::detail::throw_error(ec); + return s; + } + + /// Set the timer's expiry time as an absolute time. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * See @ref deadline_timer_reset for more information on altering the expiry + * time of an active timer. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. + */ + std::size_t expires_at(const time_type& expiry_time, + asio::error_code& ec) + { + return this->service.expires_at(this->implementation, expiry_time, ec); } /// Get the timer's expiry time relative to now. @@ -210,10 +258,38 @@ public: * @param expiry_time The expiry time to be used for the timer. * * @return The number of asynchronous operations that were cancelled. + * + * @throws asio::system_error Thrown on failure. */ std::size_t expires_from_now(const duration_type& expiry_time) { - return this->service.expires_from_now(this->implementation, expiry_time); + asio::error_code ec; + std::size_t s = this->service.expires_from_now( + this->implementation, expiry_time, ec); + asio::detail::throw_error(ec); + return s; + } + + /// Set the timer's expiry time relative to now. + /** + * This function sets the expiry time. Any pending asynchronous wait + * operations will be cancelled. The handler for each cancelled operation will + * be invoked with the asio::error::operation_aborted error code. + * + * See @ref deadline_timer_reset for more information on altering the expiry + * time of an active timer. + * + * @param expiry_time The expiry time to be used for the timer. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of asynchronous operations that were cancelled. + */ + std::size_t expires_from_now(const duration_type& expiry_time, + asio::error_code& ec) + { + return this->service.expires_from_now( + this->implementation, expiry_time, ec); } /// Perform a blocking wait on the timer. @@ -221,11 +297,25 @@ public: * This function is used to wait for the timer to expire. This function * blocks and does not return until the timer has expired. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ void wait() { - this->service.wait(this->implementation); + asio::error_code ec; + this->service.wait(this->implementation, ec); + asio::detail::throw_error(ec); + } + + /// Perform a blocking wait on the timer. + /** + * This function is used to wait for the timer to expire. This function + * blocks and does not return until the timer has expired. + * + * @param ec Set to indicate what error occurred, if any. + */ + void wait(asio::error_code& ec) + { + this->service.wait(this->implementation, ec); } /// Start an asynchronous wait on the timer. @@ -245,15 +335,15 @@ public: * will be made of the handler as required. The function signature of the * handler must be: * @code void handler( - * const asio::error& error // Result of operation + * const asio::error_code& error // Result of operation. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). */ - template - void async_wait(Handler handler) + template + void async_wait(WaitHandler handler) { this->service.async_wait(this->implementation, handler); } @@ -281,7 +371,7 @@ public: * } * } * - * void on_timeout(const asio::error& e) + * void on_timeout(const asio::error_code& e) * { * if (e != asio::error::operation_aborted) * { @@ -296,8 +386,8 @@ public: * late and the wait handler has already been executed, or will soon be * executed. If it returns 1 then the wait handler was successfully cancelled. * - * @li If a wait handler is cancelled, the asio::error passed to it - * contains the value asio::error::operation_aborted. + * @li If a wait handler is cancelled, the asio::error_code passed to + * it contains the value asio::error::operation_aborted. * * @sa asio::basic_deadline_timer */ diff --git a/libtorrent/include/libtorrent/asio/basic_io_object.hpp b/libtorrent/include/libtorrent/asio/basic_io_object.hpp index 99d8e567f..9291ff5da 100644 --- a/libtorrent/include/libtorrent/asio/basic_io_object.hpp +++ b/libtorrent/include/libtorrent/asio/basic_io_object.hpp @@ -2,7 +2,7 @@ // basic_io_object.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -23,13 +23,13 @@ namespace asio { /// Base class for all I/O objects. -template +template class basic_io_object : private noncopyable { public: /// The type of the service that will be used to provide I/O operations. - typedef Service service_type; + typedef IoObjectService service_type; /// The underlying implementation type of I/O object. typedef typename service_type::implementation_type implementation_type; @@ -50,7 +50,7 @@ public: protected: /// Construct a basic_io_object. explicit basic_io_object(asio::io_service& io_service) - : service(asio::use_service(io_service)) + : service(asio::use_service(io_service)) { service.construct(implementation); } diff --git a/libtorrent/include/libtorrent/asio/basic_socket.hpp b/libtorrent/include/libtorrent/asio/basic_socket.hpp index 2cc31404c..b0dc52e48 100644 --- a/libtorrent/include/libtorrent/asio/basic_socket.hpp +++ b/libtorrent/include/libtorrent/asio/basic_socket.hpp @@ -2,7 +2,7 @@ // basic_socket.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -19,8 +19,8 @@ #include "asio/basic_io_object.hpp" #include "asio/error.hpp" -#include "asio/error_handler.hpp" #include "asio/socket_base.hpp" +#include "asio/detail/throw_error.hpp" namespace asio { @@ -29,21 +29,18 @@ namespace asio { * The basic_socket class template provides functionality that is common to both * stream-oriented and datagram-oriented sockets. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. - * - * @par Concepts: - * Error_Source, IO_Object. */ -template +template class basic_socket - : public basic_io_object, + : public basic_io_object, public socket_base { public: /// The native representation of a socket. - typedef typename Service::native_type native_type; + typedef typename SocketService::native_type native_type; /// The protocol type. typedef Protocol protocol_type; @@ -51,11 +48,8 @@ public: /// The endpoint type. typedef typename Protocol::endpoint endpoint_type; - /// The type used for reporting errors. - typedef asio::error error_type; - /// A basic_socket is always the lowest layer. - typedef basic_socket lowest_layer_type; + typedef basic_socket lowest_layer_type; /// Construct a basic_socket without opening it. /** @@ -65,7 +59,7 @@ public: * dispatch handlers for any asynchronous operations performed on the socket. */ explicit basic_socket(asio::io_service& io_service) - : basic_io_object(io_service) + : basic_io_object(io_service) { } @@ -78,13 +72,15 @@ public: * * @param protocol An object specifying protocol parameters to be used. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ basic_socket(asio::io_service& io_service, const protocol_type& protocol) - : basic_io_object(io_service) + : basic_io_object(io_service) { - this->service.open(this->implementation, protocol, throw_error()); + asio::error_code ec; + this->service.open(this->implementation, protocol, ec); + asio::detail::throw_error(ec); } /// Construct a basic_socket, opening it and binding it to the given local @@ -100,15 +96,17 @@ public: * @param endpoint An endpoint on the local machine to which the socket will * be bound. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ basic_socket(asio::io_service& io_service, const endpoint_type& endpoint) - : basic_io_object(io_service) + : basic_io_object(io_service) { - this->service.open(this->implementation, endpoint.protocol(), - throw_error()); - this->service.bind(this->implementation, endpoint, throw_error()); + asio::error_code ec; + this->service.open(this->implementation, endpoint.protocol(), ec); + asio::detail::throw_error(ec); + this->service.bind(this->implementation, endpoint, ec); + asio::detail::throw_error(ec); } /// Construct a basic_socket on an existing native socket. @@ -122,14 +120,15 @@ public: * * @param native_socket A native socket. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ basic_socket(asio::io_service& io_service, const protocol_type& protocol, const native_type& native_socket) - : basic_io_object(io_service) + : basic_io_object(io_service) { - this->service.assign(this->implementation, protocol, native_socket, - throw_error()); + asio::error_code ec; + this->service.assign(this->implementation, protocol, native_socket, ec); + asio::detail::throw_error(ec); } /// Get a reference to the lowest layer. @@ -152,9 +151,9 @@ public: * * @param protocol An object specifying protocol parameters to be used. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @par Example: + * @par Example * @code * asio::ip::tcp::socket socket(io_service); * socket.open(asio::ip::tcp::v4()); @@ -162,7 +161,9 @@ public: */ void open(const protocol_type& protocol = protocol_type()) { - this->service.open(this->implementation, protocol, throw_error()); + asio::error_code ec; + this->service.open(this->implementation, protocol, ec); + asio::detail::throw_error(ec); } /// Open the socket using the specified protocol. @@ -171,28 +172,23 @@ public: * * @param protocol An object specifying which protocol is to be used. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @par Example: + * @par Example * @code * asio::ip::tcp::socket socket(io_service); - * asio::error error; - * socket.open(asio::ip::tcp::v4(), asio::assign_error(error)); - * if (error) + * asio::error_code ec; + * socket.open(asio::ip::tcp::v4(), ec); + * if (ec) * { * // An error occurred. * } * @endcode */ - template - void open(const protocol_type& protocol, Error_Handler error_handler) + asio::error_code open(const protocol_type& protocol, + asio::error_code& ec) { - this->service.open(this->implementation, protocol, error_handler); + return this->service.open(this->implementation, protocol, ec); } /// Assign an existing native socket to the socket. @@ -203,12 +199,13 @@ public: * * @param native_socket A native socket. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ void assign(const protocol_type& protocol, const native_type& native_socket) { - this->service.assign(this->implementation, protocol, native_socket, - throw_error()); + asio::error_code ec; + this->service.assign(this->implementation, protocol, native_socket, ec); + asio::detail::throw_error(ec); } /// Assign an existing native socket to the socket. @@ -219,19 +216,19 @@ public: * * @param native_socket A native socket. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. */ - template - void assign(const protocol_type& protocol, const native_type& native_socket, - Error_Handler error_handler) + asio::error_code assign(const protocol_type& protocol, + const native_type& native_socket, asio::error_code& ec) { - this->service.assign(this->implementation, protocol, native_socket, - error_handler); + return this->service.assign(this->implementation, + protocol, native_socket, ec); + } + + /// Determine whether the socket is open. + bool is_open() const + { + return this->service.is_open(this->implementation); } /// Close the socket. @@ -240,11 +237,13 @@ public: * or connect operations will be cancelled immediately, and will complete * with the asio::error::operation_aborted error. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ void close() { - this->service.close(this->implementation, throw_error()); + asio::error_code ec; + this->service.close(this->implementation, ec); + asio::detail::throw_error(ec); } /// Close the socket. @@ -253,29 +252,23 @@ public: * or connect operations will be cancelled immediately, and will complete * with the asio::error::operation_aborted error. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @par Example: + * @par Example * @code * asio::ip::tcp::socket socket(io_service); * ... - * asio::error error; - * socket.close(asio::assign_error(error)); - * if (error) + * asio::error_code ec; + * socket.close(ec); + * if (ec) * { * // An error occurred. * } * @endcode */ - template - void close(Error_Handler error_handler) + asio::error_code close(asio::error_code& ec) { - this->service.close(this->implementation, error_handler); + return this->service.close(this->implementation, ec); } /// Get the native socket representation. @@ -295,11 +288,13 @@ public: * operations to finish immediately, and the handlers for cancelled operations * will be passed the asio::error::operation_aborted error. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ void cancel() { - this->service.cancel(this->implementation, throw_error()); + asio::error_code ec; + this->service.cancel(this->implementation, ec); + asio::detail::throw_error(ec); } /// Cancel all asynchronous operations associated with the socket. @@ -308,17 +303,77 @@ public: * operations to finish immediately, and the handlers for cancelled operations * will be passed the asio::error::operation_aborted error. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. */ - template - void cancel(Error_Handler error_handler) + asio::error_code cancel(asio::error_code& ec) { - this->service.cancel(this->implementation, error_handler); + return this->service.cancel(this->implementation, ec); + } + + /// Determine whether the socket is at the out-of-band data mark. + /** + * This function is used to check whether the socket input is currently + * positioned at the out-of-band data mark. + * + * @return A bool indicating whether the socket is at the out-of-band data + * mark. + * + * @throws asio::system_error Thrown on failure. + */ + bool at_mark() const + { + asio::error_code ec; + bool b = this->service.at_mark(this->implementation, ec); + asio::detail::throw_error(ec); + return b; + } + + /// Determine whether the socket is at the out-of-band data mark. + /** + * This function is used to check whether the socket input is currently + * positioned at the out-of-band data mark. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return A bool indicating whether the socket is at the out-of-band data + * mark. + */ + bool at_mark(asio::error_code& ec) const + { + return this->service.at_mark(this->implementation, ec); + } + + /// Determine the number of bytes available for reading. + /** + * This function is used to determine the number of bytes that may be read + * without blocking. + * + * @return The number of bytes that may be read without blocking, or 0 if an + * error occurs. + * + * @throws asio::system_error Thrown on failure. + */ + std::size_t available() const + { + asio::error_code ec; + std::size_t s = this->service.available(this->implementation, ec); + asio::detail::throw_error(ec); + return s; + } + + /// Determine the number of bytes available for reading. + /** + * This function is used to determine the number of bytes that may be read + * without blocking. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of bytes that may be read without blocking, or 0 if an + * error occurs. + */ + std::size_t available(asio::error_code& ec) const + { + return this->service.available(this->implementation, ec); } /// Bind the socket to the given local endpoint. @@ -329,9 +384,9 @@ public: * @param endpoint An endpoint on the local machine to which the socket will * be bound. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @par Example: + * @par Example * @code * asio::ip::tcp::socket socket(io_service); * socket.open(asio::ip::tcp::v4()); @@ -341,7 +396,9 @@ public: */ void bind(const endpoint_type& endpoint) { - this->service.bind(this->implementation, endpoint, throw_error()); + asio::error_code ec; + this->service.bind(this->implementation, endpoint, ec); + asio::detail::throw_error(ec); } /// Bind the socket to the given local endpoint. @@ -352,31 +409,25 @@ public: * @param endpoint An endpoint on the local machine to which the socket will * be bound. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @par Example: + * @par Example * @code * asio::ip::tcp::socket socket(io_service); * socket.open(asio::ip::tcp::v4()); - * asio::error error; + * asio::error_code ec; * socket.bind(asio::ip::tcp::endpoint( - * asio::ip::tcp::v4(), 12345), - * asio::assign_error(error)); - * if (error) + * asio::ip::tcp::v4(), 12345), ec); + * if (ec) * { * // An error occurred. * } * @endcode */ - template - void bind(const endpoint_type& endpoint, Error_Handler error_handler) + asio::error_code bind(const endpoint_type& endpoint, + asio::error_code& ec) { - this->service.bind(this->implementation, endpoint, error_handler); + return this->service.bind(this->implementation, endpoint, ec); } /// Connect the socket to the specified endpoint. @@ -392,9 +443,9 @@ public: * @param peer_endpoint The remote endpoint to which the socket will be * connected. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @par Example: + * @par Example * @code * asio::ip::tcp::socket socket(io_service); * asio::ip::tcp::endpoint endpoint( @@ -404,7 +455,14 @@ public: */ void connect(const endpoint_type& peer_endpoint) { - this->service.connect(this->implementation, peer_endpoint, throw_error()); + asio::error_code ec; + if (!is_open()) + { + this->service.open(this->implementation, peer_endpoint.protocol(), ec); + asio::detail::throw_error(ec); + } + this->service.connect(this->implementation, peer_endpoint, ec); + asio::detail::throw_error(ec); } /// Connect the socket to the specified endpoint. @@ -420,30 +478,34 @@ public: * @param peer_endpoint The remote endpoint to which the socket will be * connected. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @par Example: + * @par Example * @code * asio::ip::tcp::socket socket(io_service); * asio::ip::tcp::endpoint endpoint( * asio::ip::address::from_string("1.2.3.4"), 12345); - * asio::error error; - * socket.connect(endpoint, asio::assign_error(error)); - * if (error) + * asio::error_code ec; + * socket.connect(endpoint, ec); + * if (ec) * { * // An error occurred. * } * @endcode */ - template - void connect(const endpoint_type& peer_endpoint, Error_Handler error_handler) + asio::error_code connect(const endpoint_type& peer_endpoint, + asio::error_code& ec) { - this->service.connect(this->implementation, peer_endpoint, error_handler); + if (!is_open()) + { + if (this->service.open(this->implementation, + peer_endpoint.protocol(), ec)) + { + return ec; + } + } + + return this->service.connect(this->implementation, peer_endpoint, ec); } /// Start an asynchronous connect. @@ -462,16 +524,16 @@ public: * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( - * const asio::error& error // Result of operation + * const asio::error_code& error // Result of operation * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * - * @par Example: + * @par Example * @code - * void connect_handler(const asio::error& error) + * void connect_handler(const asio::error_code& error) * { * if (!error) * { @@ -487,9 +549,20 @@ public: * socket.async_connect(endpoint, connect_handler); * @endcode */ - template - void async_connect(const endpoint_type& peer_endpoint, Handler handler) + template + void async_connect(const endpoint_type& peer_endpoint, ConnectHandler handler) { + if (!is_open()) + { + asio::error_code ec; + if (this->service.open(this->implementation, + peer_endpoint.protocol(), ec)) + { + this->io_service().post(asio::detail::bind_handler(handler, ec)); + return; + } + } + this->service.async_connect(this->implementation, peer_endpoint, handler); } @@ -499,9 +572,9 @@ public: * * @param option The new option value to be set on the socket. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @sa Socket_Option @n + * @sa SettableSocketOption @n * asio::socket_base::broadcast @n * asio::socket_base::do_not_route @n * asio::socket_base::keep_alive @n @@ -518,7 +591,7 @@ public: * asio::ip::multicast::hops @n * asio::ip::tcp::no_delay * - * @par Example: + * @par Example * Setting the IPPROTO_TCP/TCP_NODELAY option: * @code * asio::ip::tcp::socket socket(io_service); @@ -527,10 +600,12 @@ public: * socket.set_option(option); * @endcode */ - template - void set_option(const Socket_Option& option) + template + void set_option(const SettableSocketOption& option) { - this->service.set_option(this->implementation, option, throw_error()); + asio::error_code ec; + this->service.set_option(this->implementation, option, ec); + asio::detail::throw_error(ec); } /// Set an option on the socket. @@ -539,14 +614,9 @@ public: * * @param option The new option value to be set on the socket. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @sa Socket_Option @n + * @sa SettableSocketOption @n * asio::socket_base::broadcast @n * asio::socket_base::do_not_route @n * asio::socket_base::keep_alive @n @@ -563,24 +633,25 @@ public: * asio::ip::multicast::hops @n * asio::ip::tcp::no_delay * - * @par Example: + * @par Example * Setting the IPPROTO_TCP/TCP_NODELAY option: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::ip::tcp::no_delay option(true); - * asio::error error; - * socket.set_option(option, asio::assign_error(error)); - * if (error) + * asio::error_code ec; + * socket.set_option(option, ec); + * if (ec) * { * // An error occurred. * } * @endcode */ - template - void set_option(const Socket_Option& option, Error_Handler error_handler) + template + asio::error_code set_option(const SettableSocketOption& option, + asio::error_code& ec) { - this->service.set_option(this->implementation, option, error_handler); + return this->service.set_option(this->implementation, option, ec); } /// Get an option from the socket. @@ -589,9 +660,9 @@ public: * * @param option The option value to be obtained from the socket. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @sa Socket_Option @n + * @sa GettableSocketOption @n * asio::socket_base::broadcast @n * asio::socket_base::do_not_route @n * asio::socket_base::keep_alive @n @@ -608,7 +679,7 @@ public: * asio::ip::multicast::hops @n * asio::ip::tcp::no_delay * - * @par Example: + * @par Example * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option: * @code * asio::ip::tcp::socket socket(io_service); @@ -618,10 +689,12 @@ public: * bool is_set = option.get(); * @endcode */ - template - void get_option(Socket_Option& option) const + template + void get_option(GettableSocketOption& option) const { - this->service.get_option(this->implementation, option, throw_error()); + asio::error_code ec; + this->service.get_option(this->implementation, option, ec); + asio::detail::throw_error(ec); } /// Get an option from the socket. @@ -630,14 +703,9 @@ public: * * @param option The option value to be obtained from the socket. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @sa Socket_Option @n + * @sa GettableSocketOption @n * asio::socket_base::broadcast @n * asio::socket_base::do_not_route @n * asio::socket_base::keep_alive @n @@ -654,25 +722,26 @@ public: * asio::ip::multicast::hops @n * asio::ip::tcp::no_delay * - * @par Example: + * @par Example * Getting the value of the SOL_SOCKET/SO_KEEPALIVE option: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::ip::tcp::socket::keep_alive option; - * asio::error error; - * socket.get_option(option, asio::assign_error(error)); - * if (error) + * asio::error_code ec; + * socket.get_option(option, ec); + * if (ec) * { * // An error occurred. * } * bool is_set = option.get(); * @endcode */ - template - void get_option(Socket_Option& option, Error_Handler error_handler) const + template + asio::error_code get_option(GettableSocketOption& option, + asio::error_code& ec) const { - this->service.get_option(this->implementation, option, error_handler); + return this->service.get_option(this->implementation, option, ec); } /// Perform an IO control command on the socket. @@ -681,13 +750,13 @@ public: * * @param command The IO control command to be performed on the socket. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @sa IO_Control_Command @n + * @sa IoControlCommand @n * asio::socket_base::bytes_readable @n * asio::socket_base::non_blocking_io * - * @par Example: + * @par Example * Getting the number of bytes ready to read: * @code * asio::ip::tcp::socket socket(io_service); @@ -697,10 +766,12 @@ public: * std::size_t bytes_readable = command.get(); * @endcode */ - template - void io_control(IO_Control_Command& command) + template + void io_control(IoControlCommand& command) { - this->service.io_control(this->implementation, command, throw_error()); + asio::error_code ec; + this->service.io_control(this->implementation, command, ec); + asio::detail::throw_error(ec); } /// Perform an IO control command on the socket. @@ -709,36 +780,32 @@ public: * * @param command The IO control command to be performed on the socket. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @sa IO_Control_Command @n + * @sa IoControlCommand @n * asio::socket_base::bytes_readable @n * asio::socket_base::non_blocking_io * - * @par Example: + * @par Example * Getting the number of bytes ready to read: * @code * asio::ip::tcp::socket socket(io_service); * ... * asio::ip::tcp::socket::bytes_readable command; - * asio::error error; - * socket.io_control(command, asio::assign_error(error)); - * if (error) + * asio::error_code ec; + * socket.io_control(command, ec); + * if (ec) * { * // An error occurred. * } * std::size_t bytes_readable = command.get(); * @endcode */ - template - void io_control(IO_Control_Command& command, Error_Handler error_handler) + template + asio::error_code io_control(IoControlCommand& command, + asio::error_code& ec) { - this->service.io_control(this->implementation, command, error_handler); + return this->service.io_control(this->implementation, command, ec); } /// Get the local endpoint of the socket. @@ -747,9 +814,9 @@ public: * * @returns An object that represents the local endpoint of the socket. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @par Example: + * @par Example * @code * asio::ip::tcp::socket socket(io_service); * ... @@ -758,41 +825,36 @@ public: */ endpoint_type local_endpoint() const { - return this->service.local_endpoint(this->implementation, throw_error()); + asio::error_code ec; + endpoint_type ep = this->service.local_endpoint(this->implementation, ec); + asio::detail::throw_error(ec); + return ep; } /// Get the local endpoint of the socket. /** * This function is used to obtain the locally bound endpoint of the socket. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * * @returns An object that represents the local endpoint of the socket. - * Returns a default-constructed endpoint object if an error occurred and the - * error handler did not throw an exception. + * Returns a default-constructed endpoint object if an error occurred. * - * @par Example: + * @par Example * @code * asio::ip::tcp::socket socket(io_service); * ... - * asio::error error; - * asio::ip::tcp::endpoint endpoint - * = socket.local_endpoint(asio::assign_error(error)); - * if (error) + * asio::error_code ec; + * asio::ip::tcp::endpoint endpoint = socket.local_endpoint(ec); + * if (ec) * { * // An error occurred. * } * @endcode */ - template - endpoint_type local_endpoint(Error_Handler error_handler) const + endpoint_type local_endpoint(asio::error_code& ec) const { - return this->service.local_endpoint(this->implementation, error_handler); + return this->service.local_endpoint(this->implementation, ec); } /// Get the remote endpoint of the socket. @@ -801,9 +863,9 @@ public: * * @returns An object that represents the remote endpoint of the socket. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @par Example: + * @par Example * @code * asio::ip::tcp::socket socket(io_service); * ... @@ -812,41 +874,36 @@ public: */ endpoint_type remote_endpoint() const { - return this->service.remote_endpoint(this->implementation, throw_error()); + asio::error_code ec; + endpoint_type ep = this->service.remote_endpoint(this->implementation, ec); + asio::detail::throw_error(ec); + return ep; } /// Get the remote endpoint of the socket. /** * This function is used to obtain the remote endpoint of the socket. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * * @returns An object that represents the remote endpoint of the socket. - * Returns a default-constructed endpoint object if an error occurred and the - * error handler did not throw an exception. + * Returns a default-constructed endpoint object if an error occurred. * - * @par Example: + * @par Example * @code * asio::ip::tcp::socket socket(io_service); * ... - * asio::error error; - * asio::ip::tcp::endpoint endpoint - * = socket.remote_endpoint(asio::assign_error(error)); - * if (error) + * asio::error_code ec; + * asio::ip::tcp::endpoint endpoint = socket.remote_endpoint(ec); + * if (ec) * { * // An error occurred. * } * @endcode */ - template - endpoint_type remote_endpoint(Error_Handler error_handler) const + endpoint_type remote_endpoint(asio::error_code& ec) const { - return this->service.remote_endpoint(this->implementation, error_handler); + return this->service.remote_endpoint(this->implementation, ec); } /// Disable sends or receives on the socket. @@ -856,9 +913,9 @@ public: * * @param what Determines what types of operation will no longer be allowed. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @par Example: + * @par Example * Shutting down the send side of the socket: * @code * asio::ip::tcp::socket socket(io_service); @@ -868,7 +925,9 @@ public: */ void shutdown(shutdown_type what) { - this->service.shutdown(this->implementation, what, throw_error()); + asio::error_code ec; + this->service.shutdown(this->implementation, what, ec); + asio::detail::throw_error(ec); } /// Disable sends or receives on the socket. @@ -878,31 +937,25 @@ public: * * @param what Determines what types of operation will no longer be allowed. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @par Example: + * @par Example * Shutting down the send side of the socket: * @code * asio::ip::tcp::socket socket(io_service); * ... - * asio::error error; - * socket.shutdown(asio::ip::tcp::socket::shutdown_send, - * asio::assign_error(error)); - * if (error) + * asio::error_code ec; + * socket.shutdown(asio::ip::tcp::socket::shutdown_send, ec); + * if (ec) * { * // An error occurred. * } * @endcode */ - template - void shutdown(shutdown_type what, Error_Handler error_handler) + asio::error_code shutdown(shutdown_type what, + asio::error_code& ec) { - this->service.shutdown(this->implementation, what, error_handler); + return this->service.shutdown(this->implementation, what, ec); } protected: diff --git a/libtorrent/include/libtorrent/asio/basic_socket_acceptor.hpp b/libtorrent/include/libtorrent/asio/basic_socket_acceptor.hpp index c646dc9d2..a2d6a0356 100644 --- a/libtorrent/include/libtorrent/asio/basic_socket_acceptor.hpp +++ b/libtorrent/include/libtorrent/asio/basic_socket_acceptor.hpp @@ -2,7 +2,7 @@ // basic_socket_acceptor.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -20,9 +20,9 @@ #include "asio/basic_io_object.hpp" #include "asio/basic_socket.hpp" #include "asio/error.hpp" -#include "asio/error_handler.hpp" #include "asio/socket_acceptor_service.hpp" #include "asio/socket_base.hpp" +#include "asio/detail/throw_error.hpp" namespace asio { @@ -31,14 +31,11 @@ namespace asio { * The basic_socket_acceptor class template is used for accepting new socket * connections. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * - * @par Concepts: - * Async_Object, Error_Source. - * - * @par Example: + * @par Example * Opening a socket acceptor with the SO_REUSEADDR option enabled: * @code * asio::ip::tcp::acceptor acceptor(io_service); @@ -50,14 +47,14 @@ namespace asio { * @endcode */ template > + typename SocketAcceptorService = socket_acceptor_service > class basic_socket_acceptor - : public basic_io_object, + : public basic_io_object, public socket_base { public: /// The native representation of an acceptor. - typedef typename Service::native_type native_type; + typedef typename SocketAcceptorService::native_type native_type; /// The protocol type. typedef Protocol protocol_type; @@ -65,9 +62,6 @@ public: /// The endpoint type. typedef typename Protocol::endpoint endpoint_type; - /// The type used for reporting errors. - typedef asio::error error_type; - /// Construct an acceptor without opening it. /** * This constructor creates an acceptor without opening it to listen for new @@ -79,7 +73,7 @@ public: * acceptor. */ explicit basic_socket_acceptor(asio::io_service& io_service) - : basic_io_object(io_service) + : basic_io_object(io_service) { } @@ -93,13 +87,15 @@ public: * * @param protocol An object specifying protocol parameters to be used. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ basic_socket_acceptor(asio::io_service& io_service, const protocol_type& protocol) - : basic_io_object(io_service) + : basic_io_object(io_service) { - this->service.open(this->implementation, protocol, throw_error()); + asio::error_code ec; + this->service.open(this->implementation, protocol, ec); + asio::detail::throw_error(ec); } /// Construct an acceptor opened on the given endpoint. @@ -117,7 +113,7 @@ public: * @param reuse_addr Whether the constructor should set the socket option * socket_base::reuse_address. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * * @note This constructor is equivalent to the following code: * @code @@ -131,18 +127,22 @@ public: */ basic_socket_acceptor(asio::io_service& io_service, const endpoint_type& endpoint, bool reuse_addr = true) - : basic_io_object(io_service) + : basic_io_object(io_service) { - this->service.open(this->implementation, endpoint.protocol(), - throw_error()); + asio::error_code ec; + this->service.open(this->implementation, endpoint.protocol(), ec); + asio::detail::throw_error(ec); if (reuse_addr) { this->service.set_option(this->implementation, - socket_base::reuse_address(true), throw_error()); + socket_base::reuse_address(true), ec); + asio::detail::throw_error(ec); } - this->service.bind(this->implementation, endpoint, throw_error()); + this->service.bind(this->implementation, endpoint, ec); + asio::detail::throw_error(ec); this->service.listen(this->implementation, - socket_base::max_connections, throw_error()); + socket_base::max_connections, ec); + asio::detail::throw_error(ec); } /// Construct a basic_socket_acceptor on an existing native acceptor. @@ -158,14 +158,15 @@ public: * * @param native_acceptor A native acceptor. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ basic_socket_acceptor(asio::io_service& io_service, const protocol_type& protocol, const native_type& native_acceptor) - : basic_io_object(io_service) + : basic_io_object(io_service) { - this->service.assign(this->implementation, protocol, native_acceptor, - throw_error()); + asio::error_code ec; + this->service.assign(this->implementation, protocol, native_acceptor, ec); + asio::detail::throw_error(ec); } /// Open the acceptor using the specified protocol. @@ -175,7 +176,9 @@ public: * * @param protocol An object specifying which protocol is to be used. * - * @par Example: + * @throws asio::system_error Thrown on failure. + * + * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * acceptor.open(asio::ip::tcp::v4()); @@ -183,7 +186,9 @@ public: */ void open(const protocol_type& protocol = protocol_type()) { - this->service.open(this->implementation, protocol, throw_error()); + asio::error_code ec; + this->service.open(this->implementation, protocol, ec); + asio::detail::throw_error(ec); } /// Open the acceptor using the specified protocol. @@ -193,29 +198,23 @@ public: * * @param protocol An object specifying which protocol is to be used. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @par Example: + * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); - * asio::error error; - * acceptor.open(asio::ip::tcp::v4(), - * asio::assign_error(error)); - * if (error) + * asio::error_code ec; + * acceptor.open(asio::ip::tcp::v4(), ec); + * if (ec) * { * // An error occurred. * } * @endcode */ - template - void open(const protocol_type& protocol, Error_Handler error_handler) + asio::error_code open(const protocol_type& protocol, + asio::error_code& ec) { - this->service.open(this->implementation, protocol, error_handler); + return this->service.open(this->implementation, protocol, ec); } /// Assigns an existing native acceptor to the acceptor. @@ -226,12 +225,13 @@ public: * * @param native_acceptor A native acceptor. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ void assign(const protocol_type& protocol, const native_type& native_acceptor) { - this->service.assign(this->implementation, protocol, native_acceptor, - throw_error()); + asio::error_code ec; + this->service.assign(this->implementation, protocol, native_acceptor, ec); + asio::detail::throw_error(ec); } /// Assigns an existing native acceptor to the acceptor. @@ -242,19 +242,19 @@ public: * * @param native_acceptor A native acceptor. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. */ - template - void assign(const protocol_type& protocol, const native_type& native_acceptor, - Error_Handler error_handler) + asio::error_code assign(const protocol_type& protocol, + const native_type& native_acceptor, asio::error_code& ec) { - this->service.assign(this->implementation, protocol, native_acceptor, - error_handler); + return this->service.assign(this->implementation, + protocol, native_acceptor, ec); + } + + /// Determine whether the acceptor is open. + bool is_open() const + { + return this->service.is_open(this->implementation); } /// Bind the acceptor to the given local endpoint. @@ -265,9 +265,9 @@ public: * @param endpoint An endpoint on the local machine to which the socket * acceptor will be bound. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @par Example: + * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * acceptor.open(asio::ip::tcp::v4()); @@ -276,7 +276,9 @@ public: */ void bind(const endpoint_type& endpoint) { - this->service.bind(this->implementation, endpoint, throw_error()); + asio::error_code ec; + this->service.bind(this->implementation, endpoint, ec); + asio::detail::throw_error(ec); } /// Bind the acceptor to the given local endpoint. @@ -287,30 +289,24 @@ public: * @param endpoint An endpoint on the local machine to which the socket * acceptor will be bound. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @par Example: + * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * acceptor.open(asio::ip::tcp::v4()); - * asio::error error; - * acceptor.bind(asio::ip::tcp::endpoint(12345), - * asio::assign_error(error)); - * if (error) + * asio::error_code ec; + * acceptor.bind(asio::ip::tcp::endpoint(12345), ec); + * if (ec) * { * // An error occurred. * } * @endcode */ - template - void bind(const endpoint_type& endpoint, Error_Handler error_handler) + asio::error_code bind(const endpoint_type& endpoint, + asio::error_code& ec) { - this->service.bind(this->implementation, endpoint, error_handler); + return this->service.bind(this->implementation, endpoint, ec); } /// Place the acceptor into the state where it will listen for new @@ -320,10 +316,14 @@ public: * new connections. * * @param backlog The maximum length of the queue of pending connections. + * + * @throws asio::system_error Thrown on failure. */ void listen(int backlog = socket_base::max_connections) { - this->service.listen(this->implementation, backlog, throw_error()); + asio::error_code ec; + this->service.listen(this->implementation, backlog, ec); + asio::detail::throw_error(ec); } /// Place the acceptor into the state where it will listen for new @@ -334,30 +334,23 @@ public: * * @param backlog The maximum length of the queue of pending connections. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @par Example: + * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... - * asio::error error; - * acceptor.listen(asio::socket_base::max_connections, - * asio::assign_error(error)); - * if (error) + * asio::error_code ec; + * acceptor.listen(asio::socket_base::max_connections, ec); + * if (ec) * { * // An error occurred. * } * @endcode */ - template - void listen(int backlog, Error_Handler error_handler) + asio::error_code listen(int backlog, asio::error_code& ec) { - this->service.listen(this->implementation, backlog, error_handler); + return this->service.listen(this->implementation, backlog, ec); } /// Close the acceptor. @@ -368,11 +361,13 @@ public: * A subsequent call to open() is required before the acceptor can again be * used to again perform socket accept operations. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ void close() { - this->service.close(this->implementation, throw_error()); + asio::error_code ec; + this->service.close(this->implementation, ec); + asio::detail::throw_error(ec); } /// Close the acceptor. @@ -383,29 +378,23 @@ public: * A subsequent call to open() is required before the acceptor can again be * used to again perform socket accept operations. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @par Example: + * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... - * asio::error error; - * acceptor.close(asio::assign_error(error)); - * if (error) + * asio::error_code ec; + * acceptor.close(ec); + * if (ec) * { * // An error occurred. * } * @endcode */ - template - void close(Error_Handler error_handler) + asio::error_code close(asio::error_code& ec) { - this->service.close(this->implementation, error_handler); + return this->service.close(this->implementation, ec); } /// Get the native acceptor representation. @@ -425,11 +414,13 @@ public: * operations to finish immediately, and the handlers for cancelled operations * will be passed the asio::error::operation_aborted error. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ void cancel() { - this->service.cancel(this->implementation, throw_error()); + asio::error_code ec; + this->service.cancel(this->implementation, ec); + asio::detail::throw_error(ec); } /// Cancel all asynchronous operations associated with the acceptor. @@ -438,17 +429,11 @@ public: * operations to finish immediately, and the handlers for cancelled operations * will be passed the asio::error::operation_aborted error. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. */ - template - void cancel(Error_Handler error_handler) + asio::error_code cancel(asio::error_code& ec) { - this->service.cancel(this->implementation, error_handler); + return this->service.cancel(this->implementation, ec); } /// Set an option on the acceptor. @@ -457,13 +442,13 @@ public: * * @param option The new option value to be set on the acceptor. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @sa Socket_Option @n + * @sa SettableSocketOption @n * asio::socket_base::reuse_address * asio::socket_base::enable_connection_aborted * - * @par Example: + * @par Example * Setting the SOL_SOCKET/SO_REUSEADDR option: * @code * asio::ip::tcp::acceptor acceptor(io_service); @@ -472,10 +457,12 @@ public: * acceptor.set_option(option); * @endcode */ - template - void set_option(const Option& option) + template + void set_option(const SettableSocketOption& option) { - this->service.set_option(this->implementation, option, throw_error()); + asio::error_code ec; + this->service.set_option(this->implementation, option, ec); + asio::detail::throw_error(ec); } /// Set an option on the acceptor. @@ -484,35 +471,31 @@ public: * * @param option The new option value to be set on the acceptor. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @sa Socket_Option @n + * @sa SettableSocketOption @n * asio::socket_base::reuse_address * asio::socket_base::enable_connection_aborted * - * @par Example: + * @par Example * Setting the SOL_SOCKET/SO_REUSEADDR option: * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::ip::tcp::acceptor::reuse_address option(true); - * asio::error error; - * acceptor.set_option(option, asio::assign_error(error)); - * if (error) + * asio::error_code ec; + * acceptor.set_option(option, ec); + * if (ec) * { * // An error occurred. * } * @endcode */ - template - void set_option(const Option& option, Error_Handler error_handler) + template + asio::error_code set_option(const SettableSocketOption& option, + asio::error_code& ec) { - this->service.set_option(this->implementation, option, error_handler); + return this->service.set_option(this->implementation, option, ec); } /// Get an option from the acceptor. @@ -522,12 +505,12 @@ public: * * @param option The option value to be obtained from the acceptor. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @sa Socket_Option @n + * @sa GettableSocketOption @n * asio::socket_base::reuse_address * - * @par Example: + * @par Example * Getting the value of the SOL_SOCKET/SO_REUSEADDR option: * @code * asio::ip::tcp::acceptor acceptor(io_service); @@ -537,10 +520,12 @@ public: * bool is_set = option.get(); * @endcode */ - template - void get_option(Option& option) + template + void get_option(GettableSocketOption& option) { - this->service.get_option(this->implementation, option, throw_error()); + asio::error_code ec; + this->service.get_option(this->implementation, option, ec); + asio::detail::throw_error(ec); } /// Get an option from the acceptor. @@ -550,35 +535,31 @@ public: * * @param option The option value to be obtained from the acceptor. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @sa Socket_Option @n + * @sa GettableSocketOption @n * asio::socket_base::reuse_address * - * @par Example: + * @par Example * Getting the value of the SOL_SOCKET/SO_REUSEADDR option: * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::ip::tcp::acceptor::reuse_address option; - * asio::error error; - * acceptor.get_option(option, asio::assign_error(error)); - * if (error) + * asio::error_code ec; + * acceptor.get_option(option, ec); + * if (ec) * { * // An error occurred. * } * bool is_set = option.get(); * @endcode */ - template - void get_option(Option& option, Error_Handler error_handler) + template + asio::error_code get_option(GettableSocketOption& option, + asio::error_code& ec) { - this->service.get_option(this->implementation, option, error_handler); + return this->service.get_option(this->implementation, option, ec); } /// Get the local endpoint of the acceptor. @@ -587,9 +568,9 @@ public: * * @returns An object that represents the local endpoint of the acceptor. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @par Example: + * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... @@ -598,41 +579,37 @@ public: */ endpoint_type local_endpoint() const { - return this->service.local_endpoint(this->implementation, throw_error()); + asio::error_code ec; + endpoint_type ep = this->service.local_endpoint(this->implementation, ec); + asio::detail::throw_error(ec); + return ep; } /// Get the local endpoint of the acceptor. /** * This function is used to obtain the locally bound endpoint of the acceptor. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * * @returns An object that represents the local endpoint of the acceptor. * Returns a default-constructed endpoint object if an error occurred and the * error handler did not throw an exception. * - * @par Example: + * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... - * asio::error error; - * asio::ip::tcp::endpoint endpoint - * = acceptor.local_endpoint(asio::assign_error(error)); - * if (error) + * asio::error_code ec; + * asio::ip::tcp::endpoint endpoint = acceptor.local_endpoint(ec); + * if (ec) * { * // An error occurred. * } * @endcode */ - template - endpoint_type local_endpoint(Error_Handler error_handler) const + endpoint_type local_endpoint(asio::error_code& ec) const { - return this->service.local_endpoint(this->implementation, error_handler); + return this->service.local_endpoint(this->implementation, ec); } /// Accept a new connection. @@ -643,9 +620,9 @@ public: * * @param peer The socket into which the new connection will be accepted. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @par Example: + * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... @@ -653,10 +630,12 @@ public: * acceptor.accept(socket); * @endcode */ - template - void accept(basic_socket& peer) + template + void accept(basic_socket& peer) { - this->service.accept(this->implementation, peer, throw_error()); + asio::error_code ec; + this->service.accept(this->implementation, peer, 0, ec); + asio::detail::throw_error(ec); } /// Accept a new connection. @@ -667,31 +646,27 @@ public: * * @param peer The socket into which the new connection will be accepted. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @par Example: + * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::ip::tcp::soocket socket(io_service); - * asio::error error; - * acceptor.accept(socket, asio::assign_error(error)); - * if (error) + * asio::error_code ec; + * acceptor.accept(socket, ec); + * if (ec) * { * // An error occurred. * } * @endcode */ - template - void accept(basic_socket& peer, - Error_Handler error_handler) + template + asio::error_code accept( + basic_socket& peer, + asio::error_code& ec) { - this->service.accept(this->implementation, peer, error_handler); + return this->service.accept(this->implementation, peer, 0, ec); } /// Start an asynchronous accept. @@ -707,16 +682,16 @@ public: * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( - * const asio::error& error // Result of operation + * const asio::error_code& error // Result of operation. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). * - * @par Example: + * @par Example * @code - * void accept_handler(const asio::error& error) + * void accept_handler(const asio::error_code& error) * { * if (!error) * { @@ -732,11 +707,11 @@ public: * acceptor.async_accept(socket, accept_handler); * @endcode */ - template - void async_accept(basic_socket& peer, - Handler handler) + template + void async_accept(basic_socket& peer, + AcceptHandler handler) { - this->service.async_accept(this->implementation, peer, handler); + this->service.async_accept(this->implementation, peer, 0, handler); } /// Accept a new connection and obtain the endpoint of the peer @@ -751,23 +726,24 @@ public: * @param peer_endpoint An endpoint object which will receive the endpoint of * the remote peer. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @par Example: + * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::ip::tcp::socket socket(io_service); * asio::ip::tcp::endpoint endpoint; - * acceptor.accept_endpoint(socket, endpoint); + * acceptor.accept(socket, endpoint); * @endcode */ - template - void accept_endpoint(basic_socket& peer, + template + void accept(basic_socket& peer, endpoint_type& peer_endpoint) { - this->service.accept_endpoint(this->implementation, peer, peer_endpoint, - throw_error()); + asio::error_code ec; + this->service.accept(this->implementation, peer, &peer_endpoint, ec); + asio::detail::throw_error(ec); } /// Accept a new connection and obtain the endpoint of the peer @@ -782,34 +758,28 @@ public: * @param peer_endpoint An endpoint object which will receive the endpoint of * the remote peer. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @par Example: + * @par Example * @code * asio::ip::tcp::acceptor acceptor(io_service); * ... * asio::ip::tcp::socket socket(io_service); * asio::ip::tcp::endpoint endpoint; - * asio::error error; - * acceptor.accept_endpoint(socket, endpoint, - * asio::assign_error(error)); - * if (error) + * asio::error_code ec; + * acceptor.accept(socket, endpoint, ec); + * if (ec) * { * // An error occurred. * } * @endcode */ - template - void accept_endpoint(basic_socket& peer, - endpoint_type& peer_endpoint, Error_Handler error_handler) + template + asio::error_code accept( + basic_socket& peer, + endpoint_type& peer_endpoint, asio::error_code& ec) { - this->service.accept_endpoint(this->implementation, peer, peer_endpoint, - error_handler); + return this->service.accept(this->implementation, peer, &peer_endpoint, ec); } /// Start an asynchronous accept. @@ -831,19 +801,19 @@ public: * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( - * const asio::error& error // Result of operation + * const asio::error_code& error // Result of operation. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation * of the handler will be performed in a manner equivalent to using * asio::io_service::post(). */ - template - void async_accept_endpoint(basic_socket& peer, - endpoint_type& peer_endpoint, Handler handler) + template + void async_accept(basic_socket& peer, + endpoint_type& peer_endpoint, AcceptHandler handler) { - this->service.async_accept_endpoint(this->implementation, peer, - peer_endpoint, handler); + this->service.async_accept(this->implementation, + peer, &peer_endpoint, handler); } }; diff --git a/libtorrent/include/libtorrent/asio/basic_socket_iostream.hpp b/libtorrent/include/libtorrent/asio/basic_socket_iostream.hpp index 052b6e603..c48da7b62 100644 --- a/libtorrent/include/libtorrent/asio/basic_socket_iostream.hpp +++ b/libtorrent/include/libtorrent/asio/basic_socket_iostream.hpp @@ -2,7 +2,7 @@ // basic_socket_iostream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -33,74 +33,42 @@ #endif // !defined(ASIO_SOCKET_IOSTREAM_MAX_ARITY) // A macro that should expand to: -// template < typename T1, ..., typename Tn > -// explicit basic_socket_iostream( T1 x1, ..., Tn xn ) +// template +// explicit basic_socket_iostream(T1 x1, ..., Tn xn) // : basic_iostream(&this->boost::base_from_member< -// basic_socket_streambuf >::member) +// basic_socket_streambuf >::member) // { -// try -// { -// rdbuf()->connect ( x1, ..., xn ); -// } -// catch (asio::error&) -// { +// if (rdbuf()->connect(x1, ..., xn) == 0) // this->setstate(std::ios_base::failbit); -// if (this->exceptions() & std::ios_base::failbit) -// throw; -// } // } // This macro should only persist within this file. -#define ASIO_PRIVATE_CTR_DEF( z, n, data ) \ - template < BOOST_PP_ENUM_PARAMS(n, typename T) > \ - explicit basic_socket_iostream( BOOST_PP_ENUM_BINARY_PARAMS(n, T, x) ) \ +#define ASIO_PRIVATE_CTR_DEF(z, n, data) \ + template \ + explicit basic_socket_iostream(BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \ : std::basic_iostream(&this->boost::base_from_member< \ - basic_socket_streambuf >::member) \ + basic_socket_streambuf >::member) \ { \ - try \ - { \ - rdbuf()->connect( BOOST_PP_ENUM_PARAMS(n, x) ); \ - } \ - catch (asio::error&) \ - { \ + if (rdbuf()->connect(BOOST_PP_ENUM_PARAMS(n, x)) == 0) \ this->setstate(std::ios_base::failbit); \ - if (this->exceptions() & std::ios_base::failbit) \ - throw; \ - } \ } \ /**/ // A macro that should expand to: -// template < typename T1, ..., typename Tn > -// void connect( T1 x1, ..., Tn xn ) +// template +// void connect(T1 x1, ..., Tn xn) // { -// try -// { -// rdbuf()->connect ( x1, ..., xn ); -// } -// catch (asio::error&) -// { +// if (rdbuf()->connect(x1, ..., xn) == 0) // this->setstate(std::ios_base::failbit); -// if (this->exceptions() & std::ios_base::failbit) -// throw; -// } // } // This macro should only persist within this file. -#define ASIO_PRIVATE_CONNECT_DEF( z, n, data ) \ - template < BOOST_PP_ENUM_PARAMS(n, typename T) > \ - void connect( BOOST_PP_ENUM_BINARY_PARAMS(n, T, x) ) \ +#define ASIO_PRIVATE_CONNECT_DEF(z, n, data) \ + template \ + void connect(BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \ { \ - try \ - { \ - rdbuf()->connect( BOOST_PP_ENUM_PARAMS(n, x) ); \ - } \ - catch (asio::error&) \ - { \ + if (rdbuf()->connect(BOOST_PP_ENUM_PARAMS(n, x)) == 0) \ this->setstate(std::ios_base::failbit); \ - if (this->exceptions() & std::ios_base::failbit) \ - throw; \ - } \ } \ /**/ @@ -108,16 +76,17 @@ namespace asio { /// Iostream interface for a socket. template > + typename StreamSocketService = stream_socket_service > class basic_socket_iostream - : public boost::base_from_member >, + : public boost::base_from_member< + basic_socket_streambuf >, public std::basic_iostream { public: /// Construct a basic_socket_iostream without establishing a connection. basic_socket_iostream() : std::basic_iostream(&this->boost::base_from_member< - basic_socket_streambuf >::member) + basic_socket_streambuf >::member) { } @@ -154,15 +123,16 @@ public: /// Close the connection. void close() { - rdbuf()->close(); + if (rdbuf()->close() == 0) + this->setstate(std::ios_base::failbit); } /// Return a pointer to the underlying streambuf. - basic_socket_streambuf* rdbuf() const + basic_socket_streambuf* rdbuf() const { - return const_cast*>( + return const_cast*>( &this->boost::base_from_member< - basic_socket_streambuf >::member); + basic_socket_streambuf >::member); } }; diff --git a/libtorrent/include/libtorrent/asio/basic_socket_streambuf.hpp b/libtorrent/include/libtorrent/asio/basic_socket_streambuf.hpp index c24e00140..2c4189c52 100644 --- a/libtorrent/include/libtorrent/asio/basic_socket_streambuf.hpp +++ b/libtorrent/include/libtorrent/asio/basic_socket_streambuf.hpp @@ -2,7 +2,7 @@ // basic_socket_streambuf.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -28,61 +28,41 @@ #include "asio/detail/pop_options.hpp" #include "asio/basic_socket.hpp" -#include "asio/error_handler.hpp" #include "asio/io_service.hpp" #include "asio/stream_socket_service.hpp" +#include "asio/detail/throw_error.hpp" #if !defined(ASIO_SOCKET_STREAMBUF_MAX_ARITY) #define ASIO_SOCKET_STREAMBUF_MAX_ARITY 5 #endif // !defined(ASIO_SOCKET_STREAMBUF_MAX_ARITY) // A macro that should expand to: -// template < typename T1, ..., typename Tn > -// explicit basic_socket_streambuf( T1 x1, ..., Tn xn ) -// : basic_socket( -// boost::base_from_member::member) +// template +// basic_socket_streambuf* connect( +// T1 x1, ..., Tn xn) // { // init_buffers(); +// asio::error_code ec; +// this->basic_socket::close(ec); // typedef typename Protocol::resolver_query resolver_query; -// resolver_query query( x1, ..., xn ); -// resolve_and_connect(query); -// } -// This macro should only persist within this file. - -#define ASIO_PRIVATE_CTR_DEF( z, n, data ) \ - template < BOOST_PP_ENUM_PARAMS(n, typename T) > \ - explicit basic_socket_streambuf( BOOST_PP_ENUM_BINARY_PARAMS(n, T, x) ) \ - : basic_socket( \ - boost::base_from_member::member) \ - { \ - init_buffers(); \ - typedef typename Protocol::resolver_query resolver_query; \ - resolver_query query( BOOST_PP_ENUM_PARAMS(n, x) ); \ - resolve_and_connect(query); \ - } \ - /**/ - -// A macro that should expand to: -// template < typename T1, ..., typename Tn > -// void connect( T1 x1, ..., Tn xn ) -// { -// this->basic_socket::close(); -// init_buffers(); -// typedef typename Protocol::resolver_query resolver_query; -// resolver_query query( x1, ..., xn ); -// resolve_and_connect(query); +// resolver_query query(x1, ..., xn); +// resolve_and_connect(query, ec); +// return !ec ? this : 0; // } // This macro should only persist within this file. #define ASIO_PRIVATE_CONNECT_DEF( z, n, data ) \ - template < BOOST_PP_ENUM_PARAMS(n, typename T) > \ - void connect( BOOST_PP_ENUM_BINARY_PARAMS(n, T, x) ) \ + template \ + basic_socket_streambuf* connect( \ + BOOST_PP_ENUM_BINARY_PARAMS(n, T, x)) \ { \ - this->basic_socket::close(); \ init_buffers(); \ + asio::error_code ec; \ + this->basic_socket::close(ec); \ typedef typename Protocol::resolver_query resolver_query; \ - resolver_query query( BOOST_PP_ENUM_PARAMS(n, x) ); \ - resolve_and_connect(query); \ + resolver_query query(BOOST_PP_ENUM_PARAMS(n, x)); \ + resolve_and_connect(query, ec); \ + return !ec ? this : 0; \ } \ /**/ @@ -90,11 +70,11 @@ namespace asio { /// Iostream streambuf for a socket. template > + typename StreamSocketService = stream_socket_service > class basic_socket_streambuf : public std::streambuf, private boost::base_from_member, - public basic_socket + public basic_socket { public: /// The endpoint type. @@ -102,59 +82,50 @@ public: /// Construct a basic_socket_streambuf without establishing a connection. basic_socket_streambuf() - : basic_socket( - boost::base_from_member::member) + : basic_socket( + boost::base_from_member::member), + unbuffered_(false) { init_buffers(); } - /// Establish a connection to the specified endpoint. - explicit basic_socket_streambuf(const endpoint_type& endpoint) - : basic_socket( - boost::base_from_member::member) - { - init_buffers(); - this->basic_socket::connect(endpoint); - } - -#if defined(GENERATING_DOCUMENTATION) - /// Establish a connection to an endpoint corresponding to a resolver query. - /** - * This constructor automatically establishes a connection based on the - * supplied resolver query parameters. The arguments are used to construct - * a resolver query object. - */ - template - explicit basic_socket_streambuf(T1 t1, ..., TN tn); -#else - BOOST_PP_REPEAT_FROM_TO( - 1, BOOST_PP_INC(ASIO_SOCKET_STREAMBUF_MAX_ARITY), - ASIO_PRIVATE_CTR_DEF, _ ) -#endif - /// Destructor flushes buffered data. - ~basic_socket_streambuf() + virtual ~basic_socket_streambuf() { - sync(); + if (pptr() != pbase()) + overflow(traits_type::eof()); } - /// Establish a connection to the specified endpoint. - void connect(const endpoint_type& endpoint) + /// Establish a connection. + /** + * This function establishes a connection to the specified endpoint. + * + * @return \c this if a connection was successfully established, a null + * pointer otherwise. + */ + basic_socket_streambuf* connect( + const endpoint_type& endpoint) { - this->basic_socket::close(); init_buffers(); - this->basic_socket::connect(endpoint); + asio::error_code ec; + this->basic_socket::close(ec); + this->basic_socket::connect(endpoint, ec); + return !ec ? this : 0; } #if defined(GENERATING_DOCUMENTATION) - /// Establish a connection to an endpoint corresponding to a resolver query. + /// Establish a connection. /** * This function automatically establishes a connection based on the supplied * resolver query parameters. The arguments are used to construct a resolver * query object. + * + * @return \c this if a connection was successfully established, a null + * pointer otherwise. */ template - void connect(T1 t1, ..., TN tn); + basic_socket_streambuf* connect( + T1 t1, ..., TN tn); #else BOOST_PP_REPEAT_FROM_TO( 1, BOOST_PP_INC(ASIO_SOCKET_STREAMBUF_MAX_ARITY), @@ -162,11 +133,18 @@ public: #endif /// Close the connection. - void close() + /** + * @return \c this if a connection was successfully established, a null + * pointer otherwise. + */ + basic_socket_streambuf* close() { + asio::error_code ec; sync(); - this->basic_socket::close(); - init_buffers(); + this->basic_socket::close(ec); + if (!ec) + init_buffers(); + return !ec ? this : 0; } protected: @@ -174,17 +152,13 @@ protected: { if (gptr() == egptr()) { - asio::error error; + asio::error_code ec; std::size_t bytes_transferred = this->service.receive( this->implementation, asio::buffer(asio::buffer(get_buffer_) + putback_max), - 0, asio::assign_error(error)); - if (error) - { - if (error != asio::error::eof) - throw error; + 0, ec); + if (ec) return traits_type::eof(); - } setg(get_buffer_.begin(), get_buffer_.begin() + putback_max, get_buffer_.begin() + putback_max + bytes_transferred); return traits_type::to_int_type(*gptr()); @@ -197,42 +171,67 @@ protected: int_type overflow(int_type c) { - if (!traits_type::eq_int_type(c, traits_type::eof())) + if (unbuffered_) { - if (pptr() == epptr()) + if (traits_type::eq_int_type(c, traits_type::eof())) { - asio::const_buffer buffer = - asio::buffer(pbase(), pptr() - pbase()); - while (asio::buffer_size(buffer) > 0) - { - std::size_t bytes_transferred = this->service.send( - this->implementation, asio::buffer(buffer), - 0, asio::throw_error()); - buffer = buffer + bytes_transferred; - } - setp(put_buffer_.begin(), put_buffer_.end()); + // Nothing to do. + return traits_type::not_eof(c); } + else + { + // Send the single character immediately. + asio::error_code ec; + char_type ch = traits_type::to_char_type(c); + this->service.send(this->implementation, + asio::buffer(&ch, sizeof(char_type)), 0, ec); + if (ec) + return traits_type::eof(); + return c; + } + } + else + { + // Send all data in the output buffer. + asio::const_buffer buffer = + asio::buffer(pbase(), pptr() - pbase()); + while (asio::buffer_size(buffer) > 0) + { + asio::error_code ec; + std::size_t bytes_transferred = this->service.send( + this->implementation, asio::buffer(buffer), + 0, ec); + if (ec) + return traits_type::eof(); + buffer = buffer + bytes_transferred; + } + setp(put_buffer_.begin(), put_buffer_.end()); + // If the new character is eof then our work here is done. + if (traits_type::eq_int_type(c, traits_type::eof())) + return traits_type::not_eof(c); + + // Add the new character to the output buffer. *pptr() = traits_type::to_char_type(c); pbump(1); return c; } - - return traits_type::not_eof(c); } int sync() { - asio::const_buffer buffer = - asio::buffer(pbase(), pptr() - pbase()); - while (asio::buffer_size(buffer) > 0) + return overflow(traits_type::eof()); + } + + std::streambuf* setbuf(char_type* s, std::streamsize n) + { + if (pptr() == pbase() && s == 0 && n == 0) { - std::size_t bytes_transferred = this->service.send( - this->implementation, asio::buffer(buffer), - 0, asio::throw_error()); - buffer = buffer + bytes_transferred; + unbuffered_ = true; + setp(0, 0); + return this; } - setp(put_buffer_.begin(), put_buffer_.end()); + return 0; } @@ -242,37 +241,42 @@ private: setg(get_buffer_.begin(), get_buffer_.begin() + putback_max, get_buffer_.begin() + putback_max); - setp(put_buffer_.begin(), put_buffer_.end()); + if (unbuffered_) + setp(0, 0); + else + setp(put_buffer_.begin(), put_buffer_.end()); } - void resolve_and_connect(const typename Protocol::resolver_query& query) + void resolve_and_connect(const typename Protocol::resolver_query& query, + asio::error_code& ec) { typedef typename Protocol::resolver resolver_type; typedef typename Protocol::resolver_iterator iterator_type; resolver_type resolver( boost::base_from_member::member); - iterator_type iterator = resolver.resolve(query); - asio::error error(asio::error::host_not_found); - while (error && iterator != iterator_type()) + iterator_type i = resolver.resolve(query, ec); + if (!ec) { - this->basic_socket::close(); - this->basic_socket::connect( - *iterator, asio::assign_error(error)); - ++iterator; + iterator_type end; + ec = asio::error::host_not_found; + while (ec && i != end) + { + this->basic_socket::close(); + this->basic_socket::connect(*i, ec); + ++i; + } } - if (error) - throw error; } enum { putback_max = 8 }; enum { buffer_size = 512 }; boost::array get_buffer_; boost::array put_buffer_; + bool unbuffered_; }; } // namespace asio -#undef ASIO_PRIVATE_CTR_DEF #undef ASIO_PRIVATE_CONNECT_DEF #include "asio/detail/pop_options.hpp" diff --git a/libtorrent/include/libtorrent/asio/basic_stream_socket.hpp b/libtorrent/include/libtorrent/asio/basic_stream_socket.hpp index c2cf3c3c7..59889dc33 100644 --- a/libtorrent/include/libtorrent/asio/basic_stream_socket.hpp +++ b/libtorrent/include/libtorrent/asio/basic_stream_socket.hpp @@ -2,7 +2,7 @@ // basic_stream_socket.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -23,8 +23,9 @@ #include "asio/detail/pop_options.hpp" #include "asio/basic_socket.hpp" -#include "asio/error_handler.hpp" +#include "asio/error.hpp" #include "asio/stream_socket_service.hpp" +#include "asio/detail/throw_error.hpp" namespace asio { @@ -33,22 +34,21 @@ namespace asio { * The basic_stream_socket class template provides asynchronous and blocking * stream-oriented socket functionality. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * * @par Concepts: - * Async_Read_Stream, Async_Write_Stream, Error_Source, IO_Object, Stream, - * Sync_Read_Stream, Sync_Write_Stream. + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. */ template > + typename StreamSocketService = stream_socket_service > class basic_stream_socket - : public basic_socket + : public basic_socket { public: /// The native representation of a socket. - typedef typename Service::native_type native_type; + typedef typename StreamSocketService::native_type native_type; /// The protocol type. typedef Protocol protocol_type; @@ -66,7 +66,7 @@ public: * dispatch handlers for any asynchronous operations performed on the socket. */ explicit basic_stream_socket(asio::io_service& io_service) - : basic_socket(io_service) + : basic_socket(io_service) { } @@ -80,11 +80,11 @@ public: * * @param protocol An object specifying protocol parameters to be used. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ basic_stream_socket(asio::io_service& io_service, const protocol_type& protocol) - : basic_socket(io_service, protocol) + : basic_socket(io_service, protocol) { } @@ -101,11 +101,11 @@ public: * @param endpoint An endpoint on the local machine to which the stream * socket will be bound. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ basic_stream_socket(asio::io_service& io_service, const endpoint_type& endpoint) - : basic_socket(io_service, endpoint) + : basic_socket(io_service, endpoint) { } @@ -121,11 +121,12 @@ public: * * @param native_socket The new underlying socket implementation. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ basic_stream_socket(asio::io_service& io_service, const protocol_type& protocol, const native_type& native_socket) - : basic_socket(io_service, protocol, native_socket) + : basic_socket( + io_service, protocol, native_socket) { } @@ -139,13 +140,13 @@ public: * * @returns The number of bytes sent. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * * @note The send operation may not transmit all of the data to the peer. * Consider using the @ref write function if you need to ensure that all data * is written before the blocking operation completes. * - * @par Example: + * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code * socket.send(asio::buffer(data, size)); @@ -154,10 +155,14 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - std::size_t send(const Const_Buffers& buffers) + template + std::size_t send(const ConstBufferSequence& buffers) { - return this->service.send(this->implementation, buffers, 0, throw_error()); + asio::error_code ec; + std::size_t s = this->service.send( + this->implementation, buffers, 0, ec); + asio::detail::throw_error(ec); + return s; } /// Send some data on the socket. @@ -172,13 +177,13 @@ public: * * @returns The number of bytes sent. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * * @note The send operation may not transmit all of the data to the peer. * Consider using the @ref write function if you need to ensure that all data * is written before the blocking operation completes. * - * @par Example: + * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code * socket.send(asio::buffer(data, size), 0); @@ -187,12 +192,15 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - std::size_t send(const Const_Buffers& buffers, + template + std::size_t send(const ConstBufferSequence& buffers, socket_base::message_flags flags) { - return this->service.send(this->implementation, buffers, flags, - throw_error()); + asio::error_code ec; + std::size_t s = this->service.send( + this->implementation, buffers, flags, ec); + asio::detail::throw_error(ec); + return s; } /// Send some data on the socket. @@ -205,27 +213,19 @@ public: * * @param flags Flags specifying how the send call is to be made. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation. - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @returns The number of bytes sent. Returns 0 if an error occurred and the - * error handler did not throw an exception. + * @returns The number of bytes sent. Returns 0 if an error occurred. * * @note The send operation may not transmit all of the data to the peer. * Consider using the @ref write function if you need to ensure that all data * is written before the blocking operation completes. */ - template - std::size_t send(const Const_Buffers& buffers, - socket_base::message_flags flags, - Error_Handler error_handler) + template + std::size_t send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) { - return this->service.send(this->implementation, buffers, flags, - error_handler); + return this->service.send(this->implementation, buffers, flags, ec); } /// Start an asynchronous send. @@ -242,8 +242,8 @@ public: * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( - * const asio::error& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes sent. + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation @@ -254,7 +254,7 @@ public: * Consider using the @ref async_write function if you need to ensure that all * data is written before the asynchronous operation completes. * - * @par Example: + * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code * socket.async_send(asio::buffer(data, size), handler); @@ -263,8 +263,8 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - void async_send(const Const_Buffers& buffers, Handler handler) + template + void async_send(const ConstBufferSequence& buffers, WriteHandler handler) { this->service.async_send(this->implementation, buffers, 0, handler); } @@ -285,8 +285,8 @@ public: * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( - * const asio::error& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes sent. + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes sent. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation @@ -297,7 +297,7 @@ public: * Consider using the @ref async_write function if you need to ensure that all * data is written before the asynchronous operation completes. * - * @par Example: + * @par Example * To send a single data buffer use the @ref buffer function as follows: * @code * socket.async_send(asio::buffer(data, size), 0, handler); @@ -306,9 +306,9 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - void async_send(const Const_Buffers& buffers, - socket_base::message_flags flags, Handler handler) + template + void async_send(const ConstBufferSequence& buffers, + socket_base::message_flags flags, WriteHandler handler) { this->service.async_send(this->implementation, buffers, flags, handler); } @@ -323,7 +323,7 @@ public: * * @returns The number of bytes received. * - * @throws asio::error Thrown on failure. An error code of + * @throws asio::system_error Thrown on failure. An error code of * asio::error::eof indicates that the connection was closed by the * peer. * @@ -331,7 +331,7 @@ public: * bytes. Consider using the @ref read function if you need to ensure that the * requested amount of data is read before the blocking operation completes. * - * @par Example: + * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code @@ -341,11 +341,13 @@ public: * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - std::size_t receive(const Mutable_Buffers& buffers) + template + std::size_t receive(const MutableBufferSequence& buffers) { - return this->service.receive(this->implementation, buffers, 0, - throw_error()); + asio::error_code ec; + std::size_t s = this->service.receive(this->implementation, buffers, 0, ec); + asio::detail::throw_error(ec); + return s; } /// Receive some data on the socket. @@ -360,7 +362,7 @@ public: * * @returns The number of bytes received. * - * @throws asio::error Thrown on failure. An error code of + * @throws asio::system_error Thrown on failure. An error code of * asio::error::eof indicates that the connection was closed by the * peer. * @@ -368,7 +370,7 @@ public: * bytes. Consider using the @ref read function if you need to ensure that the * requested amount of data is read before the blocking operation completes. * - * @par Example: + * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code @@ -378,12 +380,15 @@ public: * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - std::size_t receive(const Mutable_Buffers& buffers, + template + std::size_t receive(const MutableBufferSequence& buffers, socket_base::message_flags flags) { - return this->service.receive(this->implementation, buffers, flags, - throw_error()); + asio::error_code ec; + std::size_t s = this->service.receive( + this->implementation, buffers, flags, ec); + asio::detail::throw_error(ec); + return s; } /// Receive some data on a connected socket. @@ -396,26 +401,19 @@ public: * * @param flags Flags specifying how the receive call is to be made. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @returns The number of bytes received. Returns 0 if an error occurred and - * the error handler did not throw an exception. + * @returns The number of bytes received. Returns 0 if an error occurred. * * @note The receive operation may not receive all of the requested number of * bytes. Consider using the @ref read function if you need to ensure that the * requested amount of data is read before the blocking operation completes. */ - template - std::size_t receive(const Mutable_Buffers& buffers, - socket_base::message_flags flags, Error_Handler error_handler) + template + std::size_t receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) { - return this->service.receive(this->implementation, buffers, flags, - error_handler); + return this->service.receive(this->implementation, buffers, flags, ec); } /// Start an asynchronous receive. @@ -432,8 +430,8 @@ public: * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( - * const asio::error& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes received. + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation @@ -445,7 +443,7 @@ public: * that the requested amount of data is received before the asynchronous * operation completes. * - * @par Example: + * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code @@ -455,8 +453,8 @@ public: * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - void async_receive(const Mutable_Buffers& buffers, Handler handler) + template + void async_receive(const MutableBufferSequence& buffers, ReadHandler handler) { this->service.async_receive(this->implementation, buffers, 0, handler); } @@ -477,8 +475,8 @@ public: * completes. Copies will be made of the handler as required. The function * signature of the handler must be: * @code void handler( - * const asio::error& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes received. + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes received. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation @@ -490,7 +488,7 @@ public: * that the requested amount of data is received before the asynchronous * operation completes. * - * @par Example: + * @par Example * To receive into a single data buffer use the @ref buffer function as * follows: * @code @@ -500,9 +498,9 @@ public: * multiple buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - void async_receive(const Mutable_Buffers& buffers, - socket_base::message_flags flags, Handler handler) + template + void async_receive(const MutableBufferSequence& buffers, + socket_base::message_flags flags, ReadHandler handler) { this->service.async_receive(this->implementation, buffers, flags, handler); } @@ -517,7 +515,7 @@ public: * * @returns The number of bytes written. * - * @throws asio::error Thrown on failure. An error code of + * @throws asio::system_error Thrown on failure. An error code of * asio::error::eof indicates that the connection was closed by the * peer. * @@ -525,7 +523,7 @@ public: * peer. Consider using the @ref write function if you need to ensure that * all data is written before the blocking operation completes. * - * @par Example: + * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code * socket.write_some(asio::buffer(data, size)); @@ -534,10 +532,13 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - std::size_t write_some(const Const_Buffers& buffers) + template + std::size_t write_some(const ConstBufferSequence& buffers) { - return this->service.send(this->implementation, buffers, 0, throw_error()); + asio::error_code ec; + std::size_t s = this->service.send(this->implementation, buffers, 0, ec); + asio::detail::throw_error(ec); + return s; } /// Write some data to the socket. @@ -548,25 +549,19 @@ public: * * @param buffers One or more data buffers to be written to the socket. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation. - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @returns The number of bytes written. Returns 0 if an error occurred and - * the error handler did not throw an exception. + * @returns The number of bytes written. Returns 0 if an error occurred. * * @note The write_some operation may not transmit all of the data to the * peer. Consider using the @ref write function if you need to ensure that * all data is written before the blocking operation completes. */ - template - std::size_t write_some(const Const_Buffers& buffers, - Error_Handler error_handler) + template + std::size_t write_some(const ConstBufferSequence& buffers, + asio::error_code& ec) { - return this->service.send(this->implementation, buffers, 0, error_handler); + return this->service.send(this->implementation, buffers, 0, ec); } /// Start an asynchronous write. @@ -583,8 +578,8 @@ public: * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( - * const asio::error& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes written. + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes written. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation @@ -595,7 +590,7 @@ public: * Consider using the @ref async_write function if you need to ensure that all * data is written before the asynchronous operation completes. * - * @par Example: + * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code * socket.async_write_some(asio::buffer(data, size), handler); @@ -604,8 +599,9 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - void async_write_some(const Const_Buffers& buffers, Handler handler) + template + void async_write_some(const ConstBufferSequence& buffers, + WriteHandler handler) { this->service.async_send(this->implementation, buffers, 0, handler); } @@ -620,7 +616,7 @@ public: * * @returns The number of bytes read. * - * @throws asio::error Thrown on failure. An error code of + * @throws asio::system_error Thrown on failure. An error code of * asio::error::eof indicates that the connection was closed by the * peer. * @@ -629,7 +625,7 @@ public: * the requested amount of data is read before the blocking operation * completes. * - * @par Example: + * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code * socket.read_some(asio::buffer(data, size)); @@ -638,11 +634,13 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - std::size_t read_some(const Mutable_Buffers& buffers) + template + std::size_t read_some(const MutableBufferSequence& buffers) { - return this->service.receive(this->implementation, buffers, 0, - throw_error()); + asio::error_code ec; + std::size_t s = this->service.receive(this->implementation, buffers, 0, ec); + asio::detail::throw_error(ec); + return s; } /// Read some data from the socket. @@ -653,27 +651,20 @@ public: * * @param buffers One or more buffers into which the data will be read. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation. - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @returns The number of bytes read. Returns 0 if an error occurred and the - * error handler did not throw an exception. + * @returns The number of bytes read. Returns 0 if an error occurred. * * @note The read_some operation may not read all of the requested number of * bytes. Consider using the @ref read function if you need to ensure that * the requested amount of data is read before the blocking operation * completes. */ - template - std::size_t read_some(const Mutable_Buffers& buffers, - Error_Handler error_handler) + template + std::size_t read_some(const MutableBufferSequence& buffers, + asio::error_code& ec) { - return this->service.receive(this->implementation, buffers, 0, - error_handler); + return this->service.receive(this->implementation, buffers, 0, ec); } /// Start an asynchronous read. @@ -690,8 +681,8 @@ public: * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( - * const asio::error& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes read. + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes read. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation @@ -703,7 +694,7 @@ public: * requested amount of data is read before the asynchronous operation * completes. * - * @par Example: + * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code * socket.async_read_some(asio::buffer(data, size), handler); @@ -712,101 +703,12 @@ public: * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ - template - void async_read_some(const Mutable_Buffers& buffers, Handler handler) + template + void async_read_some(const MutableBufferSequence& buffers, + ReadHandler handler) { this->service.async_receive(this->implementation, buffers, 0, handler); } - - /// Peek at the incoming data on the stream socket. - /** - * This function is used to peek at the incoming data on the stream socket, - * without removing it from the input queue. The function call will block - * until data has been read successfully or an error occurs. - * - * @param buffers One or more buffers into which the data will be read. - * - * @returns The number of bytes read. - * - * @throws asio::error Thrown on failure. - * - * @par Example: - * To peek using a single data buffer use the @ref buffer function as - * follows: - * @code socket.peek(asio::buffer(data, size)); @endcode - * See the @ref buffer documentation for information on using multiple - * buffers in one go, and how to use it with arrays, boost::array or - * std::vector. - */ - template - std::size_t peek(const Mutable_Buffers& buffers) - { - return this->service.receive(this->implementation, buffers, - socket_base::message_peek, throw_error()); - } - - /// Peek at the incoming data on the stream socket. - /** - * This function is used to peek at the incoming data on the stream socket, - * without removing it from the input queue. The function call will block - * until data has been read successfully or an error occurs. - * - * @param buffers One or more buffers into which the data will be read. - * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation. - * ); @endcode - * - * @returns The number of bytes read. Returns 0 if an error occurred and the - * error handler did not throw an exception. - */ - template - std::size_t peek(const Mutable_Buffers& buffers, Error_Handler error_handler) - { - return this->service.receive(this->implementation, buffers, - socket_base::message_peek, error_handler); - } - - /// Determine the amount of data that may be read without blocking. - /** - * This function is used to determine the amount of data, in bytes, that may - * be read from the stream socket without blocking. - * - * @returns The number of bytes of data that can be read without blocking. - * - * @throws asio::error Thrown on failure. - */ - std::size_t in_avail() - { - socket_base::bytes_readable command; - this->service.io_control(this->implementation, command, throw_error()); - return command.get(); - } - - /// Determine the amount of data that may be read without blocking. - /** - * This function is used to determine the amount of data, in bytes, that may - * be read from the stream socket without blocking. - * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode - * - * @returns The number of bytes of data that can be read without blocking. - */ - template - std::size_t in_avail(Error_Handler error_handler) - { - socket_base::bytes_readable command; - this->service.io_control(this->implementation, command, error_handler); - return command.get(); - } }; } // namespace asio diff --git a/libtorrent/include/libtorrent/asio/basic_streambuf.hpp b/libtorrent/include/libtorrent/asio/basic_streambuf.hpp index 49ce11a89..016445e0f 100644 --- a/libtorrent/include/libtorrent/asio/basic_streambuf.hpp +++ b/libtorrent/include/libtorrent/asio/basic_streambuf.hpp @@ -2,7 +2,7 @@ // basic_streambuf.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -45,8 +45,8 @@ public: /// The type used to represent the put area as a list of buffers. typedef implementation_defined mutable_buffers_type; #else - typedef asio::const_buffer_container_1 const_buffers_type; - typedef asio::mutable_buffer_container_1 mutable_buffers_type; + 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. diff --git a/libtorrent/include/libtorrent/asio/buffer.hpp b/libtorrent/include/libtorrent/asio/buffer.hpp index bd6442432..69214fdb1 100644 --- a/libtorrent/include/libtorrent/asio/buffer.hpp +++ b/libtorrent/include/libtorrent/asio/buffer.hpp @@ -2,7 +2,7 @@ // buffer.hpp // ~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -26,6 +26,20 @@ #include #include "asio/detail/pop_options.hpp" +#if defined(BOOST_MSVC) +# if defined(_HAS_ITERATOR_DEBUGGING) +# if !defined(ASIO_DISABLE_BUFFER_DEBUGGING) +# define ASIO_ENABLE_BUFFER_DEBUGGING +# endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING) +# endif // defined(_HAS_ITERATOR_DEBUGGING) +#endif // defined(BOOST_MSVC) + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) +# include "asio/detail/push_options.hpp" +# include +# include "asio/detail/pop_options.hpp" +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + namespace asio { class mutable_buffer; @@ -61,6 +75,21 @@ public: { } +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + mutable_buffer(void* data, std::size_t size, + boost::function debug_check) + : data_(data), + size_(size), + debug_check_(debug_check) + { + } + + const boost::function& get_debug_check() const + { + return debug_check_; + } +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + private: friend void* asio::detail::buffer_cast_helper( const mutable_buffer& b); @@ -69,12 +98,20 @@ private: void* data_; std::size_t size_; + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + boost::function debug_check_; +#endif // ASIO_ENABLE_BUFFER_DEBUGGING }; namespace detail { inline void* buffer_cast_helper(const mutable_buffer& b) { +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + if (b.debug_check_) + b.debug_check_(); +#endif // ASIO_ENABLE_BUFFER_DEBUGGING return b.data_; } @@ -89,10 +126,10 @@ inline std::size_t buffer_size_helper(const mutable_buffer& b) /** * @relates mutable_buffer */ -template -inline Pointer_To_Pod_Type buffer_cast(const mutable_buffer& b) +template +inline PointerToPodType buffer_cast(const mutable_buffer& b) { - return static_cast(detail::buffer_cast_helper(b)); + return static_cast(detail::buffer_cast_helper(b)); } /// Get the number of bytes in a non-modifiable buffer. @@ -114,7 +151,11 @@ inline mutable_buffer operator+(const mutable_buffer& b, std::size_t start) return mutable_buffer(); char* new_data = buffer_cast(b) + start; std::size_t new_size = buffer_size(b) - start; - return mutable_buffer(new_data, new_size); + return mutable_buffer(new_data, new_size +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + ); } /// Create a new modifiable buffer that is offset from the start of another. @@ -127,12 +168,16 @@ inline mutable_buffer operator+(std::size_t start, const mutable_buffer& b) return mutable_buffer(); char* new_data = buffer_cast(b) + start; std::size_t new_size = buffer_size(b) - start; - return mutable_buffer(new_data, new_size); + return mutable_buffer(new_data, new_size +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + ); } /// Adapts a single modifiable buffer so that it meets the requirements of the -/// Mutable_Buffers concept. -class mutable_buffer_container_1 +/// MutableBufferSequence concept. +class mutable_buffers_1 : public mutable_buffer { public: @@ -143,7 +188,7 @@ public: typedef const mutable_buffer* const_iterator; /// Construct to represent a single modifiable buffer. - explicit mutable_buffer_container_1(const mutable_buffer& b) + explicit mutable_buffers_1(const mutable_buffer& b) : mutable_buffer(b) { } @@ -188,9 +233,27 @@ public: const_buffer(const mutable_buffer& b) : data_(asio::detail::buffer_cast_helper(b)), size_(asio::detail::buffer_size_helper(b)) +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , debug_check_(b.get_debug_check()) +#endif // ASIO_ENABLE_BUFFER_DEBUGGING { } +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + const_buffer(const void* data, std::size_t size, + boost::function debug_check) + : data_(data), + size_(size), + debug_check_(debug_check) + { + } + + const boost::function& get_debug_check() const + { + return debug_check_; + } +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + private: friend const void* asio::detail::buffer_cast_helper( const const_buffer& b); @@ -199,12 +262,20 @@ private: const void* data_; std::size_t size_; + +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + boost::function debug_check_; +#endif // ASIO_ENABLE_BUFFER_DEBUGGING }; namespace detail { inline const void* buffer_cast_helper(const const_buffer& b) { +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + if (b.debug_check_) + b.debug_check_(); +#endif // ASIO_ENABLE_BUFFER_DEBUGGING return b.data_; } @@ -219,10 +290,10 @@ inline std::size_t buffer_size_helper(const const_buffer& b) /** * @relates const_buffer */ -template -inline Pointer_To_Pod_Type buffer_cast(const const_buffer& b) +template +inline PointerToPodType buffer_cast(const const_buffer& b) { - return static_cast(detail::buffer_cast_helper(b)); + return static_cast(detail::buffer_cast_helper(b)); } /// Get the number of bytes in a non-modifiable buffer. @@ -244,7 +315,11 @@ inline const_buffer operator+(const const_buffer& b, std::size_t start) return const_buffer(); const char* new_data = buffer_cast(b) + start; std::size_t new_size = buffer_size(b) - start; - return const_buffer(new_data, new_size); + return const_buffer(new_data, new_size +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + ); } /// Create a new non-modifiable buffer that is offset from the start of another. @@ -257,12 +332,16 @@ inline const_buffer operator+(std::size_t start, const const_buffer& b) return const_buffer(); const char* new_data = buffer_cast(b) + start; std::size_t new_size = buffer_size(b) - start; - return const_buffer(new_data, new_size); + return const_buffer(new_data, new_size +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + ); } /// Adapts a single non-modifiable buffer so that it meets the requirements of -/// the Const_Buffers concept. -class const_buffer_container_1 +/// the ConstBufferSequence concept. +class const_buffers_1 : public const_buffer { public: @@ -273,7 +352,7 @@ public: typedef const const_buffer* const_iterator; /// Construct to represent a single non-modifiable buffer. - explicit const_buffer_container_1(const const_buffer& b) + explicit const_buffers_1(const const_buffer& b) : const_buffer(b) { } @@ -291,6 +370,30 @@ public: } }; +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) +namespace detail { + +template +class buffer_debug_check +{ +public: + buffer_debug_check(Iterator iter) + : iter_(iter) + { + } + + void operator()() + { + *iter_; + } + +private: + Iterator iter_; +}; + +} // namespace detail +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + /** @defgroup buffer asio::buffer * * @brief The asio::buffer function is used to create a buffer object to @@ -302,9 +405,9 @@ public: * @code sock.write(asio::buffer(data, size)); @endcode * * In the above example, the return value of asio::buffer meets the - * requirements of the Const_Buffers concept so that it may be directly passed - * to the socket's write function. A buffer created for modifiable memory also - * meets the requirements of the Mutable_Buffers concept. + * requirements of the ConstBufferSequence concept so that it may be directly + * passed to the socket's write function. A buffer created for modifiable + * memory also meets the requirements of the MutableBufferSequence concept. * * An individual buffer may be created from a builtin array, std::vector or * boost::array of POD elements. This helps prevent buffer overruns by @@ -321,7 +424,7 @@ public: * * To read or write using multiple buffers (i.e. scatter-gather I/O), multiple * buffer objects may be assigned into a container that supports the - * Mutable_Buffers (for read) or Const_Buffers (for write) concepts: + * MutableBufferSequence (for read) or ConstBufferSequence (for write) concepts: * * @code * char d1[128]; @@ -343,99 +446,107 @@ public: /*@{*/ /// Create a new modifiable buffer from an existing buffer. -inline mutable_buffer_container_1 buffer(const mutable_buffer& b) +inline mutable_buffers_1 buffer(const mutable_buffer& b) { - return mutable_buffer_container_1(b); + return mutable_buffers_1(b); } /// Create a new modifiable buffer from an existing buffer. -inline mutable_buffer_container_1 buffer(const mutable_buffer& b, +inline mutable_buffers_1 buffer(const mutable_buffer& b, std::size_t max_size_in_bytes) { - return mutable_buffer_container_1( + return mutable_buffers_1( mutable_buffer(buffer_cast(b), buffer_size(b) < max_size_in_bytes - ? buffer_size(b) : max_size_in_bytes)); + ? buffer_size(b) : max_size_in_bytes +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + )); } /// Create a new non-modifiable buffer from an existing buffer. -inline const_buffer_container_1 buffer(const const_buffer& b) +inline const_buffers_1 buffer(const const_buffer& b) { - return const_buffer_container_1(b); + return const_buffers_1(b); } /// Create a new non-modifiable buffer from an existing buffer. -inline const_buffer_container_1 buffer(const const_buffer& b, +inline const_buffers_1 buffer(const const_buffer& b, std::size_t max_size_in_bytes) { - return const_buffer_container_1( + return const_buffers_1( const_buffer(buffer_cast(b), buffer_size(b) < max_size_in_bytes - ? buffer_size(b) : max_size_in_bytes)); + ? buffer_size(b) : max_size_in_bytes +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , b.get_debug_check() +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + )); } /// Create a new modifiable buffer that represents the given memory range. -inline mutable_buffer_container_1 buffer(void* data, std::size_t size_in_bytes) +inline mutable_buffers_1 buffer(void* data, std::size_t size_in_bytes) { - return mutable_buffer_container_1(mutable_buffer(data, size_in_bytes)); + return mutable_buffers_1(mutable_buffer(data, size_in_bytes)); } /// Create a new non-modifiable buffer that represents the given memory range. -inline const_buffer_container_1 buffer(const void* data, +inline const_buffers_1 buffer(const void* data, std::size_t size_in_bytes) { - return const_buffer_container_1(const_buffer(data, size_in_bytes)); + return const_buffers_1(const_buffer(data, size_in_bytes)); } /// Create a new modifiable buffer that represents the given POD array. -template -inline mutable_buffer_container_1 buffer(Pod_Type (&data)[N]) +template +inline mutable_buffers_1 buffer(PodType (&data)[N]) { - return mutable_buffer_container_1(mutable_buffer(data, N * sizeof(Pod_Type))); + return mutable_buffers_1(mutable_buffer(data, N * sizeof(PodType))); } /// Create a new modifiable buffer that represents the given POD array. -template -inline mutable_buffer_container_1 buffer(Pod_Type (&data)[N], +template +inline mutable_buffers_1 buffer(PodType (&data)[N], std::size_t max_size_in_bytes) { - return mutable_buffer_container_1( + return mutable_buffers_1( mutable_buffer(data, - N * sizeof(Pod_Type) < max_size_in_bytes - ? N * sizeof(Pod_Type) : max_size_in_bytes)); + N * sizeof(PodType) < max_size_in_bytes + ? N * sizeof(PodType) : max_size_in_bytes)); } /// Create a new non-modifiable buffer that represents the given POD array. -template -inline const_buffer_container_1 buffer(const Pod_Type (&data)[N]) +template +inline const_buffers_1 buffer(const PodType (&data)[N]) { - return const_buffer_container_1(const_buffer(data, N * sizeof(Pod_Type))); + return const_buffers_1(const_buffer(data, N * sizeof(PodType))); } /// Create a new non-modifiable buffer that represents the given POD array. -template -inline const_buffer_container_1 buffer(const Pod_Type (&data)[N], +template +inline const_buffers_1 buffer(const PodType (&data)[N], std::size_t max_size_in_bytes) { - return const_buffer_container_1( + return const_buffers_1( const_buffer(data, - N * sizeof(Pod_Type) < max_size_in_bytes - ? N * sizeof(Pod_Type) : max_size_in_bytes)); + N * sizeof(PodType) < max_size_in_bytes + ? N * sizeof(PodType) : max_size_in_bytes)); } -#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) // Borland C++ thinks the overloads: // -// unspecified buffer(boost::array& array ...); +// unspecified buffer(boost::array& array ...); // // and // -// unspecified buffer(boost::array& array ...); +// unspecified buffer(boost::array& array ...); // // are ambiguous. This will be worked around by using a buffer_types traits // class that contains typedefs for the appropriate buffer and container -// classes, based on whether Pod_Type is const or non-const. +// classes, based on whether PodType is const or non-const. namespace detail { @@ -446,109 +557,109 @@ template <> struct buffer_types_base { typedef mutable_buffer buffer_type; - typedef mutable_buffer_container_1 container_type; + typedef mutable_buffers_1 container_type; }; template <> struct buffer_types_base { typedef const_buffer buffer_type; - typedef const_buffer_container_1 container_type; + typedef const_buffers_1 container_type; }; -template +template struct buffer_types - : public buffer_types_base::value> + : public buffer_types_base::value> { }; } // namespace detail -template -inline typename detail::buffer_types::container_type -buffer(boost::array& data) +template +inline typename detail::buffer_types::container_type +buffer(boost::array& data) { - typedef typename asio::detail::buffer_types::buffer_type + typedef typename asio::detail::buffer_types::buffer_type buffer_type; - typedef typename asio::detail::buffer_types::container_type + typedef typename asio::detail::buffer_types::container_type container_type; return container_type( - buffer_type(data.c_array(), data.size() * sizeof(Pod_Type))); + buffer_type(data.c_array(), data.size() * sizeof(PodType))); } -template -inline typename detail::buffer_types::container_type -buffer(boost::array& data, std::size_t max_size_in_bytes) +template +inline typename detail::buffer_types::container_type +buffer(boost::array& data, std::size_t max_size_in_bytes) { - typedef typename asio::detail::buffer_types::buffer_type + typedef typename asio::detail::buffer_types::buffer_type buffer_type; - typedef typename asio::detail::buffer_types::container_type + typedef typename asio::detail::buffer_types::container_type container_type; return container_type( buffer_type(data.c_array(), - data.size() * sizeof(Pod_Type) < max_size_in_bytes - ? data.size() * sizeof(Pod_Type) : max_size_in_bytes)); + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes)); } -#else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +#else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) /// Create a new modifiable buffer that represents the given POD array. -template -inline mutable_buffer_container_1 buffer(boost::array& data) +template +inline mutable_buffers_1 buffer(boost::array& data) { - return mutable_buffer_container_1( - mutable_buffer(data.c_array(), data.size() * sizeof(Pod_Type))); + return mutable_buffers_1( + mutable_buffer(data.c_array(), data.size() * sizeof(PodType))); } /// Create a new modifiable buffer that represents the given POD array. -template -inline mutable_buffer_container_1 buffer(boost::array& data, +template +inline mutable_buffers_1 buffer(boost::array& data, std::size_t max_size_in_bytes) { - return mutable_buffer_container_1( + return mutable_buffers_1( mutable_buffer(data.c_array(), - data.size() * sizeof(Pod_Type) < max_size_in_bytes - ? data.size() * sizeof(Pod_Type) : max_size_in_bytes)); + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes)); } /// Create a new non-modifiable buffer that represents the given POD array. -template -inline const_buffer_container_1 buffer(boost::array& data) +template +inline const_buffers_1 buffer(boost::array& data) { - return const_buffer_container_1( - const_buffer(data.data(), data.size() * sizeof(Pod_Type))); + return const_buffers_1( + const_buffer(data.data(), data.size() * sizeof(PodType))); } /// Create a new non-modifiable buffer that represents the given POD array. -template -inline const_buffer_container_1 buffer(boost::array& data, +template +inline const_buffers_1 buffer(boost::array& data, std::size_t max_size_in_bytes) { - return const_buffer_container_1( + return const_buffers_1( const_buffer(data.data(), - data.size() * sizeof(Pod_Type) < max_size_in_bytes - ? data.size() * sizeof(Pod_Type) : max_size_in_bytes)); + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes)); } -#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) /// Create a new non-modifiable buffer that represents the given POD array. -template -inline const_buffer_container_1 buffer(const boost::array& data) +template +inline const_buffers_1 buffer(const boost::array& data) { - return const_buffer_container_1( - const_buffer(data.data(), data.size() * sizeof(Pod_Type))); + return const_buffers_1( + const_buffer(data.data(), data.size() * sizeof(PodType))); } /// Create a new non-modifiable buffer that represents the given POD array. -template -inline const_buffer_container_1 buffer(const boost::array& data, +template +inline const_buffers_1 buffer(const boost::array& data, std::size_t max_size_in_bytes) { - return const_buffer_container_1( + return const_buffers_1( const_buffer(data.data(), - data.size() * sizeof(Pod_Type) < max_size_in_bytes - ? data.size() * sizeof(Pod_Type) : max_size_in_bytes)); + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes)); } /// Create a new modifiable buffer that represents the given POD vector. @@ -556,11 +667,17 @@ inline const_buffer_container_1 buffer(const boost::array& data, * @note The buffer is invalidated by any vector operation that would also * invalidate iterators. */ -template -inline mutable_buffer_container_1 buffer(std::vector& data) +template +inline mutable_buffers_1 buffer(std::vector& data) { - return mutable_buffer_container_1( - mutable_buffer(&data[0], data.size() * sizeof(Pod_Type))); + return mutable_buffers_1( + mutable_buffer(&data[0], data.size() * sizeof(PodType) +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::vector::iterator + >(data.begin()) +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + )); } /// Create a new modifiable buffer that represents the given POD vector. @@ -568,14 +685,20 @@ inline mutable_buffer_container_1 buffer(std::vector& data) * @note The buffer is invalidated by any vector operation that would also * invalidate iterators. */ -template -inline mutable_buffer_container_1 buffer(std::vector& data, +template +inline mutable_buffers_1 buffer(std::vector& data, std::size_t max_size_in_bytes) { - return mutable_buffer_container_1( + return mutable_buffers_1( mutable_buffer(&data[0], - data.size() * sizeof(Pod_Type) < max_size_in_bytes - ? data.size() * sizeof(Pod_Type) : max_size_in_bytes)); + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::vector::iterator + >(data.begin()) +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + )); } /// Create a new non-modifiable buffer that represents the given POD vector. @@ -583,12 +706,18 @@ inline mutable_buffer_container_1 buffer(std::vector& data, * @note The buffer is invalidated by any vector operation that would also * invalidate iterators. */ -template -inline const_buffer_container_1 buffer( - const std::vector& data) +template +inline const_buffers_1 buffer( + const std::vector& data) { - return const_buffer_container_1( - const_buffer(&data[0], data.size() * sizeof(Pod_Type))); + return const_buffers_1( + const_buffer(&data[0], data.size() * sizeof(PodType) +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::vector::const_iterator + >(data.begin()) +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + )); } /// Create a new non-modifiable buffer that represents the given POD vector. @@ -596,14 +725,20 @@ inline const_buffer_container_1 buffer( * @note The buffer is invalidated by any vector operation that would also * invalidate iterators. */ -template -inline const_buffer_container_1 buffer( - const std::vector& data, std::size_t max_size_in_bytes) +template +inline const_buffers_1 buffer( + const std::vector& data, std::size_t max_size_in_bytes) { - return const_buffer_container_1( + return const_buffers_1( const_buffer(&data[0], - data.size() * sizeof(Pod_Type) < max_size_in_bytes - ? data.size() * sizeof(Pod_Type) : max_size_in_bytes)); + data.size() * sizeof(PodType) < max_size_in_bytes + ? data.size() * sizeof(PodType) : max_size_in_bytes +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check< + typename std::vector::const_iterator + >(data.begin()) +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + )); } /// Create a new non-modifiable buffer that represents the given string. @@ -611,9 +746,13 @@ inline const_buffer_container_1 buffer( * @note The buffer is invalidated by any non-const operation called on the * given string object. */ -inline const_buffer_container_1 buffer(const std::string& data) +inline const_buffers_1 buffer(const std::string& data) { - return const_buffer_container_1(const_buffer(data.data(), data.size())); + return const_buffers_1(const_buffer(data.data(), data.size() +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check(data.begin()) +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + )); } /// Create a new non-modifiable buffer that represents the given string. @@ -621,13 +760,17 @@ inline const_buffer_container_1 buffer(const std::string& data) * @note The buffer is invalidated by any non-const operation called on the * given string object. */ -inline const_buffer_container_1 buffer(const std::string& data, +inline const_buffers_1 buffer(const std::string& data, std::size_t max_size_in_bytes) { - return const_buffer_container_1( + return const_buffers_1( const_buffer(data.data(), data.size() < max_size_in_bytes - ? data.size() : max_size_in_bytes)); + ? data.size() : max_size_in_bytes +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + , detail::buffer_debug_check(data.begin()) +#endif // ASIO_ENABLE_BUFFER_DEBUGGING + )); } /*@}*/ diff --git a/libtorrent/include/libtorrent/asio/buffered_read_stream.hpp b/libtorrent/include/libtorrent/asio/buffered_read_stream.hpp index 6260d22a0..5cf5d688e 100644 --- a/libtorrent/include/libtorrent/asio/buffered_read_stream.hpp +++ b/libtorrent/include/libtorrent/asio/buffered_read_stream.hpp @@ -2,7 +2,7 @@ // buffered_read_stream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -40,13 +40,12 @@ namespace asio { * The buffered_read_stream class template can be used to add buffering to the * synchronous and asynchronous read operations of a stream. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * * @par Concepts: - * Async_Object, Async_Read_Stream, Async_Write_Stream, Error_Source, Stream, - * Sync_Read_Stream, Sync_Write_Stream. + * AsyncReadStream, AsyncWriteStream, Stream, Sync_Read_Stream, SyncWriteStream. */ template class buffered_read_stream @@ -59,9 +58,6 @@ public: /// The type of the lowest layer. typedef typename next_layer_type::lowest_layer_type lowest_layer_type; - /// The type used for reporting errors. - typedef typename next_layer_type::error_type error_type; - #if defined(GENERATING_DOCUMENTATION) /// The default buffer size. static const std::size_t default_buffer_size = implementation_defined; @@ -110,33 +106,33 @@ public: } /// Close the stream. - template - void close(Error_Handler error_handler) + asio::error_code close(asio::error_code& ec) { - next_layer_.close(error_handler); + return next_layer_.close(ec); } /// Write the given data to the stream. Returns the number of bytes written. /// Throws an exception on failure. - template - std::size_t write_some(const Const_Buffers& buffers) + template + std::size_t write_some(const ConstBufferSequence& buffers) { return next_layer_.write_some(buffers); } /// Write the given data to the stream. Returns the number of bytes written, - /// or 0 if an error occurred and the error handler did not throw. - template - std::size_t write_some(const Const_Buffers& buffers, - Error_Handler error_handler) + /// or 0 if an error occurred. + template + std::size_t write_some(const ConstBufferSequence& buffers, + asio::error_code& ec) { - return next_layer_.write_some(buffers, error_handler); + return next_layer_.write_some(buffers, ec); } /// Start an asynchronous write. The data being written must be valid for the /// lifetime of the asynchronous operation. - template - void async_write_some(const Const_Buffers& buffers, Handler handler) + template + void async_write_some(const ConstBufferSequence& buffers, + WriteHandler handler) { next_layer_.async_write_some(buffers, handler); } @@ -157,10 +153,8 @@ public: } /// Fill the buffer with some data. Returns the number of bytes placed in the - /// buffer as a result of the operation, or 0 if an error occurred and the - /// error handler did not throw. - template - std::size_t fill(Error_Handler error_handler) + /// buffer as a result of the operation, or 0 if an error occurred. + std::size_t fill(asio::error_code& ec) { detail::buffer_resize_guard resize_guard(storage_); @@ -169,18 +163,18 @@ public: storage_.resize(previous_size + next_layer_.read_some(buffer( storage_.data() + previous_size, storage_.size() - previous_size), - error_handler)); + ec)); resize_guard.commit(); return storage_.size() - previous_size; } - template + template class fill_handler { public: fill_handler(asio::io_service& io_service, detail::buffered_stream_storage& storage, - std::size_t previous_size, Handler handler) + std::size_t previous_size, ReadHandler handler) : io_service_(io_service), storage_(storage), previous_size_(previous_size), @@ -188,24 +182,24 @@ public: { } - template - void operator()(const Error& e, std::size_t bytes_transferred) + void operator()(const asio::error_code& ec, + std::size_t bytes_transferred) { storage_.resize(previous_size_ + bytes_transferred); io_service_.dispatch(detail::bind_handler( - handler_, e, bytes_transferred)); + handler_, ec, bytes_transferred)); } private: asio::io_service& io_service_; detail::buffered_stream_storage& storage_; std::size_t previous_size_; - Handler handler_; + ReadHandler handler_; }; /// Start an asynchronous fill. - template - void async_fill(Handler handler) + template + void async_fill(ReadHandler handler) { std::size_t previous_size = storage_.size(); storage_.resize(storage_.capacity()); @@ -213,13 +207,14 @@ public: buffer( storage_.data() + previous_size, storage_.size() - previous_size), - fill_handler(io_service(), storage_, previous_size, handler)); + fill_handler(io_service(), + storage_, previous_size, handler)); } /// Read some data from the stream. Returns the number of bytes read. Throws /// an exception on failure. - template - std::size_t read_some(const Mutable_Buffers& buffers) + template + std::size_t read_some(const MutableBufferSequence& buffers) { if (storage_.empty()) fill(); @@ -227,23 +222,24 @@ public: } /// Read some data from the stream. Returns the number of bytes read or 0 if - /// an error occurred and the error handler did not throw an exception. - template - std::size_t read_some(const Mutable_Buffers& buffers, - Error_Handler error_handler) + /// an error occurred. + template + std::size_t read_some(const MutableBufferSequence& buffers, + asio::error_code& ec) { - if (storage_.empty() && !fill(error_handler)) + ec = asio::error_code(); + if (storage_.empty() && !fill(ec)) return 0; return copy(buffers); } - template + template class read_some_handler { public: read_some_handler(asio::io_service& io_service, detail::buffered_stream_storage& storage, - const Mutable_Buffers& buffers, Handler handler) + const MutableBufferSequence& buffers, ReadHandler handler) : io_service_(io_service), storage_(storage), buffers_(buffers), @@ -251,12 +247,12 @@ public: { } - void operator()(const error_type& e, std::size_t) + void operator()(const asio::error_code& ec, std::size_t) { - if (e || storage_.empty()) + if (ec || storage_.empty()) { std::size_t length = 0; - io_service_.dispatch(detail::bind_handler(handler_, e, length)); + io_service_.dispatch(detail::bind_handler(handler_, ec, length)); } else { @@ -265,8 +261,8 @@ public: std::size_t bytes_avail = storage_.size(); std::size_t bytes_copied = 0; - typename Mutable_Buffers::const_iterator iter = buffers_.begin(); - typename Mutable_Buffers::const_iterator end = buffers_.end(); + typename MutableBufferSequence::const_iterator iter = buffers_.begin(); + typename MutableBufferSequence::const_iterator end = buffers_.end(); for (; iter != end && bytes_avail > 0; ++iter) { std::size_t max_length = buffer_size(*iter); @@ -279,38 +275,40 @@ public: } storage_.consume(bytes_copied); - io_service_.dispatch(detail::bind_handler(handler_, e, bytes_copied)); + io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_copied)); } } private: asio::io_service& io_service_; detail::buffered_stream_storage& storage_; - Mutable_Buffers buffers_; - Handler handler_; + MutableBufferSequence buffers_; + ReadHandler handler_; }; /// Start an asynchronous read. The buffer into which the data will be read /// must be valid for the lifetime of the asynchronous operation. - template - void async_read_some(const Mutable_Buffers& buffers, Handler handler) + template + void async_read_some(const MutableBufferSequence& buffers, + ReadHandler handler) { if (storage_.empty()) { - async_fill(read_some_handler( + async_fill(read_some_handler( io_service(), storage_, buffers, handler)); } else { std::size_t length = copy(buffers); - io_service().post(detail::bind_handler(handler, 0, length)); + io_service().post(detail::bind_handler( + handler, asio::error_code(), length)); } } /// Peek at the incoming data on the stream. Returns the number of bytes read. /// Throws an exception on failure. - template - std::size_t peek(const Mutable_Buffers& buffers) + template + std::size_t peek(const MutableBufferSequence& buffers) { if (storage_.empty()) fill(); @@ -318,11 +316,13 @@ public: } /// Peek at the incoming data on the stream. Returns the number of bytes read, - /// or 0 if an error occurred and the error handler did not throw. - template - std::size_t peek(const Mutable_Buffers& buffers, Error_Handler error_handler) + /// or 0 if an error occurred. + template + std::size_t peek(const MutableBufferSequence& buffers, + asio::error_code& ec) { - if (storage_.empty() && !fill(error_handler)) + ec = asio::error_code(); + if (storage_.empty() && !fill(ec)) return 0; return peek_copy(buffers); } @@ -334,25 +334,25 @@ public: } /// Determine the amount of data that may be read without blocking. - template - std::size_t in_avail(Error_Handler error_handler) + std::size_t in_avail(asio::error_code& ec) { + ec = asio::error_code(); return storage_.size(); } private: /// Copy data out of the internal buffer to the specified target buffer. /// Returns the number of bytes copied. - template - std::size_t copy(const Mutable_Buffers& buffers) + template + std::size_t copy(const MutableBufferSequence& buffers) { using namespace std; // For memcpy. std::size_t bytes_avail = storage_.size(); std::size_t bytes_copied = 0; - typename Mutable_Buffers::const_iterator iter = buffers.begin(); - typename Mutable_Buffers::const_iterator end = buffers.end(); + typename MutableBufferSequence::const_iterator iter = buffers.begin(); + typename MutableBufferSequence::const_iterator end = buffers.end(); for (; iter != end && bytes_avail > 0; ++iter) { std::size_t max_length = buffer_size(*iter); @@ -370,16 +370,16 @@ private: /// Copy data from the internal buffer to the specified target buffer, without /// removing the data from the internal buffer. Returns the number of bytes /// copied. - template - std::size_t peek_copy(const Mutable_Buffers& buffers) + template + std::size_t peek_copy(const MutableBufferSequence& buffers) { using namespace std; // For memcpy. std::size_t bytes_avail = storage_.size(); std::size_t bytes_copied = 0; - typename Mutable_Buffers::const_iterator iter = buffers.begin(); - typename Mutable_Buffers::const_iterator end = buffers.end(); + typename MutableBufferSequence::const_iterator iter = buffers.begin(); + typename MutableBufferSequence::const_iterator end = buffers.end(); for (; iter != end && bytes_avail > 0; ++iter) { std::size_t max_length = buffer_size(*iter); diff --git a/libtorrent/include/libtorrent/asio/buffered_read_stream_fwd.hpp b/libtorrent/include/libtorrent/asio/buffered_read_stream_fwd.hpp index 7cdf04bcf..df4270366 100644 --- a/libtorrent/include/libtorrent/asio/buffered_read_stream_fwd.hpp +++ b/libtorrent/include/libtorrent/asio/buffered_read_stream_fwd.hpp @@ -2,7 +2,7 @@ // buffered_read_stream_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/buffered_stream.hpp b/libtorrent/include/libtorrent/asio/buffered_stream.hpp index 1948fef09..b6901a6d4 100644 --- a/libtorrent/include/libtorrent/asio/buffered_stream.hpp +++ b/libtorrent/include/libtorrent/asio/buffered_stream.hpp @@ -2,7 +2,7 @@ // buffered_stream.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -36,13 +36,12 @@ namespace asio { * The buffered_stream class template can be used to add buffering to the * synchronous and asynchronous read and write operations of a stream. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * * @par Concepts: - * Async_Object, Async_Read_Stream, Async_Write_Stream, Error_Source, Stream, - * Sync_Read_Stream, Sync_Write_Stream. + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. */ template class buffered_stream @@ -55,9 +54,6 @@ public: /// The type of the lowest layer. typedef typename next_layer_type::lowest_layer_type lowest_layer_type; - /// The type used for reporting errors. - typedef typename next_layer_type::error_type error_type; - /// Construct, passing the specified argument to initialise the next layer. template explicit buffered_stream(Arg& a) @@ -100,10 +96,9 @@ public: } /// Close the stream. - template - void close(Error_Handler error_handler) + asio::error_code close(asio::error_code& ec) { - stream_impl_.close(error_handler); + return stream_impl_.close(ec); } /// Flush all data from the buffer to the next layer. Returns the number of @@ -116,41 +111,41 @@ public: /// Flush all data from the buffer to the next layer. Returns the number of /// bytes written to the next layer on the last write operation, or 0 if an - /// error occurred and the error handler did not throw. - template - std::size_t flush(Error_Handler error_handler) + /// error occurred. + std::size_t flush(asio::error_code& ec) { - return stream_impl_.next_layer().flush(error_handler); + return stream_impl_.next_layer().flush(ec); } /// Start an asynchronous flush. - template - void async_flush(Handler handler) + template + void async_flush(WriteHandler handler) { return stream_impl_.next_layer().async_flush(handler); } /// Write the given data to the stream. Returns the number of bytes written. /// Throws an exception on failure. - template - std::size_t write_some(const Const_Buffers& buffers) + template + std::size_t write_some(const ConstBufferSequence& buffers) { return stream_impl_.write_some(buffers); } /// Write the given data to the stream. Returns the number of bytes written, - /// or 0 if an error occurred and the error handler did not throw. - template - std::size_t write_some(const Const_Buffers& buffers, - Error_Handler error_handler) + /// or 0 if an error occurred. + template + std::size_t write_some(const ConstBufferSequence& buffers, + asio::error_code& ec) { - return stream_impl_.write_some(buffers, error_handler); + return stream_impl_.write_some(buffers, ec); } /// Start an asynchronous write. The data being written must be valid for the /// lifetime of the asynchronous operation. - template - void async_write_some(const Const_Buffers& buffers, Handler handler) + template + void async_write_some(const ConstBufferSequence& buffers, + WriteHandler handler) { stream_impl_.async_write_some(buffers, handler); } @@ -163,60 +158,60 @@ public: } /// Fill the buffer with some data. Returns the number of bytes placed in the - /// buffer as a result of the operation, or 0 if an error occurred and the - /// error handler did not throw. - template - std::size_t fill(Error_Handler error_handler) + /// buffer as a result of the operation, or 0 if an error occurred. + std::size_t fill(asio::error_code& ec) { - return stream_impl_.fill(error_handler); + return stream_impl_.fill(ec); } /// Start an asynchronous fill. - template - void async_fill(Handler handler) + template + void async_fill(ReadHandler handler) { stream_impl_.async_fill(handler); } /// Read some data from the stream. Returns the number of bytes read. Throws /// an exception on failure. - template - std::size_t read_some(const Mutable_Buffers& buffers) + template + std::size_t read_some(const MutableBufferSequence& buffers) { return stream_impl_.read_some(buffers); } /// Read some data from the stream. Returns the number of bytes read or 0 if - /// an error occurred and the error handler did not throw an exception. - template - std::size_t read_some(const Mutable_Buffers& buffers, - Error_Handler error_handler) + /// an error occurred. + template + std::size_t read_some(const MutableBufferSequence& buffers, + asio::error_code& ec) { - return stream_impl_.read_some(buffers, error_handler); + return stream_impl_.read_some(buffers, ec); } /// Start an asynchronous read. The buffer into which the data will be read /// must be valid for the lifetime of the asynchronous operation. - template - void async_read_some(const Mutable_Buffers& buffers, Handler handler) + template + void async_read_some(const MutableBufferSequence& buffers, + ReadHandler handler) { stream_impl_.async_read_some(buffers, handler); } /// Peek at the incoming data on the stream. Returns the number of bytes read. /// Throws an exception on failure. - template - std::size_t peek(const Mutable_Buffers& buffers) + template + std::size_t peek(const MutableBufferSequence& buffers) { return stream_impl_.peek(buffers); } /// Peek at the incoming data on the stream. Returns the number of bytes read, - /// or 0 if an error occurred and the error handler did not throw. - template - std::size_t peek(const Mutable_Buffers& buffers, Error_Handler error_handler) + /// or 0 if an error occurred. + template + std::size_t peek(const MutableBufferSequence& buffers, + asio::error_code& ec) { - return stream_impl_.peek(buffers, error_handler); + return stream_impl_.peek(buffers, ec); } /// Determine the amount of data that may be read without blocking. @@ -226,10 +221,9 @@ public: } /// Determine the amount of data that may be read without blocking. - template - std::size_t in_avail(Error_Handler error_handler) + std::size_t in_avail(asio::error_code& ec) { - return stream_impl_.in_avail(error_handler); + return stream_impl_.in_avail(ec); } private: diff --git a/libtorrent/include/libtorrent/asio/buffered_stream_fwd.hpp b/libtorrent/include/libtorrent/asio/buffered_stream_fwd.hpp index 4590ae8e3..10d1c384e 100644 --- a/libtorrent/include/libtorrent/asio/buffered_stream_fwd.hpp +++ b/libtorrent/include/libtorrent/asio/buffered_stream_fwd.hpp @@ -2,7 +2,7 @@ // buffered_stream_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/buffered_write_stream.hpp b/libtorrent/include/libtorrent/asio/buffered_write_stream.hpp index d4bd49b92..ffe3a2ee7 100644 --- a/libtorrent/include/libtorrent/asio/buffered_write_stream.hpp +++ b/libtorrent/include/libtorrent/asio/buffered_write_stream.hpp @@ -2,7 +2,7 @@ // buffered_write_stream.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -41,13 +41,12 @@ namespace asio { * The buffered_write_stream class template can be used to add buffering to the * synchronous and asynchronous write operations of a stream. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * * @par Concepts: - * Async_Object, Async_Read_Stream, Async_Write_Stream, Error_Source, Stream, - * Sync_Read_Stream, Sync_Write_Stream. + * AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream. */ template class buffered_write_stream @@ -60,9 +59,6 @@ public: /// The type of the lowest layer. typedef typename next_layer_type::lowest_layer_type lowest_layer_type; - /// The type used for reporting errors. - typedef typename next_layer_type::error_type error_type; - #if defined(GENERATING_DOCUMENTATION) /// The default buffer size. static const std::size_t default_buffer_size = implementation_defined; @@ -111,10 +107,9 @@ public: } /// Close the stream. - template - void close(Error_Handler error_handler) + asio::error_code close(asio::error_code& ec) { - next_layer_.close(error_handler); + return next_layer_.close(ec); } /// Flush all data from the buffer to the next layer. Returns the number of @@ -130,53 +125,53 @@ public: /// Flush all data from the buffer to the next layer. Returns the number of /// bytes written to the next layer on the last write operation, or 0 if an - /// error occurred and the error handler did not throw. - template - std::size_t flush(Error_Handler error_handler) + /// error occurred. + std::size_t flush(asio::error_code& ec) { std::size_t bytes_written = write(next_layer_, buffer(storage_.data(), storage_.size()), - transfer_all(), error_handler); + transfer_all(), ec); storage_.consume(bytes_written); return bytes_written; } - template + template class flush_handler { public: flush_handler(asio::io_service& io_service, - detail::buffered_stream_storage& storage, Handler handler) + detail::buffered_stream_storage& storage, WriteHandler handler) : io_service_(io_service), storage_(storage), handler_(handler) { } - void operator()(const error_type& e, std::size_t bytes_written) + void operator()(const asio::error_code& ec, + std::size_t bytes_written) { storage_.consume(bytes_written); - io_service_.dispatch(detail::bind_handler(handler_, e, bytes_written)); + io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_written)); } private: asio::io_service& io_service_; detail::buffered_stream_storage& storage_; - Handler handler_; + WriteHandler handler_; }; /// Start an asynchronous flush. - template - void async_flush(Handler handler) + template + void async_flush(WriteHandler handler) { async_write(next_layer_, buffer(storage_.data(), storage_.size()), - flush_handler(io_service(), storage_, handler)); + flush_handler(io_service(), storage_, handler)); } /// Write the given data to the stream. Returns the number of bytes written. /// Throws an exception on failure. - template - std::size_t write_some(const Const_Buffers& buffers) + template + std::size_t write_some(const ConstBufferSequence& buffers) { if (storage_.size() == storage_.capacity()) flush(); @@ -185,22 +180,23 @@ public: /// Write the given data to the stream. Returns the number of bytes written, /// or 0 if an error occurred and the error handler did not throw. - template - std::size_t write_some(const Const_Buffers& buffers, - Error_Handler error_handler) + template + std::size_t write_some(const ConstBufferSequence& buffers, + asio::error_code& ec) { - if (storage_.size() == storage_.capacity() && !flush(error_handler)) + ec = asio::error_code(); + if (storage_.size() == storage_.capacity() && !flush(ec)) return 0; return copy(buffers); } - template + template class write_some_handler { public: write_some_handler(asio::io_service& io_service, detail::buffered_stream_storage& storage, - const Const_Buffers& buffers, Handler handler) + const ConstBufferSequence& buffers, WriteHandler handler) : io_service_(io_service), storage_(storage), buffers_(buffers), @@ -208,12 +204,12 @@ public: { } - void operator()(const error_type& e, std::size_t) + void operator()(const asio::error_code& ec, std::size_t) { - if (e) + if (ec) { std::size_t length = 0; - io_service_.dispatch(detail::bind_handler(handler_, e, length)); + io_service_.dispatch(detail::bind_handler(handler_, ec, length)); } else { @@ -223,8 +219,8 @@ public: std::size_t space_avail = storage_.capacity() - orig_size; std::size_t bytes_copied = 0; - typename Const_Buffers::const_iterator iter = buffers_.begin(); - typename Const_Buffers::const_iterator end = buffers_.end(); + typename ConstBufferSequence::const_iterator iter = buffers_.begin(); + typename ConstBufferSequence::const_iterator end = buffers_.end(); for (; iter != end && space_avail > 0; ++iter) { std::size_t bytes_avail = buffer_size(*iter); @@ -237,73 +233,77 @@ public: space_avail -= length; } - io_service_.dispatch(detail::bind_handler(handler_, e, bytes_copied)); + io_service_.dispatch(detail::bind_handler(handler_, ec, bytes_copied)); } } private: asio::io_service& io_service_; detail::buffered_stream_storage& storage_; - Const_Buffers buffers_; - Handler handler_; + ConstBufferSequence buffers_; + WriteHandler handler_; }; /// Start an asynchronous write. The data being written must be valid for the /// lifetime of the asynchronous operation. - template - void async_write_some(const Const_Buffers& buffers, Handler handler) + template + void async_write_some(const ConstBufferSequence& buffers, + WriteHandler handler) { if (storage_.size() == storage_.capacity()) { - async_flush(write_some_handler( + async_flush(write_some_handler( io_service(), storage_, buffers, handler)); } else { std::size_t bytes_copied = copy(buffers); - io_service().post(detail::bind_handler(handler, 0, bytes_copied)); + io_service().post(detail::bind_handler( + handler, asio::error_code(), bytes_copied)); } } /// Read some data from the stream. Returns the number of bytes read. Throws /// an exception on failure. - template - std::size_t read_some(const Mutable_Buffers& buffers) + template + std::size_t read_some(const MutableBufferSequence& buffers) { return next_layer_.read_some(buffers); } /// Read some data from the stream. Returns the number of bytes read or 0 if - /// an error occurred and the error handler did not throw an exception. - template - std::size_t read_some(const Mutable_Buffers& buffers, - Error_Handler error_handler) + /// an error occurred. + template + std::size_t read_some(const MutableBufferSequence& buffers, + asio::error_code& ec) { - return next_layer_.read_some(buffers, error_handler); + return next_layer_.read_some(buffers, ec); } /// Start an asynchronous read. The buffer into which the data will be read /// must be valid for the lifetime of the asynchronous operation. - template - void async_read_some(const Mutable_Buffers& buffers, Handler handler) + template + void async_read_some(const MutableBufferSequence& buffers, + ReadHandler handler) { next_layer_.async_read_some(buffers, handler); } /// Peek at the incoming data on the stream. Returns the number of bytes read. /// Throws an exception on failure. - template - std::size_t peek(const Mutable_Buffers& buffers) + template + std::size_t peek(const MutableBufferSequence& buffers) { return next_layer_.peek(buffers); } /// Peek at the incoming data on the stream. Returns the number of bytes read, - /// or 0 if an error occurred and the error handler did not throw. - template - std::size_t peek(const Mutable_Buffers& buffers, Error_Handler error_handler) + /// or 0 if an error occurred. + template + std::size_t peek(const MutableBufferSequence& buffers, + asio::error_code& ec) { - return next_layer_.peek(buffers, error_handler); + return next_layer_.peek(buffers, ec); } /// Determine the amount of data that may be read without blocking. @@ -313,17 +313,16 @@ public: } /// Determine the amount of data that may be read without blocking. - template - std::size_t in_avail(Error_Handler error_handler) + std::size_t in_avail(asio::error_code& ec) { - return next_layer_.in_avail(error_handler); + return next_layer_.in_avail(ec); } private: /// Copy data into the internal buffer from the specified source buffer. /// Returns the number of bytes copied. - template - std::size_t copy(const Const_Buffers& buffers) + template + std::size_t copy(const ConstBufferSequence& buffers) { using namespace std; // For memcpy. @@ -331,8 +330,8 @@ private: std::size_t space_avail = storage_.capacity() - orig_size; std::size_t bytes_copied = 0; - typename Const_Buffers::const_iterator iter = buffers.begin(); - typename Const_Buffers::const_iterator end = buffers.end(); + typename ConstBufferSequence::const_iterator iter = buffers.begin(); + typename ConstBufferSequence::const_iterator end = buffers.end(); for (; iter != end && space_avail > 0; ++iter) { std::size_t bytes_avail = buffer_size(*iter); diff --git a/libtorrent/include/libtorrent/asio/buffered_write_stream_fwd.hpp b/libtorrent/include/libtorrent/asio/buffered_write_stream_fwd.hpp index 6cabef816..84cf36e3a 100644 --- a/libtorrent/include/libtorrent/asio/buffered_write_stream_fwd.hpp +++ b/libtorrent/include/libtorrent/asio/buffered_write_stream_fwd.hpp @@ -2,7 +2,7 @@ // buffered_write_stream_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/completion_condition.hpp b/libtorrent/include/libtorrent/asio/completion_condition.hpp index 3f8f7b611..42696d599 100644 --- a/libtorrent/include/libtorrent/asio/completion_condition.hpp +++ b/libtorrent/include/libtorrent/asio/completion_condition.hpp @@ -2,7 +2,7 @@ // completion_condition.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/datagram_socket_service.hpp b/libtorrent/include/libtorrent/asio/datagram_socket_service.hpp index 77a3af42d..1f858de61 100644 --- a/libtorrent/include/libtorrent/asio/datagram_socket_service.hpp +++ b/libtorrent/include/libtorrent/asio/datagram_socket_service.hpp @@ -2,7 +2,7 @@ // datagram_socket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -22,10 +22,12 @@ #include #include "asio/detail/pop_options.hpp" +#include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/detail/epoll_reactor.hpp" #include "asio/detail/kqueue_reactor.hpp" #include "asio/detail/select_reactor.hpp" +#include "asio/detail/service_base.hpp" #include "asio/detail/reactive_socket_service.hpp" #include "asio/detail/win_iocp_socket_service.hpp" @@ -34,9 +36,18 @@ namespace asio { /// Default service implementation for a datagram socket. template class datagram_socket_service +#if defined(GENERATING_DOCUMENTATION) : public asio::io_service::service +#else + : public asio::detail::service_base > +#endif { public: +#if defined(GENERATING_DOCUMENTATION) + /// The unique service identifier. + static asio::io_service::id id; +#endif + /// The protocol type. typedef Protocol protocol_type; @@ -75,7 +86,8 @@ public: /// Construct a new datagram socket service for the specified io_service. explicit datagram_socket_service(asio::io_service& io_service) - : asio::io_service::service(io_service), + : asio::detail::service_base< + datagram_socket_service >(io_service), service_impl_(asio::use_service(io_service)) { } @@ -98,29 +110,35 @@ public: } // Open a new datagram socket implementation. - template - void open(implementation_type& impl, const protocol_type& protocol, - Error_Handler error_handler) + asio::error_code open(implementation_type& impl, + const protocol_type& protocol, asio::error_code& ec) { if (protocol.type() == SOCK_DGRAM) - service_impl_.open(impl, protocol, error_handler); + service_impl_.open(impl, protocol, ec); else - error_handler(asio::error(asio::error::invalid_argument)); + ec = asio::error::invalid_argument; + return ec; } /// Assign an existing native socket to a datagram socket. - template - void assign(implementation_type& impl, const protocol_type& protocol, - const native_type& native_socket, Error_Handler error_handler) + asio::error_code assign(implementation_type& impl, + const protocol_type& protocol, const native_type& native_socket, + asio::error_code& ec) { - service_impl_.assign(impl, protocol, native_socket, error_handler); + return service_impl_.assign(impl, protocol, native_socket, ec); + } + + /// Determine whether the socket is open. + bool is_open(const implementation_type& impl) const + { + return service_impl_.is_open(impl); } /// Close a datagram socket implementation. - template - void close(implementation_type& impl, Error_Handler error_handler) + asio::error_code close(implementation_type& impl, + asio::error_code& ec) { - service_impl_.close(impl, error_handler); + return service_impl_.close(impl, ec); } /// Get the native socket implementation. @@ -130,154 +148,161 @@ public: } /// Cancel all asynchronous operations associated with the socket. - template - void cancel(implementation_type& impl, Error_Handler error_handler) + asio::error_code cancel(implementation_type& impl, + asio::error_code& ec) { - service_impl_.cancel(impl, error_handler); + return service_impl_.cancel(impl, ec); + } + + /// Determine whether the socket is at the out-of-band data mark. + bool at_mark(const implementation_type& impl, + asio::error_code& ec) const + { + return service_impl_.at_mark(impl, ec); + } + + /// Determine the number of bytes available for reading. + std::size_t available(const implementation_type& impl, + asio::error_code& ec) const + { + return service_impl_.available(impl, ec); } // Bind the datagram socket to the specified local endpoint. - template - void bind(implementation_type& impl, const endpoint_type& endpoint, - Error_Handler error_handler) + asio::error_code bind(implementation_type& impl, + const endpoint_type& endpoint, asio::error_code& ec) { - service_impl_.bind(impl, endpoint, error_handler); + return service_impl_.bind(impl, endpoint, ec); } /// Connect the datagram socket to the specified endpoint. - template - void connect(implementation_type& impl, const endpoint_type& peer_endpoint, - Error_Handler error_handler) + asio::error_code connect(implementation_type& impl, + const endpoint_type& peer_endpoint, asio::error_code& ec) { - service_impl_.connect(impl, peer_endpoint, error_handler); + return service_impl_.connect(impl, peer_endpoint, ec); } /// Start an asynchronous connect. - template + template void async_connect(implementation_type& impl, - const endpoint_type& peer_endpoint, Handler handler) + const endpoint_type& peer_endpoint, ConnectHandler handler) { service_impl_.async_connect(impl, peer_endpoint, handler); } /// Set a socket option. - template - void set_option(implementation_type& impl, const Option& option, - Error_Handler error_handler) + template + asio::error_code set_option(implementation_type& impl, + const SettableSocketOption& option, asio::error_code& ec) { - service_impl_.set_option(impl, option, error_handler); + return service_impl_.set_option(impl, option, ec); } /// Get a socket option. - template - void get_option(const implementation_type& impl, Option& option, - Error_Handler error_handler) const + template + asio::error_code get_option(const implementation_type& impl, + GettableSocketOption& option, asio::error_code& ec) const { - service_impl_.get_option(impl, option, error_handler); + return service_impl_.get_option(impl, option, ec); } /// Perform an IO control command on the socket. - template - void io_control(implementation_type& impl, IO_Control_Command& command, - Error_Handler error_handler) + template + asio::error_code io_control(implementation_type& impl, + IoControlCommand& command, asio::error_code& ec) { - service_impl_.io_control(impl, command, error_handler); + return service_impl_.io_control(impl, command, ec); } /// Get the local endpoint. - template endpoint_type local_endpoint(const implementation_type& impl, - Error_Handler error_handler) const + asio::error_code& ec) const { - endpoint_type endpoint; - service_impl_.get_local_endpoint(impl, endpoint, error_handler); - return endpoint; + return service_impl_.local_endpoint(impl, ec); } /// Get the remote endpoint. - template endpoint_type remote_endpoint(const implementation_type& impl, - Error_Handler error_handler) const + asio::error_code& ec) const { - endpoint_type endpoint; - service_impl_.get_remote_endpoint(impl, endpoint, error_handler); - return endpoint; + return service_impl_.remote_endpoint(impl, ec); } /// Disable sends or receives on the socket. - template - void shutdown(implementation_type& impl, socket_base::shutdown_type what, - Error_Handler error_handler) + asio::error_code shutdown(implementation_type& impl, + socket_base::shutdown_type what, asio::error_code& ec) { - service_impl_.shutdown(impl, what, error_handler); + return service_impl_.shutdown(impl, what, ec); } /// Send the given data to the peer. - template - std::size_t send(implementation_type& impl, const Const_Buffers& buffers, - socket_base::message_flags flags, Error_Handler error_handler) + template + std::size_t send(implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) { - return service_impl_.send(impl, buffers, flags, error_handler); + return service_impl_.send(impl, buffers, flags, ec); } /// Start an asynchronous send. - template - void async_send(implementation_type& impl, const Const_Buffers& buffers, - socket_base::message_flags flags, Handler handler) + template + void async_send(implementation_type& impl, const ConstBufferSequence& buffers, + socket_base::message_flags flags, WriteHandler handler) { service_impl_.async_send(impl, buffers, flags, handler); } /// Send a datagram to the specified endpoint. - template - std::size_t send_to(implementation_type& impl, const Const_Buffers& buffers, - const endpoint_type& destination, socket_base::message_flags flags, - Error_Handler error_handler) + template + std::size_t send_to(implementation_type& impl, + const ConstBufferSequence& buffers, const endpoint_type& destination, + socket_base::message_flags flags, asio::error_code& ec) { - return service_impl_.send_to(impl, buffers, destination, flags, - error_handler); + return service_impl_.send_to(impl, buffers, destination, flags, ec); } /// Start an asynchronous send. - template - void async_send_to(implementation_type& impl, const Const_Buffers& buffers, - const endpoint_type& destination, socket_base::message_flags flags, - Handler handler) + template + void async_send_to(implementation_type& impl, + const ConstBufferSequence& buffers, const endpoint_type& destination, + socket_base::message_flags flags, WriteHandler handler) { service_impl_.async_send_to(impl, buffers, destination, flags, handler); } /// Receive some data from the peer. - template - std::size_t receive(implementation_type& impl, const Mutable_Buffers& buffers, - socket_base::message_flags flags, Error_Handler error_handler) + template + std::size_t receive(implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) { - return service_impl_.receive(impl, buffers, flags, error_handler); + return service_impl_.receive(impl, buffers, flags, ec); } /// Start an asynchronous receive. - template - void async_receive(implementation_type& impl, const Mutable_Buffers& buffers, - socket_base::message_flags flags, Handler handler) + template + void async_receive(implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, ReadHandler handler) { service_impl_.async_receive(impl, buffers, flags, handler); } /// Receive a datagram with the endpoint of the sender. - template + template std::size_t receive_from(implementation_type& impl, - const Mutable_Buffers& buffers, endpoint_type& sender_endpoint, - socket_base::message_flags flags, Error_Handler error_handler) + const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, + socket_base::message_flags flags, asio::error_code& ec) { return service_impl_.receive_from(impl, buffers, sender_endpoint, flags, - error_handler); + ec); } /// Start an asynchronous receive that will get the endpoint of the sender. - template + template void async_receive_from(implementation_type& impl, - const Mutable_Buffers& buffers, endpoint_type& sender_endpoint, - socket_base::message_flags flags, Handler handler) + const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, + socket_base::message_flags flags, ReadHandler handler) { service_impl_.async_receive_from(impl, buffers, sender_endpoint, flags, handler); diff --git a/libtorrent/include/libtorrent/asio/deadline_timer.hpp b/libtorrent/include/libtorrent/asio/deadline_timer.hpp index 7deafa60b..2079c5d61 100644 --- a/libtorrent/include/libtorrent/asio/deadline_timer.hpp +++ b/libtorrent/include/libtorrent/asio/deadline_timer.hpp @@ -2,7 +2,7 @@ // deadline_timer.hpp // ~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/deadline_timer_service.hpp b/libtorrent/include/libtorrent/asio/deadline_timer_service.hpp index 2415d9be6..17b97350b 100644 --- a/libtorrent/include/libtorrent/asio/deadline_timer_service.hpp +++ b/libtorrent/include/libtorrent/asio/deadline_timer_service.hpp @@ -2,7 +2,7 @@ // deadline_timer_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -28,18 +28,29 @@ #include "asio/detail/epoll_reactor.hpp" #include "asio/detail/kqueue_reactor.hpp" #include "asio/detail/select_reactor.hpp" +#include "asio/detail/service_base.hpp" namespace asio { /// Default service implementation for a timer. -template > +template > class deadline_timer_service +#if defined(GENERATING_DOCUMENTATION) : public asio::io_service::service +#else + : public asio::detail::service_base< + deadline_timer_service > +#endif { public: +#if defined(GENERATING_DOCUMENTATION) + /// The unique service identifier. + static asio::io_service::id id; +#endif + /// The time traits type. - typedef Time_Traits traits_type; + typedef TimeTraits traits_type; /// The time type. typedef typename traits_type::time_type time_type; @@ -73,7 +84,8 @@ public: /// Construct a new timer service for the specified io_service. explicit deadline_timer_service(asio::io_service& io_service) - : asio::io_service::service(io_service), + : asio::detail::service_base< + deadline_timer_service >(io_service), service_impl_(asio::use_service(io_service)) { } @@ -96,9 +108,9 @@ public: } /// Cancel any asynchronous wait operations associated with the timer. - std::size_t cancel(implementation_type& impl) + std::size_t cancel(implementation_type& impl, asio::error_code& ec) { - return service_impl_.cancel(impl); + return service_impl_.cancel(impl, ec); } /// Get the expiry time for the timer as an absolute time. @@ -109,9 +121,9 @@ public: /// Set the expiry time for the timer as an absolute time. std::size_t expires_at(implementation_type& impl, - const time_type& expiry_time) + const time_type& expiry_time, asio::error_code& ec) { - return service_impl_.expires_at(impl, expiry_time); + return service_impl_.expires_at(impl, expiry_time, ec); } /// Get the expiry time for the timer relative to now. @@ -122,20 +134,20 @@ public: /// Set the expiry time for the timer relative to now. std::size_t expires_from_now(implementation_type& impl, - const duration_type& expiry_time) + const duration_type& expiry_time, asio::error_code& ec) { - return service_impl_.expires_from_now(impl, expiry_time); + return service_impl_.expires_from_now(impl, expiry_time, ec); } // Perform a blocking wait on the timer. - void wait(implementation_type& impl) + void wait(implementation_type& impl, asio::error_code& ec) { - service_impl_.wait(impl); + service_impl_.wait(impl, ec); } // Start an asynchronous wait on the timer. - template - void async_wait(implementation_type& impl, Handler handler) + template + void async_wait(implementation_type& impl, WaitHandler handler) { service_impl_.async_wait(impl, handler); } diff --git a/libtorrent/include/libtorrent/asio/detail/bind_handler.hpp b/libtorrent/include/libtorrent/asio/detail/bind_handler.hpp index 59c2bcef2..497bcfcc2 100644 --- a/libtorrent/include/libtorrent/asio/detail/bind_handler.hpp +++ b/libtorrent/include/libtorrent/asio/detail/bind_handler.hpp @@ -2,7 +2,7 @@ // bind_handler.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/buffer_resize_guard.hpp b/libtorrent/include/libtorrent/asio/detail/buffer_resize_guard.hpp index d72753010..0dcbe6956 100644 --- a/libtorrent/include/libtorrent/asio/detail/buffer_resize_guard.hpp +++ b/libtorrent/include/libtorrent/asio/detail/buffer_resize_guard.hpp @@ -2,7 +2,7 @@ // buffer_resize_guard.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/buffered_stream_storage.hpp b/libtorrent/include/libtorrent/asio/detail/buffered_stream_storage.hpp index 17517f9b5..2a84d876d 100644 --- a/libtorrent/include/libtorrent/asio/detail/buffered_stream_storage.hpp +++ b/libtorrent/include/libtorrent/asio/detail/buffered_stream_storage.hpp @@ -2,7 +2,7 @@ // buffered_stream_storage.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/call_stack.hpp b/libtorrent/include/libtorrent/asio/detail/call_stack.hpp index 37256ee59..1373f46c7 100644 --- a/libtorrent/include/libtorrent/asio/detail/call_stack.hpp +++ b/libtorrent/include/libtorrent/asio/detail/call_stack.hpp @@ -2,7 +2,7 @@ // call_stack.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/const_buffers_iterator.hpp b/libtorrent/include/libtorrent/asio/detail/const_buffers_iterator.hpp index f48d2df85..964294865 100644 --- a/libtorrent/include/libtorrent/asio/detail/const_buffers_iterator.hpp +++ b/libtorrent/include/libtorrent/asio/detail/const_buffers_iterator.hpp @@ -2,7 +2,7 @@ // const_buffers_iterator.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -29,9 +29,9 @@ namespace asio { namespace detail { // A proxy iterator for a sub-range in a list of buffers. -template +template class const_buffers_iterator - : public boost::iterator_facade, + : public boost::iterator_facade, const char, boost::bidirectional_traversal_tag> { public: @@ -41,7 +41,8 @@ public: } // Create an iterator for the specified position. - const_buffers_iterator(const Const_Buffers& buffers, std::size_t position) + const_buffers_iterator(const ConstBufferSequence& buffers, + std::size_t position) : begin_(buffers.begin()), current_(buffers.begin()), end_(buffers.end()), @@ -107,7 +108,7 @@ private: return; } - typename Const_Buffers::const_iterator iter = current_; + typename ConstBufferSequence::const_iterator iter = current_; while (iter != begin_) { --iter; @@ -136,9 +137,9 @@ private: asio::const_buffer current_buffer_; std::size_t current_buffer_position_; - typename Const_Buffers::const_iterator begin_; - typename Const_Buffers::const_iterator current_; - typename Const_Buffers::const_iterator end_; + typename ConstBufferSequence::const_iterator begin_; + typename ConstBufferSequence::const_iterator current_; + typename ConstBufferSequence::const_iterator end_; std::size_t position_; }; diff --git a/libtorrent/include/libtorrent/asio/detail/consuming_buffers.hpp b/libtorrent/include/libtorrent/asio/detail/consuming_buffers.hpp index 7877f95f2..cbe38a926 100644 --- a/libtorrent/include/libtorrent/asio/detail/consuming_buffers.hpp +++ b/libtorrent/include/libtorrent/asio/detail/consuming_buffers.hpp @@ -2,7 +2,7 @@ // consuming_buffers.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -32,8 +32,7 @@ template class consuming_buffers_iterator : public boost::iterator_facade< consuming_buffers_iterator, - const Buffer, - boost::forward_traversal_tag> + const Buffer, boost::forward_traversal_tag> { public: // Default constructor creates an end iterator. @@ -47,23 +46,32 @@ public: consuming_buffers_iterator(bool at_end, const Buffer& first, Buffer_Iterator begin_remainder, Buffer_Iterator end_remainder) : at_end_(at_end), - first_(first), + first_(buffer(first, max_size)), begin_remainder_(begin_remainder), - end_remainder_(end_remainder) + end_remainder_(end_remainder), + offset_(0) { } private: friend class boost::iterator_core_access; + enum { max_size = 65536 }; + void increment() { if (!at_end_) { - if (begin_remainder_ == end_remainder_) + if (begin_remainder_ == end_remainder_ + || offset_ + buffer_size(first_) >= max_size) + { at_end_ = true; + } else - first_ = *begin_remainder_++; + { + offset_ += buffer_size(first_); + first_ = buffer(*begin_remainder_++, max_size - offset_); + } } } @@ -88,6 +96,7 @@ private: Buffer first_; Buffer_Iterator begin_remainder_; Buffer_Iterator end_remainder_; + std::size_t offset_; }; // A proxy for a sub-range in a list of buffers. diff --git a/libtorrent/include/libtorrent/asio/detail/deadline_timer_service.hpp b/libtorrent/include/libtorrent/asio/detail/deadline_timer_service.hpp index c5d15a5df..c22c5a7b7 100644 --- a/libtorrent/include/libtorrent/asio/detail/deadline_timer_service.hpp +++ b/libtorrent/include/libtorrent/asio/detail/deadline_timer_service.hpp @@ -2,7 +2,7 @@ // deadline_timer_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -27,6 +27,7 @@ #include "asio/io_service.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/noncopyable.hpp" +#include "asio/detail/service_base.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/timer_queue.hpp" @@ -36,7 +37,8 @@ namespace detail { template class deadline_timer_service - : public asio::io_service::service + : public asio::detail::service_base< + deadline_timer_service > { public: // The time type. @@ -56,12 +58,19 @@ public: // Constructor. deadline_timer_service(asio::io_service& io_service) - : asio::io_service::service(io_service), + : asio::detail::service_base< + deadline_timer_service >(io_service), scheduler_(asio::use_service(io_service)) { scheduler_.add_timer_queue(timer_queue_); } + // Destructor. + ~deadline_timer_service() + { + scheduler_.remove_timer_queue(timer_queue_); + } + // Destroy all user-defined handler objects owned by the service. void shutdown_service() { @@ -77,16 +86,21 @@ public: // Destroy a timer implementation. void destroy(implementation_type& impl) { - cancel(impl); + asio::error_code ec; + cancel(impl, ec); } // Cancel any asynchronous wait operations associated with the timer. - std::size_t cancel(implementation_type& impl) + std::size_t cancel(implementation_type& impl, asio::error_code& ec) { if (!impl.might_have_pending_waits) + { + ec = asio::error_code(); return 0; + } std::size_t count = scheduler_.cancel_timer(timer_queue_, &impl); impl.might_have_pending_waits = false; + ec = asio::error_code(); return count; } @@ -98,10 +112,11 @@ public: // Set the expiry time for the timer as an absolute time. std::size_t expires_at(implementation_type& impl, - const time_type& expiry_time) + const time_type& expiry_time, asio::error_code& ec) { - std::size_t count = cancel(impl); + std::size_t count = cancel(impl, ec); impl.expiry = expiry_time; + ec = asio::error_code(); return count; } @@ -113,13 +128,14 @@ public: // Set the expiry time for the timer relative to now. std::size_t expires_from_now(implementation_type& impl, - const duration_type& expiry_time) + const duration_type& expiry_time, asio::error_code& ec) { - return expires_at(impl, Time_Traits::add(Time_Traits::now(), expiry_time)); + return expires_at(impl, + Time_Traits::add(Time_Traits::now(), expiry_time), ec); } // Perform a blocking wait on the timer. - void wait(implementation_type& impl) + void wait(implementation_type& impl, asio::error_code& ec) { time_type now = Time_Traits::now(); while (Time_Traits::less_than(now, impl.expiry)) @@ -129,9 +145,11 @@ public: ::timeval tv; tv.tv_sec = timeout.total_seconds(); tv.tv_usec = timeout.total_microseconds() % 1000000; - socket_ops::select(0, 0, 0, 0, &tv); + asio::error_code ec; + socket_ops::select(0, 0, 0, 0, &tv, ec); now = Time_Traits::now(); } + ec = asio::error_code(); } template @@ -145,10 +163,9 @@ public: { } - void operator()(int result) + void operator()(const asio::error_code& result) { - asio::error e(result); - io_service_.post(detail::bind_handler(handler_, e)); + io_service_.post(detail::bind_handler(handler_, result)); } private: @@ -163,7 +180,7 @@ public: { impl.might_have_pending_waits = true; scheduler_.schedule_timer(timer_queue_, impl.expiry, - wait_handler(io_service(), handler), &impl); + wait_handler(this->io_service(), handler), &impl); } private: diff --git a/libtorrent/include/libtorrent/asio/detail/epoll_reactor.hpp b/libtorrent/include/libtorrent/asio/detail/epoll_reactor.hpp index 5f46a93ba..d55e86454 100644 --- a/libtorrent/include/libtorrent/asio/detail/epoll_reactor.hpp +++ b/libtorrent/include/libtorrent/asio/detail/epoll_reactor.hpp @@ -2,7 +2,7 @@ // epoll_reactor.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -30,8 +30,9 @@ #include #include "asio/detail/pop_options.hpp" +#include "asio/error.hpp" #include "asio/io_service.hpp" -#include "asio/system_exception.hpp" +#include "asio/system_error.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/hash_map.hpp" #include "asio/detail/mutex.hpp" @@ -39,6 +40,7 @@ #include "asio/detail/thread.hpp" #include "asio/detail/reactor_op_queue.hpp" #include "asio/detail/select_interrupter.hpp" +#include "asio/detail/service_base.hpp" #include "asio/detail/signal_blocker.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/timer_queue.hpp" @@ -48,12 +50,12 @@ namespace detail { template class epoll_reactor - : public asio::io_service::service + : public asio::detail::service_base > { public: // Constructor. epoll_reactor(asio::io_service& io_service) - : asio::io_service::service(io_service), + : asio::detail::service_base >(io_service), mutex_(), epoll_fd_(do_epoll_create()), wait_in_progress_(false), @@ -139,7 +141,7 @@ public: return; if (!read_op_queue_.has_operation(descriptor)) - if (handler(0)) + if (handler(asio::error_code())) return; if (read_op_queue_.enqueue_operation(descriptor, handler)) @@ -155,8 +157,8 @@ public: int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); if (result != 0) { - int error = errno; - read_op_queue_.dispatch_all_operations(descriptor, error); + asio::error_code ec(errno, asio::native_ecat); + read_op_queue_.dispatch_all_operations(descriptor, ec); } } } @@ -172,7 +174,7 @@ public: return; if (!write_op_queue_.has_operation(descriptor)) - if (handler(0)) + if (handler(asio::error_code())) return; if (write_op_queue_.enqueue_operation(descriptor, handler)) @@ -188,8 +190,8 @@ public: int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); if (result != 0) { - int error = errno; - write_op_queue_.dispatch_all_operations(descriptor, error); + asio::error_code ec(errno, asio::native_ecat); + write_op_queue_.dispatch_all_operations(descriptor, ec); } } } @@ -217,8 +219,8 @@ public: int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); if (result != 0) { - int error = errno; - except_op_queue_.dispatch_all_operations(descriptor, error); + asio::error_code ec(errno, asio::native_ecat); + except_op_queue_.dispatch_all_operations(descriptor, ec); } } } @@ -248,9 +250,9 @@ public: int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); if (result != 0) { - int error = errno; - write_op_queue_.dispatch_all_operations(descriptor, error); - except_op_queue_.dispatch_all_operations(descriptor, error); + asio::error_code ec(errno, asio::native_ecat); + write_op_queue_.dispatch_all_operations(descriptor, ec); + except_op_queue_.dispatch_all_operations(descriptor, ec); } } } @@ -296,6 +298,21 @@ public: timer_queues_.push_back(&timer_queue); } + // Remove a timer queue from the reactor. + template + void remove_timer_queue(timer_queue& timer_queue) + { + asio::detail::mutex::scoped_lock lock(mutex_); + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + if (timer_queues_[i] == &timer_queue) + { + timer_queues_.erase(timer_queues_.begin() + i); + return; + } + } + } + // Schedule a timer in the given timer queue to expire at the specified // absolute time. The handler object will be invoked when the timer expires. template @@ -383,9 +400,10 @@ private: { if (events[i].events & (EPOLLERR | EPOLLHUP)) { - except_op_queue_.dispatch_all_operations(descriptor, 0); - read_op_queue_.dispatch_all_operations(descriptor, 0); - write_op_queue_.dispatch_all_operations(descriptor, 0); + asio::error_code ec; + except_op_queue_.dispatch_all_operations(descriptor, ec); + read_op_queue_.dispatch_all_operations(descriptor, ec); + write_op_queue_.dispatch_all_operations(descriptor, ec); epoll_event ev = { 0, { 0 } }; ev.events = 0; @@ -397,21 +415,22 @@ private: bool more_reads = false; bool more_writes = false; bool more_except = false; + asio::error_code ec; // Exception operations must be processed first to ensure that any // out-of-band data is read before normal data. if (events[i].events & EPOLLPRI) - more_except = except_op_queue_.dispatch_operation(descriptor, 0); + more_except = except_op_queue_.dispatch_operation(descriptor, ec); else more_except = except_op_queue_.has_operation(descriptor); if (events[i].events & EPOLLIN) - more_reads = read_op_queue_.dispatch_operation(descriptor, 0); + more_reads = read_op_queue_.dispatch_operation(descriptor, ec); else more_reads = read_op_queue_.has_operation(descriptor); if (events[i].events & EPOLLOUT) - more_writes = write_op_queue_.dispatch_operation(descriptor, 0); + more_writes = write_op_queue_.dispatch_operation(descriptor, ec); else more_writes = write_op_queue_.has_operation(descriptor); @@ -427,10 +446,10 @@ private: int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); if (result != 0) { - int error = errno; - read_op_queue_.dispatch_all_operations(descriptor, error); - write_op_queue_.dispatch_all_operations(descriptor, error); - except_op_queue_.dispatch_all_operations(descriptor, error); + ec = asio::error_code(errno, asio::native_ecat); + read_op_queue_.dispatch_all_operations(descriptor, ec); + write_op_queue_.dispatch_all_operations(descriptor, ec); + except_op_queue_.dispatch_all_operations(descriptor, ec); } } } @@ -488,8 +507,9 @@ private: int fd = epoll_create(epoll_size); if (fd == -1) { - system_exception e("epoll", errno); - boost::throw_exception(e); + boost::throw_exception(asio::system_error( + asio::error_code(errno, asio::native_ecat), + "epoll")); } return fd; } diff --git a/libtorrent/include/libtorrent/asio/detail/epoll_reactor_fwd.hpp b/libtorrent/include/libtorrent/asio/detail/epoll_reactor_fwd.hpp index 5a60b759b..87fad6325 100644 --- a/libtorrent/include/libtorrent/asio/detail/epoll_reactor_fwd.hpp +++ b/libtorrent/include/libtorrent/asio/detail/epoll_reactor_fwd.hpp @@ -2,7 +2,7 @@ // epoll_reactor_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/event.hpp b/libtorrent/include/libtorrent/asio/detail/event.hpp index 8f8b753e7..766f51716 100644 --- a/libtorrent/include/libtorrent/asio/detail/event.hpp +++ b/libtorrent/include/libtorrent/asio/detail/event.hpp @@ -2,7 +2,7 @@ // event.hpp // ~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/fd_set_adapter.hpp b/libtorrent/include/libtorrent/asio/detail/fd_set_adapter.hpp index 5266dd68c..1d01dc5fb 100644 --- a/libtorrent/include/libtorrent/asio/detail/fd_set_adapter.hpp +++ b/libtorrent/include/libtorrent/asio/detail/fd_set_adapter.hpp @@ -2,7 +2,7 @@ // fd_set_adapter.hpp // ~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/handler_alloc_helpers.hpp b/libtorrent/include/libtorrent/asio/detail/handler_alloc_helpers.hpp index d78c7e6af..68e7cb15d 100644 --- a/libtorrent/include/libtorrent/asio/detail/handler_alloc_helpers.hpp +++ b/libtorrent/include/libtorrent/asio/detail/handler_alloc_helpers.hpp @@ -2,7 +2,7 @@ // handler_alloc_helpers.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/handler_invoke_helpers.hpp b/libtorrent/include/libtorrent/asio/detail/handler_invoke_helpers.hpp index 6045122c4..b260c426c 100644 --- a/libtorrent/include/libtorrent/asio/detail/handler_invoke_helpers.hpp +++ b/libtorrent/include/libtorrent/asio/detail/handler_invoke_helpers.hpp @@ -2,7 +2,7 @@ // handler_invoke_helpers.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/hash_map.hpp b/libtorrent/include/libtorrent/asio/detail/hash_map.hpp index c68d78d34..05cebdf58 100644 --- a/libtorrent/include/libtorrent/asio/detail/hash_map.hpp +++ b/libtorrent/include/libtorrent/asio/detail/hash_map.hpp @@ -2,7 +2,7 @@ // hash_map.hpp // ~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -25,11 +25,23 @@ #include "asio/detail/pop_options.hpp" #include "asio/detail/noncopyable.hpp" +#include "asio/detail/socket_types.hpp" namespace asio { namespace detail { -using boost::hash_value; +template +inline std::size_t calculate_hash_value(const T& t) +{ + return boost::hash_value(t); +} + +#if defined(_WIN64) +inline std::size_t calculate_hash_value(SOCKET s) +{ + return static_cast(s); +} +#endif // defined(_WIN64) template class hash_map @@ -37,7 +49,7 @@ class hash_map { public: // The type of a value in the map. - typedef std::pair value_type; + typedef std::pair value_type; // The type of a non-const iterator over the hash map. typedef typename std::list::iterator iterator; @@ -86,7 +98,7 @@ public: // Find an entry in the map. iterator find(const K& k) { - size_t bucket = hash_value(k) % num_buckets; + size_t bucket = calculate_hash_value(k) % num_buckets; iterator it = buckets_[bucket].first; if (it == values_.end()) return values_.end(); @@ -104,7 +116,7 @@ public: // Find an entry in the map. const_iterator find(const K& k) const { - size_t bucket = hash_value(k) % num_buckets; + size_t bucket = calculate_hash_value(k) % num_buckets; const_iterator it = buckets_[bucket].first; if (it == values_.end()) return it; @@ -122,7 +134,7 @@ public: // Insert a new entry into the map. std::pair insert(const value_type& v) { - size_t bucket = hash_value(v.first) % num_buckets; + size_t bucket = calculate_hash_value(v.first) % num_buckets; iterator it = buckets_[bucket].first; if (it == values_.end()) { @@ -147,7 +159,7 @@ public: { assert(it != values_.end()); - size_t bucket = hash_value(it->first) % num_buckets; + size_t bucket = calculate_hash_value(it->first) % num_buckets; bool is_first = (it == buckets_[bucket].first); bool is_last = (it == buckets_[bucket].last); if (is_first && is_last) diff --git a/libtorrent/include/libtorrent/asio/detail/io_control.hpp b/libtorrent/include/libtorrent/asio/detail/io_control.hpp index ee9e8ac9f..feb02d9d5 100644 --- a/libtorrent/include/libtorrent/asio/detail/io_control.hpp +++ b/libtorrent/include/libtorrent/asio/detail/io_control.hpp @@ -2,7 +2,7 @@ // io_control.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -90,7 +90,7 @@ public: // Construct with a specific command value. bytes_readable(std::size_t value) - : value_(value) + : value_(static_cast(value)) { } diff --git a/libtorrent/include/libtorrent/asio/detail/kqueue_reactor.hpp b/libtorrent/include/libtorrent/asio/detail/kqueue_reactor.hpp index 51cabbc0a..6628803af 100644 --- a/libtorrent/include/libtorrent/asio/detail/kqueue_reactor.hpp +++ b/libtorrent/include/libtorrent/asio/detail/kqueue_reactor.hpp @@ -2,7 +2,7 @@ // kqueue_reactor.hpp // ~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -33,14 +33,16 @@ #include #include "asio/detail/pop_options.hpp" +#include "asio/error.hpp" #include "asio/io_service.hpp" -#include "asio/system_exception.hpp" +#include "asio/system_error.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/task_io_service.hpp" #include "asio/detail/thread.hpp" #include "asio/detail/reactor_op_queue.hpp" #include "asio/detail/select_interrupter.hpp" +#include "asio/detail/service_base.hpp" #include "asio/detail/signal_blocker.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/timer_queue.hpp" @@ -55,12 +57,13 @@ namespace detail { template class kqueue_reactor - : public asio::io_service::service + : public asio::detail::service_base > { public: // Constructor. kqueue_reactor(asio::io_service& io_service) - : asio::io_service::service(io_service), + : asio::detail::service_base< + kqueue_reactor >(io_service), mutex_(), kqueue_fd_(do_kqueue_create()), wait_in_progress_(false), @@ -138,7 +141,7 @@ public: return; if (!read_op_queue_.has_operation(descriptor)) - if (handler(0)) + if (handler(asio::error_code())) return; if (read_op_queue_.enqueue_operation(descriptor, handler)) @@ -147,8 +150,8 @@ public: EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0); if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { - int error = errno; - read_op_queue_.dispatch_all_operations(descriptor, error); + asio::error_code ec(errno, asio::native_ecat); + read_op_queue_.dispatch_all_operations(descriptor, ec); } } } @@ -164,7 +167,7 @@ public: return; if (!write_op_queue_.has_operation(descriptor)) - if (handler(0)) + if (handler(asio::error_code())) return; if (write_op_queue_.enqueue_operation(descriptor, handler)) @@ -173,8 +176,8 @@ public: EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0); if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { - int error = errno; - write_op_queue_.dispatch_all_operations(descriptor, error); + asio::error_code ec(errno, asio::native_ecat); + write_op_queue_.dispatch_all_operations(descriptor, ec); } } } @@ -198,8 +201,8 @@ public: EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0); if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { - int error = errno; - except_op_queue_.dispatch_all_operations(descriptor, error); + asio::error_code ec(errno, asio::native_ecat); + except_op_queue_.dispatch_all_operations(descriptor, ec); } } } @@ -221,8 +224,8 @@ public: EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0); if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { - int error = errno; - write_op_queue_.dispatch_all_operations(descriptor, error); + asio::error_code ec(errno, asio::native_ecat); + write_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -235,9 +238,9 @@ public: EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0); if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { - int error = errno; - except_op_queue_.dispatch_all_operations(descriptor, error); - write_op_queue_.dispatch_all_operations(descriptor, error); + asio::error_code ec(errno, asio::native_ecat); + except_op_queue_.dispatch_all_operations(descriptor, ec); + write_op_queue_.dispatch_all_operations(descriptor, ec); } } } @@ -285,6 +288,21 @@ public: timer_queues_.push_back(&timer_queue); } + // Remove a timer queue from the reactor. + template + void remove_timer_queue(timer_queue& timer_queue) + { + asio::detail::mutex::scoped_lock lock(mutex_); + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + if (timer_queues_[i] == &timer_queue) + { + timer_queues_.erase(timer_queues_.begin() + i); + return; + } + } + } + // Schedule a timer in the given timer queue to expire at the specified // absolute time. The handler object will be invoked when the timer expires. template @@ -378,21 +396,24 @@ private: bool more_except = false; if (events[i].flags & EV_ERROR) { - int error = events[i].data; + asio::error_code error( + events[i].data, asio::native_ecat); except_op_queue_.dispatch_all_operations(descriptor, error); read_op_queue_.dispatch_all_operations(descriptor, error); } else if (events[i].flags & EV_OOBAND) { - more_except = except_op_queue_.dispatch_operation(descriptor, 0); + asio::error_code error; + more_except = except_op_queue_.dispatch_operation(descriptor, error); if (events[i].data > 0) - more_reads = read_op_queue_.dispatch_operation(descriptor, 0); + more_reads = read_op_queue_.dispatch_operation(descriptor, error); else more_reads = read_op_queue_.has_operation(descriptor); } else { - more_reads = read_op_queue_.dispatch_operation(descriptor, 0); + asio::error_code error; + more_reads = read_op_queue_.dispatch_operation(descriptor, error); more_except = except_op_queue_.has_operation(descriptor); } @@ -406,7 +427,7 @@ private: EV_SET(&event, descriptor, EVFILT_READ, EV_DELETE, 0, 0, 0); if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { - int error = errno; + asio::error_code error(errno, asio::native_ecat); except_op_queue_.dispatch_all_operations(descriptor, error); read_op_queue_.dispatch_all_operations(descriptor, error); } @@ -417,12 +438,14 @@ private: bool more_writes = false; if (events[i].flags & EV_ERROR) { - int error = events[i].data; + asio::error_code error( + events[i].data, asio::native_ecat); write_op_queue_.dispatch_all_operations(descriptor, error); } else { - more_writes = write_op_queue_.dispatch_operation(descriptor, 0); + asio::error_code error; + more_writes = write_op_queue_.dispatch_operation(descriptor, error); } // Update the descriptor in the kqueue. @@ -433,7 +456,7 @@ private: EV_SET(&event, descriptor, EVFILT_WRITE, EV_DELETE, 0, 0, 0); if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { - int error = errno; + asio::error_code error(errno, asio::native_ecat); write_op_queue_.dispatch_all_operations(descriptor, error); } } @@ -489,8 +512,9 @@ private: int fd = kqueue(); if (fd == -1) { - system_exception e("kqueue", errno); - boost::throw_exception(e); + boost::throw_exception(asio::system_error( + asio::error_code(errno, asio::native_ecat), + "kqueue")); } return fd; } @@ -539,7 +563,7 @@ private: // Cancel all operations associated with the given descriptor. The do_cancel // function of the handler objects will be invoked. This function does not - // acquire the epoll_reactor's mutex. + // acquire the kqueue_reactor's mutex. void cancel_ops_unlocked(socket_type descriptor) { bool interrupt = read_op_queue_.cancel_operations(descriptor); @@ -552,13 +576,13 @@ private: // Mutex to protect access to internal data. asio::detail::mutex mutex_; - // The epoll file descriptor. + // The kqueue file descriptor. int kqueue_fd_; // Whether the kqueue wait call is currently in progress bool wait_in_progress_; - // The interrupter is used to break a blocking epoll_wait call. + // The interrupter is used to break a blocking kevent call. select_interrupter interrupter_; // The queue of read operations. diff --git a/libtorrent/include/libtorrent/asio/detail/kqueue_reactor_fwd.hpp b/libtorrent/include/libtorrent/asio/detail/kqueue_reactor_fwd.hpp index b9bc5a02d..5171f4215 100644 --- a/libtorrent/include/libtorrent/asio/detail/kqueue_reactor_fwd.hpp +++ b/libtorrent/include/libtorrent/asio/detail/kqueue_reactor_fwd.hpp @@ -2,7 +2,7 @@ // kqueue_reactor_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // Copyright (c) 2005 Stefan Arentz (stefan at soze dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying diff --git a/libtorrent/include/libtorrent/asio/detail/local_free_on_block_exit.hpp b/libtorrent/include/libtorrent/asio/detail/local_free_on_block_exit.hpp new file mode 100644 index 000000000..8e1f6088d --- /dev/null +++ b/libtorrent/include/libtorrent/asio/detail/local_free_on_block_exit.hpp @@ -0,0 +1,59 @@ +// +// local_free_on_block_exit.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP +#define ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +#include "asio/detail/push_options.hpp" +#include +#include "asio/detail/pop_options.hpp" + +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#include "asio/detail/noncopyable.hpp" +#include "asio/detail/socket_types.hpp" + +namespace asio { +namespace detail { + +class local_free_on_block_exit + : private noncopyable +{ +public: + // Constructor blocks all signals for the calling thread. + explicit local_free_on_block_exit(void* p) + : p_(p) + { + } + + // Destructor restores the previous signal mask. + ~local_free_on_block_exit() + { + ::LocalFree(p_); + } + +private: + void* p_; +}; + +} // namespace detail +} // namespace asio + +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_LOCAL_FREE_ON_BLOCK_EXIT_HPP diff --git a/libtorrent/include/libtorrent/asio/detail/mutex.hpp b/libtorrent/include/libtorrent/asio/detail/mutex.hpp index e861556d0..87d32ba3c 100644 --- a/libtorrent/include/libtorrent/asio/detail/mutex.hpp +++ b/libtorrent/include/libtorrent/asio/detail/mutex.hpp @@ -2,7 +2,7 @@ // mutex.hpp // ~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/noncopyable.hpp b/libtorrent/include/libtorrent/asio/detail/noncopyable.hpp index 004a68bc6..8e9d54683 100644 --- a/libtorrent/include/libtorrent/asio/detail/noncopyable.hpp +++ b/libtorrent/include/libtorrent/asio/detail/noncopyable.hpp @@ -2,7 +2,7 @@ // noncopyable.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/null_event.hpp b/libtorrent/include/libtorrent/asio/detail/null_event.hpp index 91bfc329e..df522ce0f 100644 --- a/libtorrent/include/libtorrent/asio/detail/null_event.hpp +++ b/libtorrent/include/libtorrent/asio/detail/null_event.hpp @@ -2,7 +2,7 @@ // null_event.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/null_mutex.hpp b/libtorrent/include/libtorrent/asio/detail/null_mutex.hpp index 814a18f5f..2f6a72084 100644 --- a/libtorrent/include/libtorrent/asio/detail/null_mutex.hpp +++ b/libtorrent/include/libtorrent/asio/detail/null_mutex.hpp @@ -2,7 +2,7 @@ // null_mutex.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/null_signal_blocker.hpp b/libtorrent/include/libtorrent/asio/detail/null_signal_blocker.hpp index ff7cfcaf0..c10017d98 100644 --- a/libtorrent/include/libtorrent/asio/detail/null_signal_blocker.hpp +++ b/libtorrent/include/libtorrent/asio/detail/null_signal_blocker.hpp @@ -2,7 +2,7 @@ // null_signal_blocker.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/null_thread.hpp b/libtorrent/include/libtorrent/asio/detail/null_thread.hpp index 653caa651..c013a7701 100644 --- a/libtorrent/include/libtorrent/asio/detail/null_thread.hpp +++ b/libtorrent/include/libtorrent/asio/detail/null_thread.hpp @@ -2,7 +2,7 @@ // null_thread.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -28,7 +28,7 @@ #include "asio/detail/pop_options.hpp" #include "asio/error.hpp" -#include "asio/system_exception.hpp" +#include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" namespace asio { @@ -42,7 +42,8 @@ public: template null_thread(Function f) { - system_exception e("thread", asio::error::not_supported); + asio::system_error e( + asio::error::operation_not_supported, "thread"); boost::throw_exception(e); } diff --git a/libtorrent/include/libtorrent/asio/detail/null_tss_ptr.hpp b/libtorrent/include/libtorrent/asio/detail/null_tss_ptr.hpp index 707e31e79..9f3b0ad0c 100644 --- a/libtorrent/include/libtorrent/asio/detail/null_tss_ptr.hpp +++ b/libtorrent/include/libtorrent/asio/detail/null_tss_ptr.hpp @@ -2,7 +2,7 @@ // null_tss_ptr.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/old_win_sdk_compat.hpp b/libtorrent/include/libtorrent/asio/detail/old_win_sdk_compat.hpp index 24c42ad67..da78f956d 100644 --- a/libtorrent/include/libtorrent/asio/detail/old_win_sdk_compat.hpp +++ b/libtorrent/include/libtorrent/asio/detail/old_win_sdk_compat.hpp @@ -2,7 +2,7 @@ // old_win_sdk_compat.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -24,9 +24,9 @@ #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Guess whether we are building against on old Platform SDK. -#if !defined(IPPROTO_IPV6) +#if !defined(IN6ADDR_ANY_INIT) #define ASIO_HAS_OLD_WIN_SDK 1 -#endif // !defined(IPPROTO_IPV6) +#endif // !defined(IN6ADDR_ANY_INIT) #if defined(ASIO_HAS_OLD_WIN_SDK) @@ -305,6 +305,11 @@ inline int IN6_IS_ADDR_MC_GLOBAL(const in6_addr_emulation* a) #endif // defined(ASIO_HAS_OLD_WIN_SDK) +// Even newer Platform SDKs that support IPv6 may not define IPV6_V6ONLY. +#if !defined(IPV6_V6ONLY) +# define IPV6_V6ONLY 27 +#endif + #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #include "asio/detail/pop_options.hpp" diff --git a/libtorrent/include/libtorrent/asio/detail/pipe_select_interrupter.hpp b/libtorrent/include/libtorrent/asio/detail/pipe_select_interrupter.hpp index b73fb3f2e..e203669cb 100644 --- a/libtorrent/include/libtorrent/asio/detail/pipe_select_interrupter.hpp +++ b/libtorrent/include/libtorrent/asio/detail/pipe_select_interrupter.hpp @@ -2,7 +2,7 @@ // pipe_select_interrupter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/pop_options.hpp b/libtorrent/include/libtorrent/asio/detail/pop_options.hpp index 4c942e8d3..c8b0ed93b 100644 --- a/libtorrent/include/libtorrent/asio/detail/pop_options.hpp +++ b/libtorrent/include/libtorrent/asio/detail/pop_options.hpp @@ -2,7 +2,7 @@ // pop_options.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/posix_event.hpp b/libtorrent/include/libtorrent/asio/detail/posix_event.hpp index 9d84bfa58..408c23bb9 100644 --- a/libtorrent/include/libtorrent/asio/detail/posix_event.hpp +++ b/libtorrent/include/libtorrent/asio/detail/posix_event.hpp @@ -2,7 +2,7 @@ // posix_event.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -28,7 +28,7 @@ #include #include "asio/detail/pop_options.hpp" -#include "asio/system_exception.hpp" +#include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" namespace asio { @@ -45,7 +45,9 @@ public: int error = ::pthread_mutex_init(&mutex_, 0); if (error != 0) { - system_exception e("event", error); + asio::system_error e( + asio::error_code(error, asio::native_ecat), + "event"); boost::throw_exception(e); } @@ -53,7 +55,9 @@ public: if (error != 0) { ::pthread_mutex_destroy(&mutex_); - system_exception e("event", error); + asio::system_error e( + asio::error_code(error, asio::native_ecat), + "event"); boost::throw_exception(e); } } diff --git a/libtorrent/include/libtorrent/asio/detail/posix_fd_set_adapter.hpp b/libtorrent/include/libtorrent/asio/detail/posix_fd_set_adapter.hpp index 56d8ff3dc..ae5bf6642 100644 --- a/libtorrent/include/libtorrent/asio/detail/posix_fd_set_adapter.hpp +++ b/libtorrent/include/libtorrent/asio/detail/posix_fd_set_adapter.hpp @@ -2,7 +2,7 @@ // posix_fd_set_adapter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -31,6 +31,7 @@ public: posix_fd_set_adapter() : max_descriptor_(invalid_socket) { + using namespace std; // Needed for memset on Solaris. FD_ZERO(&fd_set_); } diff --git a/libtorrent/include/libtorrent/asio/detail/posix_mutex.hpp b/libtorrent/include/libtorrent/asio/detail/posix_mutex.hpp index 4e9df4a75..154089f3c 100644 --- a/libtorrent/include/libtorrent/asio/detail/posix_mutex.hpp +++ b/libtorrent/include/libtorrent/asio/detail/posix_mutex.hpp @@ -2,7 +2,7 @@ // posix_mutex.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -28,7 +28,7 @@ #include #include "asio/detail/pop_options.hpp" -#include "asio/system_exception.hpp" +#include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/scoped_lock.hpp" @@ -47,7 +47,9 @@ public: int error = ::pthread_mutex_init(&mutex_, 0); if (error != 0) { - system_exception e("mutex", error); + asio::system_error e( + asio::error_code(error, asio::native_ecat), + "mutex"); boost::throw_exception(e); } } @@ -64,7 +66,9 @@ public: int error = ::pthread_mutex_lock(&mutex_); if (error != 0) { - system_exception e("mutex", error); + asio::system_error e( + asio::error_code(error, asio::native_ecat), + "mutex"); boost::throw_exception(e); } } @@ -75,7 +79,9 @@ public: int error = ::pthread_mutex_unlock(&mutex_); if (error != 0) { - system_exception e("mutex", error); + asio::system_error e( + asio::error_code(error, asio::native_ecat), + "mutex"); boost::throw_exception(e); } } diff --git a/libtorrent/include/libtorrent/asio/detail/posix_signal_blocker.hpp b/libtorrent/include/libtorrent/asio/detail/posix_signal_blocker.hpp index c11fc5ef6..73d0581e1 100644 --- a/libtorrent/include/libtorrent/asio/detail/posix_signal_blocker.hpp +++ b/libtorrent/include/libtorrent/asio/detail/posix_signal_blocker.hpp @@ -2,7 +2,7 @@ // posix_signal_blocker.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -26,6 +26,7 @@ #include "asio/detail/push_options.hpp" #include #include +#include #include "asio/detail/pop_options.hpp" #include "asio/detail/noncopyable.hpp" diff --git a/libtorrent/include/libtorrent/asio/detail/posix_thread.hpp b/libtorrent/include/libtorrent/asio/detail/posix_thread.hpp index 7d738fa4b..f01b40428 100644 --- a/libtorrent/include/libtorrent/asio/detail/posix_thread.hpp +++ b/libtorrent/include/libtorrent/asio/detail/posix_thread.hpp @@ -2,7 +2,7 @@ // posix_thread.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -29,7 +29,7 @@ #include #include "asio/detail/pop_options.hpp" -#include "asio/system_exception.hpp" +#include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" namespace asio { @@ -51,7 +51,9 @@ public: asio_detail_posix_thread_function, arg.get()); if (error != 0) { - system_exception e("thread", error); + asio::system_error e( + asio::error_code(error, asio::native_ecat), + "thread"); boost::throw_exception(e); } arg.release(); diff --git a/libtorrent/include/libtorrent/asio/detail/posix_tss_ptr.hpp b/libtorrent/include/libtorrent/asio/detail/posix_tss_ptr.hpp index 961120ee9..93fce3479 100644 --- a/libtorrent/include/libtorrent/asio/detail/posix_tss_ptr.hpp +++ b/libtorrent/include/libtorrent/asio/detail/posix_tss_ptr.hpp @@ -2,7 +2,7 @@ // posix_tss_ptr.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -28,7 +28,7 @@ #include #include "asio/detail/pop_options.hpp" -#include "asio/system_exception.hpp" +#include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" namespace asio { @@ -45,7 +45,9 @@ public: int error = ::pthread_key_create(&tss_key_, 0); if (error != 0) { - system_exception e("tss", error); + asio::system_error e( + asio::error_code(error, asio::native_ecat), + "tss"); boost::throw_exception(e); } } diff --git a/libtorrent/include/libtorrent/asio/detail/push_options.hpp b/libtorrent/include/libtorrent/asio/detail/push_options.hpp index 45493ed29..0b68d2933 100644 --- a/libtorrent/include/libtorrent/asio/detail/push_options.hpp +++ b/libtorrent/include/libtorrent/asio/detail/push_options.hpp @@ -2,7 +2,7 @@ // push_options.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp b/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp index 361f978af..b58f62781 100644 --- a/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp +++ b/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp @@ -2,7 +2,7 @@ // reactive_socket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -23,11 +23,11 @@ #include "asio/buffer.hpp" #include "asio/error.hpp" -#include "asio/error_handler.hpp" #include "asio/io_service.hpp" #include "asio/socket_base.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/noncopyable.hpp" +#include "asio/detail/service_base.hpp" #include "asio/detail/socket_holder.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" @@ -37,7 +37,8 @@ namespace detail { template class reactive_socket_service - : public asio::io_service::service + : public asio::detail::service_base< + reactive_socket_service > { public: // The protocol type. @@ -89,7 +90,8 @@ public: // Constructor. reactive_socket_service(asio::io_service& io_service) - : asio::io_service::service(io_service), + : asio::detail::service_base< + reactive_socket_service >(io_service), reactor_(asio::use_service(io_service)) { } @@ -116,7 +118,8 @@ public: if (impl.flags_ & implementation_type::internal_non_blocking) { ioctl_arg_type non_blocking = 0; - socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking); + asio::error_code ignored_ec; + socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec); impl.flags_ &= ~implementation_type::internal_non_blocking; } @@ -125,88 +128,100 @@ public: ::linger opt; opt.l_onoff = 0; opt.l_linger = 0; + asio::error_code ignored_ec; socket_ops::setsockopt(impl.socket_, - SOL_SOCKET, SO_LINGER, &opt, sizeof(opt)); + SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec); } - socket_ops::close(impl.socket_); + asio::error_code ignored_ec; + socket_ops::close(impl.socket_, ignored_ec); + impl.socket_ = invalid_socket; } } // Open a new socket implementation. - template - void open(implementation_type& impl, const protocol_type& protocol, - Error_Handler error_handler) + asio::error_code open(implementation_type& impl, + const protocol_type& protocol, asio::error_code& ec) { - close(impl, asio::ignore_error()); + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } socket_holder sock(socket_ops::socket(protocol.family(), - protocol.type(), protocol.protocol())); + protocol.type(), protocol.protocol(), ec)); if (sock.get() == invalid_socket) - { - error_handler(asio::error(socket_ops::get_error())); - return; - } + return ec; if (int err = reactor_.register_descriptor(sock.get())) { - error_handler(asio::error(err)); - return; + ec = asio::error_code(err, asio::native_ecat); + return ec; } impl.socket_ = sock.release(); impl.flags_ = 0; impl.protocol_ = protocol; - - error_handler(asio::error(0)); + ec = asio::error_code(); + return ec; } // Assign a native socket to a socket implementation. - template - void assign(implementation_type& impl, const protocol_type& protocol, - const native_type& native_socket, Error_Handler error_handler) + asio::error_code assign(implementation_type& impl, + const protocol_type& protocol, const native_type& native_socket, + asio::error_code& ec) { - close(impl, asio::ignore_error()); + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } if (int err = reactor_.register_descriptor(native_socket)) { - error_handler(asio::error(err)); - return; + ec = asio::error_code(err, asio::native_ecat); + return ec; } impl.socket_ = native_socket; impl.flags_ = 0; impl.protocol_ = protocol; + ec = asio::error_code(); + return ec; + } - error_handler(asio::error(0)); + // Determine whether the socket is open. + bool is_open(const implementation_type& impl) const + { + return impl.socket_ != invalid_socket; } // Destroy a socket implementation. - template - void close(implementation_type& impl, Error_Handler error_handler) + asio::error_code close(implementation_type& impl, + asio::error_code& ec) { - if (impl.socket_ != invalid_socket) + if (is_open(impl)) { reactor_.close_descriptor(impl.socket_); if (impl.flags_ & implementation_type::internal_non_blocking) { ioctl_arg_type non_blocking = 0; - socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking); + asio::error_code ignored_ec; + socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec); impl.flags_ &= ~implementation_type::internal_non_blocking; } - if (socket_ops::close(impl.socket_) == socket_error_retval) - { - error_handler(asio::error(socket_ops::get_error())); - return; - } + if (socket_ops::close(impl.socket_, ec) == socket_error_retval) + return ec; impl.socket_ = invalid_socket; } - error_handler(asio::error(0)); + ec = asio::error_code(); + return ec; } // Get the native socket representation. @@ -216,55 +231,103 @@ public: } // Cancel all operations associated with the socket. - template - void cancel(implementation_type& impl, Error_Handler error_handler) + asio::error_code cancel(implementation_type& impl, + asio::error_code& ec) { - if (impl.socket_ == invalid_socket) + if (!is_open(impl)) { - asio::error error(asio::error::bad_descriptor); - error_handler(error); + ec = asio::error::bad_descriptor; + return ec; } - else + + reactor_.cancel_ops(impl.socket_); + ec = asio::error_code(); + return ec; + } + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const implementation_type& impl, + asio::error_code& ec) const + { + if (!is_open(impl)) { - reactor_.cancel_ops(impl.socket_); - error_handler(asio::error(0)); + ec = asio::error::bad_descriptor; + return false; } + + asio::detail::ioctl_arg_type value = 0; + socket_ops::ioctl(impl.socket_, SIOCATMARK, &value, ec); +#if defined(ENOTTY) + if (ec.value() == ENOTTY) + ec = asio::error::not_socket; +#endif // defined(ENOTTY) + return ec ? false : value != 0; + } + + // Determine the number of bytes available for reading. + std::size_t available(const implementation_type& impl, + asio::error_code& ec) const + { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + + asio::detail::ioctl_arg_type value = 0; + socket_ops::ioctl(impl.socket_, FIONREAD, &value, ec); +#if defined(ENOTTY) + if (ec.value() == ENOTTY) + ec = asio::error::not_socket; +#endif // defined(ENOTTY) + return ec ? static_cast(0) : static_cast(value); } // Bind the socket to the specified local endpoint. - template - void bind(implementation_type& impl, const endpoint_type& endpoint, - Error_Handler error_handler) + asio::error_code bind(implementation_type& impl, + const endpoint_type& endpoint, asio::error_code& ec) { - if (socket_ops::bind(impl.socket_, endpoint.data(), - endpoint.size()) == socket_error_retval) - error_handler(asio::error(socket_ops::get_error())); - else - error_handler(asio::error(0)); + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); + return ec; } // Place the socket into the state where it will listen for new connections. - template - void listen(implementation_type& impl, int backlog, - Error_Handler error_handler) + asio::error_code listen(implementation_type& impl, int backlog, + asio::error_code& ec) { - if (socket_ops::listen(impl.socket_, backlog) == socket_error_retval) - error_handler(asio::error(socket_ops::get_error())); - else - error_handler(asio::error(0)); + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + socket_ops::listen(impl.socket_, backlog, ec); + return ec; } // Set a socket option. - template - void set_option(implementation_type& impl, const Option& option, - Error_Handler error_handler) + template + asio::error_code set_option(implementation_type& impl, + const Option& option, asio::error_code& ec) { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + if (option.level(impl.protocol_) == custom_socket_option_level && option.name(impl.protocol_) == enable_connection_aborted_option) { if (option.size(impl.protocol_) != sizeof(int)) { - error_handler(asio::error(asio::error::invalid_argument)); + ec = asio::error::invalid_argument; } else { @@ -272,8 +335,9 @@ public: impl.flags_ |= implementation_type::enable_connection_aborted; else impl.flags_ &= ~implementation_type::enable_connection_aborted; - error_handler(asio::error(0)); + ec = asio::error_code(); } + return ec; } else { @@ -283,26 +347,30 @@ public: impl.flags_ |= implementation_type::user_set_linger; } - if (socket_ops::setsockopt(impl.socket_, - option.level(impl.protocol_), option.name(impl.protocol_), - option.data(impl.protocol_), option.size(impl.protocol_))) - error_handler(asio::error(socket_ops::get_error())); - else - error_handler(asio::error(0)); + socket_ops::setsockopt(impl.socket_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), option.size(impl.protocol_), ec); + return ec; } } // Set a socket option. - template - void get_option(const implementation_type& impl, Option& option, - Error_Handler error_handler) const + template + asio::error_code get_option(const implementation_type& impl, + Option& option, asio::error_code& ec) const { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + if (option.level(impl.protocol_) == custom_socket_option_level && option.name(impl.protocol_) == enable_connection_aborted_option) { if (option.size(impl.protocol_) != sizeof(int)) { - error_handler(asio::error(asio::error::invalid_argument)); + ec = asio::error::invalid_argument; } else { @@ -311,96 +379,115 @@ public: *target = 1; else *target = 0; - error_handler(asio::error(0)); + option.resize(impl.protocol_, sizeof(int)); + ec = asio::error_code(); } + return ec; } else { size_t size = option.size(impl.protocol_); - if (socket_ops::getsockopt(impl.socket_, - option.level(impl.protocol_), option.name(impl.protocol_), - option.data(impl.protocol_), &size)) - error_handler(asio::error(socket_ops::get_error())); - else - error_handler(asio::error(0)); + socket_ops::getsockopt(impl.socket_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), &size, ec); + if (!ec) + option.resize(impl.protocol_, size); + return ec; } } // Perform an IO control command on the socket. - template - void io_control(implementation_type& impl, IO_Control_Command& command, - Error_Handler error_handler) + template + asio::error_code io_control(implementation_type& impl, + IO_Control_Command& command, asio::error_code& ec) { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + if (command.name() == static_cast(FIONBIO)) { if (command.get()) impl.flags_ |= implementation_type::user_set_non_blocking; else impl.flags_ &= ~implementation_type::user_set_non_blocking; - error_handler(asio::error(0)); + ec = asio::error_code(); } else { - if (socket_ops::ioctl(impl.socket_, command.name(), - static_cast(command.data()))) - error_handler(asio::error(socket_ops::get_error())); - else - error_handler(asio::error(0)); + socket_ops::ioctl(impl.socket_, command.name(), + static_cast(command.data()), ec); } + return ec; } // Get the local endpoint. - template - void get_local_endpoint(const implementation_type& impl, - endpoint_type& endpoint, Error_Handler error_handler) const + endpoint_type local_endpoint(const implementation_type& impl, + asio::error_code& ec) const { - socket_addr_len_type addr_len = endpoint.capacity(); - if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len)) + if (!is_open(impl)) { - error_handler(asio::error(socket_ops::get_error())); - return; + ec = asio::error::bad_descriptor; + return endpoint_type(); } + endpoint_type endpoint; + socket_addr_len_type addr_len = endpoint.capacity(); + if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) + return endpoint_type(); endpoint.resize(addr_len); - error_handler(asio::error(0)); + return endpoint; } // Get the remote endpoint. - template - void get_remote_endpoint(const implementation_type& impl, - endpoint_type& endpoint, Error_Handler error_handler) const + endpoint_type remote_endpoint(const implementation_type& impl, + asio::error_code& ec) const { - socket_addr_len_type addr_len = endpoint.capacity(); - if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len)) + if (!is_open(impl)) { - error_handler(asio::error(socket_ops::get_error())); - return; + ec = asio::error::bad_descriptor; + return endpoint_type(); } + endpoint_type endpoint; + socket_addr_len_type addr_len = endpoint.capacity(); + if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec)) + return endpoint_type(); endpoint.resize(addr_len); - error_handler(asio::error(0)); + return endpoint; } /// Disable sends or receives on the socket. - template - void shutdown(implementation_type& impl, socket_base::shutdown_type what, - Error_Handler error_handler) + asio::error_code shutdown(implementation_type& impl, + socket_base::shutdown_type what, asio::error_code& ec) { - if (socket_ops::shutdown(impl.socket_, what) != 0) - error_handler(asio::error(socket_ops::get_error())); - else - error_handler(asio::error(0)); + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + socket_ops::shutdown(impl.socket_, what, ec); + return ec; } // Send the given data to the peer. - template - size_t send(implementation_type& impl, const Const_Buffers& buffers, - socket_base::message_flags flags, Error_Handler error_handler) + template + size_t send(implementation_type& impl, const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + // Copy buffers into array. socket_ops::buf bufs[max_buffers]; - typename Const_Buffers::const_iterator iter = buffers.begin(); - typename Const_Buffers::const_iterator end = buffers.end(); + typename ConstBufferSequence::const_iterator iter = buffers.begin(); + typename ConstBufferSequence::const_iterator end = buffers.end(); size_t i = 0; size_t total_buffer_size = 0; for (; iter != end && i < max_buffers; ++iter, ++i) @@ -415,7 +502,7 @@ public: // A request to receive 0 bytes on a stream socket is a no-op. if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) { - error_handler(asio::error(0)); + ec = asio::error_code(); return 0; } @@ -423,40 +510,30 @@ public: for (;;) { // Try to complete the operation without blocking. - int bytes_sent = socket_ops::send(impl.socket_, bufs, i, flags); - int error = socket_ops::get_error(); + int bytes_sent = socket_ops::send(impl.socket_, bufs, i, flags, ec); // Check if operation succeeded. if (bytes_sent >= 0) - { - error_handler(asio::error(0)); return bytes_sent; - } // Operation failed. if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (error != asio::error::would_block - && error != asio::error::try_again)) - { - error_handler(asio::error(error)); + || (ec != asio::error::would_block + && ec != asio::error::try_again)) return 0; - } // Wait for socket to become ready. - if (socket_ops::poll_write(impl.socket_) < 0) - { - error_handler(asio::error(socket_ops::get_error())); + if (socket_ops::poll_write(impl.socket_, ec) < 0) return 0; - } } } - template + template class send_handler { public: send_handler(socket_type socket, asio::io_service& io_service, - const Const_Buffers& buffers, socket_base::message_flags flags, + const ConstBufferSequence& buffers, socket_base::message_flags flags, Handler handler) : socket_(socket), io_service_(io_service), @@ -467,20 +544,19 @@ public: { } - bool operator()(int result) + bool operator()(const asio::error_code& result) { // Check whether the operation was successful. - if (result != 0) + if (result) { - asio::error error(result); - io_service_.post(bind_handler(handler_, error, 0)); + io_service_.post(bind_handler(handler_, result, 0)); return true; } // Copy buffers into array. socket_ops::buf bufs[max_buffers]; - typename Const_Buffers::const_iterator iter = buffers_.begin(); - typename Const_Buffers::const_iterator end = buffers_.end(); + typename ConstBufferSequence::const_iterator iter = buffers_.begin(); + typename ConstBufferSequence::const_iterator end = buffers_.end(); size_t i = 0; for (; iter != end && i < max_buffers; ++iter, ++i) { @@ -491,16 +567,15 @@ public: } // Send the data. - int bytes = socket_ops::send(socket_, bufs, i, flags_); - asio::error error(bytes < 0 - ? socket_ops::get_error() : asio::error::success); + asio::error_code ec; + int bytes = socket_ops::send(socket_, bufs, i, flags_, ec); // Check if we need to run the operation again. - if (error == asio::error::would_block - || error == asio::error::try_again) + if (ec == asio::error::would_block + || ec == asio::error::try_again) return false; - io_service_.post(bind_handler(handler_, error, bytes < 0 ? 0 : bytes)); + io_service_.post(bind_handler(handler_, ec, bytes < 0 ? 0 : bytes)); return true; } @@ -508,29 +583,29 @@ public: socket_type socket_; asio::io_service& io_service_; asio::io_service::work work_; - Const_Buffers buffers_; + ConstBufferSequence buffers_; socket_base::message_flags flags_; Handler handler_; }; // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. - template - void async_send(implementation_type& impl, const Const_Buffers& buffers, + template + void async_send(implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, Handler handler) { - if (impl.socket_ == invalid_socket) + if (!is_open(impl)) { - asio::error error(asio::error::bad_descriptor); - io_service().post(bind_handler(handler, error, 0)); + this->io_service().post(bind_handler(handler, + asio::error::bad_descriptor, 0)); } else { if (impl.protocol_.type() == SOCK_STREAM) { // Determine total size of buffers. - typename Const_Buffers::const_iterator iter = buffers.begin(); - typename Const_Buffers::const_iterator end = buffers.end(); + typename ConstBufferSequence::const_iterator iter = buffers.begin(); + typename ConstBufferSequence::const_iterator end = buffers.end(); size_t i = 0; size_t total_buffer_size = 0; for (; iter != end && i < max_buffers; ++iter, ++i) @@ -542,8 +617,8 @@ public: // A request to receive 0 bytes on a stream socket is a no-op. if (total_buffer_size == 0) { - asio::error error(asio::error::success); - io_service().post(bind_handler(handler, error, 0)); + this->io_service().post(bind_handler(handler, + asio::error_code(), 0)); return; } } @@ -552,32 +627,38 @@ public: if (!(impl.flags_ & implementation_type::internal_non_blocking)) { ioctl_arg_type non_blocking = 1; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking)) + asio::error_code ec; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) { - asio::error error(socket_ops::get_error()); - io_service().post(bind_handler(handler, error, 0)); + this->io_service().post(bind_handler(handler, ec, 0)); return; } impl.flags_ |= implementation_type::internal_non_blocking; } reactor_.start_write_op(impl.socket_, - send_handler( - impl.socket_, io_service(), buffers, flags, handler)); + send_handler( + impl.socket_, this->io_service(), buffers, flags, handler)); } } // Send a datagram to the specified endpoint. Returns the number of bytes // sent. - template - size_t send_to(implementation_type& impl, const Const_Buffers& buffers, + template + size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, - Error_Handler error_handler) + asio::error_code& ec) { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + // Copy buffers into array. socket_ops::buf bufs[max_buffers]; - typename Const_Buffers::const_iterator iter = buffers.begin(); - typename Const_Buffers::const_iterator end = buffers.end(); + typename ConstBufferSequence::const_iterator iter = buffers.begin(); + typename ConstBufferSequence::const_iterator end = buffers.end(); size_t i = 0; for (; iter != end && i < max_buffers; ++iter, ++i) { @@ -592,40 +673,30 @@ public: { // Try to complete the operation without blocking. int bytes_sent = socket_ops::sendto(impl.socket_, bufs, i, flags, - destination.data(), destination.size()); - int error = socket_ops::get_error(); + destination.data(), destination.size(), ec); // Check if operation succeeded. if (bytes_sent >= 0) - { - error_handler(asio::error(0)); return bytes_sent; - } // Operation failed. if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (error != asio::error::would_block - && error != asio::error::try_again)) - { - error_handler(asio::error(error)); + || (ec != asio::error::would_block + && ec != asio::error::try_again)) return 0; - } // Wait for socket to become ready. - if (socket_ops::poll_write(impl.socket_) < 0) - { - error_handler(asio::error(socket_ops::get_error())); + if (socket_ops::poll_write(impl.socket_, ec) < 0) return 0; - } } } - template + template class send_to_handler { public: send_to_handler(socket_type socket, asio::io_service& io_service, - const Const_Buffers& buffers, const endpoint_type& endpoint, + const ConstBufferSequence& buffers, const endpoint_type& endpoint, socket_base::message_flags flags, Handler handler) : socket_(socket), io_service_(io_service), @@ -637,20 +708,19 @@ public: { } - bool operator()(int result) + bool operator()(const asio::error_code& result) { // Check whether the operation was successful. - if (result != 0) + if (result) { - asio::error error(result); - io_service_.post(bind_handler(handler_, error, 0)); + io_service_.post(bind_handler(handler_, result, 0)); return true; } // Copy buffers into array. socket_ops::buf bufs[max_buffers]; - typename Const_Buffers::const_iterator iter = buffers_.begin(); - typename Const_Buffers::const_iterator end = buffers_.end(); + typename ConstBufferSequence::const_iterator iter = buffers_.begin(); + typename ConstBufferSequence::const_iterator end = buffers_.end(); size_t i = 0; for (; iter != end && i < max_buffers; ++iter, ++i) { @@ -661,17 +731,16 @@ public: } // Send the data. + asio::error_code ec; int bytes = socket_ops::sendto(socket_, bufs, i, flags_, - destination_.data(), destination_.size()); - asio::error error(bytes < 0 - ? socket_ops::get_error() : asio::error::success); + destination_.data(), destination_.size(), ec); // Check if we need to run the operation again. - if (error == asio::error::would_block - || error == asio::error::try_again) + if (ec == asio::error::would_block + || ec == asio::error::try_again) return false; - io_service_.post(bind_handler(handler_, error, bytes < 0 ? 0 : bytes)); + io_service_.post(bind_handler(handler_, ec, bytes < 0 ? 0 : bytes)); return true; } @@ -679,7 +748,7 @@ public: socket_type socket_; asio::io_service& io_service_; asio::io_service::work work_; - Const_Buffers buffers_; + ConstBufferSequence buffers_; endpoint_type destination_; socket_base::message_flags flags_; Handler handler_; @@ -687,15 +756,16 @@ public: // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. - template - void async_send_to(implementation_type& impl, const Const_Buffers& buffers, + template + void async_send_to(implementation_type& impl, + const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, Handler handler) { - if (impl.socket_ == invalid_socket) + if (!is_open(impl)) { - asio::error error(asio::error::bad_descriptor); - io_service().post(bind_handler(handler, error, 0)); + this->io_service().post(bind_handler(handler, + asio::error::bad_descriptor, 0)); } else { @@ -703,30 +773,38 @@ public: if (!(impl.flags_ & implementation_type::internal_non_blocking)) { ioctl_arg_type non_blocking = 1; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking)) + asio::error_code ec; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) { - asio::error error(socket_ops::get_error()); - io_service().post(bind_handler(handler, error, 0)); + this->io_service().post(bind_handler(handler, ec, 0)); return; } impl.flags_ |= implementation_type::internal_non_blocking; } reactor_.start_write_op(impl.socket_, - send_to_handler( - impl.socket_, io_service(), buffers, destination, flags, handler)); + send_to_handler( + impl.socket_, this->io_service(), buffers, + destination, flags, handler)); } } // Receive some data from the peer. Returns the number of bytes received. - template - size_t receive(implementation_type& impl, const Mutable_Buffers& buffers, - socket_base::message_flags flags, Error_Handler error_handler) + template + size_t receive(implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + // Copy buffers into array. socket_ops::buf bufs[max_buffers]; - typename Mutable_Buffers::const_iterator iter = buffers.begin(); - typename Mutable_Buffers::const_iterator end = buffers.end(); + typename MutableBufferSequence::const_iterator iter = buffers.begin(); + typename MutableBufferSequence::const_iterator end = buffers.end(); size_t i = 0; size_t total_buffer_size = 0; for (; iter != end && i < max_buffers; ++iter, ++i) @@ -741,7 +819,7 @@ public: // A request to receive 0 bytes on a stream socket is a no-op. if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) { - error_handler(asio::error(0)); + ec = asio::error_code(); return 0; } @@ -749,47 +827,37 @@ public: for (;;) { // Try to complete the operation without blocking. - int bytes_recvd = socket_ops::recv(impl.socket_, bufs, i, flags); - int error = socket_ops::get_error(); + int bytes_recvd = socket_ops::recv(impl.socket_, bufs, i, flags, ec); // Check if operation succeeded. if (bytes_recvd > 0) - { - error_handler(asio::error(0)); return bytes_recvd; - } // Check for EOF. if (bytes_recvd == 0) { - error_handler(asio::error(asio::error::eof)); + ec = asio::error::eof; return 0; } // Operation failed. if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (error != asio::error::would_block - && error != asio::error::try_again)) - { - error_handler(asio::error(error)); + || (ec != asio::error::would_block + && ec != asio::error::try_again)) return 0; - } // Wait for socket to become ready. - if (socket_ops::poll_read(impl.socket_) < 0) - { - error_handler(asio::error(socket_ops::get_error())); + if (socket_ops::poll_read(impl.socket_, ec) < 0) return 0; - } } } - template + template class receive_handler { public: receive_handler(socket_type socket, asio::io_service& io_service, - const Mutable_Buffers& buffers, socket_base::message_flags flags, + const MutableBufferSequence& buffers, socket_base::message_flags flags, Handler handler) : socket_(socket), io_service_(io_service), @@ -800,20 +868,19 @@ public: { } - bool operator()(int result) + bool operator()(const asio::error_code& result) { // Check whether the operation was successful. - if (result != 0) + if (result) { - asio::error error(result); - io_service_.post(bind_handler(handler_, error, 0)); + io_service_.post(bind_handler(handler_, result, 0)); return true; } // Copy buffers into array. socket_ops::buf bufs[max_buffers]; - typename Mutable_Buffers::const_iterator iter = buffers_.begin(); - typename Mutable_Buffers::const_iterator end = buffers_.end(); + typename MutableBufferSequence::const_iterator iter = buffers_.begin(); + typename MutableBufferSequence::const_iterator end = buffers_.end(); size_t i = 0; for (; iter != end && i < max_buffers; ++iter, ++i) { @@ -824,20 +891,17 @@ public: } // Receive some data. - int bytes = socket_ops::recv(socket_, bufs, i, flags_); - int error_code = asio::error::success; - if (bytes < 0) - error_code = socket_ops::get_error(); - else if (bytes == 0) - error_code = asio::error::eof; - asio::error error(error_code); + asio::error_code ec; + int bytes = socket_ops::recv(socket_, bufs, i, flags_, ec); + if (bytes == 0) + ec = asio::error::eof; // Check if we need to run the operation again. - if (error == asio::error::would_block - || error == asio::error::try_again) + if (ec == asio::error::would_block + || ec == asio::error::try_again) return false; - io_service_.post(bind_handler(handler_, error, bytes < 0 ? 0 : bytes)); + io_service_.post(bind_handler(handler_, ec, bytes < 0 ? 0 : bytes)); return true; } @@ -845,29 +909,30 @@ public: socket_type socket_; asio::io_service& io_service_; asio::io_service::work work_; - Mutable_Buffers buffers_; + MutableBufferSequence buffers_; socket_base::message_flags flags_; Handler handler_; }; // Start an asynchronous receive. The buffer for the data being received // must be valid for the lifetime of the asynchronous operation. - template - void async_receive(implementation_type& impl, const Mutable_Buffers& buffers, + template + void async_receive(implementation_type& impl, + const MutableBufferSequence& buffers, socket_base::message_flags flags, Handler handler) { - if (impl.socket_ == invalid_socket) + if (!is_open(impl)) { - asio::error error(asio::error::bad_descriptor); - io_service().post(bind_handler(handler, error, 0)); + this->io_service().post(bind_handler(handler, + asio::error::bad_descriptor, 0)); } else { if (impl.protocol_.type() == SOCK_STREAM) { // Determine total size of buffers. - typename Mutable_Buffers::const_iterator iter = buffers.begin(); - typename Mutable_Buffers::const_iterator end = buffers.end(); + typename MutableBufferSequence::const_iterator iter = buffers.begin(); + typename MutableBufferSequence::const_iterator end = buffers.end(); size_t i = 0; size_t total_buffer_size = 0; for (; iter != end && i < max_buffers; ++iter, ++i) @@ -879,8 +944,8 @@ public: // A request to receive 0 bytes on a stream socket is a no-op. if (total_buffer_size == 0) { - asio::error error(asio::error::success); - io_service().post(bind_handler(handler, error, 0)); + this->io_service().post(bind_handler(handler, + asio::error_code(), 0)); return; } } @@ -889,10 +954,10 @@ public: if (!(impl.flags_ & implementation_type::internal_non_blocking)) { ioctl_arg_type non_blocking = 1; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking)) + asio::error_code ec; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) { - asio::error error(socket_ops::get_error()); - io_service().post(bind_handler(handler, error, 0)); + this->io_service().post(bind_handler(handler, ec, 0)); return; } impl.flags_ |= implementation_type::internal_non_blocking; @@ -901,29 +966,36 @@ public: if (flags & socket_base::message_out_of_band) { reactor_.start_except_op(impl.socket_, - receive_handler( - impl.socket_, io_service(), buffers, flags, handler)); + receive_handler( + impl.socket_, this->io_service(), buffers, flags, handler)); } else { reactor_.start_read_op(impl.socket_, - receive_handler( - impl.socket_, io_service(), buffers, flags, handler)); + receive_handler( + impl.socket_, this->io_service(), buffers, flags, handler)); } } } // Receive a datagram with the endpoint of the sender. Returns the number of // bytes received. - template - size_t receive_from(implementation_type& impl, const Mutable_Buffers& buffers, + template + size_t receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, - Error_Handler error_handler) + asio::error_code& ec) { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + // Copy buffers into array. socket_ops::buf bufs[max_buffers]; - typename Mutable_Buffers::const_iterator iter = buffers.begin(); - typename Mutable_Buffers::const_iterator end = buffers.end(); + typename MutableBufferSequence::const_iterator iter = buffers.begin(); + typename MutableBufferSequence::const_iterator end = buffers.end(); size_t i = 0; for (; iter != end && i < max_buffers; ++iter, ++i) { @@ -939,50 +1011,42 @@ public: // Try to complete the operation without blocking. socket_addr_len_type addr_len = sender_endpoint.capacity(); int bytes_recvd = socket_ops::recvfrom(impl.socket_, bufs, i, flags, - sender_endpoint.data(), &addr_len); - int error = socket_ops::get_error(); + sender_endpoint.data(), &addr_len, ec); // Check if operation succeeded. if (bytes_recvd > 0) { sender_endpoint.resize(addr_len); - error_handler(asio::error(0)); return bytes_recvd; } // Check for EOF. if (bytes_recvd == 0) { - error_handler(asio::error(asio::error::eof)); + ec = asio::error::eof; return 0; } // Operation failed. if ((impl.flags_ & implementation_type::user_set_non_blocking) - || (error != asio::error::would_block - && error != asio::error::try_again)) - { - error_handler(asio::error(error)); + || (ec != asio::error::would_block + && ec != asio::error::try_again)) return 0; - } // Wait for socket to become ready. - if (socket_ops::poll_read(impl.socket_) < 0) - { - error_handler(asio::error(socket_ops::get_error())); + if (socket_ops::poll_read(impl.socket_, ec) < 0) return 0; - } } } - template + template class receive_from_handler { public: receive_from_handler(socket_type socket, - asio::io_service& io_service, const Mutable_Buffers& buffers, - endpoint_type& endpoint, socket_base::message_flags flags, - Handler handler) + asio::io_service& io_service, + const MutableBufferSequence& buffers, endpoint_type& endpoint, + socket_base::message_flags flags, Handler handler) : socket_(socket), io_service_(io_service), work_(io_service), @@ -993,20 +1057,19 @@ public: { } - bool operator()(int result) + bool operator()(const asio::error_code& result) { // Check whether the operation was successful. if (result != 0) { - asio::error error(result); - io_service_.post(bind_handler(handler_, error, 0)); + io_service_.post(bind_handler(handler_, result, 0)); return true; } // Copy buffers into array. socket_ops::buf bufs[max_buffers]; - typename Mutable_Buffers::const_iterator iter = buffers_.begin(); - typename Mutable_Buffers::const_iterator end = buffers_.end(); + typename MutableBufferSequence::const_iterator iter = buffers_.begin(); + typename MutableBufferSequence::const_iterator end = buffers_.end(); size_t i = 0; for (; iter != end && i < max_buffers; ++iter, ++i) { @@ -1018,22 +1081,19 @@ public: // Receive some data. socket_addr_len_type addr_len = sender_endpoint_.capacity(); + asio::error_code ec; int bytes = socket_ops::recvfrom(socket_, bufs, i, flags_, - sender_endpoint_.data(), &addr_len); - int error_code = asio::error::success; - if (bytes < 0) - error_code = socket_ops::get_error(); - else if (bytes == 0) - error_code = asio::error::eof; - asio::error error(error_code); + sender_endpoint_.data(), &addr_len, ec); + if (bytes == 0) + ec = asio::error::eof; // Check if we need to run the operation again. - if (error == asio::error::would_block - || error == asio::error::try_again) + if (ec == asio::error::would_block + || ec == asio::error::try_again) return false; sender_endpoint_.resize(addr_len); - io_service_.post(bind_handler(handler_, error, bytes < 0 ? 0 : bytes)); + io_service_.post(bind_handler(handler_, ec, bytes < 0 ? 0 : bytes)); return true; } @@ -1041,7 +1101,7 @@ public: socket_type socket_; asio::io_service& io_service_; asio::io_service::work work_; - Mutable_Buffers buffers_; + MutableBufferSequence buffers_; endpoint_type& sender_endpoint_; socket_base::message_flags flags_; Handler handler_; @@ -1050,15 +1110,15 @@ public: // Start an asynchronous receive. The buffer for the data being received and // the sender_endpoint object must both be valid for the lifetime of the // asynchronous operation. - template + template void async_receive_from(implementation_type& impl, - const Mutable_Buffers& buffers, endpoint_type& sender_endpoint, + const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, Handler handler) { - if (impl.socket_ == invalid_socket) + if (!is_open(impl)) { - asio::error error(asio::error::bad_descriptor); - io_service().post(bind_handler(handler, error, 0)); + this->io_service().post(bind_handler(handler, + asio::error::bad_descriptor, 0)); } else { @@ -1066,166 +1126,89 @@ public: if (!(impl.flags_ & implementation_type::internal_non_blocking)) { ioctl_arg_type non_blocking = 1; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking)) + asio::error_code ec; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) { - asio::error error(socket_ops::get_error()); - io_service().post(bind_handler(handler, error, 0)); + this->io_service().post(bind_handler(handler, ec, 0)); return; } impl.flags_ |= implementation_type::internal_non_blocking; } reactor_.start_read_op(impl.socket_, - receive_from_handler( - impl.socket_, io_service(), buffers, + receive_from_handler( + impl.socket_, this->io_service(), buffers, sender_endpoint, flags, handler)); } } // Accept a new connection. - template - void accept(implementation_type& impl, Socket& peer, - Error_Handler error_handler) + template + asio::error_code accept(implementation_type& impl, + Socket& peer, endpoint_type* peer_endpoint, asio::error_code& ec) { - // We cannot accept a socket that is already open. - if (peer.native() != invalid_socket) + if (!is_open(impl)) { - error_handler(asio::error(asio::error::already_connected)); - return; + ec = asio::error::bad_descriptor; + return ec; + } + + // We cannot accept a socket that is already open. + if (peer.is_open()) + { + ec = asio::error::already_open; + return ec; } // Accept a socket. for (;;) { // Try to complete the operation without blocking. - socket_holder new_socket(socket_ops::accept(impl.socket_, 0, 0)); - int error = socket_ops::get_error(); + asio::error_code ec; + socket_holder new_socket; + socket_addr_len_type addr_len = 0; + if (peer_endpoint) + { + addr_len = peer_endpoint->capacity(); + new_socket.reset(socket_ops::accept(impl.socket_, + peer_endpoint->data(), &addr_len, ec)); + } + else + { + new_socket.reset(socket_ops::accept(impl.socket_, 0, 0, ec)); + } // Check if operation succeeded. if (new_socket.get() >= 0) { - asio::error temp_error; - peer.assign(impl.protocol_, new_socket.get(), - asio::assign_error(temp_error)); - if (temp_error) - { - error_handler(temp_error); - } - else - { + if (peer_endpoint) + peer_endpoint->resize(addr_len); + peer.assign(impl.protocol_, new_socket.get(), ec); + if (!ec) new_socket.release(); - error_handler(asio::error(0)); - } - return; + return ec; } // Operation failed. - if (error == asio::error::would_block - || error == asio::error::try_again) + if (ec == asio::error::would_block + || ec == asio::error::try_again) { if (impl.flags_ & implementation_type::user_set_non_blocking) - { - error_handler(asio::error(error)); - return; - } + return ec; // Fall through to retry operation. } - else if (error == asio::error::connection_aborted) + else if (ec == asio::error::connection_aborted) { if (impl.flags_ & implementation_type::enable_connection_aborted) - { - error_handler(asio::error(error)); - return; - } + return ec; // Fall through to retry operation. } else - { - error_handler(asio::error(error)); - return; - } + return ec; // Wait for socket to become ready. - if (socket_ops::poll_read(impl.socket_) < 0) - { - error_handler(asio::error(socket_ops::get_error())); - return; - } - } - } - - // Accept a new connection. - template - void accept_endpoint(implementation_type& impl, Socket& peer, - endpoint_type& peer_endpoint, Error_Handler error_handler) - { - // We cannot accept a socket that is already open. - if (peer.native() != invalid_socket) - { - error_handler(asio::error(asio::error::already_connected)); - return; - } - - // Accept a socket. - for (;;) - { - // Try to complete the operation without blocking. - socket_addr_len_type addr_len = peer_endpoint.capacity(); - socket_holder new_socket(socket_ops::accept( - impl.socket_, peer_endpoint.data(), &addr_len)); - int error = socket_ops::get_error(); - - // Check if operation succeeded. - if (new_socket.get() >= 0) - { - peer_endpoint.resize(addr_len); - asio::error temp_error; - peer.assign(impl.protocol_, new_socket.get(), - asio::assign_error(temp_error)); - if (temp_error) - { - error_handler(temp_error); - } - else - { - new_socket.release(); - error_handler(asio::error(0)); - } - return; - } - - // Operation failed. - if (error == asio::error::would_block - || error == asio::error::try_again) - { - if (impl.flags_ & implementation_type::user_set_non_blocking) - { - error_handler(asio::error(error)); - return; - } - // Fall through to retry operation. - } - else if (error == asio::error::connection_aborted) - { - if (impl.flags_ & implementation_type::enable_connection_aborted) - { - error_handler(asio::error(error)); - return; - } - // Fall through to retry operation. - } - else - { - error_handler(asio::error(error)); - return; - } - - // Wait for socket to become ready. - if (socket_ops::poll_read(impl.socket_) < 0) - { - error_handler(asio::error(socket_ops::get_error())); - return; - } + if (socket_ops::poll_read(impl.socket_, ec) < 0) + return ec; } } @@ -1235,50 +1218,62 @@ public: public: accept_handler(socket_type socket, asio::io_service& io_service, Socket& peer, const protocol_type& protocol, - bool enable_connection_aborted, Handler handler) + endpoint_type* peer_endpoint, bool enable_connection_aborted, + Handler handler) : socket_(socket), io_service_(io_service), work_(io_service), peer_(peer), protocol_(protocol), + peer_endpoint_(peer_endpoint), enable_connection_aborted_(enable_connection_aborted), handler_(handler) { } - bool operator()(int result) + bool operator()(const asio::error_code& result) { // Check whether the operation was successful. - if (result != 0) + if (result) { - asio::error error(result); - io_service_.post(bind_handler(handler_, error)); + io_service_.post(bind_handler(handler_, result)); return true; } // Accept the waiting connection. - socket_holder new_socket(socket_ops::accept(socket_, 0, 0)); - asio::error error(new_socket.get() == invalid_socket - ? socket_ops::get_error() : asio::error::success); + asio::error_code ec; + socket_holder new_socket; + socket_addr_len_type addr_len = 0; + if (peer_endpoint_) + { + addr_len = peer_endpoint_->capacity(); + new_socket.reset(socket_ops::accept(socket_, + peer_endpoint_->data(), &addr_len, ec)); + } + else + { + new_socket.reset(socket_ops::accept(socket_, 0, 0, ec)); + } // Check if we need to run the operation again. - if (error == asio::error::would_block - || error == asio::error::try_again) + if (ec == asio::error::would_block + || ec == asio::error::try_again) return false; - if (error == asio::error::connection_aborted + if (ec == asio::error::connection_aborted && !enable_connection_aborted_) return false; // Transfer ownership of the new socket to the peer object. - if (!error) + if (!ec) { - peer_.assign(protocol_, new_socket.get(), - asio::assign_error(error)); - if (!error) + if (peer_endpoint_) + peer_endpoint_->resize(addr_len); + peer_.assign(protocol_, new_socket.get(), ec); + if (!ec) new_socket.release(); } - io_service_.post(bind_handler(handler_, error)); + io_service_.post(bind_handler(handler_, ec)); return true; } @@ -1288,110 +1283,7 @@ public: asio::io_service::work work_; Socket& peer_; protocol_type protocol_; - bool enable_connection_aborted_; - Handler handler_; - }; - - // Start an asynchronous accept. The peer object must be valid until the - // accept's handler is invoked. - template - void async_accept(implementation_type& impl, Socket& peer, Handler handler) - { - if (impl.socket_ == invalid_socket) - { - asio::error error(asio::error::bad_descriptor); - io_service().post(bind_handler(handler, error)); - } - else if (peer.native() != invalid_socket) - { - asio::error error(asio::error::already_connected); - io_service().post(bind_handler(handler, error)); - } - else - { - // Make socket 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)) - { - asio::error error(socket_ops::get_error()); - io_service().post(bind_handler(handler, error)); - return; - } - impl.flags_ |= implementation_type::internal_non_blocking; - } - - reactor_.start_read_op(impl.socket_, - accept_handler( - impl.socket_, io_service(), peer, impl.protocol_, - (impl.flags_ & implementation_type::enable_connection_aborted) != 0, - handler)); - } - } - - template - class accept_endp_handler - { - public: - accept_endp_handler(socket_type socket, asio::io_service& io_service, - Socket& peer, endpoint_type& peer_endpoint, - bool enable_connection_aborted, Handler handler) - : socket_(socket), - io_service_(io_service), - work_(io_service), - peer_(peer), - peer_endpoint_(peer_endpoint), - enable_connection_aborted_(enable_connection_aborted), - handler_(handler) - { - } - - bool operator()(int result) - { - // Check whether the operation was successful. - if (result != 0) - { - asio::error error(result); - io_service_.post(bind_handler(handler_, error)); - return true; - } - - // Accept the waiting connection. - socket_addr_len_type addr_len = peer_endpoint_.capacity(); - socket_holder new_socket(socket_ops::accept( - socket_, peer_endpoint_.data(), &addr_len)); - asio::error error(new_socket.get() == invalid_socket - ? socket_ops::get_error() : asio::error::success); - - // Check if we need to run the operation again. - if (error == asio::error::would_block - || error == asio::error::try_again) - return false; - if (error == asio::error::connection_aborted - && !enable_connection_aborted_) - return false; - - // Transfer ownership of the new socket to the peer object. - if (!error) - { - peer_endpoint_.resize(addr_len); - peer_.assign(peer_endpoint_.protocol(), new_socket.get(), - asio::assign_error(error)); - if (!error) - new_socket.release(); - } - - io_service_.post(bind_handler(handler_, error)); - return true; - } - - private: - socket_type socket_; - asio::io_service& io_service_; - asio::io_service::work work_; - Socket& peer_; - endpoint_type& peer_endpoint_; + endpoint_type* peer_endpoint_; bool enable_connection_aborted_; Handler handler_; }; @@ -1399,18 +1291,18 @@ public: // Start an asynchronous accept. The peer and peer_endpoint objects // must be valid until the accept's handler is invoked. template - void async_accept_endpoint(implementation_type& impl, Socket& peer, - endpoint_type& peer_endpoint, Handler handler) + void async_accept(implementation_type& impl, Socket& peer, + endpoint_type* peer_endpoint, Handler handler) { - if (impl.socket_ == invalid_socket) + if (!is_open(impl)) { - asio::error error(asio::error::bad_descriptor); - io_service().post(bind_handler(handler, error)); + this->io_service().post(bind_handler(handler, + asio::error::bad_descriptor)); } - else if (peer.native() != invalid_socket) + else if (peer.is_open()) { - asio::error error(asio::error::already_connected); - io_service().post(bind_handler(handler, error)); + this->io_service().post(bind_handler(handler, + asio::error::already_open)); } else { @@ -1418,71 +1310,47 @@ public: if (!(impl.flags_ & implementation_type::internal_non_blocking)) { ioctl_arg_type non_blocking = 1; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking)) + asio::error_code ec; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) { - asio::error error(socket_ops::get_error()); - io_service().post(bind_handler(handler, error)); + this->io_service().post(bind_handler(handler, ec)); return; } impl.flags_ |= implementation_type::internal_non_blocking; } reactor_.start_read_op(impl.socket_, - accept_endp_handler( - impl.socket_, io_service(), peer, peer_endpoint, + accept_handler( + impl.socket_, this->io_service(), + peer, impl.protocol_, peer_endpoint, (impl.flags_ & implementation_type::enable_connection_aborted) != 0, handler)); } } // Connect the socket to the specified endpoint. - template - void connect(implementation_type& impl, const endpoint_type& peer_endpoint, - Error_Handler error_handler) + asio::error_code connect(implementation_type& impl, + const endpoint_type& peer_endpoint, asio::error_code& ec) { - // Open the socket if it is not already open. - if (impl.socket_ == invalid_socket) + if (!is_open(impl)) { - // Get the flags used to create the new socket. - int family = peer_endpoint.protocol().family(); - int type = peer_endpoint.protocol().type(); - int proto = peer_endpoint.protocol().protocol(); - - // Create a new socket. - impl.socket_ = socket_ops::socket(family, type, proto); - if (impl.socket_ == invalid_socket) - { - error_handler(asio::error(socket_ops::get_error())); - return; - } - - // Register the socket with the reactor. - if (int err = reactor_.register_descriptor(impl.socket_)) - { - socket_ops::close(impl.socket_); - error_handler(asio::error(err)); - return; - } + ec = asio::error::bad_descriptor; + return ec; } - else if (impl.flags_ & implementation_type::internal_non_blocking) + + 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)) - { - error_handler(asio::error(socket_ops::get_error())); - return; - } + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) + return ec; impl.flags_ &= ~implementation_type::internal_non_blocking; } // Perform the connect operation. - int result = socket_ops::connect(impl.socket_, - peer_endpoint.data(), peer_endpoint.size()); - if (result == socket_error_retval) - error_handler(asio::error(socket_ops::get_error())); - else - error_handler(asio::error(0)); + socket_ops::connect(impl.socket_, + peer_endpoint.data(), peer_endpoint.size(), ec); + return ec; } template @@ -1500,7 +1368,7 @@ public: { } - bool operator()(int result) + bool operator()(const asio::error_code& result) { // Check whether a handler has already been called for the connection. // If it has, then we don't want to do anything in this handler. @@ -1512,36 +1380,34 @@ public: reactor_.enqueue_cancel_ops_unlocked(socket_); // Check whether the operation was successful. - if (result != 0) + if (result) { - asio::error error(result); - io_service_.post(bind_handler(handler_, error)); + io_service_.post(bind_handler(handler_, result)); return true; } // Get the error code from the connect operation. int connect_error = 0; size_t connect_error_len = sizeof(connect_error); + asio::error_code ec; if (socket_ops::getsockopt(socket_, SOL_SOCKET, SO_ERROR, - &connect_error, &connect_error_len) == socket_error_retval) + &connect_error, &connect_error_len, ec) == socket_error_retval) { - asio::error error(socket_ops::get_error()); - io_service_.post(bind_handler(handler_, error)); + io_service_.post(bind_handler(handler_, ec)); return true; } // If connection failed then post the handler with the error code. if (connect_error) { - asio::error error(connect_error); - io_service_.post(bind_handler(handler_, error)); + ec = asio::error_code(connect_error, + asio::native_ecat); + io_service_.post(bind_handler(handler_, ec)); return true; } // Post the result of the successful connection operation. - asio::error error(asio::error::success); - io_service_.post(bind_handler(handler_, error)); - + io_service_.post(bind_handler(handler_, ec)); return true; } @@ -1559,41 +1425,21 @@ public: void async_connect(implementation_type& impl, const endpoint_type& peer_endpoint, Handler handler) { - // Open the socket if it is not already open. - if (impl.socket_ == invalid_socket) + if (!is_open(impl)) { - // Get the flags used to create the new socket. - int family = peer_endpoint.protocol().family(); - int type = peer_endpoint.protocol().type(); - int proto = peer_endpoint.protocol().protocol(); - - // Create a new socket. - impl.socket_ = socket_ops::socket(family, type, proto); - if (impl.socket_ == invalid_socket) - { - asio::error error(socket_ops::get_error()); - io_service().post(bind_handler(handler, error)); - return; - } - - // Register the socket with the reactor. - if (int err = reactor_.register_descriptor(impl.socket_)) - { - socket_ops::close(impl.socket_); - asio::error error(err); - io_service().post(bind_handler(handler, error)); - return; - } + this->io_service().post(bind_handler(handler, + asio::error::bad_descriptor)); + return; } // Make socket 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)) + asio::error_code ec; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) { - asio::error error(socket_ops::get_error()); - io_service().post(bind_handler(handler, error)); + this->io_service().post(bind_handler(handler, ec)); return; } impl.flags_ |= implementation_type::internal_non_blocking; @@ -1601,34 +1447,34 @@ public: // Start the connect operation. The socket is already marked as non-blocking // so the connection will take place asynchronously. + asio::error_code ec; if (socket_ops::connect(impl.socket_, peer_endpoint.data(), - peer_endpoint.size()) == 0) + peer_endpoint.size(), ec) == 0) { // The connect operation has finished successfully so we need to post the // handler immediately. - asio::error error(asio::error::success); - io_service().post(bind_handler(handler, error)); + this->io_service().post(bind_handler(handler, + asio::error_code())); } - else if (socket_ops::get_error() == asio::error::in_progress - || socket_ops::get_error() == asio::error::would_block) + else if (ec == asio::error::in_progress + || ec == asio::error::would_block) { // The connection is happening in the background, and we need to wait // until the socket becomes writeable. boost::shared_ptr completed(new bool(false)); reactor_.start_write_and_except_ops(impl.socket_, connect_handler( - impl.socket_, completed, io_service(), reactor_, handler)); + impl.socket_, completed, this->io_service(), reactor_, handler)); } else { // The connect operation has failed, so post the handler immediately. - asio::error error(socket_ops::get_error()); - io_service().post(bind_handler(handler, error)); + this->io_service().post(bind_handler(handler, ec)); } } private: - // The selector that performs event demultiplexing for the provider. + // The selector that performs event demultiplexing for the service. Reactor& reactor_; }; diff --git a/libtorrent/include/libtorrent/asio/detail/reactor_op_queue.hpp b/libtorrent/include/libtorrent/asio/detail/reactor_op_queue.hpp index dbf86c2e5..b2d1054c6 100644 --- a/libtorrent/include/libtorrent/asio/detail/reactor_op_queue.hpp +++ b/libtorrent/include/libtorrent/asio/detail/reactor_op_queue.hpp @@ -2,7 +2,7 @@ // reactor_op_queue.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -100,7 +100,8 @@ public: // Dispatch the first operation corresponding to the descriptor. Returns true // if there are more operations queued for the descriptor. - bool dispatch_operation(Descriptor descriptor, int result) + bool dispatch_operation(Descriptor descriptor, + const asio::error_code& result) { typename operation_map::iterator i = operations_.find(descriptor); if (i != operations_.end()) @@ -137,7 +138,8 @@ public: } // Dispatch all operations corresponding to the descriptor. - void dispatch_all_operations(Descriptor descriptor, int result) + void dispatch_all_operations(Descriptor descriptor, + const asio::error_code& result) { typename operation_map::iterator i = operations_.find(descriptor); if (i != operations_.end()) @@ -158,8 +160,8 @@ public: i->second = this_op; return; } - operations_.erase(i); } + operations_.erase(i); } } @@ -179,7 +181,8 @@ public: // Dispatch the operations corresponding to the ready file descriptors // contained in the given descriptor set. template - void dispatch_descriptors(const Descriptor_Set& descriptors, int result) + void dispatch_descriptors(const Descriptor_Set& descriptors, + const asio::error_code& result) { typename operation_map::iterator i = operations_.begin(); while (i != operations_.end()) @@ -282,7 +285,7 @@ private: } // Perform the operation. - bool invoke(int result) + bool invoke(const asio::error_code& result) { return invoke_func_(this, result); } @@ -294,7 +297,8 @@ private: } protected: - typedef bool (*invoke_func_type)(op_base*, int); + typedef bool (*invoke_func_type)(op_base*, + const asio::error_code&); typedef void (*destroy_func_type)(op_base*); // Construct an operation for the given descriptor. @@ -343,7 +347,8 @@ private: } // Invoke the handler. - static bool invoke_handler(op_base* base, int result) + static bool invoke_handler(op_base* base, + const asio::error_code& result) { return static_cast*>(base)->handler_(result); } diff --git a/libtorrent/include/libtorrent/asio/detail/resolver_service.hpp b/libtorrent/include/libtorrent/asio/detail/resolver_service.hpp index 31c87e58e..c820b75f3 100644 --- a/libtorrent/include/libtorrent/asio/detail/resolver_service.hpp +++ b/libtorrent/include/libtorrent/asio/detail/resolver_service.hpp @@ -2,7 +2,7 @@ // resolver_service.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -29,6 +29,7 @@ #include "asio/detail/bind_handler.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/noncopyable.hpp" +#include "asio/detail/service_base.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/thread.hpp" @@ -38,7 +39,7 @@ namespace detail { template class resolver_service - : public asio::io_service::service + : public asio::detail::service_base > { private: // Helper class to perform exception-safe cleanup of addrinfo objects. @@ -84,7 +85,8 @@ public: // Constructor. resolver_service(asio::io_service& io_service) - : asio::io_service::service(io_service), + : asio::detail::service_base< + resolver_service >(io_service), mutex_(), work_io_service_(new asio::io_service), work_(new asio::io_service::work(*work_io_service_)), @@ -104,7 +106,7 @@ public: work_.reset(); if (work_io_service_) { - work_io_service_->interrupt(); + work_io_service_->stop(); if (work_thread_) { work_thread_->join(); @@ -132,23 +134,21 @@ public: } // Resolve a query to a list of entries. - template iterator_type resolve(implementation_type&, const query_type& query, - Error_Handler error_handler) + asio::error_code& ec) { asio::detail::addrinfo_type* address_info = 0; std::string host_name = query.host_name(); std::string service_name = query.service_name(); asio::detail::addrinfo_type hints = query.hints(); - int result = socket_ops::getaddrinfo( - host_name.length() ? host_name.c_str() : 0, - service_name.c_str(), &hints, &address_info); + socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0, + service_name.c_str(), &hints, &address_info, ec); auto_addrinfo auto_address_info(address_info); - error_handler(asio::error(result)); - if (result != 0) + if (ec) return iterator_type(); + return iterator_type::create(address_info, host_name, service_name); } @@ -173,8 +173,7 @@ public: { iterator_type iterator; io_service_.post(asio::detail::bind_handler(handler_, - asio::error(asio::error::operation_aborted), - iterator)); + asio::error::operation_aborted, iterator)); return; } @@ -183,18 +182,17 @@ public: std::string host_name = query_.host_name(); std::string service_name = query_.service_name(); asio::detail::addrinfo_type hints = query_.hints(); - int result = socket_ops::getaddrinfo( - host_name.length() ? host_name.c_str() : 0, - service_name.c_str(), &hints, &address_info); + asio::error_code ec; + socket_ops::getaddrinfo(host_name.length() ? host_name.c_str() : 0, + service_name.c_str(), &hints, &address_info, ec); auto_addrinfo auto_address_info(address_info); // Invoke the handler and pass the result. - asio::error e(result); iterator_type iterator; - if (result == 0) + if (!ec) iterator = iterator_type::create(address_info, host_name, service_name); io_service_.post(asio::detail::bind_handler( - handler_, e, iterator)); + handler_, ec, iterator)); } private: @@ -215,32 +213,31 @@ public: start_work_thread(); work_io_service_->post( resolve_query_handler( - impl, query, io_service(), handler)); + impl, query, this->io_service(), handler)); } } // Resolve an endpoint to a list of entries. - template iterator_type resolve(implementation_type&, - const endpoint_type& endpoint, Error_Handler error_handler) + const endpoint_type& endpoint, asio::error_code& ec) { // First try resolving with the service name. If that fails try resolving // but allow the service to be returned as a number. char host_name[NI_MAXHOST]; char service_name[NI_MAXSERV]; int flags = endpoint.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0; - int result = socket_ops::getnameinfo(endpoint.data(), endpoint.size(), - host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags); - if (result) + socket_ops::getnameinfo(endpoint.data(), endpoint.size(), + host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec); + if (ec) { flags |= NI_NUMERICSERV; - result = socket_ops::getnameinfo(endpoint.data(), endpoint.size(), - host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags); + socket_ops::getnameinfo(endpoint.data(), endpoint.size(), + host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec); } - error_handler(asio::error(result)); - if (result != 0) + if (ec) return iterator_type(); + return iterator_type::create(endpoint, host_name, service_name); } @@ -266,8 +263,7 @@ public: { iterator_type iterator; io_service_.post(asio::detail::bind_handler(handler_, - asio::error(asio::error::operation_aborted), - iterator)); + asio::error::operation_aborted, iterator)); return; } @@ -277,22 +273,22 @@ public: char host_name[NI_MAXHOST]; char service_name[NI_MAXSERV]; int flags = endpoint_.protocol().type() == SOCK_DGRAM ? NI_DGRAM : 0; - int result = socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(), - host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags); - if (result) + asio::error_code ec; + socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(), + host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec); + if (ec) { flags |= NI_NUMERICSERV; - result = socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(), - host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags); + socket_ops::getnameinfo(endpoint_.data(), endpoint_.size(), + host_name, NI_MAXHOST, service_name, NI_MAXSERV, flags, ec); } // Invoke the handler and pass the result. - asio::error e(result); iterator_type iterator; - if (result == 0) + if (!ec) iterator = iterator_type::create(endpoint_, host_name, service_name); io_service_.post(asio::detail::bind_handler( - handler_, e, iterator)); + handler_, ec, iterator)); } private: @@ -313,7 +309,7 @@ public: start_work_thread(); work_io_service_->post( resolve_endpoint_handler( - impl, endpoint, io_service(), handler)); + impl, endpoint, this->io_service(), handler)); } } diff --git a/libtorrent/include/libtorrent/asio/detail/scoped_lock.hpp b/libtorrent/include/libtorrent/asio/detail/scoped_lock.hpp index 40ad27d2d..64c77cbab 100644 --- a/libtorrent/include/libtorrent/asio/detail/scoped_lock.hpp +++ b/libtorrent/include/libtorrent/asio/detail/scoped_lock.hpp @@ -2,7 +2,7 @@ // scoped_lock.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/select_interrupter.hpp b/libtorrent/include/libtorrent/asio/detail/select_interrupter.hpp index 6b4d51316..de7fc9611 100644 --- a/libtorrent/include/libtorrent/asio/detail/select_interrupter.hpp +++ b/libtorrent/include/libtorrent/asio/detail/select_interrupter.hpp @@ -2,7 +2,7 @@ // select_interrupter.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/select_reactor.hpp b/libtorrent/include/libtorrent/asio/detail/select_reactor.hpp index e6335aef7..83f093ae6 100644 --- a/libtorrent/include/libtorrent/asio/detail/select_reactor.hpp +++ b/libtorrent/include/libtorrent/asio/detail/select_reactor.hpp @@ -2,7 +2,7 @@ // select_reactor.hpp // ~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -31,14 +31,15 @@ #include "asio/detail/fd_set_adapter.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/noncopyable.hpp" -#include "asio/detail/task_io_service.hpp" -#include "asio/detail/thread.hpp" #include "asio/detail/reactor_op_queue.hpp" #include "asio/detail/select_interrupter.hpp" #include "asio/detail/select_reactor_fwd.hpp" +#include "asio/detail/service_base.hpp" #include "asio/detail/signal_blocker.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" +#include "asio/detail/task_io_service.hpp" +#include "asio/detail/thread.hpp" #include "asio/detail/timer_queue.hpp" namespace asio { @@ -46,12 +47,13 @@ namespace detail { template class select_reactor - : public asio::io_service::service + : public asio::detail::service_base > { public: // Constructor. select_reactor(asio::io_service& io_service) - : asio::io_service::service(io_service), + : asio::detail::service_base< + select_reactor >(io_service), mutex_(), select_in_progress_(false), interrupter_(), @@ -194,6 +196,21 @@ public: timer_queues_.push_back(&timer_queue); } + // Remove a timer queue from the reactor. + template + void remove_timer_queue(timer_queue& timer_queue) + { + asio::detail::mutex::scoped_lock lock(mutex_); + for (std::size_t i = 0; i < timer_queues_.size(); ++i) + { + if (timer_queues_[i] == &timer_queue) + { + timer_queues_.erase(timer_queues_.begin() + i); + return; + } + } + } + // Schedule a timer in the given timer queue to expire at the specified // absolute time. The handler object will be invoked when the timer expires. template @@ -275,8 +292,9 @@ private: timeval* tv = block ? get_timeout(tv_buf) : &tv_buf; select_in_progress_ = true; lock.unlock(); + asio::error_code ec; int retval = socket_ops::select(static_cast(max_fd + 1), - read_fds, write_fds, except_fds, tv); + read_fds, write_fds, except_fds, tv, ec); lock.lock(); select_in_progress_ = false; @@ -292,9 +310,12 @@ private: { // Exception operations must be processed first to ensure that any // out-of-band data is read before normal data. - except_op_queue_.dispatch_descriptors(except_fds, 0); - read_op_queue_.dispatch_descriptors(read_fds, 0); - write_op_queue_.dispatch_descriptors(write_fds, 0); + except_op_queue_.dispatch_descriptors(except_fds, + asio::error_code()); + read_op_queue_.dispatch_descriptors(read_fds, + asio::error_code()); + write_op_queue_.dispatch_descriptors(write_fds, + asio::error_code()); except_op_queue_.dispatch_cancellations(); read_op_queue_.dispatch_cancellations(); write_op_queue_.dispatch_cancellations(); diff --git a/libtorrent/include/libtorrent/asio/detail/select_reactor_fwd.hpp b/libtorrent/include/libtorrent/asio/detail/select_reactor_fwd.hpp index 35c524c7e..3e1687eae 100644 --- a/libtorrent/include/libtorrent/asio/detail/select_reactor_fwd.hpp +++ b/libtorrent/include/libtorrent/asio/detail/select_reactor_fwd.hpp @@ -2,7 +2,7 @@ // select_reactor_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/service_base.hpp b/libtorrent/include/libtorrent/asio/detail/service_base.hpp new file mode 100644 index 000000000..4f375c921 --- /dev/null +++ b/libtorrent/include/libtorrent/asio/detail/service_base.hpp @@ -0,0 +1,49 @@ +// +// service_base.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SERVICE_BASE_HPP +#define ASIO_DETAIL_SERVICE_BASE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +#include "asio/io_service.hpp" +#include "asio/detail/service_id.hpp" + +namespace asio { +namespace detail { + +// Special service base class to keep classes header-file only. +template +class service_base + : public asio::io_service::service +{ +public: + static asio::detail::service_id id; + + // Constructor. + service_base(asio::io_service& io_service) + : asio::io_service::service(io_service) + { + } +}; + +template +asio::detail::service_id service_base::id; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SERVICE_BASE_HPP diff --git a/libtorrent/include/libtorrent/asio/detail/service_id.hpp b/libtorrent/include/libtorrent/asio/detail/service_id.hpp new file mode 100644 index 000000000..8ff19097b --- /dev/null +++ b/libtorrent/include/libtorrent/asio/detail/service_id.hpp @@ -0,0 +1,37 @@ +// +// service_id.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SERVICE_ID_HPP +#define ASIO_DETAIL_SERVICE_ID_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +#include "asio/io_service.hpp" + +namespace asio { +namespace detail { + +// Special derived service id type to keep classes header-file only. +template +class service_id + : public asio::io_service::id +{ +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SERVICE_ID_HPP diff --git a/libtorrent/include/libtorrent/asio/detail/service_registry.hpp b/libtorrent/include/libtorrent/asio/detail/service_registry.hpp index d7164d088..bd1c3ea5b 100644 --- a/libtorrent/include/libtorrent/asio/detail/service_registry.hpp +++ b/libtorrent/include/libtorrent/asio/detail/service_registry.hpp @@ -2,7 +2,7 @@ // service_registry.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -22,19 +22,20 @@ #include #include "asio/detail/pop_options.hpp" +#include "asio/io_service.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/noncopyable.hpp" +#include "asio/detail/service_id.hpp" namespace asio { namespace detail { -template class service_registry : private noncopyable { public: // Constructor. - service_registry(Owner& o) + service_registry(asio::io_service& o) : owner_(o), first_service_(0) { @@ -46,7 +47,7 @@ public: // Shutdown all services. This must be done in a separate loop before the // services are destroyed since the destructors of user-defined handler // objects may try to access other service objects. - typename Owner::service* service = first_service_; + asio::io_service::service* service = first_service_; while (service) { service->shutdown_service(); @@ -56,7 +57,7 @@ public: // Destroy all services. while (first_service_) { - typename Owner::service* next_service = first_service_->next_; + asio::io_service::service* next_service = first_service_->next_; delete first_service_; first_service_ = next_service; } @@ -71,10 +72,10 @@ public: asio::detail::mutex::scoped_lock lock(mutex_); // First see if there is an existing service object for the given type. - typename Owner::service* service = first_service_; + asio::io_service::service* service = first_service_; while (service) { - if (*service->type_info_ == typeid(Service)) + if (service_id_matches(*service, Service::id)) return *static_cast(service); service = service->next_; } @@ -84,7 +85,7 @@ public: // service's constructor. lock.unlock(); std::auto_ptr new_service(new Service(owner_)); - new_service->type_info_ = &typeid(Service); + init_service_id(*new_service, Service::id); Service& new_service_ref = *new_service; lock.lock(); @@ -93,7 +94,7 @@ public: service = first_service_; while (service) { - if (*service->type_info_ == typeid(Service)) + if (service_id_matches(*service, Service::id)) return *static_cast(service); service = service->next_; } @@ -113,18 +114,20 @@ public: asio::detail::mutex::scoped_lock lock(mutex_); // Check if there is an existing service object for the given type. - typename Owner::service* service = first_service_; + asio::io_service::service* service = first_service_; while (service) { - if (*service->type_info_ == typeid(Service)) + if (service_id_matches(*service, Service::id)) return false; service = service->next_; } // Take ownership of the service object. - new_service->type_info_ = &typeid(Service); + init_service_id(*new_service, Service::id); new_service->next_ = first_service_; first_service_ = new_service; + + return true; } // Check whether a service object of the specified type already exists. @@ -133,10 +136,10 @@ public: { asio::detail::mutex::scoped_lock lock(mutex_); - typename Owner::service* service = first_service_; + asio::io_service::service* service = first_service_; while (service) { - if (*service->type_info_ == typeid(Service)) + if (service_id_matches(*service, Service::id)) return true; service = service->next_; } @@ -145,14 +148,46 @@ public: } private: + // Set a service's id. + void init_service_id(asio::io_service::service& service, + const asio::io_service::id& id) + { + service.type_info_ = 0; + service.id_ = &id; + } + + // Set a service's id. + template + void init_service_id(asio::io_service::service& service, + const asio::detail::service_id& /*id*/) + { + service.type_info_ = &typeid(Service); + service.id_ = 0; + } + + // Check if a service matches the given id. + bool service_id_matches(const asio::io_service::service& service, + const asio::io_service::id& id) + { + return service.id_ == &id; + } + + // Check if a service matches the given id. + template + bool service_id_matches(const asio::io_service::service& service, + const asio::detail::service_id& /*id*/) + { + return service.type_info_ != 0 && *service.type_info_ == typeid(Service); + } + // Mutex to protect access to internal data. mutable asio::detail::mutex mutex_; // The owner of this service registry and the services it contains. - Owner& owner_; + asio::io_service& owner_; // The first service in the list of contained services. - typename Owner::service* first_service_; + asio::io_service::service* first_service_; }; } // namespace detail diff --git a/libtorrent/include/libtorrent/asio/detail/service_registry_fwd.hpp b/libtorrent/include/libtorrent/asio/detail/service_registry_fwd.hpp new file mode 100644 index 000000000..596c24be3 --- /dev/null +++ b/libtorrent/include/libtorrent/asio/detail/service_registry_fwd.hpp @@ -0,0 +1,30 @@ +// +// service_registry_fwd.hpp +// ~~~~~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP +#define ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +namespace asio { +namespace detail { + +class service_registry; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_SERVICE_REGISTRY_FWD_HPP diff --git a/libtorrent/include/libtorrent/asio/detail/signal_blocker.hpp b/libtorrent/include/libtorrent/asio/detail/signal_blocker.hpp index 92299e3e7..3eb3ba495 100644 --- a/libtorrent/include/libtorrent/asio/detail/signal_blocker.hpp +++ b/libtorrent/include/libtorrent/asio/detail/signal_blocker.hpp @@ -2,7 +2,7 @@ // signal_blocker.hpp // ~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/signal_init.hpp b/libtorrent/include/libtorrent/asio/detail/signal_init.hpp index 95c05e852..3df395dc3 100644 --- a/libtorrent/include/libtorrent/asio/detail/signal_init.hpp +++ b/libtorrent/include/libtorrent/asio/detail/signal_init.hpp @@ -2,7 +2,7 @@ // signal_init.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/socket_holder.hpp b/libtorrent/include/libtorrent/asio/detail/socket_holder.hpp index a94e01e2c..e45f4fd61 100644 --- a/libtorrent/include/libtorrent/asio/detail/socket_holder.hpp +++ b/libtorrent/include/libtorrent/asio/detail/socket_holder.hpp @@ -2,7 +2,7 @@ // socket_holder.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -44,7 +44,10 @@ public: ~socket_holder() { if (socket_ != invalid_socket) - socket_ops::close(socket_); + { + asio::error_code ec; + socket_ops::close(socket_, ec); + } } // Get the underlying socket. @@ -58,7 +61,8 @@ public: { if (socket_ != invalid_socket) { - socket_ops::close(socket_); + asio::error_code ec; + socket_ops::close(socket_, ec); socket_ = invalid_socket; } } diff --git a/libtorrent/include/libtorrent/asio/detail/socket_ops.hpp b/libtorrent/include/libtorrent/asio/detail/socket_ops.hpp index c3f4a59b2..166319bb1 100644 --- a/libtorrent/include/libtorrent/asio/detail/socket_ops.hpp +++ b/libtorrent/include/libtorrent/asio/detail/socket_ops.hpp @@ -2,7 +2,7 @@ // socket_ops.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -19,6 +19,8 @@ #include "asio/detail/push_options.hpp" #include +#include +#include #include #include #include @@ -36,44 +38,39 @@ namespace asio { namespace detail { namespace socket_ops { -inline int get_error() +inline void clear_error(asio::error_code& ec) { + errno = 0; #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - return WSAGetLastError(); -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - return errno; -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) -} - -inline void set_error(int error) -{ - errno = error; -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - WSASetLastError(error); + WSASetLastError(0); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + ec = asio::error_code(); } template -inline ReturnType error_wrapper(ReturnType return_value) +inline ReturnType error_wrapper(ReturnType return_value, + asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - errno = WSAGetLastError(); -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + ec = asio::error_code(WSAGetLastError(), asio::native_ecat); +#else + ec = asio::error_code(errno, asio::native_ecat); +#endif return return_value; } inline socket_type accept(socket_type s, socket_addr_type* addr, - socket_addr_len_type* addrlen) + socket_addr_len_type* addrlen, asio::error_code& ec) { - set_error(0); + clear_error(ec); #if defined(__MACH__) && defined(__APPLE__) - socket_type new_s = error_wrapper(::accept(s, addr, addrlen)); + socket_type new_s = error_wrapper(::accept(s, addr, addrlen), ec); if (new_s == invalid_socket) return new_s; int optval = 1; int result = error_wrapper(::setsockopt(new_s, - SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval))); + SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); if (result != 0) { ::close(new_s); @@ -82,44 +79,44 @@ inline socket_type accept(socket_type s, socket_addr_type* addr, return new_s; #else - return error_wrapper(::accept(s, addr, addrlen)); + return error_wrapper(::accept(s, addr, addrlen), ec); #endif } inline int bind(socket_type s, const socket_addr_type* addr, - socket_addr_len_type addrlen) + socket_addr_len_type addrlen, asio::error_code& ec) { - set_error(0); - return error_wrapper(::bind(s, addr, addrlen)); + clear_error(ec); + return error_wrapper(::bind(s, addr, addrlen), ec); } -inline int close(socket_type s) +inline int close(socket_type s, asio::error_code& ec) { - set_error(0); + clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - return error_wrapper(::closesocket(s)); + return error_wrapper(::closesocket(s), ec); #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - return error_wrapper(::close(s)); + return error_wrapper(::close(s), ec); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } -inline int shutdown(socket_type s, int what) +inline int shutdown(socket_type s, int what, asio::error_code& ec) { - set_error(0); - return error_wrapper(::shutdown(s, what)); + clear_error(ec); + return error_wrapper(::shutdown(s, what), ec); } inline int connect(socket_type s, const socket_addr_type* addr, - socket_addr_len_type addrlen) + socket_addr_len_type addrlen, asio::error_code& ec) { - set_error(0); - return error_wrapper(::connect(s, addr, addrlen)); + clear_error(ec); + return error_wrapper(::connect(s, addr, addrlen), ec); } -inline int listen(socket_type s, int backlog) +inline int listen(socket_type s, int backlog, asio::error_code& ec) { - set_error(0); - return error_wrapper(::listen(s, backlog)); + clear_error(ec); + return error_wrapper(::listen(s, backlog), ec); } #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -150,16 +147,17 @@ inline void init_buf(buf& b, const void* data, size_t size) #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } -inline int recv(socket_type s, buf* bufs, size_t count, int flags) +inline int recv(socket_type s, buf* bufs, size_t count, int flags, + asio::error_code& ec) { - set_error(0); + clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Receive some data. DWORD recv_buf_count = static_cast(count); DWORD bytes_transferred = 0; DWORD recv_flags = flags; int result = error_wrapper(::WSARecv(s, bufs, - recv_buf_count, &bytes_transferred, &recv_flags, 0, 0)); + recv_buf_count, &bytes_transferred, &recv_flags, 0, 0), ec); if (result != 0) return -1; return bytes_transferred; @@ -172,21 +170,22 @@ inline int recv(socket_type s, buf* bufs, size_t count, int flags) msg.msg_control = 0; msg.msg_controllen = 0; msg.msg_flags = 0; - return error_wrapper(::recvmsg(s, &msg, flags)); + return error_wrapper(::recvmsg(s, &msg, flags), ec); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags, - socket_addr_type* addr, socket_addr_len_type* addrlen) + socket_addr_type* addr, socket_addr_len_type* addrlen, + asio::error_code& ec) { - set_error(0); + clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Receive some data. DWORD recv_buf_count = static_cast(count); DWORD bytes_transferred = 0; DWORD recv_flags = flags; int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count, - &bytes_transferred, &recv_flags, addr, addrlen, 0, 0)); + &bytes_transferred, &recv_flags, addr, addrlen, 0, 0), ec); if (result != 0) return -1; return bytes_transferred; @@ -204,22 +203,23 @@ inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags, msg.msg_control = 0; msg.msg_controllen = 0; msg.msg_flags = 0; - int result = error_wrapper(::recvmsg(s, &msg, flags)); + int result = error_wrapper(::recvmsg(s, &msg, flags), ec); *addrlen = msg.msg_namelen; return result; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } -inline int send(socket_type s, const buf* bufs, size_t count, int flags) +inline int send(socket_type s, const buf* bufs, size_t count, int flags, + asio::error_code& ec) { - set_error(0); + clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Send the data. DWORD send_buf_count = static_cast(count); DWORD bytes_transferred = 0; DWORD send_flags = flags; int result = error_wrapper(::WSASend(s, const_cast(bufs), - send_buf_count, &bytes_transferred, send_flags, 0, 0)); + send_buf_count, &bytes_transferred, send_flags, 0, 0), ec); if (result != 0) return -1; return bytes_transferred; @@ -235,20 +235,21 @@ inline int send(socket_type s, const buf* bufs, size_t count, int flags) #if defined(__linux__) flags |= MSG_NOSIGNAL; #endif // defined(__linux__) - return error_wrapper(::sendmsg(s, &msg, flags)); + return error_wrapper(::sendmsg(s, &msg, flags), ec); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } inline int sendto(socket_type s, const buf* bufs, size_t count, int flags, - const socket_addr_type* addr, socket_addr_len_type addrlen) + const socket_addr_type* addr, socket_addr_len_type addrlen, + asio::error_code& ec) { - set_error(0); + clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) // Send the data. DWORD send_buf_count = static_cast(count); DWORD bytes_transferred = 0; - int result = ::WSASendTo(s, const_cast(bufs), send_buf_count, - &bytes_transferred, flags, addr, addrlen, 0, 0); + int result = error_wrapper(::WSASendTo(s, const_cast(bufs), + send_buf_count, &bytes_transferred, flags, addr, addrlen, 0, 0), ec); if (result != 0) return -1; return bytes_transferred; @@ -269,24 +270,39 @@ inline int sendto(socket_type s, const buf* bufs, size_t count, int flags, #if defined(__linux__) flags |= MSG_NOSIGNAL; #endif // defined(__linux__) - return error_wrapper(::sendmsg(s, &msg, flags)); + return error_wrapper(::sendmsg(s, &msg, flags), ec); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } -inline socket_type socket(int af, int type, int protocol) +inline socket_type socket(int af, int type, int protocol, + asio::error_code& ec) { - set_error(0); + clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - return error_wrapper(::WSASocket(af, type, protocol, 0, 0, - WSA_FLAG_OVERLAPPED)); + socket_type s = error_wrapper(::WSASocket(af, type, protocol, 0, 0, + WSA_FLAG_OVERLAPPED), ec); + if (s == invalid_socket) + return s; + + if (af == AF_INET6) + { + // Try to enable the POSIX default behaviour of having IPV6_V6ONLY set to + // false. This will only succeed on Windows Vista and later versions of + // Windows, where a dual-stack IPv4/v6 implementation is available. + DWORD optval = 0; + ::setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + reinterpret_cast(&optval), sizeof(optval)); + } + + return s; #elif defined(__MACH__) && defined(__APPLE__) - socket_type s = error_wrapper(::socket(af, type, protocol)); + socket_type s = error_wrapper(::socket(af, type, protocol), ec); if (s == invalid_socket) return s; int optval = 1; int result = error_wrapper(::setsockopt(s, - SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval))); + SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); if (result != 0) { ::close(s); @@ -295,70 +311,94 @@ inline socket_type socket(int af, int type, int protocol) return s; #else - return error_wrapper(::socket(af, type, protocol)); + return error_wrapper(::socket(af, type, protocol), ec); #endif } inline int setsockopt(socket_type s, int level, int optname, - const void* optval, size_t optlen) + const void* optval, size_t optlen, asio::error_code& ec) { - set_error(0); + clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) return error_wrapper(::setsockopt(s, level, optname, - reinterpret_cast(optval), static_cast(optlen))); + reinterpret_cast(optval), static_cast(optlen)), ec); #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) return error_wrapper(::setsockopt(s, level, optname, optval, - static_cast(optlen))); + static_cast(optlen)), ec); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } inline int getsockopt(socket_type s, int level, int optname, void* optval, - size_t* optlen) + size_t* optlen, asio::error_code& ec) { - set_error(0); + clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) int tmp_optlen = static_cast(*optlen); int result = error_wrapper(::getsockopt(s, level, optname, - reinterpret_cast(optval), &tmp_optlen)); + reinterpret_cast(optval), &tmp_optlen), ec); *optlen = static_cast(tmp_optlen); + if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY + && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) + { + // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are only + // supported on Windows Vista and later. To simplify program logic we will + // fake success of getting this option and specify that the value is + // non-zero (i.e. true). This corresponds to the behavior of IPv6 sockets + // on Windows platforms pre-Vista. + *static_cast(optval) = 1; + clear_error(ec); + } return result; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) socklen_t tmp_optlen = static_cast(*optlen); int result = error_wrapper(::getsockopt(s, level, optname, - optval, &tmp_optlen)); + optval, &tmp_optlen), ec); *optlen = static_cast(tmp_optlen); +#if defined(__linux__) + if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int) + && (optname == SO_SNDBUF || optname == SO_RCVBUF)) + { + // On Linux, setting SO_SNDBUF or SO_RCVBUF to N actually causes the kernel + // to set the buffer size to N*2. Linux puts additional stuff into the + // buffers so that only about half is actually available to the application. + // The retrieved value is divided by 2 here to make it appear as though the + // correct value has been set. + *static_cast(optval) /= 2; + } +#endif // defined(__linux__) return result; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } inline int getpeername(socket_type s, socket_addr_type* addr, - socket_addr_len_type* addrlen) + socket_addr_len_type* addrlen, asio::error_code& ec) { - set_error(0); - return error_wrapper(::getpeername(s, addr, addrlen)); + clear_error(ec); + return error_wrapper(::getpeername(s, addr, addrlen), ec); } inline int getsockname(socket_type s, socket_addr_type* addr, - socket_addr_len_type* addrlen) + socket_addr_len_type* addrlen, asio::error_code& ec) { - set_error(0); - return error_wrapper(::getsockname(s, addr, addrlen)); + clear_error(ec); + return error_wrapper(::getsockname(s, addr, addrlen), ec); } -inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg) +inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg, + asio::error_code& ec) { - set_error(0); + clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - return error_wrapper(::ioctlsocket(s, cmd, arg)); + return error_wrapper(::ioctlsocket(s, cmd, arg), ec); #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - return error_wrapper(::ioctl(s, cmd, arg)); + return error_wrapper(::ioctl(s, cmd, arg), ec); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } inline int select(int nfds, fd_set* readfds, fd_set* writefds, - fd_set* exceptfds, timeval* timeout) + fd_set* exceptfds, timeval* timeout, asio::error_code& ec) { - set_error(0); + clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) if (!readfds && !writefds && !exceptfds && timeout) { @@ -366,6 +406,7 @@ inline int select(int nfds, fd_set* readfds, fd_set* writefds, if (milliseconds == 0) milliseconds = 1; // Force context switch. ::Sleep(milliseconds); + ec = asio::error_code(); return 0; } @@ -379,55 +420,56 @@ inline int select(int nfds, fd_set* readfds, fd_set* writefds, && timeout->tv_usec > 0 && timeout->tv_usec < 1000) timeout->tv_usec = 1000; #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - return error_wrapper(::select(nfds, readfds, writefds, exceptfds, timeout)); + return error_wrapper(::select(nfds, readfds, + writefds, exceptfds, timeout), ec); } -inline int poll_read(socket_type s) +inline int poll_read(socket_type s, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) FD_SET fds; FD_ZERO(&fds); FD_SET(s, &fds); - set_error(0); - return error_wrapper(::select(s, &fds, 0, 0, 0)); + clear_error(ec); + return error_wrapper(::select(s, &fds, 0, 0, 0), ec); #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) pollfd fds; fds.fd = s; fds.events = POLLIN; fds.revents = 0; - set_error(0); - return error_wrapper(::poll(&fds, 1, -1)); + clear_error(ec); + return error_wrapper(::poll(&fds, 1, -1), ec); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } -inline int poll_write(socket_type s) +inline int poll_write(socket_type s, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) FD_SET fds; FD_ZERO(&fds); FD_SET(s, &fds); - set_error(0); - return error_wrapper(::select(s, 0, &fds, 0, 0)); + clear_error(ec); + return error_wrapper(::select(s, 0, &fds, 0, 0), ec); #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) pollfd fds; fds.fd = s; fds.events = POLLOUT; fds.revents = 0; - set_error(0); - return error_wrapper(::poll(&fds, 1, -1)); + clear_error(ec); + return error_wrapper(::poll(&fds, 1, -1), ec); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } inline const char* inet_ntop(int af, const void* src, char* dest, size_t length, - unsigned long scope_id = 0) + unsigned long scope_id, asio::error_code& ec) { - set_error(0); + clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) using namespace std; // For memcpy. if (af != AF_INET && af != AF_INET6) { - set_error(asio::error::address_family_not_supported); + ec = asio::error::address_family_not_supported; return 0; } @@ -457,17 +499,21 @@ inline const char* inet_ntop(int af, const void* src, char* dest, size_t length, DWORD string_length = static_cast(length); int result = error_wrapper(::WSAAddressToStringA( reinterpret_cast(&address), - address_length, 0, dest, &string_length)); + address_length, 0, dest, &string_length), ec); + + // Windows may set error code on success. + if (result != socket_error_retval) + clear_error(ec); // Windows may not set an error code on failure. - if (result == socket_error_retval && get_error() == 0) - set_error(asio::error::invalid_argument); + else if (result == socket_error_retval && !ec) + ec = asio::error::invalid_argument; return result == socket_error_retval ? 0 : dest; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - const char* result = error_wrapper(::inet_ntop(af, src, dest, length)); - if (result == 0 && get_error() == 0) - set_error(asio::error::invalid_argument); + const char* result = error_wrapper(::inet_ntop(af, src, dest, length), ec); + if (result == 0 && !ec) + ec = asio::error::invalid_argument; if (result != 0 && af == AF_INET6 && scope_id != 0) { using namespace std; // For strcat and sprintf. @@ -483,15 +529,15 @@ inline const char* inet_ntop(int af, const void* src, char* dest, size_t length, } inline int inet_pton(int af, const char* src, void* dest, - unsigned long* scope_id = 0) + unsigned long* scope_id, asio::error_code& ec) { - set_error(0); + clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) using namespace std; // For memcpy and strcmp. if (af != AF_INET && af != AF_INET6) { - set_error(asio::error::address_family_not_supported); + ec = asio::error::address_family_not_supported; return -1; } @@ -500,7 +546,7 @@ inline int inet_pton(int af, const char* src, void* dest, int result = error_wrapper(::WSAStringToAddressA( const_cast(src), af, 0, reinterpret_cast(&address), - &address_length)); + &address_length), ec); if (af == AF_INET) { @@ -509,10 +555,12 @@ inline int inet_pton(int af, const char* src, void* dest, sockaddr_in4_type* ipv4_address = reinterpret_cast(&address); memcpy(dest, &ipv4_address->sin_addr, sizeof(in4_addr_type)); + clear_error(ec); } else if (strcmp(src, "255.255.255.255") == 0) { static_cast(dest)->s_addr = INADDR_NONE; + clear_error(ec); } } else // AF_INET6 @@ -524,18 +572,19 @@ inline int inet_pton(int af, const char* src, void* dest, memcpy(dest, &ipv6_address->sin6_addr, sizeof(in6_addr_type)); if (scope_id) *scope_id = ipv6_address->sin6_scope_id; + clear_error(ec); } } // Windows may not set an error code on failure. - if (result == socket_error_retval && get_error() == 0) - set_error(asio::error::invalid_argument); + if (result == socket_error_retval && !ec) + ec = asio::error::invalid_argument; return result == socket_error_retval ? -1 : 1; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - int result = error_wrapper(::inet_pton(af, src, dest)); - if (result <= 0 && get_error() == 0) - set_error(asio::error::invalid_argument); + int result = error_wrapper(::inet_pton(af, src, dest), ec); + if (result <= 0 && !ec) + ec = asio::error::invalid_argument; if (result > 0 && af == AF_INET6 && scope_id) { using namespace std; // For strchr and atoi. @@ -554,10 +603,10 @@ inline int inet_pton(int af, const char* src, void* dest, #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } -inline int gethostname(char* name, int namelen) +inline int gethostname(char* name, int namelen, asio::error_code& ec) { - set_error(0); - return error_wrapper(::gethostname(name, namelen)); + clear_error(ec); + return error_wrapper(::gethostname(name, namelen), ec); } #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) \ @@ -566,12 +615,12 @@ inline int gethostname(char* name, int namelen) // The following functions are only needed for emulation of getaddrinfo and // getnameinfo. -inline int translate_netdb_error(int error) +inline asio::error_code translate_netdb_error(int error) { switch (error) { case 0: - return asio::error::success; + return asio::error_code(); case HOST_NOT_FOUND: return asio::error::host_not_found; case TRY_AGAIN: @@ -582,61 +631,66 @@ inline int translate_netdb_error(int error) return asio::error::no_data; default: BOOST_ASSERT(false); - return get_error(); + return asio::error::invalid_argument; } } inline hostent* gethostbyaddr(const char* addr, int length, int af, - hostent* result, char* buffer, int buflength, int* error) + hostent* result, char* buffer, int buflength, asio::error_code& ec) { - set_error(0); + clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) (void)(buffer); (void)(buflength); - hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af)); - *error = get_error(); + hostent* retval = error_wrapper(::gethostbyaddr(addr, length, af), ec); if (!retval) return 0; *result = *retval; return retval; #elif defined(__sun) || defined(__QNX__) + int error = 0; hostent* retval = error_wrapper(::gethostbyaddr_r(addr, length, af, result, - buffer, buflength, error)); - *error = translate_netdb_error(*error); + buffer, buflength, &error), ec); + if (error) + ec = translate_netdb_error(error); return retval; #elif defined(__MACH__) && defined(__APPLE__) (void)(buffer); (void)(buflength); - hostent* retval = error_wrapper(::getipnodebyaddr(addr, length, af, error)); - *error = translate_netdb_error(*error); + int error = 0; + hostent* retval = error_wrapper(::getipnodebyaddr( + addr, length, af, &error), ec); + if (error) + ec = translate_netdb_error(error); if (!retval) return 0; *result = *retval; return retval; #else hostent* retval = 0; + int error = 0; error_wrapper(::gethostbyaddr_r(addr, length, af, result, buffer, - buflength, &retval, error)); - *error = translate_netdb_error(*error); + buflength, &retval, &error), ec); + if (error) + ec = translate_netdb_error(error); return retval; #endif } inline hostent* gethostbyname(const char* name, int af, struct hostent* result, - char* buffer, int buflength, int* error, int ai_flags = 0) + char* buffer, int buflength, int ai_flags, asio::error_code& ec) { - set_error(0); + clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) (void)(buffer); (void)(buflength); (void)(ai_flags); if (af != AF_INET) { - *error = asio::error::address_family_not_supported; + ec = asio::error::address_family_not_supported; return 0; } - hostent* retval = error_wrapper(::gethostbyname(name)); - *error = get_error(); + hostent* retval = error_wrapper(::gethostbyname(name), ec); if (!retval) return 0; *result = *retval; @@ -645,19 +699,23 @@ inline hostent* gethostbyname(const char* name, int af, struct hostent* result, (void)(ai_flags); if (af != AF_INET) { - *error = asio::error::address_family_not_supported; + ec = asio::error::address_family_not_supported; return 0; } + int error = 0; hostent* retval = error_wrapper(::gethostbyname_r(name, result, buffer, - buflength, error)); - *error = translate_netdb_error(*error); + buflength, &error), ec); + if (error) + ec = translate_netdb_error(error); return retval; #elif defined(__MACH__) && defined(__APPLE__) (void)(buffer); (void)(buflength); + int error = 0; hostent* retval = error_wrapper(::getipnodebyname( - name, af, ai_flags, error)); - *error = translate_netdb_error(*error); + name, af, ai_flags, &error), ec); + if (error) + ec = translate_netdb_error(error); if (!retval) return 0; *result = *retval; @@ -666,13 +724,15 @@ inline hostent* gethostbyname(const char* name, int af, struct hostent* result, (void)(ai_flags); if (af != AF_INET) { - *error = asio::error::address_family_not_supported; + ec = asio::error::address_family_not_supported; return 0; } hostent* retval = 0; - error_wrapper(::gethostbyname_r(name, result, buffer, buflength, &retval, - error)); - *error = translate_netdb_error(*error); + int error = 0; + error_wrapper(::gethostbyname_r(name, result, + buffer, buflength, &retval, &error), ec); + if (error) + ec = translate_netdb_error(error); return retval; #endif } @@ -1088,7 +1148,8 @@ inline int getaddrinfo_emulation(const char* host, const char* service, { // Check for IPv4 dotted decimal string. in4_addr_type inaddr; - if (socket_ops::inet_pton(AF_INET, sptr->host, &inaddr) == 1) + asio::error_code ec; + if (socket_ops::inet_pton(AF_INET, sptr->host, &inaddr, 0, ec) == 1) { if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET) { @@ -1111,7 +1172,7 @@ inline int getaddrinfo_emulation(const char* host, const char* service, // Check for IPv6 hex string. in6_addr_type in6addr; - if (socket_ops::inet_pton(AF_INET6, sptr->host, &in6addr) == 1) + if (socket_ops::inet_pton(AF_INET6, sptr->host, &in6addr, 0, ec) == 1) { if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET6) { @@ -1135,9 +1196,8 @@ inline int getaddrinfo_emulation(const char* host, const char* service, // Look up hostname. hostent hent; char hbuf[8192] = ""; - int herr = 0; hostent* hptr = socket_ops::gethostbyname(sptr->host, - sptr->family, &hent, hbuf, sizeof(hbuf), &herr, hints.ai_flags); + sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec); if (hptr == 0) { if (search_count == 2) @@ -1147,18 +1207,15 @@ inline int getaddrinfo_emulation(const char* host, const char* service, } freeaddrinfo_emulation(aihead); gai_free(canon); - switch (herr) - { - case HOST_NOT_FOUND: + if (ec == asio::error::host_not_found) return EAI_NONAME; - case TRY_AGAIN: + if (ec == asio::error::host_not_found_try_again) return EAI_AGAIN; - case NO_RECOVERY: + if (ec == asio::error::no_recovery) return EAI_FAIL; - case NO_DATA: - default: + if (ec == asio::error::no_data) return EAI_NONAME; - } + return EAI_NONAME; } // Check for address family mismatch if one was specified. @@ -1244,9 +1301,10 @@ inline int getaddrinfo_emulation(const char* host, const char* service, return 0; } -inline int getnameinfo_emulation(const socket_addr_type* sa, - socket_addr_len_type salen, char* host, std::size_t hostlen, - char* serv, std::size_t servlen, int flags) +inline asio::error_code getnameinfo_emulation( + const socket_addr_type* sa, socket_addr_len_type salen, char* host, + std::size_t hostlen, char* serv, std::size_t servlen, int flags, + asio::error_code& ec) { using namespace std; @@ -1258,8 +1316,7 @@ inline int getnameinfo_emulation(const socket_addr_type* sa, case AF_INET: if (salen != sizeof(sockaddr_in4_type)) { - set_error(asio::error::invalid_argument); - return 1; + return ec = asio::error::invalid_argument; } addr = reinterpret_cast( &reinterpret_cast(sa)->sin_addr); @@ -1269,8 +1326,7 @@ inline int getnameinfo_emulation(const socket_addr_type* sa, case AF_INET6: if (salen != sizeof(sockaddr_in6_type)) { - set_error(asio::error::invalid_argument); - return 1; + return ec = asio::error::invalid_argument; } addr = reinterpret_cast( &reinterpret_cast(sa)->sin6_addr); @@ -1278,27 +1334,25 @@ inline int getnameinfo_emulation(const socket_addr_type* sa, port = reinterpret_cast(sa)->sin6_port; break; default: - set_error(asio::error::address_family_not_supported); - return 1; + return ec = asio::error::address_family_not_supported; } if (host && hostlen > 0) { if (flags & NI_NUMERICHOST) { - if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen) == 0) + if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen, 0, ec) == 0) { - return 1; + return ec; } } else { hostent hent; char hbuf[8192] = ""; - int herr = 0; hostent* hptr = socket_ops::gethostbyaddr(addr, static_cast(addr_len), sa->sa_family, - &hent, hbuf, sizeof(hbuf), &herr); + &hent, hbuf, sizeof(hbuf), ec); if (hptr && hptr->h_name && hptr->h_name[0] != '\0') { if (flags & NI_NOFQDN) @@ -1318,12 +1372,12 @@ inline int getnameinfo_emulation(const socket_addr_type* sa, socket_ops::freehostent(hptr); if (flags & NI_NAMEREQD) { - set_error(asio::error::host_not_found); - return 1; + return ec = asio::error::host_not_found; } - if (socket_ops::inet_ntop(sa->sa_family, addr, host, hostlen) == 0) + if (socket_ops::inet_ntop(sa->sa_family, + addr, host, hostlen, 0, ec) == 0) { - return 1; + return ec; } } } @@ -1335,8 +1389,7 @@ inline int getnameinfo_emulation(const socket_addr_type* sa, { if (servlen < 6) { - set_error(asio::error::no_buffer_space); - return 1; + return ec = asio::error::no_buffer_space; } sprintf(serv, "%u", ntohs(port)); } @@ -1356,8 +1409,7 @@ inline int getnameinfo_emulation(const socket_addr_type* sa, { if (servlen < 6) { - set_error(asio::error::no_buffer_space); - return 1; + return ec = asio::error::no_buffer_space; } sprintf(serv, "%u", ntohs(port)); } @@ -1367,19 +1419,19 @@ inline int getnameinfo_emulation(const socket_addr_type* sa, } } - set_error(0); - return 0; + clear_error(ec); + return ec; } #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) // || defined(__MACH__) && defined(__APPLE__) -inline int translate_addrinfo_error(int error) +inline asio::error_code translate_addrinfo_error(int error) { switch (error) { case 0: - return asio::error::success; + return asio::error_code(); case EAI_AGAIN: return asio::error::host_not_found_try_again; case EAI_BADFLAGS: @@ -1397,19 +1449,26 @@ inline int translate_addrinfo_error(int error) case EAI_SOCKTYPE: return asio::error::socket_type_not_supported; default: // Possibly the non-portable EAI_SYSTEM. - return get_error(); +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + return asio::error_code( + WSAGetLastError(), asio::native_ecat); +#else + return asio::error_code( + errno, asio::native_ecat); +#endif } } -inline int getaddrinfo(const char* host, const char* service, - const addrinfo_type* hints, addrinfo_type** result) +inline asio::error_code getaddrinfo(const char* host, + const char* service, const addrinfo_type* hints, addrinfo_type** result, + asio::error_code& ec) { - set_error(0); + clear_error(ec); #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) // Building for Windows XP, Windows Server 2003, or later. int error = ::getaddrinfo(host, service, hints, result); - return translate_addrinfo_error(error); + return ec = translate_addrinfo_error(error); # else // Building for Windows 2000 or earlier. typedef int (WSAAPI *gai_t)(const char*, @@ -1419,18 +1478,18 @@ inline int getaddrinfo(const char* host, const char* service, if (gai_t gai = (gai_t)::GetProcAddress(winsock_module, "getaddrinfo")) { int error = gai(host, service, hints, result); - return translate_addrinfo_error(error); + return ec = translate_addrinfo_error(error); } } int error = getaddrinfo_emulation(host, service, hints, result); - return translate_addrinfo_error(error); + return ec = translate_addrinfo_error(error); # endif #elif defined(__MACH__) && defined(__APPLE__) int error = getaddrinfo_emulation(host, service, hints, result); - return translate_addrinfo_error(error); + return ec = translate_addrinfo_error(error); #else int error = ::getaddrinfo(host, service, hints, result); - return translate_addrinfo_error(error); + return ec = translate_addrinfo_error(error); #endif } @@ -1460,16 +1519,17 @@ inline void freeaddrinfo(addrinfo_type* ai) #endif } -inline int getnameinfo(const socket_addr_type* addr, +inline asio::error_code getnameinfo(const socket_addr_type* addr, socket_addr_len_type addrlen, char* host, std::size_t hostlen, - char* serv, std::size_t servlen, int flags) + char* serv, std::size_t servlen, int flags, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) # if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) // Building for Windows XP, Windows Server 2003, or later. - set_error(0); - int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags); - return translate_addrinfo_error(error); + clear_error(ec); + int error = ::getnameinfo(addr, addrlen, host, static_cast(hostlen), + serv, static_cast(servlen), flags); + return ec = translate_addrinfo_error(error); # else // Building for Windows 2000 or earlier. typedef int (WSAAPI *gni_t)(const socket_addr_type*, @@ -1478,15 +1538,14 @@ inline int getnameinfo(const socket_addr_type* addr, { if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo")) { - set_error(0); + clear_error(ec); int error = gni(addr, addrlen, host, hostlen, serv, servlen, flags); - return translate_addrinfo_error(error); + return ec = translate_addrinfo_error(error); } } - set_error(0); - int error = getnameinfo_emulation(addr, addrlen, - host, hostlen, serv, servlen, flags); - return translate_addrinfo_error(error); + clear_error(ec); + return getnameinfo_emulation(addr, addrlen, + host, hostlen, serv, servlen, flags, ec); # endif #elif defined(__MACH__) && defined(__APPLE__) using namespace std; // For memcpy. @@ -1494,14 +1553,13 @@ inline int getnameinfo(const socket_addr_type* addr, memcpy(&tmp_addr, addr, addrlen); tmp_addr.ss_len = addrlen; addr = reinterpret_cast(&tmp_addr); - set_error(0); - int error = getnameinfo_emulation(addr, addrlen, - host, hostlen, serv, servlen, flags); - return translate_addrinfo_error(error); + clear_error(ec); + return getnameinfo_emulation(addr, addrlen, + host, hostlen, serv, servlen, flags, ec); #else - set_error(0); + clear_error(ec); int error = ::getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags); - return translate_addrinfo_error(error); + return ec = translate_addrinfo_error(error); #endif } diff --git a/libtorrent/include/libtorrent/asio/detail/socket_option.hpp b/libtorrent/include/libtorrent/asio/detail/socket_option.hpp index c8e680e14..ee867e6b2 100644 --- a/libtorrent/include/libtorrent/asio/detail/socket_option.hpp +++ b/libtorrent/include/libtorrent/asio/detail/socket_option.hpp @@ -2,7 +2,7 @@ // socket_option.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -19,6 +19,7 @@ #include "asio/detail/push_options.hpp" #include +#include #include #include "asio/detail/pop_options.hpp" @@ -40,21 +41,34 @@ public: } // Construct with a specific option value. - boolean(bool value) - : value_(value ? 1 : 0) + explicit boolean(bool v) + : value_(v ? 1 : 0) { } - // Set the value of the boolean. - void set(bool value) + // Set the current value of the boolean. + boolean& operator=(bool v) { - value_ = value ? 1 : 0; + value_ = v ? 1 : 0; + return *this; } // Get the current value of the boolean. - bool get() const + bool value() const { - return value_; + return !!value_; + } + + // Convert to bool. + operator bool() const + { + return !!value_; + } + + // Test for false. + bool operator!() const + { + return !value_; } // Get the level of the socket option. @@ -92,6 +106,14 @@ public: return sizeof(value_); } + // Set the size of the boolean data. + template + void resize(const Protocol&, std::size_t s) + { + if (s != sizeof(value_)) + throw std::length_error("boolean socket option resize"); + } + private: int value_; }; @@ -108,19 +130,20 @@ public: } // Construct with a specific option value. - integer(int value) - : value_(value) + explicit integer(int v) + : value_(v) { } // Set the value of the int option. - void set(int value) + integer& operator=(int v) { - value_ = value; + value_ = v; + return *this; } // Get the current value of the int option. - int get() const + int value() const { return value_; } @@ -160,76 +183,16 @@ public: return sizeof(value_); } -private: - int value_; -}; - -// Helper template for implementing unsigned integer options. -template -class unsigned_integer -{ -public: - // Default constructor. - unsigned_integer() - : value_(0) - { - } - - // Construct with a specific option value. - unsigned_integer(unsigned int value) - : value_(value) - { - } - - // Set the value of the int option. - void set(unsigned int value) - { - value_ = value; - } - - // Get the current value of the int option. - unsigned int get() const - { - return value_; - } - - // Get the level of the socket option. + // Set the size of the int data. template - int level(const Protocol&) const + void resize(const Protocol&, std::size_t s) { - return Level; - } - - // Get the name of the socket option. - template - int name(const Protocol&) const - { - return Name; - } - - // Get the address of the int data. - template - unsigned int* data(const Protocol&) - { - return &value_; - } - - // Get the address of the int data. - template - const unsigned int* data(const Protocol&) const - { - return &value_; - } - - // Get the size of the int data. - template - std::size_t size(const Protocol&) const - { - return sizeof(value_); + if (s != sizeof(value_)) + throw std::length_error("integer socket option resize"); } private: - unsigned int value_; + int value_; }; // Helper template for implementing linger options. @@ -245,10 +208,10 @@ public: } // Construct with specific option values. - linger(bool value, unsigned short timeout) + linger(bool e, int t) { - value_.l_onoff = value ? 1 : 0; - value_.l_linger = timeout; + enabled(e); + timeout(t); } // Set the value for whether linger is enabled. @@ -264,15 +227,19 @@ public: } // Set the value for the linger timeout. - void timeout(unsigned short value) + void timeout(int value) { +#if defined(WIN32) + value_.l_linger = static_cast(value); +#else value_.l_linger = value; +#endif } // Get the value for the linger timeout. - unsigned short timeout() const + int timeout() const { - return value_.l_linger; + return static_cast(value_.l_linger); } // Get the level of the socket option. @@ -310,6 +277,14 @@ public: return sizeof(value_); } + // Set the size of the int data. + template + void resize(const Protocol&, std::size_t s) + { + if (s != sizeof(value_)) + throw std::length_error("linger socket option resize"); + } + private: ::linger value_; }; diff --git a/libtorrent/include/libtorrent/asio/detail/socket_select_interrupter.hpp b/libtorrent/include/libtorrent/asio/detail/socket_select_interrupter.hpp index e833213de..6117d309d 100644 --- a/libtorrent/include/libtorrent/asio/detail/socket_select_interrupter.hpp +++ b/libtorrent/include/libtorrent/asio/detail/socket_select_interrupter.hpp @@ -2,7 +2,7 @@ // socket_select_interrupter.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -22,6 +22,7 @@ #include "asio/detail/pop_options.hpp" #include "asio/error.hpp" +#include "asio/system_error.hpp" #include "asio/detail/socket_holder.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" @@ -35,17 +36,18 @@ public: // Constructor. socket_select_interrupter() { - socket_holder acceptor(socket_ops::socket(AF_INET, SOCK_STREAM, - IPPROTO_TCP)); + asio::error_code ec; + socket_holder acceptor(socket_ops::socket( + AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); if (acceptor.get() == invalid_socket) { - asio::error e(socket_ops::get_error()); + asio::system_error e(ec, "socket_select_interrupter"); boost::throw_exception(e); } int opt = 1; socket_ops::setsockopt(acceptor.get(), - SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec); sockaddr_in4_type addr; socket_addr_len_type addr_len = sizeof(addr); @@ -53,67 +55,69 @@ public: addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_port = 0; if (socket_ops::bind(acceptor.get(), (const socket_addr_type*)&addr, - addr_len) == socket_error_retval) + addr_len, ec) == socket_error_retval) { - asio::error e(socket_ops::get_error()); + asio::system_error e(ec, "socket_select_interrupter"); boost::throw_exception(e); } - if (getsockname(acceptor.get(), (socket_addr_type*)&addr, &addr_len) - == socket_error_retval) + if (socket_ops::getsockname(acceptor.get(), (socket_addr_type*)&addr, + &addr_len, ec) == socket_error_retval) { - asio::error e(socket_ops::get_error()); + asio::system_error e(ec, "socket_select_interrupter"); boost::throw_exception(e); } - if (socket_ops::listen(acceptor.get(), SOMAXCONN) == socket_error_retval) + if (socket_ops::listen(acceptor.get(), + SOMAXCONN, ec) == socket_error_retval) { - asio::error e(socket_ops::get_error()); + asio::system_error e(ec, "socket_select_interrupter"); boost::throw_exception(e); } - socket_holder client(socket_ops::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)); + socket_holder client(socket_ops::socket( + AF_INET, SOCK_STREAM, IPPROTO_TCP, ec)); if (client.get() == invalid_socket) { - asio::error e(socket_ops::get_error()); + asio::system_error e(ec, "socket_select_interrupter"); boost::throw_exception(e); } if (socket_ops::connect(client.get(), (const socket_addr_type*)&addr, - addr_len) == socket_error_retval) + addr_len, ec) == socket_error_retval) { - asio::error e(socket_ops::get_error()); + asio::system_error e(ec, "socket_select_interrupter"); boost::throw_exception(e); } - socket_holder server(socket_ops::accept(acceptor.get(), 0, 0)); + socket_holder server(socket_ops::accept(acceptor.get(), 0, 0, ec)); if (server.get() == invalid_socket) { - asio::error e(socket_ops::get_error()); + asio::system_error e(ec, "socket_select_interrupter"); boost::throw_exception(e); } ioctl_arg_type non_blocking = 1; - if (socket_ops::ioctl(client.get(), FIONBIO, &non_blocking)) + if (socket_ops::ioctl(client.get(), FIONBIO, &non_blocking, ec)) { - asio::error e(socket_ops::get_error()); + asio::system_error e(ec, "socket_select_interrupter"); boost::throw_exception(e); } opt = 1; socket_ops::setsockopt(client.get(), - IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); + IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); non_blocking = 1; - if (socket_ops::ioctl(server.get(), FIONBIO, &non_blocking)) + if (socket_ops::ioctl(server.get(), FIONBIO, &non_blocking, ec)) { - asio::error e(socket_ops::get_error()); + asio::system_error e(ec, "socket_select_interrupter"); boost::throw_exception(e); } opt = 1; socket_ops::setsockopt(server.get(), - IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt)); + IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt), ec); read_descriptor_ = server.release(); write_descriptor_ = client.release(); @@ -122,10 +126,11 @@ public: // Destructor. ~socket_select_interrupter() { + asio::error_code ec; if (read_descriptor_ != invalid_socket) - socket_ops::close(read_descriptor_); + socket_ops::close(read_descriptor_, ec); if (write_descriptor_ != invalid_socket) - socket_ops::close(write_descriptor_); + socket_ops::close(write_descriptor_, ec); } // Interrupt the select call. @@ -134,7 +139,8 @@ public: char byte = 0; socket_ops::buf b; socket_ops::init_buf(b, &byte, 1); - socket_ops::send(write_descriptor_, &b, 1, 0); + asio::error_code ec; + socket_ops::send(write_descriptor_, &b, 1, 0, ec); } // Reset the select interrupt. Returns true if the call was interrupted. @@ -143,10 +149,11 @@ public: char data[1024]; socket_ops::buf b; socket_ops::init_buf(b, data, sizeof(data)); - int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0); + asio::error_code ec; + int bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); bool was_interrupted = (bytes_read > 0); while (bytes_read == sizeof(data)) - bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0); + bytes_read = socket_ops::recv(read_descriptor_, &b, 1, 0, ec); return was_interrupted; } diff --git a/libtorrent/include/libtorrent/asio/detail/socket_types.hpp b/libtorrent/include/libtorrent/asio/detail/socket_types.hpp index 631edbe1c..b2a03f2f1 100644 --- a/libtorrent/include/libtorrent/asio/detail/socket_types.hpp +++ b/libtorrent/include/libtorrent/asio/detail/socket_types.hpp @@ -2,7 +2,7 @@ // socket_types.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -100,6 +100,7 @@ # include # if defined(__sun) # include +# include # endif #endif #include "asio/detail/pop_options.hpp" @@ -169,13 +170,6 @@ const int message_do_not_route = MSG_DONTROUTE; const int custom_socket_option_level = 0xA5100000; const int enable_connection_aborted_option = 1; -#if defined(_WIN64) -std::size_t hash_value(SOCKET s) -{ - return static_cast(s); -} -#endif // defined(_WIN64) - } // namespace detail } // namespace asio diff --git a/libtorrent/include/libtorrent/asio/detail/strand_service.hpp b/libtorrent/include/libtorrent/asio/detail/strand_service.hpp index 778cff66f..f10289090 100644 --- a/libtorrent/include/libtorrent/asio/detail/strand_service.hpp +++ b/libtorrent/include/libtorrent/asio/detail/strand_service.hpp @@ -2,7 +2,7 @@ // strand_service.hpp // ~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -30,13 +30,14 @@ #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/noncopyable.hpp" +#include "asio/detail/service_base.hpp" namespace asio { namespace detail { // Default service implementation for a strand. class strand_service - : public asio::io_service::service + : public asio::detail::service_base { public: class handler_base; @@ -241,12 +242,9 @@ public: return impl_->handler_storage_.address(); } - template - friend void asio_handler_invoke(Function function, - invoke_current_handler*) - { - function(); - } + // The asio_handler_invoke hook is not defined here since the default one + // provides the correct behaviour, and including it here breaks MSVC 7.1 + // in some situations. private: strand_service& service_impl_; @@ -354,7 +352,7 @@ public: // Construct a new strand service for the specified io_service. explicit strand_service(asio::io_service& io_service) - : asio::io_service::service(io_service), + : asio::detail::service_base(io_service), mutex_(), impl_list_(0) { @@ -430,7 +428,7 @@ public: // This handler now has the lock, so can be dispatched immediately. impl->current_handler_ = ptr.get(); lock.unlock(); - io_service().dispatch(invoke_current_handler(*this, impl)); + this->io_service().dispatch(invoke_current_handler(*this, impl)); ptr.release(); } else @@ -470,7 +468,7 @@ public: // This handler now has the lock, so can be dispatched immediately. impl->current_handler_ = ptr.get(); lock.unlock(); - io_service().post(invoke_current_handler(*this, impl)); + this->io_service().post(invoke_current_handler(*this, impl)); ptr.release(); } else diff --git a/libtorrent/include/libtorrent/asio/detail/task_io_service.hpp b/libtorrent/include/libtorrent/asio/detail/task_io_service.hpp index fbe56cbc3..07df1c18a 100644 --- a/libtorrent/include/libtorrent/asio/detail/task_io_service.hpp +++ b/libtorrent/include/libtorrent/asio/detail/task_io_service.hpp @@ -2,7 +2,7 @@ // task_io_service.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -17,12 +17,14 @@ #include "asio/detail/push_options.hpp" +#include "asio/error_code.hpp" #include "asio/io_service.hpp" #include "asio/detail/call_stack.hpp" #include "asio/detail/event.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" #include "asio/detail/mutex.hpp" +#include "asio/detail/service_base.hpp" #include "asio/detail/task_io_service_fwd.hpp" namespace asio { @@ -30,23 +32,27 @@ namespace detail { template class task_io_service - : public asio::io_service::service + : public asio::detail::service_base > { public: // Constructor. task_io_service(asio::io_service& io_service) - : asio::io_service::service(io_service), + : asio::detail::service_base >(io_service), mutex_(), task_(use_service(io_service)), outstanding_work_(0), handler_queue_(&task_handler_), handler_queue_end_(&task_handler_), - interrupted_(false), + stopped_(false), shutdown_(false), first_idle_thread_(0) { } + void init(size_t /*concurrency_hint*/) + { + } + // Destroy all user-defined handler objects owned by the service. void shutdown_service() { @@ -69,7 +75,7 @@ public: } // Run the event loop until interrupted or no more work. - size_t run() + size_t run(asio::error_code& ec) { typename call_stack::context ctx(this); @@ -80,14 +86,14 @@ public: asio::detail::mutex::scoped_lock lock(mutex_); size_t n = 0; - while (do_one(lock, &this_idle_thread)) + while (do_one(lock, &this_idle_thread, ec)) if (n != (std::numeric_limits::max)()) ++n; return n; } // Run until interrupted or one operation is performed. - size_t run_one() + size_t run_one(asio::error_code& ec) { typename call_stack::context ctx(this); @@ -97,45 +103,45 @@ public: asio::detail::mutex::scoped_lock lock(mutex_); - return do_one(lock, &this_idle_thread); + return do_one(lock, &this_idle_thread, ec); } // Poll for operations without blocking. - size_t poll() + size_t poll(asio::error_code& ec) { typename call_stack::context ctx(this); asio::detail::mutex::scoped_lock lock(mutex_); size_t n = 0; - while (do_one(lock, 0)) + while (do_one(lock, 0, ec)) if (n != (std::numeric_limits::max)()) ++n; return n; } // Poll for one operation without blocking. - size_t poll_one() + size_t poll_one(asio::error_code& ec) { typename call_stack::context ctx(this); asio::detail::mutex::scoped_lock lock(mutex_); - return do_one(lock, 0); + return do_one(lock, 0, ec); } // Interrupt the event processing loop. - void interrupt() + void stop() { asio::detail::mutex::scoped_lock lock(mutex_); - interrupt_all_threads(); + stop_all_threads(); } // Reset in preparation for a subsequent run invocation. void reset() { asio::detail::mutex::scoped_lock lock(mutex_); - interrupted_ = false; + stopped_ = false; } // Notify that some work has started. @@ -150,7 +156,7 @@ public: { asio::detail::mutex::scoped_lock lock(mutex_); if (--outstanding_work_ == 0) - interrupt_all_threads(); + stop_all_threads(); } // Request invocation of the given handler. @@ -204,17 +210,18 @@ private: struct idle_thread_info; size_t do_one(asio::detail::mutex::scoped_lock& lock, - idle_thread_info* this_idle_thread) + idle_thread_info* this_idle_thread, asio::error_code& ec) { - if (outstanding_work_ == 0 && !interrupted_) + if (outstanding_work_ == 0 && !stopped_) { - interrupt_all_threads(); + stop_all_threads(); + ec = asio::error_code(); return 0; } bool polling = !this_idle_thread; bool task_has_run = false; - while (!interrupted_) + while (!stopped_) { if (handler_queue_) { @@ -230,7 +237,10 @@ private: { // If the task has already run and we're polling then we're done. if (task_has_run && polling) + { + ec = asio::error_code(); return 0; + } task_has_run = true; task_cleanup c(lock, *this); @@ -247,6 +257,7 @@ private: // Invoke the handler. May throw an exception. h->call(); // call() deletes the handler object + ec = asio::error_code(); return 1; } } @@ -281,17 +292,19 @@ private: } else { + ec = asio::error_code(); return 0; } } + ec = asio::error_code(); return 0; } - // Interrupt the task and all idle threads. - void interrupt_all_threads() + // Stop the task and all idle threads. + void stop_all_threads() { - interrupted_ = true; + stopped_ = true; interrupt_all_idle_threads(); if (task_handler_.next_ == 0 && handler_queue_end_ != &task_handler_) task_.interrupt(); @@ -326,6 +339,7 @@ private: } class task_cleanup; + friend class task_cleanup; // The base class for all handler wrappers. A function pointer is used // instead of virtual functions to avoid the associated overhead. @@ -412,8 +426,6 @@ private: }; // Helper class to perform task-related operations on block exit. - class task_cleanup; - friend class task_cleanup; class task_cleanup { public: @@ -466,7 +478,7 @@ private: { lock_.lock(); if (--task_io_service_.outstanding_work_ == 0) - task_io_service_.interrupt_all_threads(); + task_io_service_.stop_all_threads(); } private: @@ -500,8 +512,8 @@ private: // The end of a linked list of handlers that are ready to be delivered. handler_base* handler_queue_end_; - // Flag to indicate that the dispatcher has been interrupted. - bool interrupted_; + // Flag to indicate that the dispatcher has been stopped. + bool stopped_; // Flag to indicate that the dispatcher has been shut down. bool shutdown_; diff --git a/libtorrent/include/libtorrent/asio/detail/task_io_service_fwd.hpp b/libtorrent/include/libtorrent/asio/detail/task_io_service_fwd.hpp index 8100beac7..208a9d3ca 100644 --- a/libtorrent/include/libtorrent/asio/detail/task_io_service_fwd.hpp +++ b/libtorrent/include/libtorrent/asio/detail/task_io_service_fwd.hpp @@ -2,7 +2,7 @@ // task_io_service_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/thread.hpp b/libtorrent/include/libtorrent/asio/detail/thread.hpp index 9d7452b8a..b334c38af 100644 --- a/libtorrent/include/libtorrent/asio/detail/thread.hpp +++ b/libtorrent/include/libtorrent/asio/detail/thread.hpp @@ -2,7 +2,7 @@ // thread.hpp // ~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/throw_error.hpp b/libtorrent/include/libtorrent/asio/detail/throw_error.hpp new file mode 100644 index 000000000..d2ad09a2e --- /dev/null +++ b/libtorrent/include/libtorrent/asio/detail/throw_error.hpp @@ -0,0 +1,44 @@ +// +// throw_error.hpp +// ~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_THROW_ERROR_HPP +#define ASIO_DETAIL_THROW_ERROR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +#include "asio/detail/push_options.hpp" +#include +#include "asio/detail/pop_options.hpp" + +#include "asio/error_code.hpp" +#include "asio/system_error.hpp" + +namespace asio { +namespace detail { + +inline void throw_error(const asio::error_code& err) +{ + if (err) + { + asio::system_error e(err); + boost::throw_exception(e); + } +} + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_THROW_ERROR_HPP diff --git a/libtorrent/include/libtorrent/asio/detail/timer_queue.hpp b/libtorrent/include/libtorrent/asio/detail/timer_queue.hpp index 2526da948..ab6eac263 100644 --- a/libtorrent/include/libtorrent/asio/detail/timer_queue.hpp +++ b/libtorrent/include/libtorrent/asio/detail/timer_queue.hpp @@ -2,7 +2,7 @@ // timer_queue.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -111,7 +111,7 @@ public: { timer_base* t = heap_[0]; remove_timer(t); - t->invoke(0); + t->invoke(asio::error_code()); } } @@ -160,7 +160,7 @@ private: { public: // Perform the timer operation and then destroy. - void invoke(int result) + void invoke(const asio::error_code& result) { invoke_func_(this, result); } @@ -172,7 +172,8 @@ private: } protected: - typedef void (*invoke_func_type)(timer_base*, int); + typedef void (*invoke_func_type)(timer_base*, + const asio::error_code&); typedef void (*destroy_func_type)(timer_base*); // Constructor. @@ -234,7 +235,8 @@ private: } // Invoke the handler and then destroy it. - static void invoke_handler(timer_base* base, int result) + static void invoke_handler(timer_base* base, + const asio::error_code& result) { std::auto_ptr > t(static_cast*>(base)); t->handler_(result); diff --git a/libtorrent/include/libtorrent/asio/detail/timer_queue_base.hpp b/libtorrent/include/libtorrent/asio/detail/timer_queue_base.hpp index 22f3bb1e5..c8be49748 100644 --- a/libtorrent/include/libtorrent/asio/detail/timer_queue_base.hpp +++ b/libtorrent/include/libtorrent/asio/detail/timer_queue_base.hpp @@ -2,7 +2,7 @@ // timer_queue_base.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/tss_ptr.hpp b/libtorrent/include/libtorrent/asio/detail/tss_ptr.hpp index 24ce434c2..8a860a68f 100644 --- a/libtorrent/include/libtorrent/asio/detail/tss_ptr.hpp +++ b/libtorrent/include/libtorrent/asio/detail/tss_ptr.hpp @@ -2,7 +2,7 @@ // tss_ptr.hpp // ~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/win_event.hpp b/libtorrent/include/libtorrent/asio/detail/win_event.hpp index b08cf8a08..8de9383da 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_event.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_event.hpp @@ -2,7 +2,7 @@ // win_event.hpp // ~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -23,7 +23,7 @@ #if defined(BOOST_WINDOWS) -#include "asio/system_exception.hpp" +#include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" @@ -45,7 +45,9 @@ public: if (!event_) { DWORD last_error = ::GetLastError(); - system_exception e("event", last_error); + asio::system_error e( + asio::error_code(last_error, asio::native_ecat), + "event"); boost::throw_exception(e); } } diff --git a/libtorrent/include/libtorrent/asio/detail/win_fd_set_adapter.hpp b/libtorrent/include/libtorrent/asio/detail/win_fd_set_adapter.hpp index 1f393dc11..f2632c4d0 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_fd_set_adapter.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_fd_set_adapter.hpp @@ -2,7 +2,7 @@ // win_fd_set_adapter.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -28,6 +28,8 @@ namespace detail { class win_fd_set_adapter { public: + enum { win_fd_set_size = 1024 }; + win_fd_set_adapter() : max_descriptor_(invalid_socket) { @@ -62,7 +64,6 @@ public: private: // This structure is defined to be compatible with the Windows API fd_set // structure, but without being dependent on the value of FD_SETSIZE. - enum { win_fd_set_size = 1024 }; struct win_fd_set { u_int fd_count; diff --git a/libtorrent/include/libtorrent/asio/detail/win_iocp_io_service.hpp b/libtorrent/include/libtorrent/asio/detail/win_iocp_io_service.hpp index e39fd33a6..4957fb01a 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_iocp_io_service.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_iocp_io_service.hpp @@ -2,7 +2,7 @@ // win_iocp_io_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -27,10 +27,11 @@ #include "asio/detail/pop_options.hpp" #include "asio/io_service.hpp" -#include "asio/system_exception.hpp" +#include "asio/system_error.hpp" #include "asio/detail/call_stack.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/service_base.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/win_iocp_operation.hpp" @@ -38,7 +39,7 @@ namespace asio { namespace detail { class win_iocp_io_service - : public asio::io_service::service + : public asio::detail::service_base { public: // Base class for all operations. @@ -46,16 +47,24 @@ public: // Constructor. win_iocp_io_service(asio::io_service& io_service) - : asio::io_service::service(io_service), - iocp_(::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0)), + : asio::detail::service_base(io_service), + iocp_(), outstanding_work_(0), - interrupted_(0), + stopped_(0), shutdown_(0) { + } + + void init(size_t concurrency_hint) + { + iocp_.handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, + static_cast((std::min)(concurrency_hint, DWORD(~0)))); if (!iocp_.handle) { DWORD last_error = ::GetLastError(); - system_exception e("iocp", last_error); + asio::system_error e( + asio::error_code(last_error, asio::native_ecat), + "iocp"); boost::throw_exception(e); } } @@ -74,84 +83,98 @@ public: DWORD_PTR completion_key = 0; #endif LPOVERLAPPED overlapped = 0; - ::GetQueuedCompletionStatus(iocp_.handle, + ::SetLastError(0); + BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, &completion_key, &overlapped, 0); DWORD last_error = ::GetLastError(); - if (last_error == WAIT_TIMEOUT) + if (!ok && overlapped == 0 && last_error == WAIT_TIMEOUT) break; if (overlapped) static_cast(overlapped)->destroy(); } } - // Register a socket with the IO completion port. - void register_socket(socket_type sock) + // Register a handle with the IO completion port. + void register_handle(HANDLE handle) { - HANDLE sock_as_handle = reinterpret_cast(sock); - ::CreateIoCompletionPort(sock_as_handle, iocp_.handle, 0, 0); + ::CreateIoCompletionPort(handle, iocp_.handle, 0, 0); } - // Run the event loop until interrupted or no more work. - size_t run() + // Run the event loop until stopped or no more work. + size_t run(asio::error_code& ec) { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + ec = asio::error_code(); return 0; + } call_stack::context ctx(this); size_t n = 0; - while (do_one(true)) + while (do_one(true, ec)) if (n != (std::numeric_limits::max)()) ++n; return n; } - // Run until interrupted or one operation is performed. - size_t run_one() + // Run until stopped or one operation is performed. + size_t run_one(asio::error_code& ec) { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + ec = asio::error_code(); return 0; + } call_stack::context ctx(this); - return do_one(true); + return do_one(true, ec); } // Poll for operations without blocking. - size_t poll() + size_t poll(asio::error_code& ec) { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + ec = asio::error_code(); return 0; + } call_stack::context ctx(this); size_t n = 0; - while (do_one(false)) + while (do_one(false, ec)) if (n != (std::numeric_limits::max)()) ++n; return n; } // Poll for one operation without blocking. - size_t poll_one() + size_t poll_one(asio::error_code& ec) { if (::InterlockedExchangeAdd(&outstanding_work_, 0) == 0) + { + ec = asio::error_code(); return 0; + } call_stack::context ctx(this); - return do_one(false); + return do_one(false, ec); } - // Interrupt the event processing loop. - void interrupt() + // Stop the event processing loop. + void stop() { - if (::InterlockedExchange(&interrupted_, 1) == 0) + if (::InterlockedExchange(&stopped_, 1) == 0) { if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) { DWORD last_error = ::GetLastError(); - system_exception e("pqcs", last_error); + asio::system_error e( + asio::error_code(last_error, asio::native_ecat), + "pqcs"); boost::throw_exception(e); } } @@ -160,7 +183,7 @@ public: // Reset in preparation for a subsequent run invocation. void reset() { - ::InterlockedExchange(&interrupted_, 0); + ::InterlockedExchange(&stopped_, 0); } // Notify that some work has started. @@ -173,7 +196,7 @@ public: void work_finished() { if (::InterlockedDecrement(&outstanding_work_) == 0) - interrupt(); + stop(); } // Request invocation of the given handler. @@ -204,7 +227,9 @@ public: if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, ptr.get())) { DWORD last_error = ::GetLastError(); - system_exception e("pqcs", last_error); + asio::system_error e( + asio::error_code(last_error, asio::native_ecat), + "pqcs"); boost::throw_exception(e); } @@ -221,7 +246,9 @@ public: bytes_transferred, op_last_error, op)) { DWORD last_error = ::GetLastError(); - system_exception e("pqcs", last_error); + asio::system_error e( + asio::error_code(last_error, asio::native_ecat), + "pqcs"); boost::throw_exception(e); } } @@ -230,7 +257,7 @@ private: // Dequeues at most one operation from the I/O completion port, and then // executes it. Returns the number of operations that were dequeued (i.e. // either 0 or 1). - size_t do_one(bool block) + size_t do_one(bool block, asio::error_code& ec) { for (;;) { @@ -244,11 +271,16 @@ private: LPOVERLAPPED overlapped = 0; ::SetLastError(0); BOOL ok = ::GetQueuedCompletionStatus(iocp_.handle, &bytes_transferred, - &completion_key, &overlapped, block ? INFINITE : 0); + &completion_key, &overlapped, block ? 1000 : 0); DWORD last_error = ::GetLastError(); if (!ok && overlapped == 0) + { + if (block && last_error == WAIT_TIMEOUT) + continue; + ec = asio::error_code(); return 0; + } if (overlapped) { @@ -266,22 +298,25 @@ private: operation* op = static_cast(overlapped); op->do_completion(last_error, bytes_transferred); + ec = asio::error_code(); return 1; } else { - // The interrupted_ flag is always checked to ensure that any leftover + // The stopped_ flag is always checked to ensure that any leftover // interrupts from a previous run invocation are ignored. - if (::InterlockedExchangeAdd(&interrupted_, 0) != 0) + if (::InterlockedExchangeAdd(&stopped_, 0) != 0) { // Wake up next thread that is blocked on GetQueuedCompletionStatus. if (!::PostQueuedCompletionStatus(iocp_.handle, 0, 0, 0)) { DWORD last_error = ::GetLastError(); - system_exception e("pqcs", last_error); - boost::throw_exception(e); + ec = asio::error_code(last_error, + asio::native_ecat); + return 0; } + ec = asio::error_code(); return 0; } } @@ -365,15 +400,15 @@ private: struct iocp_holder { HANDLE handle; - iocp_holder(HANDLE h) : handle(h) {} - ~iocp_holder() { ::CloseHandle(handle); } + iocp_holder() : handle(0) {} + ~iocp_holder() { if (handle) ::CloseHandle(handle); } } iocp_; // The count of unfinished work. long outstanding_work_; - // Flag to indicate whether the event loop has been interrupted. - long interrupted_; + // Flag to indicate whether the event loop has been stopped. + long stopped_; // Flag to indicate whether the service has been shut down. long shutdown_; diff --git a/libtorrent/include/libtorrent/asio/detail/win_iocp_io_service_fwd.hpp b/libtorrent/include/libtorrent/asio/detail/win_iocp_io_service_fwd.hpp index 005677207..184fdfa18 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_iocp_io_service_fwd.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_iocp_io_service_fwd.hpp @@ -2,7 +2,7 @@ // win_iocp_io_service_fwd.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/win_iocp_operation.hpp b/libtorrent/include/libtorrent/asio/detail/win_iocp_operation.hpp index 79eb348b4..34b0fad90 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_iocp_operation.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_iocp_operation.hpp @@ -2,7 +2,7 @@ // win_iocp_operation.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/win_iocp_socket_service.hpp b/libtorrent/include/libtorrent/asio/detail/win_iocp_socket_service.hpp index 3e4cd4d64..667553960 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_iocp_socket_service.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_iocp_socket_service.hpp @@ -2,7 +2,7 @@ // win_iocp_socket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -29,7 +29,6 @@ #include "asio/buffer.hpp" #include "asio/error.hpp" -#include "asio/error_handler.hpp" #include "asio/io_service.hpp" #include "asio/socket_base.hpp" #include "asio/detail/bind_handler.hpp" @@ -47,7 +46,7 @@ namespace detail { template class win_iocp_socket_service - : public asio::io_service::service + : public asio::detail::service_base > { public: // The protocol type. @@ -92,6 +91,11 @@ public: return socket_; } + HANDLE as_handle() const + { + return reinterpret_cast(socket_); + } + bool have_remote_endpoint() const { return have_remote_endpoint_; @@ -169,7 +173,8 @@ public: // Constructor. win_iocp_socket_service(asio::io_service& io_service) - : asio::io_service::service(io_service), + : asio::detail::service_base< + win_iocp_socket_service >(io_service), iocp_service_(asio::use_service(io_service)), reactor_(0), mutex_(), @@ -185,7 +190,8 @@ public: implementation_type* impl = impl_list_; while (impl) { - close(*impl, asio::ignore_error()); + asio::error_code ignored_ec; + close(*impl, ignored_ec); impl = impl->next_; } } @@ -225,11 +231,13 @@ public: ::linger opt; opt.l_onoff = 0; opt.l_linger = 0; + asio::error_code ignored_ec; socket_ops::setsockopt(impl.socket_, - SOL_SOCKET, SO_LINGER, &opt, sizeof(opt)); + SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec); } - socket_ops::close(impl.socket_); + asio::error_code ignored_ec; + socket_ops::close(impl.socket_, ignored_ec); impl.socket_ = invalid_socket; impl.cancel_token_.reset(); impl.safe_cancellation_thread_id_ = 0; @@ -248,50 +256,61 @@ public: } // Open a new socket implementation. - template - void open(implementation_type& impl, const protocol_type& protocol, - Error_Handler error_handler) + asio::error_code open(implementation_type& impl, + const protocol_type& protocol, asio::error_code& ec) { - close(impl, asio::ignore_error()); - - socket_holder sock(socket_ops::socket(protocol.family(), protocol.type(), - protocol.protocol())); - if (sock.get() == invalid_socket) + if (is_open(impl)) { - error_handler(asio::error(socket_ops::get_error())); - return; + ec = asio::error::already_open; + return ec; } - iocp_service_.register_socket(sock.get()); + socket_holder sock(socket_ops::socket(protocol.family(), protocol.type(), + protocol.protocol(), ec)); + if (sock.get() == invalid_socket) + return ec; + + HANDLE sock_as_handle = reinterpret_cast(sock.get()); + iocp_service_.register_handle(sock_as_handle); impl.socket_ = sock.release(); impl.cancel_token_.reset(static_cast(0), noop_deleter()); impl.protocol_ = protocol; - - error_handler(asio::error(0)); + ec = asio::error_code(); + return ec; } // Assign a native socket to a socket implementation. - template - void assign(implementation_type& impl, const protocol_type& protocol, - const native_type& native_socket, Error_Handler error_handler) + asio::error_code assign(implementation_type& impl, + const protocol_type& protocol, const native_type& native_socket, + asio::error_code& ec) { - close(impl, asio::ignore_error()); + if (is_open(impl)) + { + ec = asio::error::already_open; + return ec; + } - iocp_service_.register_socket(native_socket); + iocp_service_.register_handle(native_socket.as_handle()); impl.socket_ = native_socket; impl.cancel_token_.reset(static_cast(0), noop_deleter()); impl.protocol_ = protocol; + ec = asio::error_code(); + return ec; + } - error_handler(asio::error(0)); + // Determine whether the socket is open. + bool is_open(const implementation_type& impl) const + { + return impl.socket_ != invalid_socket; } // Destroy a socket implementation. - template - void close(implementation_type& impl, Error_Handler error_handler) + asio::error_code close(implementation_type& impl, + asio::error_code& ec) { - if (impl.socket_ != invalid_socket) + if (is_open(impl)) { // Check if the reactor was created, in which case we need to close the // socket on the reactor as well to cancel any operations that might be @@ -302,20 +321,16 @@ public: if (reactor) reactor->close_descriptor(impl.socket_); - if (socket_ops::close(impl.socket_) == socket_error_retval) - { - error_handler(asio::error(socket_ops::get_error())); - return; - } - else - { - impl.socket_ = invalid_socket; - impl.cancel_token_.reset(); - impl.safe_cancellation_thread_id_ = 0; - } + if (socket_ops::close(impl.socket_, ec) == socket_error_retval) + return ec; + + impl.socket_ = invalid_socket; + impl.cancel_token_.reset(); + impl.safe_cancellation_thread_id_ = 0; } - error_handler(asio::error(0)); + ec = asio::error_code(); + return ec; } // Get the native socket representation. @@ -325,18 +340,17 @@ public: } // Cancel all operations associated with the socket. - template - void cancel(implementation_type& impl, Error_Handler error_handler) + asio::error_code cancel(implementation_type& impl, + asio::error_code& ec) { - if (impl.socket_ == invalid_socket) + if (!is_open(impl)) { - asio::error error(asio::error::bad_descriptor); - error_handler(error); + ec = asio::error::bad_descriptor; } else if (impl.safe_cancellation_thread_id_ == 0) { // No operations have been started, so there's nothing to cancel. - error_handler(asio::error(0)); + ec = asio::error_code(); } else if (impl.safe_cancellation_thread_id_ == ::GetCurrentThreadId()) { @@ -347,55 +361,98 @@ public: if (!::CancelIo(sock_as_handle)) { DWORD last_error = ::GetLastError(); - error_handler(asio::error(last_error)); + ec = asio::error_code(last_error, asio::native_ecat); } else { - error_handler(asio::error(0)); + ec = asio::error_code(); } } else { // Asynchronous operations have been started from more than one thread, // so cancellation is not safe. - error_handler(asio::error(asio::error::not_supported)); + ec = asio::error::operation_not_supported; } + + return ec; + } + + // Determine whether the socket is at the out-of-band data mark. + bool at_mark(const implementation_type& impl, + asio::error_code& ec) const + { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return false; + } + + asio::detail::ioctl_arg_type value = 0; + socket_ops::ioctl(impl.socket_, SIOCATMARK, &value, ec); + return ec ? false : value != 0; + } + + // Determine the number of bytes available for reading. + std::size_t available(const implementation_type& impl, + asio::error_code& ec) const + { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + + asio::detail::ioctl_arg_type value = 0; + socket_ops::ioctl(impl.socket_, FIONREAD, &value, ec); + return ec ? static_cast(0) : static_cast(value); } // Bind the socket to the specified local endpoint. - template - void bind(implementation_type& impl, const endpoint_type& endpoint, - Error_Handler error_handler) + asio::error_code bind(implementation_type& impl, + const endpoint_type& endpoint, asio::error_code& ec) { - if (socket_ops::bind(impl.socket_, endpoint.data(), - endpoint.size()) == socket_error_retval) - error_handler(asio::error(socket_ops::get_error())); - else - error_handler(asio::error(0)); + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + socket_ops::bind(impl.socket_, endpoint.data(), endpoint.size(), ec); + return ec; } // Place the socket into the state where it will listen for new connections. - template - void listen(implementation_type& impl, int backlog, - Error_Handler error_handler) + asio::error_code listen(implementation_type& impl, int backlog, + asio::error_code& ec) { - if (socket_ops::listen(impl.socket_, backlog) == socket_error_retval) - error_handler(asio::error(socket_ops::get_error())); - else - error_handler(asio::error(0)); + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + socket_ops::listen(impl.socket_, backlog, ec); + return ec; } // Set a socket option. - template - void set_option(implementation_type& impl, const Option& option, - Error_Handler error_handler) + template + asio::error_code set_option(implementation_type& impl, + const Option& option, asio::error_code& ec) { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + if (option.level(impl.protocol_) == custom_socket_option_level && option.name(impl.protocol_) == enable_connection_aborted_option) { if (option.size(impl.protocol_) != sizeof(int)) { - error_handler(asio::error(asio::error::invalid_argument)); + ec = asio::error::invalid_argument; } else { @@ -403,8 +460,9 @@ public: impl.flags_ |= implementation_type::enable_connection_aborted; else impl.flags_ &= ~implementation_type::enable_connection_aborted; - error_handler(asio::error(0)); + ec = asio::error_code(); } + return ec; } else { @@ -414,26 +472,30 @@ public: impl.flags_ |= implementation_type::user_set_linger; } - if (socket_ops::setsockopt(impl.socket_, - option.level(impl.protocol_), option.name(impl.protocol_), - option.data(impl.protocol_), option.size(impl.protocol_))) - error_handler(asio::error(socket_ops::get_error())); - else - error_handler(asio::error(0)); + socket_ops::setsockopt(impl.socket_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), option.size(impl.protocol_), ec); + return ec; } } // Set a socket option. - template - void get_option(const implementation_type& impl, Option& option, - Error_Handler error_handler) const + template + asio::error_code get_option(const implementation_type& impl, + Option& option, asio::error_code& ec) const { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + if (option.level(impl.protocol_) == custom_socket_option_level && option.name(impl.protocol_) == enable_connection_aborted_option) { if (option.size(impl.protocol_) != sizeof(int)) { - error_handler(asio::error(asio::error::invalid_argument)); + ec = asio::error::invalid_argument; } else { @@ -442,108 +504,126 @@ public: *target = 1; else *target = 0; - error_handler(asio::error(0)); + option.resize(impl.protocol_, sizeof(int)); + ec = asio::error_code(); } + return ec; } else { size_t size = option.size(impl.protocol_); - if (socket_ops::getsockopt(impl.socket_, - option.level(impl.protocol_), option.name(impl.protocol_), - option.data(impl.protocol_), &size)) - error_handler(asio::error(socket_ops::get_error())); - else - error_handler(asio::error(0)); + socket_ops::getsockopt(impl.socket_, + option.level(impl.protocol_), option.name(impl.protocol_), + option.data(impl.protocol_), &size, ec); + if (!ec) + option.resize(impl.protocol_, size); + return ec; } } // Perform an IO control command on the socket. - template - void io_control(implementation_type& impl, IO_Control_Command& command, - Error_Handler error_handler) + template + asio::error_code io_control(implementation_type& impl, + IO_Control_Command& command, asio::error_code& ec) { - if (socket_ops::ioctl(impl.socket_, command.name(), - static_cast(command.data()))) - error_handler(asio::error(socket_ops::get_error())); - else - error_handler(asio::error(0)); + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + socket_ops::ioctl(impl.socket_, command.name(), + static_cast(command.data()), ec); + return ec; } // Get the local endpoint. - template - void get_local_endpoint(const implementation_type& impl, - endpoint_type& endpoint, Error_Handler error_handler) const + endpoint_type local_endpoint(const implementation_type& impl, + asio::error_code& ec) const { - socket_addr_len_type addr_len = endpoint.capacity(); - if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len)) + if (!is_open(impl)) { - error_handler(asio::error(socket_ops::get_error())); - return; + ec = asio::error::bad_descriptor; + return endpoint_type(); } + endpoint_type endpoint; + socket_addr_len_type addr_len = endpoint.capacity(); + if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) + return endpoint_type(); endpoint.resize(addr_len); - error_handler(asio::error(0)); + return endpoint; } // Get the remote endpoint. - template - void get_remote_endpoint(const implementation_type& impl, - endpoint_type& endpoint, Error_Handler error_handler) const + endpoint_type remote_endpoint(const implementation_type& impl, + asio::error_code& ec) const { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return endpoint_type(); + } + if (impl.socket_.have_remote_endpoint()) { // Check if socket is still connected. DWORD connect_time = 0; size_t connect_time_len = sizeof(connect_time); if (socket_ops::getsockopt(impl.socket_, SOL_SOCKET, SO_CONNECT_TIME, - &connect_time, &connect_time_len) == socket_error_retval) + &connect_time, &connect_time_len, ec) == socket_error_retval) { - error_handler(asio::error(socket_ops::get_error())); - return; + return endpoint_type(); } if (connect_time == 0xFFFFFFFF) { - error_handler(asio::error(asio::error::not_connected)); - return; + ec = asio::error::not_connected; + return endpoint_type(); } - endpoint = impl.socket_.remote_endpoint(); - error_handler(asio::error(0)); + ec = asio::error_code(); + return impl.socket_.remote_endpoint(); } else { + endpoint_type endpoint; socket_addr_len_type addr_len = endpoint.capacity(); - if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len)) - { - error_handler(asio::error(socket_ops::get_error())); - return; - } - + if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec)) + return endpoint_type(); endpoint.resize(addr_len); - error_handler(asio::error(0)); + return endpoint; } } /// Disable sends or receives on the socket. - template - void shutdown(implementation_type& impl, socket_base::shutdown_type what, - Error_Handler error_handler) + asio::error_code shutdown(implementation_type& impl, + socket_base::shutdown_type what, asio::error_code& ec) { - if (socket_ops::shutdown(impl.socket_, what) != 0) - error_handler(asio::error(socket_ops::get_error())); - else - error_handler(asio::error(0)); + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return ec; + } + + socket_ops::shutdown(impl.socket_, what, ec); + return ec; } // Send the given data to the peer. Returns the number of bytes sent. - template - size_t send(implementation_type& impl, const Const_Buffers& buffers, - socket_base::message_flags flags, Error_Handler error_handler) + template + size_t send(implementation_type& impl, const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + // Copy buffers into WSABUF array. ::WSABUF bufs[max_buffers]; - typename Const_Buffers::const_iterator iter = buffers.begin(); - typename Const_Buffers::const_iterator end = buffers.end(); + typename ConstBufferSequence::const_iterator iter = buffers.begin(); + typename ConstBufferSequence::const_iterator end = buffers.end(); DWORD i = 0; size_t total_buffer_size = 0; for (; iter != end && i < max_buffers; ++iter, ++i) @@ -558,7 +638,7 @@ public: // A request to receive 0 bytes on a stream socket is a no-op. if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) { - error_handler(asio::error(0)); + ec = asio::error_code(); return 0; } @@ -571,25 +651,27 @@ public: DWORD last_error = ::WSAGetLastError(); if (last_error == ERROR_NETNAME_DELETED) last_error = WSAECONNRESET; - error_handler(asio::error(last_error)); + else if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + ec = asio::error_code(last_error, asio::native_ecat); return 0; } - error_handler(asio::error(0)); + ec = asio::error_code(); return bytes_transferred; } - template + template class send_operation : public operation { public: send_operation(asio::io_service& io_service, weak_cancel_token_type cancel_token, - const Const_Buffers& buffers, Handler handler) + const ConstBufferSequence& buffers, Handler handler) : operation( - &send_operation::do_completion_impl, - &send_operation::destroy_impl), + &send_operation::do_completion_impl, + &send_operation::destroy_impl), work_(io_service), cancel_token_(cancel_token), buffers_(buffers), @@ -602,18 +684,37 @@ public: DWORD last_error, size_t bytes_transferred) { // Take ownership of the operation object. - typedef send_operation op_type; + typedef send_operation op_type; op_type* handler_op(static_cast(op)); typedef handler_alloc_traits alloc_traits; handler_ptr ptr(handler_op->handler_, handler_op); - // Map ERROR_NETNAME_DELETED to more useful error. - if (last_error == ERROR_NETNAME_DELETED) +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + typename ConstBufferSequence::const_iterator iter + = handler_op->buffers_.begin(); + typename ConstBufferSequence::const_iterator end + = handler_op->buffers_.end(); + while (iter != end) + { + asio::const_buffer buffer(*iter); + asio::buffer_cast(buffer); + ++iter; + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + // Map non-portable errors to their portable counterparts. + asio::error_code ec(last_error, asio::native_ecat); + if (ec.value() == ERROR_NETNAME_DELETED) { if (handler_op->cancel_token_.expired()) - last_error = ERROR_OPERATION_ABORTED; + ec = asio::error::operation_aborted; else - last_error = WSAECONNRESET; + ec = asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; } // Make a copy of the handler so that the memory can be deallocated before @@ -624,15 +725,14 @@ public: ptr.reset(); // Call the handler. - asio::error error(last_error); asio_handler_invoke_helpers::invoke( - detail::bind_handler(handler, error, bytes_transferred), &handler); + detail::bind_handler(handler, ec, bytes_transferred), &handler); } static void destroy_impl(operation* op) { // Take ownership of the operation object. - typedef send_operation op_type; + typedef send_operation op_type; op_type* handler_op(static_cast(op)); typedef handler_alloc_traits alloc_traits; handler_ptr ptr(handler_op->handler_, handler_op); @@ -640,33 +740,40 @@ public: asio::io_service::work work_; weak_cancel_token_type cancel_token_; - Const_Buffers buffers_; + ConstBufferSequence buffers_; Handler handler_; }; // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. - template - void async_send(implementation_type& impl, const Const_Buffers& buffers, + template + void async_send(implementation_type& impl, const ConstBufferSequence& buffers, socket_base::message_flags flags, Handler handler) { + if (!is_open(impl)) + { + this->io_service().post(bind_handler(handler, + asio::error::bad_descriptor, 0)); + return; + } + // Update the ID of the thread from which cancellation is safe. if (impl.safe_cancellation_thread_id_ == 0) impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else + else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) impl.safe_cancellation_thread_id_ = ~DWORD(0); // Allocate and construct an operation to wrap the handler. - typedef send_operation value_type; + typedef send_operation value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); handler_ptr ptr(raw_ptr, - io_service(), impl.cancel_token_, buffers, handler); + this->io_service(), impl.cancel_token_, buffers, handler); // Copy buffers into WSABUF array. ::WSABUF bufs[max_buffers]; - typename Const_Buffers::const_iterator iter = buffers.begin(); - typename Const_Buffers::const_iterator end = buffers.end(); + typename ConstBufferSequence::const_iterator iter = buffers.begin(); + typename ConstBufferSequence::const_iterator end = buffers.end(); DWORD i = 0; size_t total_buffer_size = 0; for (; iter != end && i < max_buffers; ++iter, ++i) @@ -681,8 +788,9 @@ public: // A request to receive 0 bytes on a stream socket is a no-op. if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) { + asio::io_service::work work(this->io_service()); ptr.reset(); - asio::error error(asio::error::success); + asio::error_code error; iocp_service_.post(bind_handler(handler, error, 0)); return; } @@ -696,9 +804,10 @@ public: // Check if the operation completed immediately. if (result != 0 && last_error != WSA_IO_PENDING) { + asio::io_service::work work(this->io_service()); ptr.reset(); - asio::error error(last_error); - iocp_service_.post(bind_handler(handler, error, bytes_transferred)); + asio::error_code ec(last_error, asio::native_ecat); + iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else { @@ -708,15 +817,21 @@ public: // Send a datagram to the specified endpoint. Returns the number of bytes // sent. - template - size_t send_to(implementation_type& impl, const Const_Buffers& buffers, + template + size_t send_to(implementation_type& impl, const ConstBufferSequence& buffers, const endpoint_type& destination, socket_base::message_flags flags, - Error_Handler error_handler) + asio::error_code& ec) { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + // Copy buffers into WSABUF array. ::WSABUF bufs[max_buffers]; - typename Const_Buffers::const_iterator iter = buffers.begin(); - typename Const_Buffers::const_iterator end = buffers.end(); + typename ConstBufferSequence::const_iterator iter = buffers.begin(); + typename ConstBufferSequence::const_iterator end = buffers.end(); DWORD i = 0; for (; iter != end && i < max_buffers; ++iter, ++i) { @@ -733,24 +848,26 @@ public: if (result != 0) { DWORD last_error = ::WSAGetLastError(); - error_handler(asio::error(last_error)); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + ec = asio::error_code(last_error, asio::native_ecat); return 0; } - error_handler(asio::error(0)); + ec = asio::error_code(); return bytes_transferred; } - template + template class send_to_operation : public operation { public: send_to_operation(asio::io_service& io_service, - const Const_Buffers& buffers, Handler handler) + const ConstBufferSequence& buffers, Handler handler) : operation( - &send_to_operation::do_completion_impl, - &send_to_operation::destroy_impl), + &send_to_operation::do_completion_impl, + &send_to_operation::destroy_impl), work_(io_service), buffers_(buffers), handler_(handler) @@ -762,11 +879,32 @@ public: DWORD last_error, size_t bytes_transferred) { // Take ownership of the operation object. - typedef send_to_operation op_type; + typedef send_to_operation op_type; op_type* handler_op(static_cast(op)); typedef handler_alloc_traits alloc_traits; handler_ptr ptr(handler_op->handler_, handler_op); +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + typename ConstBufferSequence::const_iterator iter + = handler_op->buffers_.begin(); + typename ConstBufferSequence::const_iterator end + = handler_op->buffers_.end(); + while (iter != end) + { + asio::const_buffer buffer(*iter); + asio::buffer_cast(buffer); + ++iter; + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + // Map non-portable errors to their portable counterparts. + asio::error_code ec(last_error, asio::native_ecat); + if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; + } + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Handler handler(handler_op->handler_); @@ -775,48 +913,55 @@ public: ptr.reset(); // Call the handler. - asio::error error(last_error); asio_handler_invoke_helpers::invoke( - detail::bind_handler(handler, error, bytes_transferred), &handler); + detail::bind_handler(handler, ec, bytes_transferred), &handler); } static void destroy_impl(operation* op) { // Take ownership of the operation object. - typedef send_to_operation op_type; + typedef send_to_operation op_type; op_type* handler_op(static_cast(op)); typedef handler_alloc_traits alloc_traits; handler_ptr ptr(handler_op->handler_, handler_op); } asio::io_service::work work_; - Const_Buffers buffers_; + ConstBufferSequence buffers_; Handler handler_; }; // Start an asynchronous send. The data being sent must be valid for the // lifetime of the asynchronous operation. - template - void async_send_to(implementation_type& impl, const Const_Buffers& buffers, - const endpoint_type& destination, socket_base::message_flags flags, - Handler handler) + template + void async_send_to(implementation_type& impl, + const ConstBufferSequence& buffers, const endpoint_type& destination, + socket_base::message_flags flags, Handler handler) { + if (!is_open(impl)) + { + this->io_service().post(bind_handler(handler, + asio::error::bad_descriptor, 0)); + return; + } + // Update the ID of the thread from which cancellation is safe. if (impl.safe_cancellation_thread_id_ == 0) impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else + else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) impl.safe_cancellation_thread_id_ = ~DWORD(0); // Allocate and construct an operation to wrap the handler. - typedef send_to_operation value_type; + typedef send_to_operation value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, io_service(), buffers, handler); + handler_ptr ptr(raw_ptr, + this->io_service(), buffers, handler); // Copy buffers into WSABUF array. ::WSABUF bufs[max_buffers]; - typename Const_Buffers::const_iterator iter = buffers.begin(); - typename Const_Buffers::const_iterator end = buffers.end(); + typename ConstBufferSequence::const_iterator iter = buffers.begin(); + typename ConstBufferSequence::const_iterator end = buffers.end(); DWORD i = 0; for (; iter != end && i < max_buffers; ++iter, ++i) { @@ -835,9 +980,10 @@ public: // Check if the operation completed immediately. if (result != 0 && last_error != WSA_IO_PENDING) { + asio::io_service::work work(this->io_service()); ptr.reset(); - asio::error error(last_error); - iocp_service_.post(bind_handler(handler, error, bytes_transferred)); + asio::error_code ec(last_error, asio::native_ecat); + iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else { @@ -846,14 +992,21 @@ public: } // Receive some data from the peer. Returns the number of bytes received. - template - size_t receive(implementation_type& impl, const Mutable_Buffers& buffers, - socket_base::message_flags flags, Error_Handler error_handler) + template + size_t receive(implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + // Copy buffers into WSABUF array. ::WSABUF bufs[max_buffers]; - typename Mutable_Buffers::const_iterator iter = buffers.begin(); - typename Mutable_Buffers::const_iterator end = buffers.end(); + typename MutableBufferSequence::const_iterator iter = buffers.begin(); + typename MutableBufferSequence::const_iterator end = buffers.end(); DWORD i = 0; size_t total_buffer_size = 0; for (; iter != end && i < max_buffers; ++iter, ++i) @@ -867,7 +1020,7 @@ public: // A request to receive 0 bytes on a stream socket is a no-op. if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) { - error_handler(asio::error(0)); + ec = asio::error_code(); return 0; } @@ -881,30 +1034,34 @@ public: DWORD last_error = ::WSAGetLastError(); if (last_error == ERROR_NETNAME_DELETED) last_error = WSAECONNRESET; - error_handler(asio::error(last_error)); + else if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + ec = asio::error_code(last_error, asio::native_ecat); return 0; } if (bytes_transferred == 0) { - error_handler(asio::error(asio::error::eof)); + ec = asio::error::eof; return 0; } - error_handler(asio::error(0)); + ec = asio::error_code(); return bytes_transferred; } - template + template class receive_operation : public operation { public: receive_operation(asio::io_service& io_service, weak_cancel_token_type cancel_token, - const Mutable_Buffers& buffers, Handler handler) + const MutableBufferSequence& buffers, Handler handler) : operation( - &receive_operation::do_completion_impl, - &receive_operation::destroy_impl), + &receive_operation< + MutableBufferSequence, Handler>::do_completion_impl, + &receive_operation< + MutableBufferSequence, Handler>::destroy_impl), work_(io_service), cancel_token_(cancel_token), buffers_(buffers), @@ -917,24 +1074,43 @@ public: DWORD last_error, size_t bytes_transferred) { // Take ownership of the operation object. - typedef receive_operation op_type; + typedef receive_operation op_type; op_type* handler_op(static_cast(op)); typedef handler_alloc_traits alloc_traits; handler_ptr ptr(handler_op->handler_, handler_op); - // Map ERROR_NETNAME_DELETED to more useful error. - if (last_error == ERROR_NETNAME_DELETED) +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + typename MutableBufferSequence::const_iterator iter + = handler_op->buffers_.begin(); + typename MutableBufferSequence::const_iterator end + = handler_op->buffers_.end(); + while (iter != end) + { + asio::mutable_buffer buffer(*iter); + asio::buffer_cast(buffer); + ++iter; + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + // Map non-portable errors to their portable counterparts. + asio::error_code ec(last_error, asio::native_ecat); + if (ec.value() == ERROR_NETNAME_DELETED) { if (handler_op->cancel_token_.expired()) - last_error = ERROR_OPERATION_ABORTED; + ec = asio::error::operation_aborted; else - last_error = WSAECONNRESET; + ec = asio::error::connection_reset; + } + else if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; } // Check for connection closed. - else if (last_error == 0 && bytes_transferred == 0) + else if (!ec && bytes_transferred == 0) { - last_error = asio::error::eof; + ec = asio::error::eof; } // Make a copy of the handler so that the memory can be deallocated before @@ -945,15 +1121,14 @@ public: ptr.reset(); // Call the handler. - asio::error error(last_error); asio_handler_invoke_helpers::invoke( - detail::bind_handler(handler, error, bytes_transferred), &handler); + detail::bind_handler(handler, ec, bytes_transferred), &handler); } static void destroy_impl(operation* op) { // Take ownership of the operation object. - typedef receive_operation op_type; + typedef receive_operation op_type; op_type* handler_op(static_cast(op)); typedef handler_alloc_traits alloc_traits; handler_ptr ptr(handler_op->handler_, handler_op); @@ -961,33 +1136,41 @@ public: asio::io_service::work work_; weak_cancel_token_type cancel_token_; - Mutable_Buffers buffers_; + MutableBufferSequence buffers_; Handler handler_; }; // Start an asynchronous receive. The buffer for the data being received // must be valid for the lifetime of the asynchronous operation. - template - void async_receive(implementation_type& impl, const Mutable_Buffers& buffers, + template + void async_receive(implementation_type& impl, + const MutableBufferSequence& buffers, socket_base::message_flags flags, Handler handler) { + if (!is_open(impl)) + { + this->io_service().post(bind_handler(handler, + asio::error::bad_descriptor, 0)); + return; + } + // Update the ID of the thread from which cancellation is safe. if (impl.safe_cancellation_thread_id_ == 0) impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else + else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) impl.safe_cancellation_thread_id_ = ~DWORD(0); // Allocate and construct an operation to wrap the handler. - typedef receive_operation value_type; + typedef receive_operation value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); handler_ptr ptr(raw_ptr, - io_service(), impl.cancel_token_, buffers, handler); + this->io_service(), impl.cancel_token_, buffers, handler); // Copy buffers into WSABUF array. ::WSABUF bufs[max_buffers]; - typename Mutable_Buffers::const_iterator iter = buffers.begin(); - typename Mutable_Buffers::const_iterator end = buffers.end(); + typename MutableBufferSequence::const_iterator iter = buffers.begin(); + typename MutableBufferSequence::const_iterator end = buffers.end(); DWORD i = 0; size_t total_buffer_size = 0; for (; iter != end && i < max_buffers; ++iter, ++i) @@ -1001,8 +1184,9 @@ public: // A request to receive 0 bytes on a stream socket is a no-op. if (impl.protocol_.type() == SOCK_STREAM && total_buffer_size == 0) { + asio::io_service::work work(this->io_service()); ptr.reset(); - asio::error error(asio::error::success); + asio::error_code error; iocp_service_.post(bind_handler(handler, error, 0)); return; } @@ -1015,9 +1199,10 @@ public: DWORD last_error = ::WSAGetLastError(); if (result != 0 && last_error != WSA_IO_PENDING) { + asio::io_service::work work(this->io_service()); ptr.reset(); - asio::error error(last_error); - iocp_service_.post(bind_handler(handler, error, bytes_transferred)); + asio::error_code ec(last_error, asio::native_ecat); + iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else { @@ -1027,15 +1212,22 @@ public: // Receive a datagram with the endpoint of the sender. Returns the number of // bytes received. - template - size_t receive_from(implementation_type& impl, const Mutable_Buffers& buffers, + template + size_t receive_from(implementation_type& impl, + const MutableBufferSequence& buffers, endpoint_type& sender_endpoint, socket_base::message_flags flags, - Error_Handler error_handler) + asio::error_code& ec) { + if (!is_open(impl)) + { + ec = asio::error::bad_descriptor; + return 0; + } + // Copy buffers into WSABUF array. ::WSABUF bufs[max_buffers]; - typename Mutable_Buffers::const_iterator iter = buffers.begin(); - typename Mutable_Buffers::const_iterator end = buffers.end(); + typename MutableBufferSequence::const_iterator iter = buffers.begin(); + typename MutableBufferSequence::const_iterator end = buffers.end(); DWORD i = 0; for (; iter != end && i < max_buffers; ++iter, ++i) { @@ -1053,32 +1245,36 @@ public: if (result != 0) { DWORD last_error = ::WSAGetLastError(); - error_handler(asio::error(last_error)); + if (last_error == ERROR_PORT_UNREACHABLE) + last_error = WSAECONNREFUSED; + ec = asio::error_code(last_error, asio::native_ecat); return 0; } if (bytes_transferred == 0) { - error_handler(asio::error(asio::error::eof)); + ec = asio::error::eof; return 0; } sender_endpoint.resize(endpoint_size); - error_handler(asio::error(0)); + ec = asio::error_code(); return bytes_transferred; } - template + template class receive_from_operation : public operation { public: receive_from_operation(asio::io_service& io_service, - endpoint_type& endpoint, const Mutable_Buffers& buffers, + endpoint_type& endpoint, const MutableBufferSequence& buffers, Handler handler) : operation( - &receive_from_operation::do_completion_impl, - &receive_from_operation::destroy_impl), + &receive_from_operation< + MutableBufferSequence, Handler>::do_completion_impl, + &receive_from_operation< + MutableBufferSequence, Handler>::destroy_impl), endpoint_(endpoint), endpoint_size_(endpoint.capacity()), work_(io_service), @@ -1097,15 +1293,36 @@ public: DWORD last_error, size_t bytes_transferred) { // Take ownership of the operation object. - typedef receive_from_operation op_type; + typedef receive_from_operation op_type; op_type* handler_op(static_cast(op)); typedef handler_alloc_traits alloc_traits; handler_ptr ptr(handler_op->handler_, handler_op); - // Check for connection closed. - if (last_error == 0 && bytes_transferred == 0) +#if defined(ASIO_ENABLE_BUFFER_DEBUGGING) + // Check whether buffers are still valid. + typename MutableBufferSequence::const_iterator iter + = handler_op->buffers_.begin(); + typename MutableBufferSequence::const_iterator end + = handler_op->buffers_.end(); + while (iter != end) { - last_error = asio::error::eof; + asio::mutable_buffer buffer(*iter); + asio::buffer_cast(buffer); + ++iter; + } +#endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) + + // Map non-portable errors to their portable counterparts. + asio::error_code ec(last_error, asio::native_ecat); + if (ec.value() == ERROR_PORT_UNREACHABLE) + { + ec = asio::error::connection_refused; + } + + // Check for connection closed. + if (!ec && bytes_transferred == 0) + { + ec = asio::error::eof; } // Record the size of the endpoint returned by the operation. @@ -1119,15 +1336,14 @@ public: ptr.reset(); // Call the handler. - asio::error error(last_error); asio_handler_invoke_helpers::invoke( - detail::bind_handler(handler, error, bytes_transferred), &handler); + detail::bind_handler(handler, ec, bytes_transferred), &handler); } static void destroy_impl(operation* op) { // Take ownership of the operation object. - typedef receive_from_operation op_type; + typedef receive_from_operation op_type; op_type* handler_op(static_cast(op)); typedef handler_alloc_traits alloc_traits; handler_ptr ptr(handler_op->handler_, handler_op); @@ -1136,35 +1352,42 @@ public: endpoint_type& endpoint_; int endpoint_size_; asio::io_service::work work_; - Mutable_Buffers buffers_; + MutableBufferSequence buffers_; Handler handler_; }; // Start an asynchronous receive. The buffer for the data being received and // the sender_endpoint object must both be valid for the lifetime of the // asynchronous operation. - template + template void async_receive_from(implementation_type& impl, - const Mutable_Buffers& buffers, endpoint_type& sender_endp, + const MutableBufferSequence& buffers, endpoint_type& sender_endp, socket_base::message_flags flags, Handler handler) { + if (!is_open(impl)) + { + this->io_service().post(bind_handler(handler, + asio::error::bad_descriptor, 0)); + return; + } + // Update the ID of the thread from which cancellation is safe. if (impl.safe_cancellation_thread_id_ == 0) impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else + else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) impl.safe_cancellation_thread_id_ = ~DWORD(0); // Allocate and construct an operation to wrap the handler. - typedef receive_from_operation value_type; + typedef receive_from_operation value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); handler_ptr ptr(raw_ptr, - io_service(), sender_endp, buffers, handler); + this->io_service(), sender_endp, buffers, handler); // Copy buffers into WSABUF array. ::WSABUF bufs[max_buffers]; - typename Mutable_Buffers::const_iterator iter = buffers.begin(); - typename Mutable_Buffers::const_iterator end = buffers.end(); + typename MutableBufferSequence::const_iterator iter = buffers.begin(); + typename MutableBufferSequence::const_iterator end = buffers.end(); DWORD i = 0; for (; iter != end && i < max_buffers; ++iter, ++i) { @@ -1182,9 +1405,10 @@ public: DWORD last_error = ::WSAGetLastError(); if (result != 0 && last_error != WSA_IO_PENDING) { + asio::io_service::work work(this->io_service()); ptr.reset(); - asio::error error(last_error); - iocp_service_.post(bind_handler(handler, error, bytes_transferred)); + asio::error_code ec(last_error, asio::native_ecat); + iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else { @@ -1193,23 +1417,42 @@ public: } // Accept a new connection. - template - void accept(implementation_type& impl, Socket& peer, - Error_Handler error_handler) + template + asio::error_code accept(implementation_type& impl, Socket& peer, + endpoint_type* peer_endpoint, asio::error_code& ec) { - // We cannot accept a socket that is already open. - if (peer.native() != invalid_socket) + if (!is_open(impl)) { - error_handler(asio::error(asio::error::already_connected)); - return; + ec = asio::error::bad_descriptor; + return ec; + } + + // We cannot accept a socket that is already open. + if (peer.is_open()) + { + ec = asio::error::already_open; + return ec; } for (;;) { - socket_holder new_socket(socket_ops::accept(impl.socket_, 0, 0)); - if (int err = socket_ops::get_error()) + asio::error_code ec; + socket_holder new_socket; + socket_addr_len_type addr_len = 0; + if (peer_endpoint) { - if (err == asio::error::connection_aborted + addr_len = peer_endpoint->capacity(); + new_socket.reset(socket_ops::accept(impl.socket_, + peer_endpoint->data(), &addr_len, ec)); + } + else + { + new_socket.reset(socket_ops::accept(impl.socket_, 0, 0, ec)); + } + + if (ec) + { + if (ec == asio::error::connection_aborted && !(impl.flags_ & implementation_type::enable_connection_aborted)) { // Retry accept operation. @@ -1217,76 +1460,17 @@ public: } else { - error_handler(asio::error(err)); - return; + return ec; } } - asio::error temp_error; - peer.assign(impl.protocol_, new_socket.get(), - asio::assign_error(temp_error)); - if (temp_error) - { - error_handler(temp_error); - return; - } - else - { + if (peer_endpoint) + peer_endpoint->resize(addr_len); + + peer.assign(impl.protocol_, new_socket.get(), ec); + if (!ec) new_socket.release(); - error_handler(asio::error(0)); - return; - } - } - } - - // Accept a new connection. - template - void accept_endpoint(implementation_type& impl, Socket& peer, - endpoint_type& peer_endpoint, Error_Handler error_handler) - { - // We cannot accept a socket that is already open. - if (peer.native() != invalid_socket) - { - error_handler(asio::error(asio::error::already_connected)); - return; - } - - for (;;) - { - socket_addr_len_type addr_len = peer_endpoint.capacity(); - socket_holder new_socket(socket_ops::accept( - impl.socket_, peer_endpoint.data(), &addr_len)); - if (int err = socket_ops::get_error()) - { - if (err == asio::error::connection_aborted - && !(impl.flags_ & implementation_type::enable_connection_aborted)) - { - // Retry accept operation. - continue; - } - else - { - error_handler(asio::error(err)); - return; - } - } - - peer_endpoint.resize(addr_len); - - asio::error temp_error; - peer.assign(impl.protocol_, new_socket.get(), - asio::assign_error(temp_error)); - if (temp_error) - { - error_handler(temp_error); - return; - } - else - { - new_socket.release(); - error_handler(asio::error(0)); - return; - } + return ec; } } @@ -1295,8 +1479,9 @@ public: : public operation { public: - accept_operation(win_iocp_io_service& io_service, socket_type socket, - socket_type new_socket, Socket& peer, const protocol_type& protocol, + accept_operation(win_iocp_io_service& io_service, + socket_type socket, socket_type new_socket, Socket& peer, + const protocol_type& protocol, endpoint_type* peer_endpoint, bool enable_connection_aborted, Handler handler) : operation( &accept_operation::do_completion_impl, @@ -1306,6 +1491,7 @@ public: new_socket_(new_socket), peer_(peer), protocol_(protocol), + peer_endpoint_(peer_endpoint), work_(io_service.io_service()), enable_connection_aborted_(enable_connection_aborted), handler_(handler) @@ -1340,12 +1526,12 @@ public: // Map Windows error ERROR_NETNAME_DELETED to connection_aborted. if (last_error == ERROR_NETNAME_DELETED) { - last_error = asio::error::connection_aborted; + last_error = WSAECONNABORTED; } // Restart the accept operation if we got the connection_aborted error // and the enable_connection_aborted socket option is not set. - if (last_error == asio::error::connection_aborted + if (last_error == WSAECONNABORTED && !ptr.get()->enable_connection_aborted_) { // Reset OVERLAPPED structure. @@ -1357,11 +1543,11 @@ public: // Create a new socket for the next connection, since the AcceptEx call // fails with WSAEINVAL if we try to reuse the same socket. + asio::error_code ec; ptr.get()->new_socket_.reset(); - ptr.get()->new_socket_.reset( - socket_ops::socket(ptr.get()->protocol_.family(), - ptr.get()->protocol_.type(), ptr.get()->protocol_.protocol())); - last_error = socket_ops::get_error(); + ptr.get()->new_socket_.reset(socket_ops::socket( + ptr.get()->protocol_.family(), ptr.get()->protocol_.type(), + ptr.get()->protocol_.protocol(), ec)); if (ptr.get()->new_socket() != invalid_socket) { // Accept a connection. @@ -1375,7 +1561,7 @@ public: if (!result && last_error != WSA_IO_PENDING) { if (last_error == ERROR_NETNAME_DELETED - || last_error == asio::error::connection_aborted) + || last_error == WSAECONNABORTED) { // Post this handler so that operation will be restarted again. ptr.get()->io_service_.post_completion(ptr.get(), last_error, 0); @@ -1409,7 +1595,7 @@ public: &local_addr, &local_addr_length, &remote_addr, &remote_addr_length); if (remote_addr_length > peer_endpoint.capacity()) { - last_error = asio::error::invalid_argument; + last_error = WSAEINVAL; } else { @@ -1424,11 +1610,12 @@ public: if (last_error == 0) { SOCKET update_ctx_param = handler_op->socket_; + asio::error_code ec; if (socket_ops::setsockopt(handler_op->new_socket_.get(), SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, - &update_ctx_param, sizeof(SOCKET)) != 0) + &update_ctx_param, sizeof(SOCKET), ec) != 0) { - last_error = socket_ops::get_error(); + last_error = ec.value(); } } @@ -1436,16 +1623,19 @@ public: // socket to the peer object. if (last_error == 0) { - asio::error temp_error; + asio::error_code ec; handler_op->peer_.assign(handler_op->protocol_, - native_type(handler_op->new_socket_.get(), peer_endpoint), - asio::assign_error(temp_error)); - if (temp_error) - last_error = temp_error.code(); + native_type(handler_op->new_socket_.get(), peer_endpoint), ec); + if (ec) + last_error = ec.value(); else handler_op->new_socket_.release(); } + // Pass endpoint back to caller. + if (handler_op->peer_endpoint_) + *handler_op->peer_endpoint_ = peer_endpoint; + // Make a copy of the handler so that the memory can be deallocated before // the upcall is made. Handler handler(handler_op->handler_); @@ -1454,9 +1644,9 @@ public: ptr.reset(); // Call the handler. - asio::error error(last_error); + asio::error_code ec(last_error, asio::native_ecat); asio_handler_invoke_helpers::invoke( - detail::bind_handler(handler, error), &handler); + detail::bind_handler(handler, ec), &handler); } static void destroy_impl(operation* op) @@ -1473,281 +1663,7 @@ public: socket_holder new_socket_; Socket& peer_; protocol_type protocol_; - asio::io_service::work work_; - unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; - bool enable_connection_aborted_; - Handler handler_; - }; - - // Start an asynchronous accept. The peer object must be valid until the - // accept's handler is invoked. - template - void async_accept(implementation_type& impl, Socket& peer, Handler handler) - { - // Update the ID of the thread from which cancellation is safe. - if (impl.safe_cancellation_thread_id_ == 0) - impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else - impl.safe_cancellation_thread_id_ = ~DWORD(0); - - // Check whether acceptor has been initialised. - if (impl.socket_ == invalid_socket) - { - asio::error error(asio::error::bad_descriptor); - io_service().post(bind_handler(handler, error)); - return; - } - - // Check that peer socket has not already been connected. - if (peer.native() != invalid_socket) - { - asio::error error(asio::error::already_connected); - io_service().post(bind_handler(handler, error)); - return; - } - - // Create a new socket for the connection. - socket_holder sock(socket_ops::socket(impl.protocol_.family(), - impl.protocol_.type(), impl.protocol_.protocol())); - if (sock.get() == invalid_socket) - { - asio::error error(socket_ops::get_error()); - io_service().post(bind_handler(handler, error)); - return; - } - - // Allocate and construct an operation to wrap the handler. - typedef accept_operation value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - socket_type new_socket = sock.get(); - bool enable_connection_aborted = - (impl.flags_ & implementation_type::enable_connection_aborted); - handler_ptr ptr(raw_ptr, - iocp_service_, impl.socket_, new_socket, peer, impl.protocol_, - enable_connection_aborted, handler); - sock.release(); - - // Accept a connection. - DWORD bytes_read = 0; - BOOL result = ::AcceptEx(impl.socket_, ptr.get()->new_socket(), - ptr.get()->output_buffer(), 0, ptr.get()->address_length(), - ptr.get()->address_length(), &bytes_read, ptr.get()); - DWORD last_error = ::WSAGetLastError(); - - // Check if the operation completed immediately. - if (!result && last_error != WSA_IO_PENDING) - { - if (!enable_connection_aborted - && (last_error == ERROR_NETNAME_DELETED - || last_error == asio::error::connection_aborted)) - { - // Post handler so that operation will be restarted again. We do not - // perform the AcceptEx again here to avoid the possibility of starving - // other handlers. - iocp_service_.post_completion(ptr.get(), last_error, 0); - ptr.release(); - } - else - { - ptr.reset(); - asio::error error(last_error); - iocp_service_.post(bind_handler(handler, error)); - } - } - else - { - ptr.release(); - } - } - - template - class accept_endp_operation - : public operation - { - public: - accept_endp_operation(win_iocp_io_service& io_service, - socket_type socket, socket_type new_socket, Socket& peer, - const protocol_type& protocol, endpoint_type& peer_endpoint, - bool enable_connection_aborted, Handler handler) - : operation( - &accept_endp_operation::do_completion_impl, - &accept_endp_operation::destroy_impl), - io_service_(io_service), - socket_(socket), - new_socket_(new_socket), - peer_(peer), - protocol_(protocol), - peer_endpoint_(peer_endpoint), - work_(io_service.io_service()), - enable_connection_aborted_(enable_connection_aborted), - handler_(handler) - { - } - - socket_type new_socket() - { - return new_socket_.get(); - } - - void* output_buffer() - { - return output_buffer_; - } - - DWORD address_length() - { - return sizeof(sockaddr_storage_type) + 16; - } - - private: - static void do_completion_impl(operation* op, - DWORD last_error, size_t bytes_transferred) - { - // Take ownership of the operation object. - typedef accept_endp_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - - // Map Windows error ERROR_NETNAME_DELETED to connection_aborted. - if (last_error == ERROR_NETNAME_DELETED) - { - last_error = asio::error::connection_aborted; - } - - // Restart the accept operation if we got the connection_aborted error - // and the enable_connection_aborted socket option is not set. - if (last_error == asio::error::connection_aborted - && !ptr.get()->enable_connection_aborted_) - { - // Reset OVERLAPPED structure. - ptr.get()->Internal = 0; - ptr.get()->InternalHigh = 0; - ptr.get()->Offset = 0; - ptr.get()->OffsetHigh = 0; - ptr.get()->hEvent = 0; - - // Create a new socket for the next connection, since the AcceptEx call - // fails with WSAEINVAL if we try to reuse the same socket. - ptr.get()->new_socket_.reset(); - ptr.get()->new_socket_.reset( - socket_ops::socket(ptr.get()->protocol_.family(), - ptr.get()->protocol_.type(), ptr.get()->protocol_.protocol())); - last_error = socket_ops::get_error(); - if (ptr.get()->new_socket() != invalid_socket) - { - // Accept a connection. - DWORD bytes_read = 0; - BOOL result = ::AcceptEx(ptr.get()->socket_, ptr.get()->new_socket(), - ptr.get()->output_buffer(), 0, ptr.get()->address_length(), - ptr.get()->address_length(), &bytes_read, ptr.get()); - last_error = ::WSAGetLastError(); - - // Check if the operation completed immediately. - if (!result && last_error != WSA_IO_PENDING) - { - if (last_error == ERROR_NETNAME_DELETED - || last_error == asio::error::connection_aborted) - { - // Post this handler so that operation will be restarted again. - ptr.get()->io_service_.post_completion(ptr.get(), last_error, 0); - ptr.release(); - return; - } - else - { - // Operation already complete. Continue with rest of this handler. - } - } - else - { - // Asynchronous operation has been successfully restarted. - ptr.release(); - return; - } - } - } - - // Get the address of the peer. - if (last_error == 0) - { - LPSOCKADDR local_addr = 0; - int local_addr_length = 0; - LPSOCKADDR remote_addr = 0; - int remote_addr_length = 0; - GetAcceptExSockaddrs(handler_op->output_buffer(), 0, - handler_op->address_length(), handler_op->address_length(), - &local_addr, &local_addr_length, &remote_addr, &remote_addr_length); - if (remote_addr_length > handler_op->peer_endpoint_.capacity()) - { - last_error = asio::error::invalid_argument; - } - else - { - using namespace std; // For memcpy. - memcpy(handler_op->peer_endpoint_.data(), - remote_addr, remote_addr_length); - handler_op->peer_endpoint_.resize(remote_addr_length); - } - } - - // Need to set the SO_UPDATE_ACCEPT_CONTEXT option so that getsockname - // and getpeername will work on the accepted socket. - if (last_error == 0) - { - SOCKET update_ctx_param = handler_op->socket_; - if (socket_ops::setsockopt(handler_op->new_socket_.get(), - SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, - &update_ctx_param, sizeof(SOCKET)) != 0) - { - last_error = socket_ops::get_error(); - } - } - - // If the socket was successfully accepted, transfer ownership of the - // socket to the peer object. - if (last_error == 0) - { - asio::error temp_error; - handler_op->peer_.assign(handler_op->peer_endpoint_.protocol(), - native_type(handler_op->new_socket_.get(), - handler_op->peer_endpoint_), - asio::assign_error(temp_error)); - if (temp_error) - last_error = temp_error.code(); - else - handler_op->new_socket_.release(); - } - - // Make a copy of the handler so that the memory can be deallocated before - // the upcall is made. - Handler handler(handler_op->handler_); - - // Free the memory associated with the handler. - ptr.reset(); - - // Call the handler. - asio::error error(last_error); - asio_handler_invoke_helpers::invoke( - detail::bind_handler(handler, error), &handler); - } - - static void destroy_impl(operation* op) - { - // Take ownership of the operation object. - typedef accept_endp_operation op_type; - op_type* handler_op(static_cast(op)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(handler_op->handler_, handler_op); - } - - win_iocp_io_service& io_service_; - socket_type socket_; - socket_holder new_socket_; - Socket& peer_; - protocol_type protocol_; - endpoint_type& peer_endpoint_; + endpoint_type* peer_endpoint_; asio::io_service::work work_; unsigned char output_buffer_[(sizeof(sockaddr_storage_type) + 16) * 2]; bool enable_connection_aborted_; @@ -1757,43 +1673,43 @@ public: // Start an asynchronous accept. The peer and peer_endpoint objects // must be valid until the accept's handler is invoked. template - void async_accept_endpoint(implementation_type& impl, Socket& peer, - endpoint_type& peer_endpoint, Handler handler) + void async_accept(implementation_type& impl, Socket& peer, + endpoint_type* peer_endpoint, Handler handler) { + // Check whether acceptor has been initialised. + if (!is_open(impl)) + { + this->io_service().post(bind_handler(handler, + asio::error::bad_descriptor)); + return; + } + + // Check that peer socket has not already been opened. + if (peer.is_open()) + { + this->io_service().post(bind_handler(handler, + asio::error::already_open)); + return; + } + // Update the ID of the thread from which cancellation is safe. if (impl.safe_cancellation_thread_id_ == 0) impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else + else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) impl.safe_cancellation_thread_id_ = ~DWORD(0); - // Check whether acceptor has been initialised. - if (impl.socket_ == invalid_socket) - { - asio::error error(asio::error::bad_descriptor); - io_service().post(bind_handler(handler, error)); - return; - } - - // Check that peer socket has not already been connected. - if (peer.native() != invalid_socket) - { - asio::error error(asio::error::already_connected); - io_service().post(bind_handler(handler, error)); - return; - } - // Create a new socket for the connection. + asio::error_code ec; socket_holder sock(socket_ops::socket(impl.protocol_.family(), - impl.protocol_.type(), impl.protocol_.protocol())); + impl.protocol_.type(), impl.protocol_.protocol(), ec)); if (sock.get() == invalid_socket) { - asio::error error(socket_ops::get_error()); - io_service().post(bind_handler(handler, error)); + this->io_service().post(bind_handler(handler, ec)); return; } // Allocate and construct an operation to wrap the handler. - typedef accept_endp_operation value_type; + typedef accept_operation value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); socket_type new_socket = sock.get(); @@ -1816,7 +1732,7 @@ public: { if (!enable_connection_aborted && (last_error == ERROR_NETNAME_DELETED - || last_error == asio::error::connection_aborted)) + || last_error == WSAECONNABORTED)) { // Post handler so that operation will be restarted again. We do not // perform the AcceptEx again here to avoid the possibility of starving @@ -1826,9 +1742,10 @@ public: } else { + asio::io_service::work work(this->io_service()); ptr.reset(); - asio::error error(last_error); - iocp_service_.post(bind_handler(handler, error)); + asio::error_code ec(last_error, asio::native_ecat); + iocp_service_.post(bind_handler(handler, ec)); } } else @@ -1838,35 +1755,19 @@ public: } // Connect the socket to the specified endpoint. - template - void connect(implementation_type& impl, const endpoint_type& peer_endpoint, - Error_Handler error_handler) + asio::error_code connect(implementation_type& impl, + const endpoint_type& peer_endpoint, asio::error_code& ec) { - // Open the socket if it is not already open. - if (impl.socket_ == invalid_socket) + if (!is_open(impl)) { - // Get the flags used to create the new socket. - int family = peer_endpoint.protocol().family(); - int type = peer_endpoint.protocol().type(); - int proto = peer_endpoint.protocol().protocol(); - - // Create a new socket. - impl.socket_ = socket_ops::socket(family, type, proto); - if (impl.socket_ == invalid_socket) - { - error_handler(asio::error(socket_ops::get_error())); - return; - } - iocp_service_.register_socket(impl.socket_); + ec = asio::error::bad_descriptor; + return ec; } // Perform the connect operation. - int result = socket_ops::connect(impl.socket_, - peer_endpoint.data(), peer_endpoint.size()); - if (result == socket_error_retval) - error_handler(asio::error(socket_ops::get_error())); - else - error_handler(asio::error(0)); + socket_ops::connect(impl.socket_, + peer_endpoint.data(), peer_endpoint.size(), ec); + return ec; } template @@ -1886,7 +1787,7 @@ public: { } - bool operator()(int result) + bool operator()(const asio::error_code& result) { // Check whether a handler has already been called for the connection. // If it has, then we don't want to do anything in this handler. @@ -1898,44 +1799,43 @@ public: reactor_.enqueue_cancel_ops_unlocked(socket_); // Check whether the operation was successful. - if (result != 0) + if (result) { - asio::error error(result); - io_service_.post(bind_handler(handler_, error)); + io_service_.post(bind_handler(handler_, result)); return true; } // Get the error code from the connect operation. int connect_error = 0; size_t connect_error_len = sizeof(connect_error); + asio::error_code ec; if (socket_ops::getsockopt(socket_, SOL_SOCKET, SO_ERROR, - &connect_error, &connect_error_len) == socket_error_retval) + &connect_error, &connect_error_len, ec) == socket_error_retval) { - asio::error error(socket_ops::get_error()); - io_service_.post(bind_handler(handler_, error)); + io_service_.post(bind_handler(handler_, ec)); return true; } // If connection failed then post the handler with the error code. if (connect_error) { - asio::error error(connect_error); - io_service_.post(bind_handler(handler_, error)); + ec = asio::error_code( + connect_error, asio::native_ecat); + io_service_.post(bind_handler(handler_, ec)); return true; } // Make the socket blocking again (the default). ioctl_arg_type non_blocking = 0; - if (socket_ops::ioctl(socket_, FIONBIO, &non_blocking)) + if (socket_ops::ioctl(socket_, FIONBIO, &non_blocking, ec)) { - asio::error error(socket_ops::get_error()); - io_service_.post(bind_handler(handler_, error)); + io_service_.post(bind_handler(handler_, ec)); return true; } // Post the result of the successful connection operation. - asio::error error(asio::error::success); - io_service_.post(bind_handler(handler_, error)); + ec = asio::error_code(); + io_service_.post(bind_handler(handler_, ec)); return true; } @@ -1953,10 +1853,17 @@ public: void async_connect(implementation_type& impl, const endpoint_type& peer_endpoint, Handler handler) { + if (!is_open(impl)) + { + this->io_service().post(bind_handler(handler, + asio::error::bad_descriptor)); + return; + } + // Update the ID of the thread from which cancellation is safe. if (impl.safe_cancellation_thread_id_ == 0) impl.safe_cancellation_thread_id_ = ::GetCurrentThreadId(); - else + else if (impl.safe_cancellation_thread_id_ != ::GetCurrentThreadId()) impl.safe_cancellation_thread_id_ = ~DWORD(0); // Check if the reactor was already obtained from the io_service. @@ -1965,64 +1872,43 @@ public: reinterpret_cast(&reactor_), 0, 0)); if (!reactor) { - reactor = &(asio::use_service(io_service())); + reactor = &(asio::use_service(this->io_service())); interlocked_exchange_pointer( reinterpret_cast(&reactor_), reactor); } - // Open the socket if it is not already open. - if (impl.socket_ == invalid_socket) - { - // Get the flags used to create the new socket. - int family = peer_endpoint.protocol().family(); - int type = peer_endpoint.protocol().type(); - int proto = peer_endpoint.protocol().protocol(); - - // Create a new socket. - impl.socket_ = socket_ops::socket(family, type, proto); - if (impl.socket_ == invalid_socket) - { - asio::error error(socket_ops::get_error()); - io_service().post(bind_handler(handler, error)); - return; - } - iocp_service_.register_socket(impl.socket_); - } - // Mark the socket as non-blocking so that the connection will take place // asynchronously. ioctl_arg_type non_blocking = 1; - if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking)) + asio::error_code ec; + if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec)) { - asio::error error(socket_ops::get_error()); - io_service().post(bind_handler(handler, error)); + this->io_service().post(bind_handler(handler, ec)); return; } // Start the connect operation. if (socket_ops::connect(impl.socket_, peer_endpoint.data(), - peer_endpoint.size()) == 0) + peer_endpoint.size(), ec) == 0) { // The connect operation has finished successfully so we need to post the // handler immediately. - asio::error error(asio::error::success); - io_service().post(bind_handler(handler, error)); + this->io_service().post(bind_handler(handler, ec)); } - else if (socket_ops::get_error() == asio::error::in_progress - || socket_ops::get_error() == asio::error::would_block) + else if (ec == asio::error::in_progress + || ec == asio::error::would_block) { // The connection is happening in the background, and we need to wait // until the socket becomes writeable. boost::shared_ptr completed(new bool(false)); reactor->start_write_and_except_ops(impl.socket_, connect_handler( - impl.socket_, completed, io_service(), *reactor, handler)); + impl.socket_, completed, this->io_service(), *reactor, handler)); } else { // The connect operation has failed, so post the handler immediately. - asio::error error(socket_ops::get_error()); - io_service().post(bind_handler(handler, error)); + this->io_service().post(bind_handler(handler, ec)); } } diff --git a/libtorrent/include/libtorrent/asio/detail/win_mutex.hpp b/libtorrent/include/libtorrent/asio/detail/win_mutex.hpp index 9f3dd85c9..82659831f 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_mutex.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_mutex.hpp @@ -2,7 +2,7 @@ // win_mutex.hpp // ~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -23,7 +23,7 @@ #if defined(BOOST_WINDOWS) -#include "asio/system_exception.hpp" +#include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/scoped_lock.hpp" @@ -47,7 +47,9 @@ public: int error = do_init(); if (error != 0) { - system_exception e("mutex", error); + asio::system_error e( + asio::error_code(error, asio::native_ecat), + "mutex"); boost::throw_exception(e); } } @@ -64,7 +66,9 @@ public: int error = do_lock(); if (error != 0) { - system_exception e("mutex", error); + asio::system_error e( + asio::error_code(error, asio::native_ecat), + "mutex"); boost::throw_exception(e); } } diff --git a/libtorrent/include/libtorrent/asio/detail/win_signal_blocker.hpp b/libtorrent/include/libtorrent/asio/detail/win_signal_blocker.hpp index a1c2e992b..892c40f89 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_signal_blocker.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_signal_blocker.hpp @@ -2,7 +2,7 @@ // win_signal_blocker.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/detail/win_thread.hpp b/libtorrent/include/libtorrent/asio/detail/win_thread.hpp index 4e6adb880..a6c9b15d2 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_thread.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_thread.hpp @@ -2,7 +2,7 @@ // win_thread.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -23,7 +23,7 @@ #if defined(BOOST_WINDOWS) -#include "asio/system_exception.hpp" +#include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" @@ -53,7 +53,9 @@ public: if (!thread_) { DWORD last_error = ::GetLastError(); - system_exception e("thread", last_error); + asio::system_error e( + asio::error_code(last_error, asio::native_ecat), + "thread"); boost::throw_exception(e); } arg.release(); diff --git a/libtorrent/include/libtorrent/asio/detail/win_tss_ptr.hpp b/libtorrent/include/libtorrent/asio/detail/win_tss_ptr.hpp index 5381094c5..d3e2f8161 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_tss_ptr.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_tss_ptr.hpp @@ -2,7 +2,7 @@ // win_tss_ptr.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -23,7 +23,7 @@ #if defined(BOOST_WINDOWS) -#include "asio/system_exception.hpp" +#include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" @@ -46,7 +46,9 @@ public: if (tss_key_ == TLS_OUT_OF_INDEXES) { DWORD last_error = ::GetLastError(); - system_exception e("tss", last_error); + asio::system_error e( + asio::error_code(last_error, asio::native_ecat), + "tss"); boost::throw_exception(e); } } diff --git a/libtorrent/include/libtorrent/asio/detail/winsock_init.hpp b/libtorrent/include/libtorrent/asio/detail/winsock_init.hpp index 7ae66d0e5..67c69e8ce 100644 --- a/libtorrent/include/libtorrent/asio/detail/winsock_init.hpp +++ b/libtorrent/include/libtorrent/asio/detail/winsock_init.hpp @@ -2,7 +2,7 @@ // winsock_init.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -28,7 +28,7 @@ #include #include "asio/detail/pop_options.hpp" -#include "asio/system_exception.hpp" +#include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" @@ -84,7 +84,9 @@ public: // catch the exception. if (this != &instance_ && ref_->result() != 0) { - system_exception e("winsock", ref_->result()); + asio::system_error e( + asio::error_code(ref_->result(), asio::native_ecat), + "winsock"); boost::throw_exception(e); } } diff --git a/libtorrent/include/libtorrent/asio/detail/wrapped_handler.hpp b/libtorrent/include/libtorrent/asio/detail/wrapped_handler.hpp index e77b38dd8..f757fd3dc 100644 --- a/libtorrent/include/libtorrent/asio/detail/wrapped_handler.hpp +++ b/libtorrent/include/libtorrent/asio/detail/wrapped_handler.hpp @@ -2,7 +2,7 @@ // wrapped_handler.hpp // ~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/error.hpp b/libtorrent/include/libtorrent/asio/error.hpp index c52df6cd8..935cc6796 100644 --- a/libtorrent/include/libtorrent/asio/error.hpp +++ b/libtorrent/include/libtorrent/asio/error.hpp @@ -2,7 +2,7 @@ // error.hpp // ~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -18,369 +18,349 @@ #include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp" -#include -#include #include -#include -#include -#include -#include -#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -# include -#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +#include #include "asio/detail/pop_options.hpp" +#include "asio/error_code.hpp" #include "asio/detail/socket_types.hpp" -#include "asio/detail/win_local_free_on_block_exit.hpp" - -namespace asio { #if defined(GENERATING_DOCUMENTATION) /// INTERNAL ONLY. +# define ASIO_NATIVE_ERROR(e) implementation_defined +/// INTERNAL ONLY. # define ASIO_SOCKET_ERROR(e) implementation_defined /// INTERNAL ONLY. # define ASIO_NETDB_ERROR(e) implementation_defined /// INTERNAL ONLY. # define ASIO_GETADDRINFO_ERROR(e) implementation_defined /// INTERNAL ONLY. -# define ASIO_OS_ERROR(e_win, e_posix) implementation_defined +# define ASIO_WIN_OR_POSIX(e_win, e_posix) implementation_defined #elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# define ASIO_SOCKET_ERROR(e) WSA ## e -# define ASIO_NETDB_ERROR(e) WSA ## e -# define ASIO_GETADDRINFO_ERROR(e) e -# define ASIO_OS_ERROR(e_win, e_posix) e_win +# define ASIO_NATIVE_ERROR(e) \ + asio::error_code(e, \ + asio::native_ecat) +# define ASIO_SOCKET_ERROR(e) \ + asio::error_code(WSA ## e, \ + asio::native_ecat) +# define ASIO_NETDB_ERROR(e) \ + asio::error_code(WSA ## e, \ + asio::native_ecat) +# define ASIO_GETADDRINFO_ERROR(e) \ + asio::error_code(WSA ## e, \ + asio::native_ecat) +# define ASIO_MISC_ERROR(e) \ + asio::error_code(e, \ + asio::misc_ecat) +# define ASIO_WIN_OR_POSIX(e_win, e_posix) e_win #else -# define ASIO_SOCKET_ERROR(e) e -# define ASIO_NETDB_ERROR(e) 16384 + e -# define ASIO_GETADDRINFO_ERROR(e) 32768 + e -# define ASIO_OS_ERROR(e_win, e_posix) e_posix +# define ASIO_NATIVE_ERROR(e) \ + asio::error_code(e, \ + asio::native_ecat) +# define ASIO_SOCKET_ERROR(e) \ + asio::error_code(e, \ + asio::native_ecat) +# define ASIO_NETDB_ERROR(e) \ + asio::error_code(e, \ + asio::netdb_ecat) +# define ASIO_GETADDRINFO_ERROR(e) \ + asio::error_code(e, \ + asio::addrinfo_ecat) +# define ASIO_MISC_ERROR(e) \ + asio::error_code(e, \ + asio::misc_ecat) +# define ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix #endif -/// The error class is used to encapsulate system error codes. -class error - : public std::exception +namespace asio { + +namespace detail { + +/// Hack to keep asio library header-file-only. +template +class error_base { public: - /// Error codes. - enum code_type - { - /// Permission denied. - access_denied = ASIO_SOCKET_ERROR(EACCES), + // boostify: error category declarations go here. - /// Address family not supported by protocol. - address_family_not_supported = ASIO_SOCKET_ERROR(EAFNOSUPPORT), + /// Permission denied. + static const asio::error_code access_denied; - /// Address already in use. - address_in_use = ASIO_SOCKET_ERROR(EADDRINUSE), + /// Address family not supported by protocol. + static const asio::error_code address_family_not_supported; - /// Transport endpoint is already connected. - already_connected = ASIO_SOCKET_ERROR(EISCONN), + /// Address already in use. + static const asio::error_code address_in_use; - /// Operation already in progress. - already_started = ASIO_SOCKET_ERROR(EALREADY), + /// Transport endpoint is already connected. + static const asio::error_code already_connected; - /// A connection has been aborted. - connection_aborted = ASIO_SOCKET_ERROR(ECONNABORTED), + /// Already open. + static const asio::error_code already_open; - /// Connection refused. - connection_refused = ASIO_SOCKET_ERROR(ECONNREFUSED), + /// Operation already in progress. + static const asio::error_code already_started; - /// Connection reset by peer. - connection_reset = ASIO_SOCKET_ERROR(ECONNRESET), + /// A connection has been aborted. + static const asio::error_code connection_aborted; - /// Bad file descriptor. - bad_descriptor = ASIO_SOCKET_ERROR(EBADF), + /// Connection refused. + static const asio::error_code connection_refused; - /// End of file or stream. - eof = ASIO_OS_ERROR(ERROR_HANDLE_EOF, -1), + /// Connection reset by peer. + static const asio::error_code connection_reset; - /// Bad address. - fault = ASIO_SOCKET_ERROR(EFAULT), + /// Bad file descriptor. + static const asio::error_code bad_descriptor; - /// Host not found (authoritative). - host_not_found = ASIO_NETDB_ERROR(HOST_NOT_FOUND), + /// End of file or stream. + static const asio::error_code eof; - /// Host not found (non-authoritative). - host_not_found_try_again = ASIO_NETDB_ERROR(TRY_AGAIN), + /// Bad address. + static const asio::error_code fault; - /// No route to host. - host_unreachable = ASIO_SOCKET_ERROR(EHOSTUNREACH), + /// Host not found (authoritative). + static const asio::error_code host_not_found; - /// Operation now in progress. - in_progress = ASIO_SOCKET_ERROR(EINPROGRESS), + /// Host not found (non-authoritative). + static const asio::error_code host_not_found_try_again; - /// Interrupted system call. - interrupted = ASIO_SOCKET_ERROR(EINTR), + /// No route to host. + static const asio::error_code host_unreachable; - /// Invalid argument. - invalid_argument = ASIO_SOCKET_ERROR(EINVAL), + /// Operation now in progress. + static const asio::error_code in_progress; - /// Message too long. - message_size = ASIO_SOCKET_ERROR(EMSGSIZE), + /// Interrupted system call. + static const asio::error_code interrupted; - /// Network is down. - network_down = ASIO_SOCKET_ERROR(ENETDOWN), + /// Invalid argument. + static const asio::error_code invalid_argument; - /// Network dropped connection on reset. - network_reset = ASIO_SOCKET_ERROR(ENETRESET), + /// Message too long. + static const asio::error_code message_size; - /// Network is unreachable. - network_unreachable = ASIO_SOCKET_ERROR(ENETUNREACH), + /// Network is down. + static const asio::error_code network_down; - /// Too many open files. - no_descriptors = ASIO_SOCKET_ERROR(EMFILE), + /// Network dropped connection on reset. + static const asio::error_code network_reset; - /// No buffer space available. - no_buffer_space = ASIO_SOCKET_ERROR(ENOBUFS), + /// Network is unreachable. + static const asio::error_code network_unreachable; - /// The query is valid but does not have associated address data. - no_data = ASIO_NETDB_ERROR(NO_DATA), + /// Too many open files. + static const asio::error_code no_descriptors; - /// Cannot allocate memory. - no_memory = ASIO_OS_ERROR(ERROR_OUTOFMEMORY, ENOMEM), + /// No buffer space available. + static const asio::error_code no_buffer_space; - /// Operation not permitted. - no_permission = ASIO_OS_ERROR(ERROR_ACCESS_DENIED, EPERM), + /// The query is valid but does not have associated address data. + static const asio::error_code no_data; - /// Protocol not available. - no_protocol_option = ASIO_SOCKET_ERROR(ENOPROTOOPT), + /// Cannot allocate memory. + static const asio::error_code no_memory; - /// A non-recoverable error occurred. - no_recovery = ASIO_NETDB_ERROR(NO_RECOVERY), + /// Operation not permitted. + static const asio::error_code no_permission; - /// Transport endpoint is not connected. - not_connected = ASIO_SOCKET_ERROR(ENOTCONN), + /// Protocol not available. + static const asio::error_code no_protocol_option; - /// Socket operation on non-socket. - not_socket = ASIO_SOCKET_ERROR(ENOTSOCK), + /// A non-recoverable error occurred. + static const asio::error_code no_recovery; - /// Operation not supported. - not_supported = ASIO_SOCKET_ERROR(EOPNOTSUPP), + /// Transport endpoint is not connected. + static const asio::error_code not_connected; - /// Operation cancelled. - operation_aborted = ASIO_OS_ERROR(ERROR_OPERATION_ABORTED, ECANCELED), + /// Element not found. + static const asio::error_code not_found; - /// The service is not supported for the given socket type. - service_not_found = ASIO_OS_ERROR( - WSATYPE_NOT_FOUND, - ASIO_GETADDRINFO_ERROR(EAI_SERVICE)), + /// Socket operation on non-socket. + static const asio::error_code not_socket; - /// The socket type is not supported. - socket_type_not_supported = ASIO_OS_ERROR( - WSAESOCKTNOSUPPORT, - ASIO_GETADDRINFO_ERROR(EAI_SOCKTYPE)), + /// Operation cancelled. + static const asio::error_code operation_aborted; - /// Cannot send after transport endpoint shutdown. - shut_down = ASIO_SOCKET_ERROR(ESHUTDOWN), + /// Operation not supported. + static const asio::error_code operation_not_supported; - /// Success. - success = 0, + /// The service is not supported for the given socket type. + static const asio::error_code service_not_found; - /// Connection timed out. - timed_out = ASIO_SOCKET_ERROR(ETIMEDOUT), + /// The socket type is not supported. + static const asio::error_code socket_type_not_supported; - /// Resource temporarily unavailable. - try_again = ASIO_OS_ERROR(ERROR_RETRY, EAGAIN), + /// Cannot send after transport endpoint shutdown. + static const asio::error_code shut_down; - /// The socket is marked non-blocking and the requested operation would - /// block. - would_block = ASIO_SOCKET_ERROR(EWOULDBLOCK) - }; + /// Connection timed out. + static const asio::error_code timed_out; - /// Default constructor. - error() - : code_(success) - { - } + /// Resource temporarily unavailable. + static const asio::error_code try_again; - /// Construct with a specific error code. - error(int code) - : code_(code) - { - } - - /// Copy constructor. - error(const error& e) - : std::exception(e), - code_(e.code_) - { - } - - /// Destructor. - virtual ~error() throw () - { - } - - /// Assignment operator. - error& operator=(const error& e) - { - code_ = e.code_; - what_.reset(); - return *this; - } - - /// Get a string representation of the exception. - virtual const char* what() const throw () - { -#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - try - { - if (!what_) - { - char* msg = 0; - DWORD length = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_FROM_SYSTEM - | FORMAT_MESSAGE_IGNORE_INSERTS, 0, code_, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msg, 0, 0); - detail::win_local_free_on_block_exit local_free_obj(msg); - if (length && msg[length - 1] == '\n') - msg[--length] = '\0'; - if (length && msg[length - 1] == '\r') - msg[--length] = '\0'; - if (length) - what_.reset(new std::string(msg)); - else - return "asio error"; - } - return what_->c_str(); - } - catch (std::exception&) - { - return "asio error"; - } -#else // defined(BOOST_WINDOWS) - switch (code_) - { - case error::eof: - return "End of file."; - case error::host_not_found: - return "Host not found (authoritative)."; - case error::host_not_found_try_again: - return "Host not found (non-authoritative), try again later."; - case error::no_recovery: - return "A non-recoverable error occurred during database lookup."; - case error::no_data: - return "The query is valid, but it does not have associated data."; -#if !defined(__sun) - case error::operation_aborted: - return "Operation aborted."; -#endif // !defined(__sun) - case error::service_not_found: - return "Service not found."; - case error::socket_type_not_supported: - return "Socket type not supported."; - default: -#if defined(__sun) || defined(__QNX__) - return strerror(code_); -#elif defined(__MACH__) && defined(__APPLE__) \ - || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) - try - { - char buf[256] = ""; - strerror_r(code_, buf, sizeof(buf)); - what_.reset(new std::string(buf)); - return what_->c_str(); - } - catch (std::exception&) - { - return "asio error"; - } -#else - try - { - char buf[256] = ""; - what_.reset(new std::string(strerror_r(code_, buf, sizeof(buf)))); - return what_->c_str(); - } - catch (std::exception&) - { - return "asio error"; - } -#endif - } -#endif // defined(BOOST_WINDOWS) - } - - /// Get the code associated with the error. - int code() const - { - return code_; - } - - struct unspecified_bool_type_t - { - }; - - typedef unspecified_bool_type_t* unspecified_bool_type; - - /// Operator returns non-null if there is a non-success error code. - operator unspecified_bool_type() const - { - if (code_ == success) - return 0; - else - return reinterpret_cast(1); - } - - /// Operator to test if the error represents success. - bool operator!() const - { - return code_ == success; - } - - /// Equality operator to compare two error objects. - friend bool operator==(const error& e1, const error& e2) - { - return e1.code_ == e2.code_; - } - - /// Inequality operator to compare two error objects. - friend bool operator!=(const error& e1, const error& e2) - { - return e1.code_ != e2.code_; - } + /// The socket is marked non-blocking and the requested operation would block. + static const asio::error_code would_block; private: - // The code associated with the error. - int code_; - - // The string representation of the error. - mutable boost::scoped_ptr what_; + error_base(); }; -/// Output the string associated with an error. -/** - * Used to output a human-readable string that is associated with an error. - * - * @param os The output stream to which the string will be written. - * - * @param e The error to be written. - * - * @return The output stream. - * - * @relates asio::error - */ -#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -std::ostream& operator<<(std::ostream& os, const error& e) +// boostify: error category definitions go here. + +template const asio::error_code +error_base::access_denied = ASIO_SOCKET_ERROR(EACCES); + +template const asio::error_code +error_base::address_family_not_supported = ASIO_SOCKET_ERROR( + EAFNOSUPPORT); + +template const asio::error_code +error_base::address_in_use = ASIO_SOCKET_ERROR(EADDRINUSE); + +template const asio::error_code +error_base::already_connected = ASIO_SOCKET_ERROR(EISCONN); + +template const asio::error_code +error_base::already_open = ASIO_MISC_ERROR(1); + +template const asio::error_code +error_base::already_started = ASIO_SOCKET_ERROR(EALREADY); + +template const asio::error_code +error_base::connection_aborted = ASIO_SOCKET_ERROR(ECONNABORTED); + +template const asio::error_code +error_base::connection_refused = ASIO_SOCKET_ERROR(ECONNREFUSED); + +template const asio::error_code +error_base::connection_reset = ASIO_SOCKET_ERROR(ECONNRESET); + +template const asio::error_code +error_base::bad_descriptor = ASIO_SOCKET_ERROR(EBADF); + +template const asio::error_code +error_base::eof = ASIO_MISC_ERROR(2); + +template const asio::error_code +error_base::fault = ASIO_SOCKET_ERROR(EFAULT); + +template const asio::error_code +error_base::host_not_found = ASIO_NETDB_ERROR(HOST_NOT_FOUND); + +template const asio::error_code +error_base::host_not_found_try_again = ASIO_NETDB_ERROR(TRY_AGAIN); + +template const asio::error_code +error_base::host_unreachable = ASIO_SOCKET_ERROR(EHOSTUNREACH); + +template const asio::error_code +error_base::in_progress = ASIO_SOCKET_ERROR(EINPROGRESS); + +template const asio::error_code +error_base::interrupted = ASIO_SOCKET_ERROR(EINTR); + +template const asio::error_code +error_base::invalid_argument = ASIO_SOCKET_ERROR(EINVAL); + +template const asio::error_code +error_base::message_size = ASIO_SOCKET_ERROR(EMSGSIZE); + +template const asio::error_code +error_base::network_down = ASIO_SOCKET_ERROR(ENETDOWN); + +template const asio::error_code +error_base::network_reset = ASIO_SOCKET_ERROR(ENETRESET); + +template const asio::error_code +error_base::network_unreachable = ASIO_SOCKET_ERROR(ENETUNREACH); + +template const asio::error_code +error_base::no_descriptors = ASIO_SOCKET_ERROR(EMFILE); + +template const asio::error_code +error_base::no_buffer_space = ASIO_SOCKET_ERROR(ENOBUFS); + +template const asio::error_code +error_base::no_data = ASIO_NETDB_ERROR(NO_DATA); + +template const asio::error_code +error_base::no_memory = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(ERROR_OUTOFMEMORY), + ASIO_NATIVE_ERROR(ENOMEM)); + +template const asio::error_code +error_base::no_permission = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(ERROR_ACCESS_DENIED), + ASIO_NATIVE_ERROR(EPERM)); + +template const asio::error_code +error_base::no_protocol_option = ASIO_SOCKET_ERROR(ENOPROTOOPT); + +template const asio::error_code +error_base::no_recovery = ASIO_NETDB_ERROR(NO_RECOVERY); + +template const asio::error_code +error_base::not_connected = ASIO_SOCKET_ERROR(ENOTCONN); + +template const asio::error_code +error_base::not_found = ASIO_MISC_ERROR(3); + +template const asio::error_code +error_base::not_socket = ASIO_SOCKET_ERROR(ENOTSOCK); + +template const asio::error_code +error_base::operation_aborted = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(ERROR_OPERATION_ABORTED), + ASIO_NATIVE_ERROR(ECANCELED)); + +template const asio::error_code +error_base::operation_not_supported = ASIO_SOCKET_ERROR(EOPNOTSUPP); + +template const asio::error_code +error_base::service_not_found = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(WSATYPE_NOT_FOUND), + ASIO_GETADDRINFO_ERROR(EAI_SERVICE)); + +template const asio::error_code +error_base::socket_type_not_supported = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(WSAESOCKTNOSUPPORT), + ASIO_GETADDRINFO_ERROR(EAI_SOCKTYPE)); + +template const asio::error_code +error_base::shut_down = ASIO_SOCKET_ERROR(ESHUTDOWN); + +template const asio::error_code +error_base::timed_out = ASIO_SOCKET_ERROR(ETIMEDOUT); + +template const asio::error_code +error_base::try_again = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(ERROR_RETRY), + ASIO_NATIVE_ERROR(EAGAIN)); + +template const asio::error_code +error_base::would_block = ASIO_SOCKET_ERROR(EWOULDBLOCK); + +} // namespace detail + +/// Contains error constants. +class error : public asio::detail::error_base { - os << e.what(); - return os; -} -#else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -template -Ostream& operator<<(Ostream& os, const error& e) -{ - os << e.what(); - return os; -} -#endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +private: + error(); +}; } // namespace asio +#undef ASIO_NATIVE_ERROR #undef ASIO_SOCKET_ERROR #undef ASIO_NETDB_ERROR #undef ASIO_GETADDRINFO_ERROR -#undef ASIO_OS_ERROR +#undef ASIO_MISC_ERROR +#undef ASIO_WIN_OR_POSIX + +#include "asio/impl/error_code.ipp" #include "asio/detail/pop_options.hpp" diff --git a/libtorrent/include/libtorrent/asio/error_code.hpp b/libtorrent/include/libtorrent/asio/error_code.hpp new file mode 100644 index 000000000..0614490e2 --- /dev/null +++ b/libtorrent/include/libtorrent/asio/error_code.hpp @@ -0,0 +1,139 @@ +// +// error_code.hpp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_ERROR_CODE_HPP +#define ASIO_ERROR_CODE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +#include "asio/detail/push_options.hpp" +#include +#include +#include "asio/detail/pop_options.hpp" + +#if defined(GENERATING_DOCUMENTATION) +# define ASIO_WIN_OR_POSIX(e_win, e_posix) implementation_defined +#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) +# define ASIO_WIN_OR_POSIX(e_win, e_posix) e_win +#else +# define ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix +#endif + +namespace asio { + +/// Available error code categories. +enum error_category +{ + /// Native error codes. + native_ecat = ASIO_WIN_OR_POSIX(0, 0), + + /// Error codes from NetDB functions. + netdb_ecat = ASIO_WIN_OR_POSIX(native_ecat, 1), + + /// Error codes from getaddrinfo. + addrinfo_ecat = ASIO_WIN_OR_POSIX(native_ecat, 2), + + /// Miscellaneous error codes. + misc_ecat = ASIO_WIN_OR_POSIX(3, 3), + + /// SSL error codes. + ssl_ecat = ASIO_WIN_OR_POSIX(4, 4) +}; + +/// Class to represent an error code value. +class error_code +{ +public: + /// The underlying representation of an error code. + typedef int value_type; + + /// Default constructor. + error_code() + : value_(0), + category_(native_ecat) + { + } + + /// Construct with specific error code and category. + error_code(value_type v, error_category c) + : value_(v), + category_(c) + { + } + + /// Get the error value. + value_type value() const + { + return value_; + } + + /// Get the error category. + error_category category() const + { + return category_; + } + + /// Get the message associated with the error. + std::string message() const; + + struct unspecified_bool_type_t + { + }; + + typedef unspecified_bool_type_t* unspecified_bool_type; + + /// Operator returns non-null if there is a non-success error code. + operator unspecified_bool_type() const + { + if (value_ == 0) + return 0; + else + return reinterpret_cast(1); + } + + /// Operator to test if the error represents success. + bool operator!() const + { + return value_ == 0; + } + + /// Equality operator to compare two error objects. + friend bool operator==(const error_code& e1, const error_code& e2) + { + return e1.value_ == e2.value_ && e1.category_ == e2.category_; + } + + /// Inequality operator to compare two error objects. + friend bool operator!=(const error_code& e1, const error_code& e2) + { + return e1.value_ != e2.value_ || e1.category_ != e2.category_; + } + +private: + // The value associated with the error code. + value_type value_; + + // The category associated with the error code. + error_category category_; +}; + +} // namespace asio + +#undef ASIO_WIN_OR_POSIX + +#include "asio/error.hpp" + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_ERROR_CODE_HPP diff --git a/libtorrent/include/libtorrent/asio/handler_alloc_hook.hpp b/libtorrent/include/libtorrent/asio/handler_alloc_hook.hpp index d15c85061..042b1fecd 100644 --- a/libtorrent/include/libtorrent/asio/handler_alloc_hook.hpp +++ b/libtorrent/include/libtorrent/asio/handler_alloc_hook.hpp @@ -2,7 +2,7 @@ // handler_alloc_hook.hpp // ~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -42,7 +42,7 @@ namespace asio { * before the upcall to the handler is performed. This allows the same memory to * be reused for a subsequent asynchronous operation initiated by the handler. * - * @par Example: + * @par Example * @code * class my_handler; * @@ -78,7 +78,7 @@ inline void* asio_handler_allocate(std::size_t size, ...) inline void asio_handler_deallocate(void* pointer, std::size_t size, ...) { (void)(size); - return ::operator delete(pointer); + ::operator delete(pointer); } } // namespace asio diff --git a/libtorrent/include/libtorrent/asio/handler_invoke_hook.hpp b/libtorrent/include/libtorrent/asio/handler_invoke_hook.hpp index 124b76e20..4ba5db329 100644 --- a/libtorrent/include/libtorrent/asio/handler_invoke_hook.hpp +++ b/libtorrent/include/libtorrent/asio/handler_invoke_hook.hpp @@ -2,7 +2,7 @@ // handler_invoke_hook.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -45,7 +45,7 @@ namespace asio { * function(); * @endcode * - * @par Example: + * @par Example * @code * class my_handler; * diff --git a/libtorrent/include/libtorrent/asio/impl/error_code.ipp b/libtorrent/include/libtorrent/asio/impl/error_code.ipp new file mode 100644 index 000000000..da2f98833 --- /dev/null +++ b/libtorrent/include/libtorrent/asio/impl/error_code.ipp @@ -0,0 +1,98 @@ +// +// error_code.ipp +// ~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_ERROR_CODE_IPP +#define ASIO_ERROR_CODE_IPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +#include "asio/detail/push_options.hpp" +#include +#include +#include +#include "asio/detail/pop_options.hpp" + +#include "asio/error.hpp" +#include "asio/detail/local_free_on_block_exit.hpp" +#include "asio/detail/socket_types.hpp" + +namespace asio { + +inline std::string error_code::message() const +{ + if (*this == error::already_open) + return "Already open."; + if (*this == error::not_found) + return "Not found."; + if (category_ == ssl_ecat) + return "SSL error."; +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) + value_type value = value_; + if (*this == error::eof) + value = ERROR_HANDLE_EOF; + char* msg = 0; + DWORD length = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, 0, value, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msg, 0, 0); + detail::local_free_on_block_exit local_free_obj(msg); + if (length && msg[length - 1] == '\n') + msg[--length] = '\0'; + if (length && msg[length - 1] == '\r') + msg[--length] = '\0'; + if (length) + return msg; + else + return "asio error"; +#else // defined(BOOST_WINDOWS) + if (*this == error::eof) + return "End of file."; + if (*this == error::host_not_found) + return "Host not found (authoritative)."; + if (*this == error::host_not_found_try_again) + return "Host not found (non-authoritative), try again later."; + if (*this == error::no_recovery) + return "A non-recoverable error occurred during database lookup."; + if (*this == error::no_data) + return "The query is valid, but it does not have associated data."; + if (*this == error::not_found) + return "Element not found."; +#if !defined(__sun) + if (*this == error::operation_aborted) + return "Operation aborted."; +#endif // !defined(__sun) + if (*this == error::service_not_found) + return "Service not found."; + if (*this == error::socket_type_not_supported) + return "Socket type not supported."; +#if defined(__sun) || defined(__QNX__) + return strerror(value_); +#elif defined(__MACH__) && defined(__APPLE__) \ +|| defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) \ +|| defined(_AIX) + char buf[256] = ""; + strerror_r(value_, buf, sizeof(buf)); + return buf; +#else + char buf[256] = ""; + return strerror_r(value_, buf, sizeof(buf)); +#endif +#endif // defined(BOOST_WINDOWS) +} + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_ERROR_CODE_IPP diff --git a/libtorrent/include/libtorrent/asio/impl/io_service.ipp b/libtorrent/include/libtorrent/asio/impl/io_service.ipp index 5e017831b..e973619d1 100644 --- a/libtorrent/include/libtorrent/asio/impl/io_service.ipp +++ b/libtorrent/include/libtorrent/asio/impl/io_service.ipp @@ -2,7 +2,7 @@ // io_service.ipp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -17,43 +17,94 @@ #include "asio/detail/push_options.hpp" +#include "asio/detail/push_options.hpp" +#include +#include "asio/detail/pop_options.hpp" + #include "asio/detail/epoll_reactor.hpp" #include "asio/detail/kqueue_reactor.hpp" #include "asio/detail/select_reactor.hpp" +#include "asio/detail/service_registry.hpp" #include "asio/detail/task_io_service.hpp" +#include "asio/detail/throw_error.hpp" #include "asio/detail/win_iocp_io_service.hpp" namespace asio { inline io_service::io_service() - : service_registry_(*this), - impl_(service_registry_.use_service()) + : service_registry_(new asio::detail::service_registry(*this)), + impl_(service_registry_->use_service()) { + impl_.init((std::numeric_limits::max)()); } -inline size_t io_service::run() +inline io_service::io_service(std::size_t concurrency_hint) + : service_registry_(new asio::detail::service_registry(*this)), + impl_(service_registry_->use_service()) { - return impl_.run(); + impl_.init(concurrency_hint); } -inline size_t io_service::run_one() +inline io_service::~io_service() { - return impl_.run_one(); + delete service_registry_; } -inline size_t io_service::poll() +inline std::size_t io_service::run() { - return impl_.poll(); + asio::error_code ec; + std::size_t s = impl_.run(ec); + asio::detail::throw_error(ec); + return s; } -inline size_t io_service::poll_one() +inline std::size_t io_service::run(asio::error_code& ec) { - return impl_.poll_one(); + return impl_.run(ec); } -inline void io_service::interrupt() +inline std::size_t io_service::run_one() { - impl_.interrupt(); + asio::error_code ec; + std::size_t s = impl_.run_one(ec); + asio::detail::throw_error(ec); + return s; +} + +inline std::size_t io_service::run_one(asio::error_code& ec) +{ + return impl_.run_one(ec); +} + +inline std::size_t io_service::poll() +{ + asio::error_code ec; + std::size_t s = impl_.poll(ec); + asio::detail::throw_error(ec); + return s; +} + +inline std::size_t io_service::poll(asio::error_code& ec) +{ + return impl_.poll(ec); +} + +inline std::size_t io_service::poll_one() +{ + asio::error_code ec; + std::size_t s = impl_.poll_one(ec); + asio::detail::throw_error(ec); + return s; +} + +inline std::size_t io_service::poll_one(asio::error_code& ec) +{ + return impl_.poll_one(ec); +} + +inline void io_service::stop() +{ + impl_.stop(); } inline void io_service::reset() @@ -125,22 +176,34 @@ inline asio::io_service& io_service::service::io_service() template inline Service& use_service(io_service& ios) { - return ios.service_registry_.template use_service(); + // Check that Service meets the necessary type requirements. + (void)static_cast(static_cast(0)); + (void)static_cast(&Service::id); + + return ios.service_registry_->template use_service(); } template void add_service(io_service& ios, Service* svc) { + // Check that Service meets the necessary type requirements. + (void)static_cast(static_cast(0)); + (void)static_cast(&Service::id); + if (&ios != &svc->io_service()) boost::throw_exception(invalid_service_owner()); - if (!ios.service_registry_.template add_service(svc)) + if (!ios.service_registry_->template add_service(svc)) boost::throw_exception(service_already_exists()); } template bool has_service(io_service& ios) { - return ios.service_registry_.template has_service(); + // Check that Service meets the necessary type requirements. + (void)static_cast(static_cast(0)); + (void)static_cast(&Service::id); + + return ios.service_registry_->template has_service(); } } // namespace asio diff --git a/libtorrent/include/libtorrent/asio/impl/read.ipp b/libtorrent/include/libtorrent/asio/impl/read.ipp index dece26985..f30f50fb0 100644 --- a/libtorrent/include/libtorrent/asio/impl/read.ipp +++ b/libtorrent/include/libtorrent/asio/impl/read.ipp @@ -2,7 +2,7 @@ // read.ipp // ~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -17,102 +17,115 @@ #include "asio/detail/push_options.hpp" +#include "asio/detail/push_options.hpp" +#include +#include "asio/detail/pop_options.hpp" + #include "asio/buffer.hpp" #include "asio/completion_condition.hpp" -#include "asio/error_handler.hpp" +#include "asio/error.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/consuming_buffers.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/throw_error.hpp" namespace asio { -template -std::size_t read(Sync_Read_Stream& s, const Mutable_Buffers& buffers, - Completion_Condition completion_condition, Error_Handler error_handler) +template +std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, asio::error_code& ec) { asio::detail::consuming_buffers< - mutable_buffer, Mutable_Buffers> tmp(buffers); + mutable_buffer, MutableBufferSequence> tmp(buffers); std::size_t total_transferred = 0; while (tmp.begin() != tmp.end()) { - typename Sync_Read_Stream::error_type e; - std::size_t bytes_transferred = s.read_some(tmp, assign_error(e)); + std::size_t bytes_transferred = s.read_some(tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; - if (completion_condition(e, total_transferred)) - { - error_handler(e); + if (completion_condition(ec, total_transferred)) return total_transferred; - } } - typename Sync_Read_Stream::error_type e; - error_handler(e); + ec = asio::error_code(); return total_transferred; } -template -inline std::size_t read(Sync_Read_Stream& s, const Mutable_Buffers& buffers) +template +inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers) { - return read(s, buffers, transfer_all(), throw_error()); + asio::error_code ec; + std::size_t bytes_transferred = read(s, buffers, transfer_all(), ec); + asio::detail::throw_error(ec); + return bytes_transferred; } -template -inline std::size_t read(Sync_Read_Stream& s, const Mutable_Buffers& buffers, - Completion_Condition completion_condition) +template +inline std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + CompletionCondition completion_condition) { - return read(s, buffers, completion_condition, throw_error()); + asio::error_code ec; + std::size_t bytes_transferred = read(s, buffers, completion_condition, ec); + asio::detail::throw_error(ec); + return bytes_transferred; } -template -std::size_t read(Sync_Read_Stream& s, +template +std::size_t read(SyncReadStream& s, asio::basic_streambuf& b, - Completion_Condition completion_condition, Error_Handler error_handler) + CompletionCondition completion_condition, asio::error_code& ec) { std::size_t total_transferred = 0; for (;;) { - typename Sync_Read_Stream::error_type e; - std::size_t bytes_transferred = s.read_some( - b.prepare(512), assign_error(e)); + 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 (completion_condition(e, total_transferred)) - { - error_handler(e); + if (b.size() == b.max_size() + || completion_condition(ec, total_transferred)) return total_transferred; - } } } -template -inline std::size_t read(Sync_Read_Stream& s, +template +inline std::size_t read(SyncReadStream& s, asio::basic_streambuf& b) { - return read(s, b, transfer_all(), throw_error()); + asio::error_code ec; + std::size_t bytes_transferred = read(s, b, transfer_all(), ec); + asio::detail::throw_error(ec); + return bytes_transferred; } -template -inline std::size_t read(Sync_Read_Stream& s, +template +inline std::size_t read(SyncReadStream& s, asio::basic_streambuf& b, - Completion_Condition completion_condition) + CompletionCondition completion_condition) { - return read(s, b, completion_condition, throw_error()); + asio::error_code ec; + std::size_t bytes_transferred = read(s, b, completion_condition, ec); + asio::detail::throw_error(ec); + return bytes_transferred; } namespace detail { - template + template class read_handler { public: - read_handler(Async_Read_Stream& stream, const Mutable_Buffers& buffers, - Completion_Condition completion_condition, Handler handler) + typedef asio::detail::consuming_buffers< + mutable_buffer, MutableBufferSequence> buffers_type; + + read_handler(AsyncReadStream& stream, const buffers_type& buffers, + CompletionCondition completion_condition, ReadHandler handler) : stream_(stream), buffers_(buffers), total_transferred_(0), @@ -121,15 +134,15 @@ namespace detail { } - void operator()(const typename Async_Read_Stream::error_type& e, + void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); - if (completion_condition_(e, total_transferred_) + if (completion_condition_(ec, total_transferred_) || buffers_.begin() == buffers_.end()) { - handler_(e, total_transferred_); + handler_(ec, total_transferred_); } else { @@ -138,74 +151,76 @@ namespace detail } //private: - Async_Read_Stream& stream_; - asio::detail::consuming_buffers< - mutable_buffer, Mutable_Buffers> buffers_; + AsyncReadStream& stream_; + buffers_type buffers_; std::size_t total_transferred_; - Completion_Condition completion_condition_; - Handler handler_; + CompletionCondition completion_condition_; + ReadHandler handler_; }; - template + template inline void* asio_handler_allocate(std::size_t size, - read_handler* this_handler) + read_handler* this_handler) { return asio_handler_alloc_helpers::allocate( size, &this_handler->handler_); } - template + template inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_handler* this_handler) + read_handler* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, &this_handler->handler_); } - template + template inline void asio_handler_invoke(const Function& function, - read_handler* this_handler) + read_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, &this_handler->handler_); } } // namespace detail -template -inline void async_read(Async_Read_Stream& s, const Mutable_Buffers& buffers, - Completion_Condition completion_condition, Handler handler) +template +inline void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, ReadHandler handler) { - s.async_read_some(buffers, - detail::read_handler( - s, buffers, completion_condition, handler)); + asio::detail::consuming_buffers< + mutable_buffer, MutableBufferSequence> tmp(buffers); + s.async_read_some(tmp, + detail::read_handler( + s, tmp, completion_condition, handler)); } -template -inline void async_read(Async_Read_Stream& s, const Mutable_Buffers& buffers, - Handler handler) +template +inline void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, + ReadHandler handler) { async_read(s, buffers, transfer_all(), handler); } namespace detail { - template + template class read_streambuf_handler { public: - read_streambuf_handler(Async_Read_Stream& stream, + read_streambuf_handler(AsyncReadStream& stream, basic_streambuf& streambuf, - Completion_Condition completion_condition, Handler handler) + CompletionCondition completion_condition, ReadHandler handler) : stream_(stream), streambuf_(streambuf), total_transferred_(0), @@ -214,75 +229,80 @@ namespace detail { } - void operator()(const typename Async_Read_Stream::error_type& e, + void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { total_transferred_ += bytes_transferred; streambuf_.commit(bytes_transferred); - if (completion_condition_(e, total_transferred_)) + if (streambuf_.size() == streambuf_.max_size() + || completion_condition_(ec, total_transferred_)) { - handler_(e, total_transferred_); + handler_(ec, total_transferred_); } else { - stream_.async_read_some(streambuf_.prepare(512), *this); + std::size_t bytes_available = + std::min(512, streambuf_.max_size() - streambuf_.size()); + stream_.async_read_some(streambuf_.prepare(bytes_available), *this); } } //private: - Async_Read_Stream& stream_; + AsyncReadStream& stream_; asio::basic_streambuf& streambuf_; std::size_t total_transferred_; - Completion_Condition completion_condition_; - Handler handler_; + CompletionCondition completion_condition_; + ReadHandler handler_; }; - template + template inline void* asio_handler_allocate(std::size_t size, - read_streambuf_handler* this_handler) + read_streambuf_handler* this_handler) { return asio_handler_alloc_helpers::allocate( size, &this_handler->handler_); } - template + template inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_streambuf_handler* this_handler) + read_streambuf_handler* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, &this_handler->handler_); } - template + template inline void asio_handler_invoke(const Function& function, - read_streambuf_handler* this_handler) + read_streambuf_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, &this_handler->handler_); } } // namespace detail -template -inline void async_read(Async_Read_Stream& s, +template +inline void async_read(AsyncReadStream& s, asio::basic_streambuf& b, - Completion_Condition completion_condition, Handler handler) + CompletionCondition completion_condition, ReadHandler handler) { - s.async_read_some(b.prepare(512), - detail::read_streambuf_handler( + std::size_t bytes_available = + std::min(512, b.max_size() - b.size()); + s.async_read_some(b.prepare(bytes_available), + detail::read_streambuf_handler( s, b, completion_condition, handler)); } -template -inline void async_read(Async_Read_Stream& s, - asio::basic_streambuf& b, Handler handler) +template +inline void async_read(AsyncReadStream& s, + asio::basic_streambuf& b, ReadHandler handler) { async_read(s, b, transfer_all(), handler); } diff --git a/libtorrent/include/libtorrent/asio/impl/read_until.ipp b/libtorrent/include/libtorrent/asio/impl/read_until.ipp index accb8d955..64c15ec7d 100644 --- a/libtorrent/include/libtorrent/asio/impl/read_until.ipp +++ b/libtorrent/include/libtorrent/asio/impl/read_until.ipp @@ -2,7 +2,7 @@ // read_until.ipp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -25,25 +25,28 @@ #include "asio/detail/pop_options.hpp" #include "asio/buffer.hpp" -#include "asio/error_handler.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/const_buffers_iterator.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/throw_error.hpp" namespace asio { -template -inline std::size_t read_until(Sync_Read_Stream& s, +template +inline std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, char delim) { - return read_until(s, b, delim, throw_error()); + asio::error_code ec; + std::size_t bytes_transferred = read_until(s, b, delim, ec); + asio::detail::throw_error(ec); + return bytes_transferred; } -template -std::size_t read_until(Sync_Read_Stream& s, +template +std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, char delim, - Error_Handler error_handler) + asio::error_code& ec) { std::size_t next_search_start = 0; for (;;) @@ -62,6 +65,7 @@ std::size_t read_until(Sync_Read_Stream& s, if (iter != end) { // Found a match. We're done. + ec = asio::error_code(); return iter.position() + 1; } else @@ -70,22 +74,30 @@ std::size_t read_until(Sync_Read_Stream& s, next_search_start = end.position(); } - // Need more data. - typename Sync_Read_Stream::error_type error; - b.commit(s.read_some(b.prepare(512), asio::assign_error(error))); - if (error) + // Check if buffer is full. + if (b.size() == b.max_size()) { - error_handler(error); + ec = error::not_found; return 0; } + + // Need more data. + std::size_t bytes_available = + std::min(512, b.max_size() - b.size()); + b.commit(s.read_some(b.prepare(bytes_available), ec)); + if (ec) + return 0; } } -template -inline std::size_t read_until(Sync_Read_Stream& s, +template +inline std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, const std::string& delim) { - return read_until(s, b, delim, throw_error()); + asio::error_code ec; + std::size_t bytes_transferred = read_until(s, b, delim, ec); + asio::detail::throw_error(ec); + return bytes_transferred; } namespace detail @@ -123,10 +135,10 @@ namespace detail } } // namespace detail -template -std::size_t read_until(Sync_Read_Stream& s, +template +std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, const std::string& delim, - Error_Handler error_handler) + asio::error_code& ec) { std::size_t next_search_start = 0; for (;;) @@ -148,6 +160,7 @@ std::size_t read_until(Sync_Read_Stream& s, if (result.second) { // Full match. We're done. + ec = asio::error_code(); return result.first.position() + delim.length(); } else @@ -162,28 +175,36 @@ std::size_t read_until(Sync_Read_Stream& s, next_search_start = end.position(); } - // Need more data. - typename Sync_Read_Stream::error_type error; - b.commit(s.read_some(b.prepare(512), asio::assign_error(error))); - if (error) + // Check if buffer is full. + if (b.size() == b.max_size()) { - error_handler(error); + ec = error::not_found; return 0; } + + // Need more data. + std::size_t bytes_available = + std::min(512, b.max_size() - b.size()); + b.commit(s.read_some(b.prepare(bytes_available), ec)); + if (ec) + return 0; } } -template -inline std::size_t read_until(Sync_Read_Stream& s, +template +inline std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, const boost::regex& expr) { - return read_until(s, b, expr, throw_error()); + asio::error_code ec; + std::size_t bytes_transferred = read_until(s, b, expr, ec); + asio::detail::throw_error(ec); + return bytes_transferred; } -template -std::size_t read_until(Sync_Read_Stream& s, +template +std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, const boost::regex& expr, - Error_Handler error_handler) + asio::error_code& ec) { std::size_t next_search_start = 0; for (;;) @@ -205,6 +226,7 @@ std::size_t read_until(Sync_Read_Stream& s, if (match_results[0].matched) { // Full match. We're done. + ec = asio::error_code(); return match_results[0].second.position(); } else @@ -219,26 +241,31 @@ std::size_t read_until(Sync_Read_Stream& s, next_search_start = end.position(); } - // Need more data. - typename Sync_Read_Stream::error_type error; - b.commit(s.read_some(b.prepare(512), asio::assign_error(error))); - if (error) + // Check if buffer is full. + if (b.size() == b.max_size()) { - error_handler(error); + ec = error::not_found; return 0; } + + // Need more data. + std::size_t bytes_available = + std::min(512, b.max_size() - b.size()); + b.commit(s.read_some(b.prepare(bytes_available), ec)); + if (ec) + return 0; } } namespace detail { - template + template class read_until_delim_handler { public: - read_until_delim_handler(Async_Read_Stream& stream, + read_until_delim_handler(AsyncReadStream& stream, asio::basic_streambuf& streambuf, char delim, - std::size_t next_search_start, Handler handler) + std::size_t next_search_start, ReadHandler handler) : stream_(stream), streambuf_(streambuf), delim_(delim), @@ -247,14 +274,14 @@ namespace detail { } - void operator()(const typename Async_Read_Stream::error_type& e, + void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { // Check for errors. - if (e) + if (ec) { std::size_t bytes = 0; - handler_(e, bytes); + handler_(ec, bytes); return; } @@ -276,55 +303,67 @@ namespace detail { // Found a match. We're done. std::size_t bytes = iter.position() + 1; - handler_(e, bytes); + handler_(ec, bytes); return; } - // No match. Start a new asynchronous read operation to obtain more data. + // No match. Check if buffer is full. + if (streambuf_.size() == streambuf_.max_size()) + { + std::size_t bytes = 0; + handler_(error::not_found, bytes); + return; + } + + // Next search can start with the new data. next_search_start_ = end.position(); - stream_.async_read_some(streambuf_.prepare(512), *this); + + // Start a new asynchronous read operation to obtain more data. + std::size_t bytes_available = + std::min(512, streambuf_.max_size() - streambuf_.size()); + stream_.async_read_some(streambuf_.prepare(bytes_available), *this); } //private: - Async_Read_Stream& stream_; + AsyncReadStream& stream_; asio::basic_streambuf& streambuf_; char delim_; std::size_t next_search_start_; - Handler handler_; + ReadHandler handler_; }; - template + template inline void* asio_handler_allocate(std::size_t size, - read_until_delim_handler* this_handler) + read_until_delim_handler* this_handler) { return asio_handler_alloc_helpers::allocate( size, &this_handler->handler_); } - template + template inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_delim_handler* this_handler) + read_until_delim_handler* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, &this_handler->handler_); } - template + template inline void asio_handler_invoke(const Function& function, - read_until_delim_handler* this_handler) + read_until_delim_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, &this_handler->handler_); } } // namespace detail -template -void async_read_until(Async_Read_Stream& s, - asio::basic_streambuf& b, char delim, Handler handler) +template +void async_read_until(AsyncReadStream& s, + asio::basic_streambuf& b, char delim, ReadHandler handler) { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< @@ -340,28 +379,37 @@ void async_read_until(Async_Read_Stream& s, if (iter != end) { // Found a match. We're done. - typename Async_Read_Stream::error_type error; + asio::error_code ec; std::size_t bytes = iter.position() + 1; - s.io_service().post(detail::bind_handler(handler, error, bytes)); + s.io_service().post(detail::bind_handler(handler, ec, bytes)); return; } - // No match. Start a new asynchronous read operation to obtain more data. - s.async_read_some(b.prepare(512), - detail::read_until_delim_handler( + // No match. Check if buffer is full. + if (b.size() == b.max_size()) + { + s.io_service().post(detail::bind_handler(handler, error::not_found, 0)); + return; + } + + // Start a new asynchronous read operation to obtain more data. + std::size_t bytes_available = + std::min(512, b.max_size() - b.size()); + s.async_read_some(b.prepare(bytes_available), + detail::read_until_delim_handler( s, b, delim, end.position(), handler)); } namespace detail { - template + template class read_until_delim_string_handler { public: - read_until_delim_string_handler(Async_Read_Stream& stream, + read_until_delim_string_handler(AsyncReadStream& stream, asio::basic_streambuf& streambuf, const std::string& delim, std::size_t next_search_start, - Handler handler) + ReadHandler handler) : stream_(stream), streambuf_(streambuf), delim_(delim), @@ -370,14 +418,14 @@ namespace detail { } - void operator()(const typename Async_Read_Stream::error_type& e, + void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { // Check for errors. - if (e) + if (ec) { std::size_t bytes = 0; - handler_(e, bytes); + handler_(ec, bytes); return; } @@ -402,7 +450,7 @@ namespace detail { // Full match. We're done. std::size_t bytes = result.first.position() + delim_.length(); - handler_(e, bytes); + handler_(ec, bytes); return; } else @@ -417,51 +465,61 @@ namespace detail next_search_start_ = end.position(); } - // No match. Start a new asynchronous read operation to obtain more data. - stream_.async_read_some(streambuf_.prepare(512), *this); + // Check if buffer is full. + if (streambuf_.size() == streambuf_.max_size()) + { + std::size_t bytes = 0; + handler_(error::not_found, bytes); + return; + } + + // Start a new asynchronous read operation to obtain more data. + std::size_t bytes_available = + std::min(512, streambuf_.max_size() - streambuf_.size()); + stream_.async_read_some(streambuf_.prepare(bytes_available), *this); } //private: - Async_Read_Stream& stream_; + AsyncReadStream& stream_; asio::basic_streambuf& streambuf_; std::string delim_; std::size_t next_search_start_; - Handler handler_; + ReadHandler handler_; }; - template + template inline void* asio_handler_allocate(std::size_t size, - read_until_delim_string_handler* this_handler) + read_until_delim_string_handler* this_handler) { return asio_handler_alloc_helpers::allocate( size, &this_handler->handler_); } - template + template inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_delim_string_handler* this_handler) + read_until_delim_string_handler* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, &this_handler->handler_); } - template + template inline void asio_handler_invoke(const Function& function, - read_until_delim_string_handler* this_handler) + read_until_delim_string_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, &this_handler->handler_); } } // namespace detail -template -void async_read_until(Async_Read_Stream& s, +template +void async_read_until(AsyncReadStream& s, asio::basic_streambuf& b, const std::string& delim, - Handler handler) + ReadHandler handler) { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< @@ -481,9 +539,9 @@ void async_read_until(Async_Read_Stream& s, if (result.second) { // Full match. We're done. - typename Async_Read_Stream::error_type error; + asio::error_code ec; std::size_t bytes = result.first.position() + delim.length(); - s.io_service().post(detail::bind_handler(handler, error, bytes)); + s.io_service().post(detail::bind_handler(handler, ec, bytes)); return; } else @@ -498,23 +556,32 @@ void async_read_until(Async_Read_Stream& s, next_search_start = end.position(); } - // No match. Start a new asynchronous read operation to obtain more data. - s.async_read_some(b.prepare(512), + // Check if buffer is full. + if (b.size() == b.max_size()) + { + s.io_service().post(detail::bind_handler(handler, error::not_found, 0)); + return; + } + + // Start a new asynchronous read operation to obtain more data. + std::size_t bytes_available = + std::min(512, b.max_size() - b.size()); + s.async_read_some(b.prepare(bytes_available), detail::read_until_delim_string_handler< - Async_Read_Stream, Allocator, Handler>( + AsyncReadStream, Allocator, ReadHandler>( s, b, delim, next_search_start, handler)); } namespace detail { - template + template class read_until_expr_handler { public: - read_until_expr_handler(Async_Read_Stream& stream, + read_until_expr_handler(AsyncReadStream& stream, asio::basic_streambuf& streambuf, const boost::regex& expr, std::size_t next_search_start, - Handler handler) + ReadHandler handler) : stream_(stream), streambuf_(streambuf), expr_(expr), @@ -523,14 +590,14 @@ namespace detail { } - void operator()(const typename Async_Read_Stream::error_type& e, + void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { // Check for errors. - if (e) + if (ec) { std::size_t bytes = 0; - handler_(e, bytes); + handler_(ec, bytes); return; } @@ -555,7 +622,7 @@ namespace detail { // Full match. We're done. std::size_t bytes = match_results[0].second.position(); - handler_(e, bytes); + handler_(ec, bytes); return; } else @@ -570,51 +637,61 @@ namespace detail next_search_start_ = end.position(); } - // No match. Start a new asynchronous read operation to obtain more data. - stream_.async_read_some(streambuf_.prepare(512), *this); + // Check if buffer is full. + if (streambuf_.size() == streambuf_.max_size()) + { + std::size_t bytes = 0; + handler_(error::not_found, bytes); + return; + } + + // Start a new asynchronous read operation to obtain more data. + std::size_t bytes_available = + std::min(512, streambuf_.max_size() - streambuf_.size()); + stream_.async_read_some(streambuf_.prepare(bytes_available), *this); } //private: - Async_Read_Stream& stream_; + AsyncReadStream& stream_; asio::basic_streambuf& streambuf_; boost::regex expr_; std::size_t next_search_start_; - Handler handler_; + ReadHandler handler_; }; - template + template inline void* asio_handler_allocate(std::size_t size, - read_until_expr_handler* this_handler) + read_until_expr_handler* this_handler) { return asio_handler_alloc_helpers::allocate( size, &this_handler->handler_); } - template + template inline void asio_handler_deallocate(void* pointer, std::size_t size, - read_until_expr_handler* this_handler) + read_until_expr_handler* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, &this_handler->handler_); } - template + template inline void asio_handler_invoke(const Function& function, - read_until_expr_handler* this_handler) + read_until_expr_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, &this_handler->handler_); } } // namespace detail -template -void async_read_until(Async_Read_Stream& s, +template +void async_read_until(AsyncReadStream& s, asio::basic_streambuf& b, const boost::regex& expr, - Handler handler) + ReadHandler handler) { // Determine the range of the data to be searched. typedef typename asio::basic_streambuf< @@ -634,9 +711,9 @@ void async_read_until(Async_Read_Stream& s, if (match_results[0].matched) { // Full match. We're done. - typename Async_Read_Stream::error_type error; + asio::error_code ec; std::size_t bytes = match_results[0].second.position(); - s.io_service().post(detail::bind_handler(handler, error, bytes)); + s.io_service().post(detail::bind_handler(handler, ec, bytes)); return; } else @@ -651,9 +728,18 @@ void async_read_until(Async_Read_Stream& s, next_search_start = end.position(); } - // No match. Start a new asynchronous read operation to obtain more data. - s.async_read_some(b.prepare(512), - detail::read_until_expr_handler( + // Check if buffer is full. + if (b.size() == b.max_size()) + { + s.io_service().post(detail::bind_handler(handler, error::not_found, 0)); + return; + } + + // Start a new asynchronous read operation to obtain more data. + std::size_t bytes_available = + std::min(512, b.max_size() - b.size()); + s.async_read_some(b.prepare(bytes_available), + detail::read_until_expr_handler( s, b, expr, next_search_start, handler)); } diff --git a/libtorrent/include/libtorrent/asio/impl/write.ipp b/libtorrent/include/libtorrent/asio/impl/write.ipp index 88b14b239..8c2d1d33f 100644 --- a/libtorrent/include/libtorrent/asio/impl/write.ipp +++ b/libtorrent/include/libtorrent/asio/impl/write.ipp @@ -2,7 +2,7 @@ // write.ipp // ~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -19,92 +19,99 @@ #include "asio/buffer.hpp" #include "asio/completion_condition.hpp" -#include "asio/error_handler.hpp" #include "asio/detail/bind_handler.hpp" #include "asio/detail/consuming_buffers.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/throw_error.hpp" namespace asio { -template -std::size_t write(Sync_Write_Stream& s, const Const_Buffers& buffers, - Completion_Condition completion_condition, Error_Handler error_handler) +template +std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, asio::error_code& ec) { asio::detail::consuming_buffers< - const_buffer, Const_Buffers> tmp(buffers); + const_buffer, ConstBufferSequence> tmp(buffers); std::size_t total_transferred = 0; while (tmp.begin() != tmp.end()) { - typename Sync_Write_Stream::error_type e; - std::size_t bytes_transferred = s.write_some(tmp, assign_error(e)); + std::size_t bytes_transferred = s.write_some(tmp, ec); tmp.consume(bytes_transferred); total_transferred += bytes_transferred; - if (completion_condition(e, total_transferred)) - { - error_handler(e); + if (completion_condition(ec, total_transferred)) return total_transferred; - } } - typename Sync_Write_Stream::error_type e; - error_handler(e); + ec = asio::error_code(); return total_transferred; } -template -inline std::size_t write(Sync_Write_Stream& s, const Const_Buffers& buffers) +template +inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers) { - return write(s, buffers, transfer_all(), throw_error()); -} - -template -inline std::size_t write(Sync_Write_Stream& s, const Const_Buffers& buffers, - Completion_Condition completion_condition) -{ - return write(s, buffers, completion_condition, throw_error()); -} - -template -std::size_t write(Sync_Write_Stream& s, - asio::basic_streambuf& b, - Completion_Condition completion_condition, Error_Handler error_handler) -{ - typename Sync_Write_Stream::error_type error; - std::size_t bytes_transferred = write(s, b.data(), - completion_condition, asio::assign_error(error)); - b.consume(bytes_transferred); - error_handler(error); + asio::error_code ec; + std::size_t bytes_transferred = write(s, buffers, transfer_all(), ec); + asio::detail::throw_error(ec); return bytes_transferred; } -template -inline std::size_t write(Sync_Write_Stream& s, - asio::basic_streambuf& b) +template +inline std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition) { - return write(s, b, transfer_all(), throw_error()); + asio::error_code ec; + std::size_t bytes_transferred = write(s, buffers, completion_condition, ec); + asio::detail::throw_error(ec); + return bytes_transferred; } -template -inline std::size_t write(Sync_Write_Stream& s, +template +std::size_t write(SyncWriteStream& s, asio::basic_streambuf& b, - Completion_Condition completion_condition) + CompletionCondition completion_condition, asio::error_code& ec) { - return write(s, b, completion_condition, throw_error()); + std::size_t bytes_transferred = write(s, b.data(), completion_condition, ec); + b.consume(bytes_transferred); + return bytes_transferred; +} + +template +inline std::size_t write(SyncWriteStream& s, + asio::basic_streambuf& b) +{ + asio::error_code ec; + std::size_t bytes_transferred = write(s, b, transfer_all(), ec); + asio::detail::throw_error(ec); + return bytes_transferred; +} + +template +inline std::size_t write(SyncWriteStream& s, + asio::basic_streambuf& b, + CompletionCondition completion_condition) +{ + asio::error_code ec; + std::size_t bytes_transferred = write(s, b, completion_condition, ec); + asio::detail::throw_error(ec); + return bytes_transferred; } namespace detail { - template + template class write_handler { public: - write_handler(Async_Write_Stream& stream, const Const_Buffers& buffers, - Completion_Condition completion_condition, Handler handler) + typedef asio::detail::consuming_buffers< + const_buffer, ConstBufferSequence> buffers_type; + + write_handler(AsyncWriteStream& stream, const buffers_type& buffers, + CompletionCondition completion_condition, WriteHandler handler) : stream_(stream), buffers_(buffers), total_transferred_(0), @@ -113,15 +120,15 @@ namespace detail { } - void operator()(const typename Async_Write_Stream::error_type& e, + void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { total_transferred_ += bytes_transferred; buffers_.consume(bytes_transferred); - if (completion_condition_(e, total_transferred_) + if (completion_condition_(ec, total_transferred_) || buffers_.begin() == buffers_.end()) { - handler_(e, total_transferred_); + handler_(ec, total_transferred_); } else { @@ -130,131 +137,137 @@ namespace detail } //private: - Async_Write_Stream& stream_; - asio::detail::consuming_buffers< - const_buffer, Const_Buffers> buffers_; + AsyncWriteStream& stream_; + buffers_type buffers_; std::size_t total_transferred_; - Completion_Condition completion_condition_; - Handler handler_; + CompletionCondition completion_condition_; + WriteHandler handler_; }; - template + template inline void* asio_handler_allocate(std::size_t size, - write_handler* this_handler) + write_handler* this_handler) { return asio_handler_alloc_helpers::allocate( size, &this_handler->handler_); } - template + template inline void asio_handler_deallocate(void* pointer, std::size_t size, - write_handler* this_handler) + write_handler* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, &this_handler->handler_); } - template + template inline void asio_handler_invoke(const Function& function, - write_handler* this_handler) + write_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, &this_handler->handler_); } } // namespace detail -template -inline void async_write(Async_Write_Stream& s, const Const_Buffers& buffers, - Completion_Condition completion_condition, Handler handler) +template +inline void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, WriteHandler handler) { - s.async_write_some(buffers, - detail::write_handler( - s, buffers, completion_condition, handler)); + asio::detail::consuming_buffers< + const_buffer, ConstBufferSequence> tmp(buffers); + s.async_write_some(tmp, + detail::write_handler( + s, tmp, completion_condition, handler)); } -template -inline void async_write(Async_Write_Stream& s, const Const_Buffers& buffers, - Handler handler) +template +inline void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, + WriteHandler handler) { async_write(s, buffers, transfer_all(), handler); } namespace detail { - template + template class write_streambuf_handler { public: write_streambuf_handler(asio::basic_streambuf& streambuf, - Handler handler) + WriteHandler handler) : streambuf_(streambuf), handler_(handler) { } - void operator()(const typename Async_Write_Stream::error_type& e, + void operator()(const asio::error_code& ec, std::size_t bytes_transferred) { streambuf_.consume(bytes_transferred); - handler_(e, bytes_transferred); + handler_(ec, bytes_transferred); } //private: asio::basic_streambuf& streambuf_; - Handler handler_; + WriteHandler handler_; }; - template + template inline void* asio_handler_allocate(std::size_t size, - write_streambuf_handler* this_handler) + write_streambuf_handler* this_handler) { return asio_handler_alloc_helpers::allocate( size, &this_handler->handler_); } - template + template inline void asio_handler_deallocate(void* pointer, std::size_t size, - write_streambuf_handler* this_handler) + write_streambuf_handler* this_handler) { asio_handler_alloc_helpers::deallocate( pointer, size, &this_handler->handler_); } - template + template inline void asio_handler_invoke(const Function& function, - write_streambuf_handler* this_handler) + write_streambuf_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, &this_handler->handler_); } } // namespace detail -template -inline void async_write(Async_Write_Stream& s, +template +inline void async_write(AsyncWriteStream& s, asio::basic_streambuf& b, - Completion_Condition completion_condition, Handler handler) + CompletionCondition completion_condition, WriteHandler handler) { async_write(s, b.data(), completion_condition, - detail::write_streambuf_handler( - b, handler)); + detail::write_streambuf_handler< + AsyncWriteStream, Allocator, WriteHandler>(b, handler)); } -template -inline void async_write(Async_Write_Stream& s, - asio::basic_streambuf& b, Handler handler) +template +inline void async_write(AsyncWriteStream& s, + asio::basic_streambuf& b, WriteHandler handler) { async_write(s, b, transfer_all(), handler); } diff --git a/libtorrent/include/libtorrent/asio/io_service.hpp b/libtorrent/include/libtorrent/asio/io_service.hpp index 6808f3d45..731a7ac9a 100644 --- a/libtorrent/include/libtorrent/asio/io_service.hpp +++ b/libtorrent/include/libtorrent/asio/io_service.hpp @@ -2,7 +2,7 @@ // io_service.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -25,11 +25,12 @@ #include #include "asio/detail/pop_options.hpp" +#include "asio/error_code.hpp" #include "asio/detail/epoll_reactor_fwd.hpp" #include "asio/detail/kqueue_reactor_fwd.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/select_reactor_fwd.hpp" -#include "asio/detail/service_registry.hpp" +#include "asio/detail/service_registry_fwd.hpp" #include "asio/detail/signal_init.hpp" #include "asio/detail/task_io_service_fwd.hpp" #include "asio/detail/win_iocp_io_service_fwd.hpp" @@ -51,7 +52,7 @@ namespace asio { * The io_service class also includes facilities intended for developers of * custom asynchronous services. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Safe, with the exception that calling reset() * while there are unfinished run() calls results in undefined behaviour. @@ -80,18 +81,31 @@ public: class work; friend class work; + class id; + class service; class strand; - /// Default constructor. + /// Constructor. io_service(); + /// Constructor. + /** + * Construct with a hint about the required level of concurrency. + * + * @param concurrency_hint A suggestion to the implementation on how many + * threads it should allow to run simultaneously. + */ + explicit io_service(std::size_t concurrency_hint); + + /// Destructor. + ~io_service(); + /// Run the io_service's event processing loop. /** * The run() function blocks until all work has finished and there are no - * more handlers to be dispatched, or until the io_service has been - * interrupted. + * more handlers to be dispatched, or until the io_service has been stopped. * * Multiple threads may call the run() function to set up a pool of threads * from which the io_service may execute handlers. @@ -100,27 +114,71 @@ public: * after a call to reset(). * * @return The number of handlers that were executed. + * + * @throws asio::system_error Thrown on failure. */ - size_t run(); + std::size_t run(); + + /// Run the io_service's event processing loop. + /** + * The run() function blocks until all work has finished and there are no + * more handlers to be dispatched, or until the io_service has been stopped. + * + * Multiple threads may call the run() function to set up a pool of threads + * from which the io_service may execute handlers. + * + * The run() function may be safely called again once it has completed only + * after a call to reset(). + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of handlers that were executed. + */ + std::size_t run(asio::error_code& ec); /// Run the io_service's event processing loop to execute at most one handler. /** * The run_one() function blocks until one handler has been dispatched, or - * until the io_service has been interrupted. + * until the io_service has been stopped. + * + * @return The number of handlers that were executed. + * + * @throws asio::system_error Thrown on failure. + */ + std::size_t run_one(); + + /// Run the io_service's event processing loop to execute at most one handler. + /** + * The run_one() function blocks until one handler has been dispatched, or + * until the io_service has been stopped. + * + * @param ec Set to indicate what error occurred, if any. * * @return The number of handlers that were executed. */ - size_t run_one(); + std::size_t run_one(asio::error_code& ec); /// Run the io_service's event processing loop to execute ready handlers. /** * The poll() function runs handlers that are ready to run, without blocking, - * until the io_service has been interrupted or there are no more ready - * handlers. + * until the io_service has been stopped or there are no more ready handlers. + * + * @return The number of handlers that were executed. + * + * @throws asio::system_error Thrown on failure. + */ + std::size_t poll(); + + /// Run the io_service's event processing loop to execute ready handlers. + /** + * The poll() function runs handlers that are ready to run, without blocking, + * until the io_service has been stopped or there are no more ready handlers. + * + * @param ec Set to indicate what error occurred, if any. * * @return The number of handlers that were executed. */ - size_t poll(); + std::size_t poll(asio::error_code& ec); /// Run the io_service's event processing loop to execute one ready handler. /** @@ -128,29 +186,38 @@ public: * without blocking. * * @return The number of handlers that were executed. - */ - size_t poll_one(); - - /// Interrupt the io_service's event processing loop. - /** - * This function does not block, but instead simply signals to the io_service - * that all invocations of its run() or run_one() member functions should - * return as soon as possible. * - * Note that if the run() function is interrupted and is not called again - * later then its work may not have finished and handlers may not be - * delivered. In this case an io_service implementation is not required to - * make any guarantee that the resources associated with unfinished work will - * be cleaned up. + * @throws asio::system_error Thrown on failure. */ - void interrupt(); + std::size_t poll_one(); + + /// Run the io_service's event processing loop to execute one ready handler. + /** + * The poll_one() function runs at most one handler that is ready to run, + * without blocking. + * + * @param ec Set to indicate what error occurred, if any. + * + * @return The number of handlers that were executed. + */ + std::size_t poll_one(asio::error_code& ec); + + /// Stop the io_service's event processing loop. + /** + * This function does not block, but instead simply signals the io_service to + * stop. All invocations of its run() or run_one() member functions should + * return as soon as possible. Subsequent calls to run(), run_one(), poll() + * or poll_one() will return immediately until reset() is called. + */ + void stop(); /// Reset the io_service in preparation for a subsequent run() invocation. /** * This function must be called prior to any second or later set of - * invocations of the run(), run_one(), poll() or poll_one() functions. It - * allows the io_service to reset any internal state, such as an interrupt - * flag. + * invocations of the run(), run_one(), poll() or poll_one() functions when a + * previous invocation of these functions returned due to the io_service + * being stopped or running out of work. This function allows the io_service + * to reset any internal state, such as a "stopped" flag. * * This function must not be called while there are any unfinished calls to * the run(), run_one(), poll() or poll_one() functions. @@ -170,8 +237,8 @@ public: * a copy of the handler object as required. The function signature of the * handler must be: @code void handler(); @endcode */ - template - void dispatch(Handler handler); + template + void dispatch(CompletionHandler handler); /// Request the io_service to invoke the given handler and return immediately. /** @@ -187,8 +254,8 @@ public: * a copy of the handler object as required. The function signature of the * handler must be: @code void handler(); @endcode */ - template - void post(Handler handler); + template + void post(CompletionHandler handler); /// Create a new handler that automatically dispatches the wrapped handler /// on the io_service. @@ -274,7 +341,7 @@ private: #endif // The service registry. - detail::service_registry service_registry_; + asio::detail::service_registry* service_registry_; // The implementation. impl_type& impl_; @@ -328,6 +395,15 @@ private: asio::io_service& io_service_; }; +/// Class used to uniquely identify a service. +class io_service::id + : private noncopyable +{ +public: + /// Constructor. + id() {} +}; + /// Base class for all io_service services. class io_service::service : private noncopyable @@ -350,9 +426,10 @@ private: /// Destroy all user-defined handler objects owned by the service. virtual void shutdown_service() = 0; - friend class detail::service_registry; + friend class asio::detail::service_registry; asio::io_service& owner_; const std::type_info* type_info_; + const asio::io_service::id* id_; service* next_; }; @@ -393,10 +470,10 @@ public: * asio::io_service::run(), asio::io_service::run_one(), * asio::io_service::poll() or asio::io_service::poll_one() * call may be restarted @em without the need for an intervening call to - * asio::io_service::reset(). This allows the thread to rejoin the io_service's - * thread pool without impacting any other threads in the pool. + * asio::io_service::reset(). This allows the thread to rejoin the + * io_service's thread pool without impacting any other threads in the pool. * - * @par Example: + * @par Example * @code * asio::io_service io_service; * ... diff --git a/libtorrent/include/libtorrent/asio/ip/address.hpp b/libtorrent/include/libtorrent/asio/ip/address.hpp index 5d9a6e3a1..1b2c548bf 100644 --- a/libtorrent/include/libtorrent/asio/ip/address.hpp +++ b/libtorrent/include/libtorrent/asio/ip/address.hpp @@ -2,7 +2,7 @@ // address.hpp // ~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -24,9 +24,9 @@ #include "asio/detail/pop_options.hpp" #include "asio/error.hpp" -#include "asio/error_handler.hpp" #include "asio/ip/address_v4.hpp" #include "asio/ip/address_v6.hpp" +#include "asio/detail/throw_error.hpp" namespace asio { namespace ip { @@ -36,7 +36,7 @@ namespace ip { * The asio::ip::address class provides the ability to use either IP * version 4 or version 6 addresses. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ @@ -119,9 +119,9 @@ public: { if (type_ != ipv4) { - asio::error error( + asio::system_error e( asio::error::address_family_not_supported); - boost::throw_exception(error); + boost::throw_exception(e); } return ipv4_address_; } @@ -131,9 +131,9 @@ public: { if (type_ != ipv6) { - asio::error error( + asio::system_error e( asio::error::address_family_not_supported); - boost::throw_exception(error); + boost::throw_exception(e); } return ipv6_address_; } @@ -147,53 +147,47 @@ public: } /// Get the address as a string in dotted decimal format. - template - std::string to_string(Error_Handler error_handler) const + std::string to_string(asio::error_code& ec) const { if (type_ == ipv6) - return ipv6_address_.to_string(error_handler); - return ipv4_address_.to_string(error_handler); + return ipv6_address_.to_string(ec); + return ipv4_address_.to_string(ec); } /// Create an address from an IPv4 address string in dotted decimal form, /// or from an IPv6 address in hexadecimal notation. static address from_string(const char* str) { - return from_string(str, asio::throw_error()); + asio::error_code ec; + address addr = from_string(str, ec); + asio::detail::throw_error(ec); + return addr; } /// Create an address from an IPv4 address string in dotted decimal form, /// or from an IPv6 address in hexadecimal notation. - template - static address from_string(const char* str, Error_Handler error_handler) + static address from_string(const char* str, asio::error_code& ec) { - asio::error error; asio::ip::address_v6 ipv6_address = - asio::ip::address_v6::from_string(str, - asio::assign_error(error)); - if (!error) + asio::ip::address_v6::from_string(str, ec); + if (!ec) { address tmp; tmp.type_ = ipv6; tmp.ipv6_address_ = ipv6_address; - error_handler(error); return tmp; } - error = asio::error(); asio::ip::address_v4 ipv4_address = - asio::ip::address_v4::from_string(str, - asio::assign_error(error)); - if (!error) + asio::ip::address_v4::from_string(str, ec); + if (!ec) { address tmp; tmp.type_ = ipv4; tmp.ipv4_address_ = ipv4_address; - error_handler(error); return tmp; } - error_handler(error); return address(); } @@ -201,16 +195,15 @@ public: /// or from an IPv6 address in hexadecimal notation. static address from_string(const std::string& str) { - return from_string(str.c_str(), asio::throw_error()); + return from_string(str.c_str()); } /// Create an address from an IPv4 address string in dotted decimal form, /// or from an IPv6 address in hexadecimal notation. - template static address from_string(const std::string& str, - Error_Handler error_handler) + asio::error_code& ec) { - return from_string(str.c_str(), error_handler); + return from_string(str.c_str(), ec); } /// Compare two addresses for equality. diff --git a/libtorrent/include/libtorrent/asio/ip/address_v4.hpp b/libtorrent/include/libtorrent/asio/ip/address_v4.hpp index eea9919b4..ae3891c95 100644 --- a/libtorrent/include/libtorrent/asio/ip/address_v4.hpp +++ b/libtorrent/include/libtorrent/asio/ip/address_v4.hpp @@ -2,7 +2,7 @@ // address_v4.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -24,9 +24,9 @@ #include "asio/detail/pop_options.hpp" #include "asio/error.hpp" -#include "asio/error_handler.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" +#include "asio/detail/throw_error.hpp" namespace asio { namespace ip { @@ -36,7 +36,7 @@ namespace ip { * The asio::ip::address_v4 class provides the ability to use and * manipulate IP version 4 addresses. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ @@ -96,63 +96,54 @@ public: /// Get the address as a string in dotted decimal format. std::string to_string() const { - return to_string(asio::throw_error()); + asio::error_code ec; + std::string addr = to_string(ec); + asio::detail::throw_error(ec); + return addr; } /// Get the address as a string in dotted decimal format. - template - std::string to_string(Error_Handler error_handler) const + std::string to_string(asio::error_code& ec) const { char addr_str[asio::detail::max_addr_v4_str_len]; const char* addr = asio::detail::socket_ops::inet_ntop(AF_INET, &addr_, addr_str, - asio::detail::max_addr_v4_str_len); + asio::detail::max_addr_v4_str_len, 0, ec); if (addr == 0) - { - asio::error e(asio::detail::socket_ops::get_error()); - error_handler(e); return std::string(); - } - asio::error e; - error_handler(e); return addr; } /// Create an address from an IP address string in dotted decimal form. static address_v4 from_string(const char* str) { - return from_string(str, asio::throw_error()); + asio::error_code ec; + address_v4 addr = from_string(str, ec); + asio::detail::throw_error(ec); + return addr; } /// Create an address from an IP address string in dotted decimal form. - template - static address_v4 from_string(const char* str, Error_Handler error_handler) + static address_v4 from_string(const char* str, asio::error_code& ec) { address_v4 tmp; if (asio::detail::socket_ops::inet_pton( - AF_INET, str, &tmp.addr_) <= 0) - { - asio::error e(asio::detail::socket_ops::get_error()); - error_handler(e); + AF_INET, str, &tmp.addr_, 0, ec) <= 0) return address_v4(); - } - asio::error e; - error_handler(e); return tmp; } /// Create an address from an IP address string in dotted decimal form. static address_v4 from_string(const std::string& str) { - return from_string(str.c_str(), asio::throw_error()); + return from_string(str.c_str()); } /// Create an address from an IP address string in dotted decimal form. - template static address_v4 from_string(const std::string& str, - Error_Handler error_handler) + asio::error_code& ec) { - return from_string(str.c_str(), error_handler); + return from_string(str.c_str(), ec); } /// Determine whether the address is a class A address. @@ -274,9 +265,9 @@ template std::basic_ostream& operator<<( std::basic_ostream& os, const address_v4& addr) { - asio::error e; - std::string s = addr.to_string(asio::assign_error(e)); - if (e) + asio::error_code ec; + std::string s = addr.to_string(ec); + if (ec) os.setstate(std::ios_base::failbit); else for (std::string::iterator i = s.begin(); i != s.end(); ++i) diff --git a/libtorrent/include/libtorrent/asio/ip/address_v6.hpp b/libtorrent/include/libtorrent/asio/ip/address_v6.hpp index 85f0ebc1a..f732955fa 100644 --- a/libtorrent/include/libtorrent/asio/ip/address_v6.hpp +++ b/libtorrent/include/libtorrent/asio/ip/address_v6.hpp @@ -2,7 +2,7 @@ // address_v6.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -21,14 +21,15 @@ #include #include #include +#include #include #include #include "asio/detail/pop_options.hpp" #include "asio/error.hpp" -#include "asio/error_handler.hpp" #include "asio/detail/socket_ops.hpp" #include "asio/detail/socket_types.hpp" +#include "asio/detail/throw_error.hpp" #include "asio/ip/address_v4.hpp" namespace asio { @@ -39,7 +40,7 @@ namespace ip { * The asio::ip::address_v6 class provides the ability to use and * manipulate IP version 6 addresses. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ @@ -80,13 +81,19 @@ public: return *this; } - /// Get the scope ID of the address. + /// The scope ID of the address. + /** + * Returns the scope ID associated with the IPv6 address. + */ unsigned long scope_id() const { return scope_id_; } - /// Set the scope ID of the address. + /// The scope ID of the address. + /** + * Modifies the scope ID associated with the IPv6 address. + */ void scope_id(unsigned long id) { scope_id_ = id; @@ -104,63 +111,54 @@ public: /// Get the address as a string. std::string to_string() const { - return to_string(asio::throw_error()); + asio::error_code ec; + std::string addr = to_string(ec); + asio::detail::throw_error(ec); + return addr; } /// Get the address as a string. - template - std::string to_string(Error_Handler error_handler) const + std::string to_string(asio::error_code& ec) const { char addr_str[asio::detail::max_addr_v6_str_len]; const char* addr = asio::detail::socket_ops::inet_ntop(AF_INET6, &addr_, addr_str, - asio::detail::max_addr_v6_str_len, scope_id_); + asio::detail::max_addr_v6_str_len, scope_id_, ec); if (addr == 0) - { - asio::error e(asio::detail::socket_ops::get_error()); - error_handler(e); return std::string(); - } - asio::error e; - error_handler(e); return addr; } /// Create an address from an IP address string. static address_v6 from_string(const char* str) { - return from_string(str, asio::throw_error()); + asio::error_code ec; + address_v6 addr = from_string(str, ec); + asio::detail::throw_error(ec); + return addr; } /// Create an address from an IP address string. - template - static address_v6 from_string(const char* str, Error_Handler error_handler) + static address_v6 from_string(const char* str, asio::error_code& ec) { address_v6 tmp; if (asio::detail::socket_ops::inet_pton( - AF_INET6, str, &tmp.addr_, &tmp.scope_id_) <= 0) - { - asio::error e(asio::detail::socket_ops::get_error()); - error_handler(e); + AF_INET6, str, &tmp.addr_, &tmp.scope_id_, ec) <= 0) return address_v6(); - } - asio::error e; - error_handler(e); return tmp; } /// Create an address from an IP address string. static address_v6 from_string(const std::string& str) { - return from_string(str.c_str(), asio::throw_error()); + return from_string(str.c_str()); } /// Create an address from an IP address string. - template static address_v6 from_string(const std::string& str, - Error_Handler error_handler) + asio::error_code& ec) { - return from_string(str.c_str(), error_handler); + return from_string(str.c_str(), ec); } /// Converts an IPv4-mapped or IPv4-compatible address to an IPv4 address. @@ -168,23 +166,45 @@ public: { if (!is_v4_mapped() && !is_v4_compatible()) throw std::bad_cast(); - address_v4::bytes_type v4_bytes = { addr_.s6_addr[12], - addr_.s6_addr[13], addr_.s6_addr[14], addr_.s6_addr[15] }; + 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); } /// Determine whether the address is a loopback address. bool is_loopback() const { +#if defined(__BORLANDC__) + return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) + && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) + && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) + && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) + && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) + && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) + && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) + && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 1)); +#else using namespace asio::detail; return IN6_IS_ADDR_LOOPBACK(&addr_) != 0; +#endif } /// Determine whether the address is unspecified. bool is_unspecified() const { +#if defined(__BORLANDC__) + return ((addr_.s6_addr[0] == 0) && (addr_.s6_addr[1] == 0) + && (addr_.s6_addr[2] == 0) && (addr_.s6_addr[3] == 0) + && (addr_.s6_addr[4] == 0) && (addr_.s6_addr[5] == 0) + && (addr_.s6_addr[6] == 0) && (addr_.s6_addr[7] == 0) + && (addr_.s6_addr[8] == 0) && (addr_.s6_addr[9] == 0) + && (addr_.s6_addr[10] == 0) && (addr_.s6_addr[11] == 0) + && (addr_.s6_addr[12] == 0) && (addr_.s6_addr[13] == 0) + && (addr_.s6_addr[14] == 0) && (addr_.s6_addr[15] == 0)); +#else using namespace asio::detail; return IN6_IS_ADDR_UNSPECIFIED(&addr_) != 0; +#endif } /// Determine whether the address is link local. @@ -325,8 +345,8 @@ public: static address_v6 v4_mapped(const address_v4& addr) { address_v4::bytes_type v4_bytes = addr.to_bytes(); - bytes_type v6_bytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, - v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] }; + bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, + v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; return address_v6(v6_bytes); } @@ -334,8 +354,8 @@ public: static address_v6 v4_compatible(const address_v4& addr) { address_v4::bytes_type v4_bytes = addr.to_bytes(); - bytes_type v6_bytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] }; + bytes_type v6_bytes = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + v4_bytes[0], v4_bytes[1], v4_bytes[2], v4_bytes[3] } }; return address_v6(v6_bytes); } @@ -363,9 +383,9 @@ template std::basic_ostream& operator<<( std::basic_ostream& os, const address_v6& addr) { - asio::error e; - std::string s = addr.to_string(asio::assign_error(e)); - if (e) + asio::error_code ec; + std::string s = addr.to_string(ec); + if (ec) os.setstate(std::ios_base::failbit); else for (std::string::iterator i = s.begin(); i != s.end(); ++i) diff --git a/libtorrent/include/libtorrent/asio/ip/basic_endpoint.hpp b/libtorrent/include/libtorrent/asio/ip/basic_endpoint.hpp index 56ce99eca..3ca91dc03 100644 --- a/libtorrent/include/libtorrent/asio/ip/basic_endpoint.hpp +++ b/libtorrent/include/libtorrent/asio/ip/basic_endpoint.hpp @@ -2,7 +2,7 @@ // basic_endpoint.hpp // ~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -22,7 +22,7 @@ #include #include #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -# include +# include #endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) #include "asio/detail/pop_options.hpp" @@ -39,19 +39,19 @@ namespace ip { * The asio::ip::basic_endpoint class template describes an endpoint that * may be associated with a particular socket. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * * @par Concepts: * Endpoint. */ -template +template class basic_endpoint { public: /// The protocol type associated with the endpoint. - typedef Protocol protocol_type; + typedef InternetProtocol protocol_type; /// The type of the endpoint structure. This type is dependent on the /// underlying implementation of the socket layer. @@ -85,7 +85,7 @@ public: /// in6addr_any). This constructor would typically be used for accepting new /// connections. /** - * @par Examples: + * @par Examples * To initialise an IPv4 TCP endpoint for port 1234, use: * @code * asio::ip::tcp::endpoint ep(asio::ip::tcp::v4(), 1234); @@ -96,7 +96,7 @@ public: * asio::ip::udp::endpoint ep(asio::ip::udp::v6(), 9876); * @endcode */ - basic_endpoint(const Protocol& protocol, unsigned short port_num) + basic_endpoint(const InternetProtocol& protocol, unsigned short port_num) : data_() { using namespace std; // For memcpy. @@ -172,9 +172,9 @@ public: /// The protocol associated with the endpoint. protocol_type protocol() const { - if (data_.ss_family == AF_INET) - return Protocol::v4(); - return Protocol::v6(); + if (is_v4()) + return InternetProtocol::v4(); + return InternetProtocol::v6(); } /// Get the underlying endpoint in the native type. @@ -192,7 +192,7 @@ public: /// Get the underlying size of the endpoint in the native type. size_type size() const { - if (data_.ss_family == AF_INET) + if (is_v4()) return sizeof(asio::detail::sockaddr_in4_type); else return sizeof(asio::detail::sockaddr_in6_type); @@ -203,7 +203,7 @@ public: { if (size > size_type(sizeof(data_))) { - asio::error e(asio::error::invalid_argument); + asio::system_error e(asio::error::invalid_argument); boost::throw_exception(e); } } @@ -218,7 +218,7 @@ public: /// the host's byte order. unsigned short port() const { - if (data_.ss_family == AF_INET) + if (is_v4()) { return asio::detail::socket_ops::network_to_host_short( reinterpret_cast( @@ -236,7 +236,7 @@ public: /// the host's byte order. void port(unsigned short port_num) { - if (data_.ss_family == AF_INET) + if (is_v4()) { reinterpret_cast(data_).sin_port = asio::detail::socket_ops::host_to_network_short(port_num); @@ -252,7 +252,7 @@ public: asio::ip::address address() const { using namespace std; // For memcpy. - if (data_.ss_family == AF_INET) + if (is_v4()) { const asio::detail::sockaddr_in4_type& data = reinterpret_cast( @@ -275,27 +275,27 @@ public: /// Set the IP address associated with the endpoint. void address(const asio::ip::address& addr) { - basic_endpoint tmp_endpoint(addr, port()); + basic_endpoint tmp_endpoint(addr, port()); data_ = tmp_endpoint.data_; } /// Compare two endpoints for equality. - friend bool operator==(const basic_endpoint& e1, - const basic_endpoint& e2) + friend bool operator==(const basic_endpoint& e1, + const basic_endpoint& e2) { return e1.address() == e2.address() && e1.port() == e2.port(); } /// Compare two endpoints for inequality. - friend bool operator!=(const basic_endpoint& e1, - const basic_endpoint& e2) + friend bool operator!=(const basic_endpoint& e1, + const basic_endpoint& e2) { return e1.address() != e2.address() || e1.port() != e2.port(); } /// Compare endpoints for ordering. - friend bool operator<(const basic_endpoint& e1, - const basic_endpoint& e2) + friend bool operator<(const basic_endpoint& e1, + const basic_endpoint& e2) { if (e1.address() < e2.address()) return true; @@ -305,6 +305,16 @@ public: } private: + // Helper function to determine whether the endpoint is IPv4. + bool is_v4() const + { +#if defined(_AIX) + return data_.__ss_family == AF_INET; +#else + return data_.ss_family == AF_INET; +#endif + } + // The underlying IP socket address. asio::detail::sockaddr_storage_type data_; }; @@ -322,9 +332,9 @@ private: * @relates asio::ip::basic_endpoint */ #if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -template +template std::ostream& operator<<(std::ostream& os, - const basic_endpoint& endpoint) + const basic_endpoint& endpoint) { const address& addr = endpoint.address(); if (addr.is_v4()) @@ -335,10 +345,10 @@ std::ostream& operator<<(std::ostream& os, return os; } #else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) -template +template std::basic_ostream& operator<<( std::basic_ostream& os, - const basic_endpoint& endpoint) + const basic_endpoint& endpoint) { const address& addr = endpoint.address(); if (addr.is_v4()) diff --git a/libtorrent/include/libtorrent/asio/ip/basic_resolver.hpp b/libtorrent/include/libtorrent/asio/ip/basic_resolver.hpp new file mode 100644 index 000000000..8c9d25486 --- /dev/null +++ b/libtorrent/include/libtorrent/asio/ip/basic_resolver.hpp @@ -0,0 +1,245 @@ +// +// basic_resolver.hpp +// ~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IP_BASIC_RESOLVER_HPP +#define ASIO_IP_BASIC_RESOLVER_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +#include "asio/basic_io_object.hpp" +#include "asio/error.hpp" +#include "asio/ip/resolver_service.hpp" +#include "asio/detail/throw_error.hpp" + +namespace asio { +namespace ip { + +/// Provides endpoint resolution functionality. +/** + * The basic_resolver class template provides the ability to resolve a query + * to a list of endpoints. + * + * @par Thread Safety + * @e Distinct @e objects: Safe.@n + * @e Shared @e objects: Unsafe. + */ +template > +class basic_resolver + : public basic_io_object +{ +public: + /// The protocol type. + typedef InternetProtocol protocol_type; + + /// The endpoint type. + typedef typename InternetProtocol::endpoint endpoint_type; + + /// The query type. + typedef typename InternetProtocol::resolver_query query; + + /// The iterator type. + typedef typename InternetProtocol::resolver_iterator iterator; + + /// Constructor. + /** + * This constructor creates a basic_resolver. + * + * @param io_service The io_service object that the resolver will use to + * dispatch handlers for any asynchronous operations performed on the timer. + */ + explicit basic_resolver(asio::io_service& io_service) + : basic_io_object(io_service) + { + } + + /// Cancel any asynchronous operations that are waiting on the resolver. + /** + * This function forces the completion of any pending asynchronous + * operations on the host resolver. The handler for each cancelled operation + * will be invoked with the asio::error::operation_aborted error code. + */ + void cancel() + { + return this->service.cancel(this->implementation); + } + + /// Resolve a query to a list of entries. + /** + * This function is used to resolve a query into a list of endpoint entries. + * + * @param q A query object that determines what endpoints will be returned. + * + * @returns A forward-only iterator that can be used to traverse the list + * of endpoint entries. + * + * @throws asio::system_error Thrown on failure. + * + * @note A default constructed iterator represents the end of the list. + * + * A successful call to this function is guaranteed to return at least one + * entry. + */ + iterator resolve(const query& q) + { + asio::error_code ec; + iterator i = this->service.resolve(this->implementation, q, ec); + asio::detail::throw_error(ec); + return i; + } + + /// Resolve a query to a list of entries. + /** + * This function is used to resolve a query into a list of endpoint entries. + * + * @param q A query object that determines what endpoints will be returned. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns A forward-only iterator that can be used to traverse the list + * of endpoint entries. Returns a default constructed iterator if an error + * occurs. + * + * @note A default constructed iterator represents the end of the list. + * + * A successful call to this function is guaranteed to return at least one + * entry. + */ + iterator resolve(const query& q, asio::error_code& ec) + { + return this->service.resolve(this->implementation, q, ec); + } + + /// Asynchronously resolve a query to a list of entries. + /** + * This function is used to asynchronously resolve a query into a list of + * endpoint entries. + * + * @param q A query object that determines what endpoints will be returned. + * + * @param handler The handler to be called when the resolve operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * resolver::iterator iterator // Forward-only iterator that can + * // be used to traverse the list + * // of endpoint entries. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @note A default constructed iterator represents the end of the list. + * + * A successful resolve operation is guaranteed to pass at least one entry to + * the handler. + */ + template + void async_resolve(const query& q, ResolveHandler handler) + { + return this->service.async_resolve(this->implementation, q, handler); + } + + /// Resolve an endpoint to a list of entries. + /** + * This function is used to resolve an endpoint into a list of endpoint + * entries. + * + * @param e An endpoint object that determines what endpoints will be + * returned. + * + * @returns A forward-only iterator that can be used to traverse the list + * of endpoint entries. + * + * @throws asio::system_error Thrown on failure. + * + * @note A default constructed iterator represents the end of the list. + * + * A successful call to this function is guaranteed to return at least one + * entry. + */ + iterator resolve(const endpoint_type& e) + { + asio::error_code ec; + iterator i = this->service.resolve(this->implementation, e, ec); + asio::detail::throw_error(ec); + return i; + } + + /// Resolve an endpoint to a list of entries. + /** + * This function is used to resolve an endpoint into a list of endpoint + * entries. + * + * @param e An endpoint object that determines what endpoints will be + * returned. + * + * @param ec Set to indicate what error occurred, if any. + * + * @returns A forward-only iterator that can be used to traverse the list + * of endpoint entries. Returns a default constructed iterator if an error + * occurs. + * + * @note A default constructed iterator represents the end of the list. + * + * A successful call to this function is guaranteed to return at least one + * entry. + */ + iterator resolve(const endpoint_type& e, asio::error_code& ec) + { + return this->service.resolve(this->implementation, e, ec); + } + + /// Asynchronously resolve an endpoint to a list of entries. + /** + * This function is used to asynchronously resolve an endpoint into a list of + * endpoint entries. + * + * @param e An endpoint object that determines what endpoints will be + * returned. + * + * @param handler The handler to be called when the resolve operation + * completes. Copies will be made of the handler as required. The function + * signature of the handler must be: + * @code void handler( + * const asio::error_code& error, // Result of operation. + * resolver::iterator iterator // Forward-only iterator that can + * // be used to traverse the list + * // of endpoint entries. + * ); @endcode + * Regardless of whether the asynchronous operation completes immediately or + * not, the handler will not be invoked from within this function. Invocation + * of the handler will be performed in a manner equivalent to using + * asio::io_service::post(). + * + * @note A default constructed iterator represents the end of the list. + * + * A successful resolve operation is guaranteed to pass at least one entry to + * the handler. + */ + template + void async_resolve(const endpoint_type& e, ResolveHandler handler) + { + return this->service.async_resolve(this->implementation, e, handler); + } +}; + +} // namespace ip +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IP_BASIC_RESOLVER_HPP diff --git a/libtorrent/include/libtorrent/asio/ip/basic_resolver_entry.hpp b/libtorrent/include/libtorrent/asio/ip/basic_resolver_entry.hpp index 6198425ab..03184d8f5 100644 --- a/libtorrent/include/libtorrent/asio/ip/basic_resolver_entry.hpp +++ b/libtorrent/include/libtorrent/asio/ip/basic_resolver_entry.hpp @@ -2,7 +2,7 @@ // basic_resolver_entry.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -29,22 +29,19 @@ namespace ip { * The asio::ip::basic_resolver_entry class template describes an entry * as returned by a resolver. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. - * - * @par Concepts: - * Endpoint. */ -template +template class basic_resolver_entry { public: /// The protocol type associated with the endpoint entry. - typedef Protocol protocol_type; + typedef InternetProtocol protocol_type; /// The endpoint type associated with the endpoint entry. - typedef typename Protocol::endpoint endpoint_type; + typedef typename InternetProtocol::endpoint endpoint_type; /// Default constructor. basic_resolver_entry() diff --git a/libtorrent/include/libtorrent/asio/ip/basic_resolver_iterator.hpp b/libtorrent/include/libtorrent/asio/ip/basic_resolver_iterator.hpp index 12984ee79..9edec2b0a 100644 --- a/libtorrent/include/libtorrent/asio/ip/basic_resolver_iterator.hpp +++ b/libtorrent/include/libtorrent/asio/ip/basic_resolver_iterator.hpp @@ -2,7 +2,7 @@ // basic_resolver_iterator.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -38,17 +38,17 @@ namespace ip { * iterators over the results returned by a resolver. * * The iterator's value_type, obtained when the iterator is dereferenced, is: - * @code const basic_resolver_entry @endcode + * @code const basic_resolver_entry @endcode * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. */ -template +template class basic_resolver_iterator : public boost::iterator_facade< - basic_resolver_iterator, - const basic_resolver_entry, + basic_resolver_iterator, + const basic_resolver_entry, boost::forward_traversal_tag> { public: @@ -78,12 +78,14 @@ public: || address_info->ai_family == PF_INET6) { using namespace std; // For memcpy. - typename Protocol::endpoint endpoint; - endpoint.resize(address_info->ai_addrlen); + typename InternetProtocol::endpoint endpoint; + endpoint.resize( + static_cast( + address_info->ai_addrlen)); memcpy(endpoint.data(), address_info->ai_addr, address_info->ai_addrlen); iter.values_->push_back( - basic_resolver_entry(endpoint, + basic_resolver_entry(endpoint, actual_host_name, service_name)); } address_info = address_info->ai_next; @@ -99,13 +101,14 @@ public: /// Create an iterator from an endpoint, host name and service name. static basic_resolver_iterator create( - const typename Protocol::endpoint& endpoint, + const typename InternetProtocol::endpoint& endpoint, const std::string& host_name, const std::string& service_name) { basic_resolver_iterator iter; iter.values_.reset(new values_type); iter.values_->push_back( - basic_resolver_entry(endpoint, host_name, service_name)); + basic_resolver_entry( + endpoint, host_name, service_name)); iter.iter_ = iter.values_->begin(); return iter; } @@ -133,12 +136,12 @@ private: return iter_ == other.iter_; } - const basic_resolver_entry& dereference() const + const basic_resolver_entry& dereference() const { return *iter_; } - typedef std::vector > values_type; + typedef std::vector > values_type; boost::shared_ptr values_; typename values_type::const_iterator iter_; }; diff --git a/libtorrent/include/libtorrent/asio/ip/basic_resolver_query.hpp b/libtorrent/include/libtorrent/asio/ip/basic_resolver_query.hpp index ddee4b1c3..0fdd003fe 100644 --- a/libtorrent/include/libtorrent/asio/ip/basic_resolver_query.hpp +++ b/libtorrent/include/libtorrent/asio/ip/basic_resolver_query.hpp @@ -2,7 +2,7 @@ // basic_resolver_query.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -33,20 +33,17 @@ namespace ip { * The asio::ip::basic_resolver_query class template describes a query * that can be passed to a resolver. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. - * - * @par Concepts: - * Endpoint. */ -template +template class basic_resolver_query : public resolver_query_base { public: /// The protocol type associated with the endpoint query. - typedef Protocol protocol_type; + typedef InternetProtocol protocol_type; /// Construct with specified service name for any protocol. basic_resolver_query(const std::string& service_name, @@ -55,7 +52,7 @@ public: host_name_(), service_name_(service_name) { - typename Protocol::endpoint endpoint; + typename InternetProtocol::endpoint endpoint; hints_.ai_flags = flags; hints_.ai_family = PF_UNSPEC; hints_.ai_socktype = endpoint.protocol().type(); @@ -91,7 +88,7 @@ public: host_name_(host_name), service_name_(service_name) { - typename Protocol::endpoint endpoint; + typename InternetProtocol::endpoint endpoint; hints_.ai_flags = flags; hints_.ai_family = PF_UNSPEC; hints_.ai_socktype = endpoint.protocol().type(); diff --git a/libtorrent/include/libtorrent/asio/ip/detail/socket_option.hpp b/libtorrent/include/libtorrent/asio/ip/detail/socket_option.hpp index ae733e987..db7f8edc4 100644 --- a/libtorrent/include/libtorrent/asio/ip/detail/socket_option.hpp +++ b/libtorrent/include/libtorrent/asio/ip/detail/socket_option.hpp @@ -2,7 +2,7 @@ // socket_option.hpp // ~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -44,21 +44,34 @@ public: } // Construct with a specific option value. - boolean(bool value) - : value_(value ? 1 : 0) + explicit boolean(bool v) + : value_(v ? 1 : 0) { } // Set the value of the boolean. - void set(bool value) + boolean& operator=(bool v) { - value_ = value ? 1 : 0; + value_ = v ? 1 : 0; + return *this; } // Get the current value of the boolean. - bool get() const + bool value() const { - return value_; + return !!value_; + } + + // Convert to bool. + operator bool() const + { + return !!value_; + } + + // Test for false. + bool operator!() const + { + return !value_; } // Get the level of the socket option. @@ -100,35 +113,44 @@ public: return sizeof(value_); } + // Set the size of the boolean data. + template + void resize(const Protocol&, std::size_t s) + { + if (s != sizeof(value_)) + throw std::length_error("boolean socket option resize"); + } + private: int value_; }; -// Helper template for implementing integer options. +// Helper template for implementing unicast hops options. template -class integer +class unicast_hops { public: // Default constructor. - integer() + unicast_hops() : value_(0) { } // Construct with a specific option value. - integer(int value) - : value_(value) + explicit unicast_hops(int v) + : value_(v) { } - // Set the value of the int option. - void set(int value) + // Set the value of the option. + unicast_hops& operator=(int v) { - value_ = value; + value_ = v; + return *this; } - // Get the current value of the int option. - int get() const + // Get the current value of the option. + int value() const { return value_; } @@ -151,31 +173,149 @@ public: return IPv4_Name; } - // Get the address of the int data. + // Get the address of the data. template int* data(const Protocol&) { return &value_; } - // Get the address of the int data. + // Get the address of the data. template const int* data(const Protocol&) const { return &value_; } - // Get the size of the int data. + // Get the size of the data. template std::size_t size(const Protocol&) const { return sizeof(value_); } + // Set the size of the data. + template + void resize(const Protocol&, std::size_t s) + { + if (s != sizeof(value_)) + throw std::length_error("unicast hops socket option resize"); + } + private: int value_; }; +// Helper template for implementing multicast hops options. +template +class multicast_hops +{ +public: + // Default constructor. + multicast_hops() + : ipv4_value_(0), + ipv6_value_(0) + { + } + + // Construct with a specific option value. + explicit multicast_hops(int v) + { + if (v < 0 || v > 255) + throw std::out_of_range("multicast hops value out of range"); + ipv4_value_ = static_cast(v); + ipv6_value_ = v; + } + + // Set the value of the option. + multicast_hops& operator=(int v) + { + if (v < 0 || v > 255) + throw std::out_of_range("multicast hops value out of range"); + ipv4_value_ = static_cast(v); + ipv6_value_ = v; + return *this; + } + + // Get the current value of the option. + int value() const + { + return ipv6_value_; + } + + // Get the level of the socket option. + template + int level(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return IPv6_Level; + return IPv4_Level; + } + + // Get the name of the socket option. + template + int name(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return IPv6_Name; + return IPv4_Name; + } + + // Get the address of the data. + template + void* data(const Protocol& protocol) + { + if (protocol.family() == PF_INET6) + return &ipv6_value_; + return &ipv4_value_; + } + + // Get the address of the data. + template + const void* data(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return &ipv6_value_; + return &ipv4_value_; + } + + // Get the size of the data. + template + std::size_t size(const Protocol& protocol) const + { + if (protocol.family() == PF_INET6) + return sizeof(ipv6_value_); + return sizeof(ipv4_value_); + } + + // Set the size of the data. + template + void resize(const Protocol& protocol, std::size_t s) + { + if (protocol.family() == PF_INET6) + { + if (s != sizeof(ipv6_value_)) + throw std::length_error("multicast hops socket option resize"); + if (ipv6_value_ < 0) + ipv4_value_ = 0; + else if (ipv6_value_ > 255) + ipv4_value_ = 255; + else + ipv4_value_ = static_cast(ipv6_value_); + } + else + { + if (s != sizeof(ipv4_value_)) + throw std::length_error("multicast hops socket option resize"); + ipv6_value_ = ipv4_value_; + } + } + +private: + unsigned char ipv4_value_; + int ipv6_value_; +}; + // Helper template for implementing ip_mreq-based options. template class multicast_request @@ -197,7 +337,7 @@ public: } // Construct with multicast address only. - multicast_request(const asio::ip::address& multicast_address) + explicit multicast_request(const asio::ip::address& multicast_address) { if (multicast_address.is_v6()) { @@ -230,7 +370,8 @@ public: } // Construct with multicast address and IPv4 address specifying an interface. - multicast_request(const asio::ip::address_v4& multicast_address, + explicit multicast_request( + const asio::ip::address_v4& multicast_address, const asio::ip::address_v4& network_interface = asio::ip::address_v4::any()) { @@ -247,7 +388,8 @@ public: } // Construct with multicast address and IPv6 network interface index. - multicast_request(const asio::ip::address_v6& multicast_address, + explicit multicast_request( + const asio::ip::address_v6& multicast_address, unsigned long network_interface = 0) { ipv4_value_.imr_multiaddr.s_addr = @@ -282,15 +424,6 @@ public: return IPv4_Name; } - // Get the address of the option data. - template - void* data(const Protocol& protocol) - { - if (protocol.family() == PF_INET6) - return &ipv6_value_; - return &ipv4_value_; - } - // Get the address of the option data. template const void* data(const Protocol& protocol) const @@ -329,7 +462,7 @@ public: } // Construct with IPv4 interface. - network_interface(const asio::ip::address_v4& ipv4_interface) + explicit network_interface(const asio::ip::address_v4& ipv4_interface) { ipv4_value_.s_addr = asio::detail::socket_ops::host_to_network_long( @@ -338,7 +471,7 @@ public: } // Construct with IPv6 interface. - network_interface(unsigned long ipv6_interface) + explicit network_interface(unsigned long ipv6_interface) { ipv4_value_.s_addr = asio::detail::socket_ops::host_to_network_long( @@ -364,15 +497,6 @@ public: return IPv4_Name; } - // Get the address of the option data. - template - void* data(const Protocol& protocol) - { - if (protocol.family() == PF_INET6) - return &ipv6_value_; - return &ipv4_value_; - } - // Get the address of the option data. template const void* data(const Protocol& protocol) const diff --git a/libtorrent/include/libtorrent/asio/ip/host_name.hpp b/libtorrent/include/libtorrent/asio/ip/host_name.hpp index 23c906a6a..15adc08cc 100644 --- a/libtorrent/include/libtorrent/asio/ip/host_name.hpp +++ b/libtorrent/include/libtorrent/asio/ip/host_name.hpp @@ -2,7 +2,7 @@ // host_name.hpp // ~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -21,8 +21,9 @@ #include #include "asio/detail/pop_options.hpp" -#include "asio/error_handler.hpp" +#include "asio/error.hpp" #include "asio/detail/socket_ops.hpp" +#include "asio/detail/throw_error.hpp" namespace asio { namespace ip { @@ -31,27 +32,28 @@ namespace ip { std::string host_name(); /// Get the current host name. -template -std::string host_name(Error_Handler error_handler); +std::string host_name(asio::error_code& ec); inline std::string host_name() -{ - return host_name(asio::throw_error()); -} - -template -std::string host_name(Error_Handler error_handler) { char name[1024]; - if (asio::detail::socket_ops::gethostname(name, sizeof(name)) != 0) + asio::error_code ec; + if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) { - asio::error error(asio::detail::socket_ops::get_error()); - error_handler(error); + asio::detail::throw_error(ec); return std::string(); } return std::string(name); } +inline std::string host_name(asio::error_code& ec) +{ + char name[1024]; + if (asio::detail::socket_ops::gethostname(name, sizeof(name), ec) != 0) + return std::string(); + return std::string(name); +} + } // namespace ip } // namespace asio diff --git a/libtorrent/include/libtorrent/asio/ip/multicast.hpp b/libtorrent/include/libtorrent/asio/ip/multicast.hpp index 616e9020c..0d90659ca 100644 --- a/libtorrent/include/libtorrent/asio/ip/multicast.hpp +++ b/libtorrent/include/libtorrent/asio/ip/multicast.hpp @@ -2,7 +2,7 @@ // multicast.hpp // ~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -32,7 +32,7 @@ namespace multicast { /** * Implements the IPPROTO_IP/IP_ADD_MEMBERSHIP socket option. * - * @par Examples: + * @par Examples * Setting the option to join a multicast group: * @code * asio::ip::udp::socket socket(io_service); @@ -44,7 +44,7 @@ namespace multicast { * @endcode * * @par Concepts: - * Socket_Option, IP_MReq_Socket_Option. + * SettableSocketOption. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined join_group; @@ -57,7 +57,7 @@ typedef asio::ip::detail::socket_option::multicast_request< /** * Implements the IPPROTO_IP/IP_DROP_MEMBERSHIP socket option. * - * @par Examples: + * @par Examples * Setting the option to leave a multicast group: * @code * asio::ip::udp::socket socket(io_service); @@ -69,7 +69,7 @@ typedef asio::ip::detail::socket_option::multicast_request< * @endcode * * @par Concepts: - * Socket_Option, IP_MReq_Socket_Option. + * SettableSocketOption. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined leave_group; @@ -82,7 +82,7 @@ typedef asio::ip::detail::socket_option::multicast_request< /** * Implements the IPPROTO_IP/IP_MULTICAST_IF socket option. * - * @par Examples: + * @par Examples * Setting the option: * @code * asio::ip::udp::socket socket(io_service); @@ -94,7 +94,7 @@ typedef asio::ip::detail::socket_option::multicast_request< * @endcode * * @par Concepts: - * Socket_Option, IP_Network_Interface_Socket_Option. + * SettableSocketOption. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined outbound_interface; @@ -108,7 +108,7 @@ typedef asio::ip::detail::socket_option::network_interface< /** * Implements the IPPROTO_IP/IP_MULTICAST_TTL socket option. * - * @par Examples: + * @par Examples * Setting the option: * @code * asio::ip::udp::socket socket(io_service); @@ -124,16 +124,16 @@ typedef asio::ip::detail::socket_option::network_interface< * ... * asio::ip::multicast::hops option; * socket.get_option(option); - * int ttl = option.get(); + * int ttl = option.value(); * @endcode * * @par Concepts: - * Socket_Option, Integer_Socket_Option. + * GettableSocketOption, SettableSocketOption. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined hops; #else -typedef asio::ip::detail::socket_option::integer< +typedef asio::ip::detail::socket_option::multicast_hops< IPPROTO_IP, IP_MULTICAST_TTL, IPPROTO_IPV6, IPV6_MULTICAST_HOPS> hops; #endif @@ -142,7 +142,7 @@ typedef asio::ip::detail::socket_option::integer< /** * Implements the IPPROTO_IP/IP_MULTICAST_LOOP socket option. * - * @par Examples: + * @par Examples * Setting the option: * @code * asio::ip::udp::socket socket(io_service); @@ -158,11 +158,11 @@ typedef asio::ip::detail::socket_option::integer< * ... * asio::ip::multicast::enable_loopback option; * socket.get_option(option); - * bool is_set = option.get(); + * bool is_set = option.value(); * @endcode * * @par Concepts: - * Socket_Option, Boolean_Socket_Option. + * GettableSocketOption, SettableSocketOption. */ #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined enable_loopback; diff --git a/libtorrent/include/libtorrent/asio/ip/resolver_query_base.hpp b/libtorrent/include/libtorrent/asio/ip/resolver_query_base.hpp index a8c7ad6dc..5b76fb3c2 100644 --- a/libtorrent/include/libtorrent/asio/ip/resolver_query_base.hpp +++ b/libtorrent/include/libtorrent/asio/ip/resolver_query_base.hpp @@ -2,7 +2,7 @@ // resolver_query_base.hpp // ~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/ip/resolver_service.hpp b/libtorrent/include/libtorrent/asio/ip/resolver_service.hpp new file mode 100644 index 000000000..6d5193ea8 --- /dev/null +++ b/libtorrent/include/libtorrent/asio/ip/resolver_service.hpp @@ -0,0 +1,140 @@ +// +// resolver_service.hpp +// ~~~~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_IP_RESOLVER_SERVICE_HPP +#define ASIO_IP_RESOLVER_SERVICE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +#include "asio/error.hpp" +#include "asio/io_service.hpp" +#include "asio/detail/resolver_service.hpp" +#include "asio/detail/service_base.hpp" + +namespace asio { +namespace ip { + +/// Default service implementation for a resolver. +template +class resolver_service +#if defined(GENERATING_DOCUMENTATION) + : public asio::io_service::service +#else + : public asio::detail::service_base< + resolver_service > +#endif +{ +public: +#if defined(GENERATING_DOCUMENTATION) + /// The unique service identifier. + static asio::io_service::id id; +#endif + + /// The protocol type. + typedef InternetProtocol protocol_type; + + /// The endpoint type. + typedef typename InternetProtocol::endpoint endpoint_type; + + /// The query type. + typedef typename InternetProtocol::resolver_query query_type; + + /// The iterator type. + typedef typename InternetProtocol::resolver_iterator iterator_type; + +private: + // The type of the platform-specific implementation. + typedef asio::detail::resolver_service + service_impl_type; + +public: + /// The type of a resolver implementation. +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined implementation_type; +#else + typedef typename service_impl_type::implementation_type implementation_type; +#endif + + /// Construct a new resolver service for the specified io_service. + explicit resolver_service(asio::io_service& io_service) + : asio::detail::service_base< + resolver_service >(io_service), + service_impl_(asio::use_service(io_service)) + { + } + + /// Destroy all user-defined handler objects owned by the service. + void shutdown_service() + { + } + + /// Construct a new resolver implementation. + void construct(implementation_type& impl) + { + service_impl_.construct(impl); + } + + /// Destroy a resolver implementation. + void destroy(implementation_type& impl) + { + service_impl_.destroy(impl); + } + + /// Cancel pending asynchronous operations. + void cancel(implementation_type& impl) + { + service_impl_.cancel(impl); + } + + /// Resolve a query to a list of entries. + iterator_type resolve(implementation_type& impl, const query_type& query, + asio::error_code& ec) + { + return service_impl_.resolve(impl, query, ec); + } + + /// Asynchronously resolve a query to a list of entries. + template + void async_resolve(implementation_type& impl, const query_type& query, + Handler handler) + { + service_impl_.async_resolve(impl, query, handler); + } + + /// Resolve an endpoint to a list of entries. + iterator_type resolve(implementation_type& impl, + const endpoint_type& endpoint, asio::error_code& ec) + { + return service_impl_.resolve(impl, endpoint, ec); + } + + /// Asynchronously resolve an endpoint to a list of entries. + template + void async_resolve(implementation_type& impl, const endpoint_type& endpoint, + ResolveHandler handler) + { + return service_impl_.async_resolve(impl, endpoint, handler); + } + +private: + // The service that provides the platform-specific implementation. + service_impl_type& service_impl_; +}; + +} // namespace ip +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_IP_RESOLVER_SERVICE_HPP diff --git a/libtorrent/include/libtorrent/asio/ip/tcp.hpp b/libtorrent/include/libtorrent/asio/ip/tcp.hpp index 92532f12e..447210caf 100644 --- a/libtorrent/include/libtorrent/asio/ip/tcp.hpp +++ b/libtorrent/include/libtorrent/asio/ip/tcp.hpp @@ -2,7 +2,7 @@ // tcp.hpp // ~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -17,11 +17,11 @@ #include "asio/detail/push_options.hpp" -#include "asio/basic_resolver.hpp" #include "asio/basic_socket_acceptor.hpp" #include "asio/basic_socket_iostream.hpp" #include "asio/basic_stream_socket.hpp" #include "asio/ip/basic_endpoint.hpp" +#include "asio/ip/basic_resolver.hpp" #include "asio/ip/basic_resolver_iterator.hpp" #include "asio/ip/basic_resolver_query.hpp" #include "asio/detail/socket_option.hpp" @@ -34,12 +34,12 @@ namespace ip { /** * The asio::ip::tcp class contains flags necessary for TCP sockets. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Safe. * * @par Concepts: - * Protocol. + * Protocol, InternetProtocol. */ class tcp { @@ -99,23 +99,23 @@ public: /** * Implements the IPPROTO_TCP/TCP_NODELAY socket option. * - * @par Examples: + * @par Examples * Setting the option: * @code - * asio::ipv6::tcp::socket socket(io_service); + * asio::ip::tcp::socket socket(io_service); * ... - * asio::ipv6::tcp::no_delay option(true); + * asio::ip::tcp::no_delay option(true); * socket.set_option(option); * @endcode * * @par * Getting the current option value: * @code - * asio::ipv6::tcp::socket socket(io_service); + * asio::ip::tcp::socket socket(io_service); * ... - * asio::ipv6::tcp::no_delay option; + * asio::ip::tcp::no_delay option; * socket.get_option(option); - * bool is_set = option.get(); + * bool is_set = option.value(); * @endcode * * @par Concepts: @@ -128,6 +128,18 @@ public: IPPROTO_TCP, TCP_NODELAY> no_delay; #endif + /// Compare two protocols for equality. + friend bool operator==(const tcp& p1, const tcp& p2) + { + return p1.family_ == p2.family_; + } + + /// Compare two protocols for inequality. + friend bool operator!=(const tcp& p1, const tcp& p2) + { + return p1.family_ != p2.family_; + } + private: // Construct with a specific family. explicit tcp(int family) diff --git a/libtorrent/include/libtorrent/asio/ip/udp.hpp b/libtorrent/include/libtorrent/asio/ip/udp.hpp index 7cc822615..ed3bb8536 100644 --- a/libtorrent/include/libtorrent/asio/ip/udp.hpp +++ b/libtorrent/include/libtorrent/asio/ip/udp.hpp @@ -2,7 +2,7 @@ // udp.hpp // ~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -18,8 +18,8 @@ #include "asio/detail/push_options.hpp" #include "asio/basic_datagram_socket.hpp" -#include "asio/basic_resolver.hpp" #include "asio/ip/basic_endpoint.hpp" +#include "asio/ip/basic_resolver.hpp" #include "asio/ip/basic_resolver_iterator.hpp" #include "asio/ip/basic_resolver_query.hpp" #include "asio/detail/socket_types.hpp" @@ -31,12 +31,12 @@ namespace ip { /** * The asio::ip::udp class contains flags necessary for UDP sockets. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Safe. * * @par Concepts: - * Protocol. + * Protocol, InternetProtocol. */ class udp { @@ -86,6 +86,18 @@ public: /// The UDP resolver type. typedef basic_resolver resolver; + /// Compare two protocols for equality. + friend bool operator==(const udp& p1, const udp& p2) + { + return p1.family_ == p2.family_; + } + + /// Compare two protocols for inequality. + friend bool operator!=(const udp& p1, const udp& p2) + { + return p1.family_ != p2.family_; + } + private: // Construct with a specific family. explicit udp(int family) diff --git a/libtorrent/include/libtorrent/asio/is_read_buffered.hpp b/libtorrent/include/libtorrent/asio/is_read_buffered.hpp index 7c9c2b70f..091ba8c5f 100644 --- a/libtorrent/include/libtorrent/asio/is_read_buffered.hpp +++ b/libtorrent/include/libtorrent/asio/is_read_buffered.hpp @@ -2,7 +2,7 @@ // is_read_buffered.hpp // ~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/is_write_buffered.hpp b/libtorrent/include/libtorrent/asio/is_write_buffered.hpp index d0221180d..946f7468c 100644 --- a/libtorrent/include/libtorrent/asio/is_write_buffered.hpp +++ b/libtorrent/include/libtorrent/asio/is_write_buffered.hpp @@ -2,7 +2,7 @@ // is_write_buffered.hpp // ~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/placeholders.hpp b/libtorrent/include/libtorrent/asio/placeholders.hpp index 04727d786..0c1b6b4a6 100644 --- a/libtorrent/include/libtorrent/asio/placeholders.hpp +++ b/libtorrent/include/libtorrent/asio/placeholders.hpp @@ -2,14 +2,14 @@ // placeholders.hpp // ~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef ASIO_ARG_HPP -#define ASIO_ARG_HPP +#ifndef ASIO_PLACEHOLDERS_HPP +#define ASIO_PLACEHOLDERS_HPP #if defined(_MSC_VER) && (_MSC_VER >= 1200) # pragma once @@ -19,62 +19,89 @@ #include "asio/detail/push_options.hpp" #include +#include #include "asio/detail/pop_options.hpp" namespace asio { - namespace placeholders { -namespace { - -#if defined(__BORLANDC__) - -static inline boost::arg<1> error() -{ - return boost::arg<1>(); -} - -static inline boost::arg<2> bytes_transferred() -{ - return boost::arg<2>(); -} - -static inline boost::arg<2> iterator() -{ - return boost::arg<2>(); -} - -#elif defined(_MSC_VER) && (_MSC_VER < 1400) - -static boost::arg<1> error; -static boost::arg<2> bytes_transferred; -static boost::arg<2> iterator; - -#else +#if defined(GENERATING_DOCUMENTATION) /// An argument placeholder, for use with @ref boost_bind, that corresponds to /// the error argument of a handler for any of the asynchronous functions. -boost::arg<1> error; +unspecified error; /// An argument placeholder, for use with @ref boost_bind, that corresponds to /// the bytes_transferred argument of a handler for asynchronous functions such /// as asio::basic_stream_socket::async_write_some or /// asio::async_write. -boost::arg<2> bytes_transferred; +unspecified bytes_transferred; /// An argument placeholder, for use with @ref boost_bind, that corresponds to /// the iterator argument of a handler for asynchronous functions such as /// asio::basic_resolver::resolve. -boost::arg<2> iterator; +unspecified iterator; + +#elif defined(__BORLANDC__) || defined(__GNUC__) + +inline boost::arg<1> error() +{ + return boost::arg<1>(); +} + +inline boost::arg<2> bytes_transferred() +{ + return boost::arg<2>(); +} + +inline boost::arg<2> iterator() +{ + return boost::arg<2>(); +} + +#else + +namespace detail +{ + template + struct placeholder + { + static boost::arg& get() + { + static boost::arg result; + return result; + } + }; +} + +#if BOOST_WORKAROUND(BOOST_MSVC, < 1400) + +static boost::arg<1>& error + = asio::placeholders::detail::placeholder<1>::get(); +static boost::arg<2>& bytes_transferred + = asio::placeholders::detail::placeholder<2>::get(); +static boost::arg<2>& iterator + = asio::placeholders::detail::placeholder<2>::get(); + +#else + +namespace +{ + boost::arg<1>& error + = asio::placeholders::detail::placeholder<1>::get(); + boost::arg<2>& bytes_transferred + = asio::placeholders::detail::placeholder<2>::get(); + boost::arg<2>& iterator + = asio::placeholders::detail::placeholder<2>::get(); +} // namespace #endif -} // namespace +#endif } // namespace placeholders - } // namespace asio #include "asio/detail/pop_options.hpp" -#endif // ASIO_ARG_HPP +#endif // ASIO_PLACEHOLDERS_HPP diff --git a/libtorrent/include/libtorrent/asio/read.hpp b/libtorrent/include/libtorrent/asio/read.hpp index 612dfcae8..6e9772dee 100644 --- a/libtorrent/include/libtorrent/asio/read.hpp +++ b/libtorrent/include/libtorrent/asio/read.hpp @@ -2,7 +2,7 @@ // read.hpp // ~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -23,6 +23,7 @@ #include "asio/detail/pop_options.hpp" #include "asio/basic_streambuf.hpp" +#include "asio/error.hpp" namespace asio { @@ -45,7 +46,7 @@ namespace asio { * read_some function. * * @param s The stream from which the data is to be read. The type must support - * the Sync_Read_Stream concept. + * the SyncReadStream concept. * * @param buffers One or more buffers into which the data will be read. The sum * of the buffer sizes indicates the maximum number of bytes to read from the @@ -53,9 +54,9 @@ namespace asio { * * @returns The number of bytes transferred. * - * @throws Sync_Read_Stream::error_type Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @par Example: + * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code asio::read(s, asio::buffer(data, size)); @endcode * See the @ref buffer documentation for information on reading into multiple @@ -65,11 +66,10 @@ namespace asio { * @note This overload is equivalent to calling: * @code asio::read( * s, buffers, - * asio::transfer_all(), - * asio::throw_error()); @endcode + * asio::transfer_all()); @endcode */ -template -std::size_t read(Sync_Read_Stream& s, const Mutable_Buffers& buffers); +template +std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers); /// Attempt to read a certain amount of data from a stream before returning. /** @@ -85,7 +85,7 @@ std::size_t read(Sync_Read_Stream& s, const Mutable_Buffers& buffers); * read_some function. * * @param s The stream from which the data is to be read. The type must support - * the Sync_Read_Stream concept. + * the SyncReadStream concept. * * @param buffers One or more buffers into which the data will be read. The sum * of the buffer sizes indicates the maximum number of bytes to read from the @@ -95,36 +95,31 @@ std::size_t read(Sync_Read_Stream& s, const Mutable_Buffers& buffers); * whether the read operation is complete. The signature of the function object * must be: * @code bool completion_condition( - * const Sync_Read_Stream::error_type& error, // Result of latest read_some - * // operation. + * const asio::error_code& error, // Result of latest read_some + * // operation. * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * std::size_t bytes_transferred // Number of bytes transferred + * // so far. * ); @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. * * @returns The number of bytes transferred. * - * @throws Sync_Read_Stream::error_type Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @par Example: + * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code asio::read(s, asio::buffer(data, size), * asio::transfer_at_least(32)); @endcode * See the @ref buffer documentation for information on reading into multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. - * - * @note This overload is equivalent to calling: - * @code asio::read( - * s, buffers, completion_condition, - * asio::throw_error()); @endcode */ -template -std::size_t read(Sync_Read_Stream& s, const Mutable_Buffers& buffers, - Completion_Condition completion_condition); +template +std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + CompletionCondition completion_condition); /// Attempt to read a certain amount of data from a stream before returning. /** @@ -140,7 +135,7 @@ std::size_t read(Sync_Read_Stream& s, const Mutable_Buffers& buffers, * read_some function. * * @param s The stream from which the data is to be read. The type must support - * the Sync_Read_Stream concept. + * the SyncReadStream concept. * * @param buffers One or more buffers into which the data will be read. The sum * of the buffer sizes indicates the maximum number of bytes to read from the @@ -150,32 +145,24 @@ std::size_t read(Sync_Read_Stream& s, const Mutable_Buffers& buffers, * whether the read operation is complete. The signature of the function object * must be: * @code bool completion_condition( - * const Sync_Read_Stream::error_type& error, // Result of latest read_some - * // operation. + * const asio::error_code& error, // Result of latest read_some + * // operation. * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * std::size_t bytes_transferred // Number of bytes transferred + * // so far. * ); @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. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const Sync_Read_Stream::error_type& error // Result of operation. - * ); @endcode - * The error handler is only called if the completion_condition indicates that - * the operation is complete. + * @param ec Set to indicate what error occurred, if any. * - * @returns The number of bytes read. If an error occurs, and the error handler - * does not throw an exception, returns the total number of bytes successfully - * transferred prior to the error. + * @returns The number of bytes read. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. */ -template -std::size_t read(Sync_Read_Stream& s, const Mutable_Buffers& buffers, - Completion_Condition completion_condition, Error_Handler error_handler); +template +std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, asio::error_code& ec); /// Attempt to read a certain amount of data from a stream before returning. /** @@ -188,22 +175,21 @@ std::size_t read(Sync_Read_Stream& s, const Mutable_Buffers& buffers, * read_some function. * * @param s The stream from which the data is to be read. The type must support - * the Sync_Read_Stream concept. + * the SyncReadStream concept. * * @param b The basic_streambuf object into which the data will be read. * * @returns The number of bytes transferred. * - * @throws Sync_Read_Stream::error_type Thrown on failure. + * @throws asio::system_error Thrown on failure. * * @note This overload is equivalent to calling: * @code asio::read( * s, b, - * asio::transfer_all(), - * asio::throw_error()); @endcode + * asio::transfer_all()); @endcode */ -template -std::size_t read(Sync_Read_Stream& s, basic_streambuf& b); +template +std::size_t read(SyncReadStream& s, basic_streambuf& b); /// Attempt to read a certain amount of data from a stream before returning. /** @@ -216,7 +202,7 @@ std::size_t read(Sync_Read_Stream& s, basic_streambuf& b); * read_some function. * * @param s The stream from which the data is to be read. The type must support - * the Sync_Read_Stream concept. + * the SyncReadStream concept. * * @param b The basic_streambuf object into which the data will be read. * @@ -224,28 +210,23 @@ std::size_t read(Sync_Read_Stream& s, basic_streambuf& b); * whether the read operation is complete. The signature of the function object * must be: * @code bool completion_condition( - * const Sync_Read_Stream::error_type& error, // Result of latest read_some - * // operation. + * const asio::error_code& error, // Result of latest read_some + * // operation. * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * std::size_t bytes_transferred // Number of bytes transferred + * // so far. * ); @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. * * @returns The number of bytes transferred. * - * @throws Sync_Read_Stream::error_type Thrown on failure. - * - * @note This overload is equivalent to calling: - * @code asio::read( - * s, b, completion_condition, - * asio::throw_error()); @endcode + * @throws asio::system_error Thrown on failure. */ -template -std::size_t read(Sync_Read_Stream& s, basic_streambuf& b, - Completion_Condition completion_condition); +template +std::size_t read(SyncReadStream& s, basic_streambuf& b, + CompletionCondition completion_condition); /// Attempt to read a certain amount of data from a stream before returning. /** @@ -258,7 +239,7 @@ std::size_t read(Sync_Read_Stream& s, basic_streambuf& b, * read_some function. * * @param s The stream from which the data is to be read. The type must support - * the Sync_Read_Stream concept. + * the SyncReadStream concept. * * @param b The basic_streambuf object into which the data will be read. * @@ -266,32 +247,24 @@ std::size_t read(Sync_Read_Stream& s, basic_streambuf& b, * whether the read operation is complete. The signature of the function object * must be: * @code bool completion_condition( - * const Sync_Read_Stream::error_type& error, // Result of latest read_some - * // operation. + * const asio::error_code& error, // Result of latest read_some + * // operation. * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * std::size_t bytes_transferred // Number of bytes transferred + * // so far. * ); @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. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const Sync_Read_Stream::error_type& error // Result of operation. - * ); @endcode - * The error handler is only called if the completion_condition indicates that - * the operation is complete. + * @param ec Set to indicate what error occurred, if any. * - * @returns The number of bytes read. If an error occurs, and the error handler - * does not throw an exception, returns the total number of bytes successfully - * transferred prior to the error. + * @returns The number of bytes read. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. */ -template -std::size_t read(Sync_Read_Stream& s, basic_streambuf& b, - Completion_Condition completion_condition, Error_Handler error_handler); +template +std::size_t read(SyncReadStream& s, basic_streambuf& b, + CompletionCondition completion_condition, asio::error_code& ec); /*@}*/ /** @@ -316,7 +289,7 @@ std::size_t read(Sync_Read_Stream& s, basic_streambuf& b, * async_read_some function. * * @param s The stream from which the data is to be read. The type must support - * the Async_Read_Stream concept. + * the AsyncReadStream concept. * * @param buffers One or more buffers into which the data will be read. The sum * of the buffer sizes indicates the maximum number of bytes to read from the @@ -328,21 +301,20 @@ std::size_t read(Sync_Read_Stream& s, basic_streambuf& b, * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( - * const Async_Read_Stream::error_type& error, // Result of operation. + * const asio::error_code& error, // Result of operation. * - * std::size_t bytes_transferred // Number of bytes copied into - * // the buffers. If an error - * // occurred, this will be the - * // number of bytes successfully - * // transferred prior to the - * // error. + * std::size_t bytes_transferred // Number of bytes copied into the + * // buffers. If an error occurred, + * // this will be the number of + * // bytes successfully transferred + * // prior to the error. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * - * @par Example: + * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code * asio::async_read(s, asio::buffer(data, size), handler); @@ -357,10 +329,10 @@ std::size_t read(Sync_Read_Stream& s, basic_streambuf& b, * asio::transfer_all(), * handler); @endcode */ -template -void async_read(Async_Read_Stream& s, const Mutable_Buffers& buffers, - Handler handler); +template +void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, + ReadHandler handler); /// Start an asynchronous operation to read a certain amount of data from a /// stream. @@ -376,7 +348,7 @@ void async_read(Async_Read_Stream& s, const Mutable_Buffers& buffers, * @li The completion_condition function object returns true. * * @param s The stream from which the data is to be read. The type must support - * the Async_Read_Stream concept. + * the AsyncReadStream concept. * * @param buffers One or more buffers into which the data will be read. The sum * of the buffer sizes indicates the maximum number of bytes to read from the @@ -388,11 +360,11 @@ void async_read(Async_Read_Stream& s, const Mutable_Buffers& buffers, * whether the read operation is complete. The signature of the function object * must be: * @code bool completion_condition( - * const Async_Read_Stream::error_type& error, // Result of latest read_some - * // operation. + * const asio::error_code& error, // Result of latest read_some + * // operation. * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * std::size_t bytes_transferred // Number of bytes transferred + * // so far. * ); @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 @@ -402,21 +374,20 @@ void async_read(Async_Read_Stream& s, const Mutable_Buffers& buffers, * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( - * const Async_Read_Stream::error_type& error, // Result of operation. + * const asio::error_code& error, // Result of operation. * - * std::size_t bytes_transferred // Number of bytes copied into - * // the buffers. If an error - * // occurred, this will be the - * // number of bytes successfully - * // transferred prior to the - * // error. + * std::size_t bytes_transferred // Number of bytes copied into the + * // buffers. If an error occurred, + * // this will be the number of + * // bytes successfully transferred + * // prior to the error. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * - * @par Example: + * @par Example * To read into a single data buffer use the @ref buffer function as follows: * @code asio::async_read(s, * asio::buffer(data, size), @@ -426,10 +397,10 @@ void async_read(Async_Read_Stream& s, const Mutable_Buffers& buffers, * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ -template -void async_read(Async_Read_Stream& s, const Mutable_Buffers& buffers, - Completion_Condition completion_condition, Handler handler); +template +void async_read(AsyncReadStream& s, const MutableBufferSequence& buffers, + CompletionCondition completion_condition, ReadHandler handler); /// Start an asynchronous operation to read a certain amount of data from a /// stream. @@ -441,12 +412,12 @@ void async_read(Async_Read_Stream& s, const Mutable_Buffers& buffers, * * @li An error occurred. * - * @param s The stream from which the data is to be read. The type must support - * the Async_Read_Stream concept. - * * This operation is implemented in terms of one 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 + * the AsyncReadStream concept. + * * @param b A basic_streambuf object into which the data will be read. Ownership * of the streambuf is retained by the caller, which must guarantee that it * remains valid until the handler is called. @@ -455,14 +426,13 @@ void async_read(Async_Read_Stream& s, const Mutable_Buffers& buffers, * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( - * const Async_Read_Stream::error_type& error, // Result of operation. + * const asio::error_code& error, // Result of operation. * - * std::size_t bytes_transferred // Number of bytes copied into - * // the buffers. If an error - * // occurred, this will be the - * // number of bytes successfully - * // transferred prior to the - * // error. + * std::size_t bytes_transferred // Number of bytes copied into the + * // buffers. If an error occurred, + * // this will be the number of + * // bytes successfully transferred + * // prior to the error. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of @@ -475,9 +445,9 @@ void async_read(Async_Read_Stream& s, const Mutable_Buffers& buffers, * asio::transfer_all(), * handler); @endcode */ -template -void async_read(Async_Read_Stream& s, basic_streambuf& b, - Handler handler); +template +void async_read(AsyncReadStream& s, basic_streambuf& b, + ReadHandler handler); /// Start an asynchronous operation to read a certain amount of data from a /// stream. @@ -493,7 +463,7 @@ void async_read(Async_Read_Stream& s, basic_streambuf& b, * async_read_some function. * * @param s The stream from which the data is to be read. The type must support - * the Async_Read_Stream concept. + * the AsyncReadStream concept. * * @param b A basic_streambuf object into which the data will be read. Ownership * of the streambuf is retained by the caller, which must guarantee that it @@ -503,11 +473,11 @@ void async_read(Async_Read_Stream& s, basic_streambuf& b, * whether the read operation is complete. The signature of the function object * must be: * @code bool completion_condition( - * const Async_Read_Stream::error_type& error, // Result of latest read_some - * // operation. + * const asio::error_code& error, // Result of latest read_some + * // operation. * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * std::size_t bytes_transferred // Number of bytes transferred + * // so far. * ); @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 @@ -517,24 +487,23 @@ void async_read(Async_Read_Stream& s, basic_streambuf& b, * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( - * const Async_Read_Stream::error_type& error, // Result of operation. + * const asio::error_code& error, // Result of operation. * - * std::size_t bytes_transferred // Number of bytes copied into - * // the buffers. If an error - * // occurred, this will be the - * // number of bytes successfully - * // transferred prior to the - * // error. + * std::size_t bytes_transferred // Number of bytes copied into the + * // buffers. If an error occurred, + * // this will be the number of + * // bytes successfully transferred + * // prior to the error. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). */ -template -void async_read(Async_Read_Stream& s, basic_streambuf& b, - Completion_Condition completion_condition, Handler handler); +template +void async_read(AsyncReadStream& s, basic_streambuf& b, + CompletionCondition completion_condition, ReadHandler handler); /*@}*/ diff --git a/libtorrent/include/libtorrent/asio/read_until.hpp b/libtorrent/include/libtorrent/asio/read_until.hpp index 473b02613..6917ec6b8 100644 --- a/libtorrent/include/libtorrent/asio/read_until.hpp +++ b/libtorrent/include/libtorrent/asio/read_until.hpp @@ -2,7 +2,7 @@ // read_until.hpp // ~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -25,6 +25,7 @@ #include "asio/detail/pop_options.hpp" #include "asio/basic_streambuf.hpp" +#include "asio/error.hpp" namespace asio { @@ -48,7 +49,7 @@ namespace asio { * delimiter, the function returns immediately. * * @param s The stream from which the data is to be read. The type must support - * the Sync_Read_Stream concept. + * the SyncReadStream concept. * * @param b A streambuf object into which the data will be read. * @@ -57,23 +58,18 @@ namespace asio { * @returns The number of bytes in the streambuf's get area up to and including * the delimiter. * - * @throws Sync_Read_Stream::error_type Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @par Example: + * @par Example * To read data into a streambuf until a newline is encountered: * @code asio::streambuf b; * asio::read_until(s, b, '\n'); * std::istream is(&b); * std::string line; * std::getline(is, line); @endcode - * - * @note This overload is equivalent to calling: - * @code asio::read_until( - * s, b, delim, - * asio::throw_error()); @endcode */ -template -std::size_t read_until(Sync_Read_Stream& s, +template +std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, char delim); /// Read data into a streambuf until a delimiter is encountered. @@ -91,29 +87,21 @@ std::size_t read_until(Sync_Read_Stream& s, * delimiter, the function returns immediately. * * @param s The stream from which the data is to be read. The type must support - * the Sync_Read_Stream concept. + * the SyncReadStream concept. * * @param b A streambuf object into which the data will be read. * * @param delim The delimiter character. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const Sync_Read_Stream::error_type& error // Result of operation. - * ); @endcode - * The error handler is only called if the completion_condition indicates that - * the operation is complete. + * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes in the streambuf's get area up to and including - * the delimiter. Returns 0 if an error occurred and the error handler did not - * throw an exception. + * the delimiter. Returns 0 if an error occurred. */ -template -std::size_t read_until(Sync_Read_Stream& s, +template +std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, char delim, - Error_Handler error_handler); + asio::error_code& ec); /// Read data into a streambuf until a delimiter is encountered. /** @@ -130,7 +118,7 @@ std::size_t read_until(Sync_Read_Stream& s, * delimiter, the function returns immediately. * * @param s The stream from which the data is to be read. The type must support - * the Sync_Read_Stream concept. + * the SyncReadStream concept. * * @param b A streambuf object into which the data will be read. * @@ -139,23 +127,18 @@ std::size_t read_until(Sync_Read_Stream& s, * @returns The number of bytes in the streambuf's get area up to and including * the delimiter. * - * @throws Sync_Read_Stream::error_type Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @par Example: + * @par Example * To read data into a streambuf until a newline is encountered: * @code asio::streambuf b; * asio::read_until(s, b, "\r\n"); * std::istream is(&b); * std::string line; * std::getline(is, line); @endcode - * - * @note This overload is equivalent to calling: - * @code asio::read_until( - * s, b, delim, - * asio::throw_error()); @endcode */ -template -std::size_t read_until(Sync_Read_Stream& s, +template +std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, const std::string& delim); /// Read data into a streambuf until a delimiter is encountered. @@ -173,29 +156,21 @@ std::size_t read_until(Sync_Read_Stream& s, * delimiter, the function returns immediately. * * @param s The stream from which the data is to be read. The type must support - * the Sync_Read_Stream concept. + * the SyncReadStream concept. * * @param b A streambuf object into which the data will be read. * * @param delim The delimiter string. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const Sync_Read_Stream::error_type& error // Result of operation. - * ); @endcode - * The error handler is only called if the completion_condition indicates that - * the operation is complete. + * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes in the streambuf's get area up to and including - * the delimiter. Returns 0 if an error occurred and the error handler did not - * throw an exception. + * the delimiter. Returns 0 if an error occurred. */ -template -std::size_t read_until(Sync_Read_Stream& s, +template +std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, const std::string& delim, - Error_Handler error_handler); + asio::error_code& ec); /// Read data into a streambuf until a regular expression is located. /** @@ -212,7 +187,7 @@ std::size_t read_until(Sync_Read_Stream& s, * matches the regular expression, the function returns immediately. * * @param s The stream from which the data is to be read. The type must support - * the Sync_Read_Stream concept. + * the SyncReadStream concept. * * @param b A streambuf object into which the data will be read. * @@ -221,23 +196,18 @@ std::size_t read_until(Sync_Read_Stream& s, * @returns The number of bytes in the streambuf's get area up to and including * the substring that matches the regular expression. * - * @throws Sync_Read_Stream::error_type Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @par Example: + * @par Example * To read data into a streambuf until a CR-LF sequence is encountered: * @code asio::streambuf b; * asio::read_until(s, b, boost::regex("\r\n")); * std::istream is(&b); * std::string line; * std::getline(is, line); @endcode - * - * @note This overload is equivalent to calling: - * @code asio::read_until( - * s, b, expr, - * asio::throw_error()); @endcode */ -template -std::size_t read_until(Sync_Read_Stream& s, +template +std::size_t read_until(SyncReadStream& s, asio::basic_streambuf& b, const boost::regex& expr); /// Read data into a streambuf until a regular expression is located. @@ -255,28 +225,22 @@ std::size_t read_until(Sync_Read_Stream& s, * matches the regular expression, the function returns immediately. * * @param s The stream from which the data is to be read. The type must support - * the Sync_Read_Stream concept. + * the SyncReadStream concept. * * @param b A streambuf object into which the data will be read. * * @param expr The regular expression. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const Sync_Read_Stream::error_type& error // Result of operation. - * ); @endcode - * The error handler is only called if the completion_condition indicates that - * the operation is complete. + * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes in the streambuf's get area up to and including -* the substring that matches the regular expression. -*/ -template -std::size_t read_until(Sync_Read_Stream& s, - asio::basic_streambuf& b, const boost::regex& expr, - Error_Handler error_handler); + * the substring that matches the regular expression. Returns 0 if an error + * occurred. + */ +template +std::size_t read_until(SyncReadStream& s, + asio::basic_streambuf& b, const boost::regex& expr, + asio::error_code& ec); /*@}*/ /** @@ -301,7 +265,7 @@ std::size_t read_until(Sync_Read_Stream& s, * delimiter, the asynchronous operation completes immediately. * * @param s The stream from which the data is to be read. The type must support - * the Async_Read_Stream concept. + * the AsyncReadStream concept. * * @param b A streambuf object into which the data will be read. Ownership of * the streambuf is retained by the caller, which must guarantee that it remains @@ -313,23 +277,23 @@ std::size_t read_until(Sync_Read_Stream& s, * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( - * const Async_Read_Stream::error_type& error, // Result of operation. + * const asio::error_code& error, // Result of operation. * - * std::size_t bytes_transferred // The number of bytes in the - * // streambuf's get area up to - * // and including the delimiter. - * // 0 if an error occurred. + * std::size_t bytes_transferred // The number of bytes in the + * // streambuf's get area up to + * // and including the delimiter. + * // 0 if an error occurred. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * - * @par Example: + * @par Example * To asynchronously read data into a streambuf until a newline is encountered: * @code asio::streambuf b; * ... - * void handler(const asio::error& e, std::size_t size) + * void handler(const asio::error_code& e, std::size_t size) * { * if (!e) * { @@ -342,9 +306,10 @@ std::size_t read_until(Sync_Read_Stream& s, * ... * asio::async_read_until(s, b, '\n', handler); @endcode */ -template -void async_read_until(Async_Read_Stream& s, - asio::basic_streambuf& b, char delim, Handler handler); +template +void async_read_until(AsyncReadStream& s, + asio::basic_streambuf& b, + char delim, ReadHandler handler); /// Start an asynchronous operation to read data into a streambuf until a /// delimiter is encountered. @@ -363,7 +328,7 @@ void async_read_until(Async_Read_Stream& s, * delimiter, the asynchronous operation completes immediately. * * @param s The stream from which the data is to be read. The type must support - * the Async_Read_Stream concept. + * the AsyncReadStream concept. * * @param b A streambuf object into which the data will be read. Ownership of * the streambuf is retained by the caller, which must guarantee that it remains @@ -375,23 +340,23 @@ void async_read_until(Async_Read_Stream& s, * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( - * const Async_Read_Stream::error_type& error, // Result of operation. + * const asio::error_code& error, // Result of operation. * - * std::size_t bytes_transferred // The number of bytes in the - * // streambuf's get area up to - * // and including the delimiter. - * // 0 if an error occurred. + * std::size_t bytes_transferred // The number of bytes in the + * // streambuf's get area up to + * // and including the delimiter. + * // 0 if an error occurred. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * - * @par Example: + * @par Example * To asynchronously read data into a streambuf until a newline is encountered: * @code asio::streambuf b; * ... - * void handler(const asio::error& e, std::size_t size) + * void handler(const asio::error_code& e, std::size_t size) * { * if (!e) * { @@ -404,10 +369,10 @@ void async_read_until(Async_Read_Stream& s, * ... * asio::async_read_until(s, b, "\r\n", handler); @endcode */ -template -void async_read_until(Async_Read_Stream& s, - asio::basic_streambuf& b, const std::string& delim, - Handler handler); +template +void async_read_until(AsyncReadStream& s, + asio::basic_streambuf& b, const std::string& delim, + ReadHandler handler); /// Start an asynchronous operation to read data into a streambuf until a /// regular expression is located. @@ -427,7 +392,7 @@ void async_read_until(Async_Read_Stream& s, * that matches the regular expression, the function returns immediately. * * @param s The stream from which the data is to be read. The type must support - * the Async_Read_Stream concept. + * the AsyncReadStream concept. * * @param b A streambuf object into which the data will be read. Ownership of * the streambuf is retained by the caller, which must guarantee that it remains @@ -439,26 +404,26 @@ void async_read_until(Async_Read_Stream& s, * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( - * const Async_Read_Stream::error_type& error, // Result of operation. + * const asio::error_code& error, // Result of operation. * - * std::size_t bytes_transferred // The number of bytes in the - * // streambuf's get area up to - * // and including the substring - * // that matches the regular - * // expression. 0 if an error - * // occurred. + * std::size_t bytes_transferred // The number of bytes in the + * // streambuf's get area up to + * // and including the substring + * // that matches the regular. + * // expression. 0 if an error + * // occurred. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * - * @par Example: + * @par Example * To asynchronously read data into a streambuf until a CR-LF sequence is * encountered: * @code asio::streambuf b; * ... - * void handler(const asio::error& e, std::size_t size) + * void handler(const asio::error_code& e, std::size_t size) * { * if (!e) * { @@ -471,10 +436,10 @@ void async_read_until(Async_Read_Stream& s, * ... * asio::async_read_until(s, b, boost::regex("\r\n"), handler); @endcode */ -template -void async_read_until(Async_Read_Stream& s, +template +void async_read_until(AsyncReadStream& s, asio::basic_streambuf& b, const boost::regex& expr, - Handler handler); + ReadHandler handler); /*@}*/ diff --git a/libtorrent/include/libtorrent/asio/socket_acceptor_service.hpp b/libtorrent/include/libtorrent/asio/socket_acceptor_service.hpp index 8c7eb43c9..965bff39e 100644 --- a/libtorrent/include/libtorrent/asio/socket_acceptor_service.hpp +++ b/libtorrent/include/libtorrent/asio/socket_acceptor_service.hpp @@ -2,7 +2,7 @@ // socket_acceptor_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -18,10 +18,12 @@ #include "asio/detail/push_options.hpp" #include "asio/basic_socket.hpp" +#include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/detail/epoll_reactor.hpp" #include "asio/detail/kqueue_reactor.hpp" #include "asio/detail/select_reactor.hpp" +#include "asio/detail/service_base.hpp" #include "asio/detail/reactive_socket_service.hpp" #include "asio/detail/win_iocp_socket_service.hpp" @@ -30,9 +32,18 @@ namespace asio { /// Default service implementation for a socket acceptor. template class socket_acceptor_service +#if defined(GENERATING_DOCUMENTATION) : public asio::io_service::service +#else + : public asio::detail::service_base > +#endif { public: +#if defined(GENERATING_DOCUMENTATION) + /// The unique service identifier. + static asio::io_service::id id; +#endif + /// The protocol type. typedef Protocol protocol_type; @@ -71,7 +82,8 @@ public: /// Construct a new socket acceptor service for the specified io_service. explicit socket_acceptor_service(asio::io_service& io_service) - : asio::io_service::service(io_service), + : asio::detail::service_base< + socket_acceptor_service >(io_service), service_impl_(asio::use_service(io_service)) { } @@ -94,50 +106,53 @@ public: } /// Open a new socket acceptor implementation. - template - void open(implementation_type& impl, const protocol_type& protocol, - Error_Handler error_handler) + asio::error_code open(implementation_type& impl, + const protocol_type& protocol, asio::error_code& ec) { - service_impl_.open(impl, protocol, error_handler); + return service_impl_.open(impl, protocol, ec); } /// Assign an existing native acceptor to a socket acceptor. - template - void assign(implementation_type& impl, const protocol_type& protocol, - const native_type& native_acceptor, Error_Handler error_handler) + asio::error_code assign(implementation_type& impl, + const protocol_type& protocol, const native_type& native_acceptor, + asio::error_code& ec) { - service_impl_.assign(impl, protocol, native_acceptor, error_handler); + return service_impl_.assign(impl, protocol, native_acceptor, ec); + } + + /// Determine whether the acceptor is open. + bool is_open(const implementation_type& impl) const + { + return service_impl_.is_open(impl); } /// Cancel all asynchronous operations associated with the acceptor. - template - void cancel(implementation_type& impl, Error_Handler error_handler) + asio::error_code cancel(implementation_type& impl, + asio::error_code& ec) { - service_impl_.cancel(impl, error_handler); + return service_impl_.cancel(impl, ec); } /// Bind the socket acceptor to the specified local endpoint. - template - void bind(implementation_type& impl, const endpoint_type& endpoint, - Error_Handler error_handler) + asio::error_code bind(implementation_type& impl, + const endpoint_type& endpoint, asio::error_code& ec) { - service_impl_.bind(impl, endpoint, error_handler); + return service_impl_.bind(impl, endpoint, ec); } /// Place the socket acceptor into the state where it will listen for new /// connections. - template - void listen(implementation_type& impl, int backlog, - Error_Handler error_handler) + asio::error_code listen(implementation_type& impl, int backlog, + asio::error_code& ec) { - service_impl_.listen(impl, backlog, error_handler); + return service_impl_.listen(impl, backlog, ec); } /// Close a socket acceptor implementation. - template - void close(implementation_type& impl, Error_Handler error_handler) + asio::error_code close(implementation_type& impl, + asio::error_code& ec) { - service_impl_.close(impl, error_handler); + return service_impl_.close(impl, ec); } /// Get the native acceptor implementation. @@ -147,64 +162,52 @@ public: } /// Set a socket option. - template - void set_option(implementation_type& impl, const Option& option, - Error_Handler error_handler) + template + asio::error_code set_option(implementation_type& impl, + const SettableSocketOption& option, asio::error_code& ec) { - service_impl_.set_option(impl, option, error_handler); + return service_impl_.set_option(impl, option, ec); } - /// Set a socket option. - template - void get_option(implementation_type& impl, Option& option, - Error_Handler error_handler) + /// Get a socket option. + template + asio::error_code get_option(const implementation_type& impl, + GettableSocketOption& option, asio::error_code& ec) const { - service_impl_.get_option(impl, option, error_handler); + return service_impl_.get_option(impl, option, ec); + } + + /// Perform an IO control command on the socket. + template + asio::error_code io_control(implementation_type& impl, + IoControlCommand& command, asio::error_code& ec) + { + return service_impl_.io_control(impl, command, ec); } /// Get the local endpoint. - template endpoint_type local_endpoint(const implementation_type& impl, - Error_Handler error_handler) const + asio::error_code& ec) const { - endpoint_type endpoint; - service_impl_.get_local_endpoint(impl, endpoint, error_handler); - return endpoint; + return service_impl_.local_endpoint(impl, ec); } /// Accept a new connection. - template - void accept(implementation_type& impl, - basic_socket& peer, - Error_Handler error_handler) + template + asio::error_code accept(implementation_type& impl, + basic_socket& peer, + endpoint_type* peer_endpoint, asio::error_code& ec) { - service_impl_.accept(impl, peer, error_handler); - } - - /// Accept a new connection. - template - void accept_endpoint(implementation_type& impl, - basic_socket& peer, - endpoint_type& peer_endpoint, Error_Handler error_handler) - { - service_impl_.accept_endpoint(impl, peer, peer_endpoint, error_handler); + return service_impl_.accept(impl, peer, peer_endpoint, ec); } /// Start an asynchronous accept. - template + template void async_accept(implementation_type& impl, - basic_socket& peer, Handler handler) + basic_socket& peer, + endpoint_type* peer_endpoint, AcceptHandler handler) { - service_impl_.async_accept(impl, peer, handler); - } - - /// Start an asynchronous accept. - template - void async_accept_endpoint(implementation_type& impl, - basic_socket& peer, - endpoint_type& peer_endpoint, Handler handler) - { - service_impl_.async_accept_endpoint(impl, peer, peer_endpoint, handler); + service_impl_.async_accept(impl, peer, peer_endpoint, handler); } private: diff --git a/libtorrent/include/libtorrent/asio/socket_base.hpp b/libtorrent/include/libtorrent/asio/socket_base.hpp index 48e37357c..1239989a9 100644 --- a/libtorrent/include/libtorrent/asio/socket_base.hpp +++ b/libtorrent/include/libtorrent/asio/socket_base.hpp @@ -2,7 +2,7 @@ // socket_base.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -78,7 +78,7 @@ public: /** * Implements the SOL_SOCKET/SO_BROADCAST socket option. * - * @par Examples: + * @par Examples * Setting the option: * @code * asio::ip::udp::socket socket(io_service); @@ -94,7 +94,7 @@ public: * ... * asio::socket_base::broadcast option; * socket.get_option(option); - * bool is_set = option.get(); + * bool is_set = option.value(); * @endcode * * @par Concepts: @@ -107,11 +107,44 @@ public: SOL_SOCKET, SO_BROADCAST> broadcast; #endif + /// Socket option to enable socket-level debugging. + /** + * Implements the SOL_SOCKET/SO_DEBUG socket option. + * + * @par Examples + * Setting the option: + * @code + * asio::ip::tcp::socket socket(io_service); + * ... + * asio::socket_base::debug option(true); + * socket.set_option(option); + * @endcode + * + * @par + * Getting the current option value: + * @code + * asio::ip::tcp::socket socket(io_service); + * ... + * asio::socket_base::debug option; + * socket.get_option(option); + * bool is_set = option.value(); + * @endcode + * + * @par Concepts: + * Socket_Option, Boolean_Socket_Option. + */ +#if defined(GENERATING_DOCUMENTATION) + typedef implementation_defined debug; +#else + typedef asio::detail::socket_option::boolean< + SOL_SOCKET, SO_DEBUG> debug; +#endif + /// Socket option to prevent routing, use local interfaces only. /** * Implements the SOL_SOCKET/SO_DONTROUTE socket option. * - * @par Examples: + * @par Examples * Setting the option: * @code * asio::ip::udp::socket socket(io_service); @@ -127,7 +160,7 @@ public: * ... * asio::socket_base::do_not_route option; * socket.get_option(option); - * bool is_set = option.get(); + * bool is_set = option.value(); * @endcode * * @par Concepts: @@ -144,7 +177,7 @@ public: /** * Implements the SOL_SOCKET/SO_KEEPALIVE socket option. * - * @par Examples: + * @par Examples * Setting the option: * @code * asio::ip::tcp::socket socket(io_service); @@ -160,7 +193,7 @@ public: * ... * asio::socket_base::keep_alive option; * socket.get_option(option); - * bool is_set = option.get(); + * bool is_set = option.value(); * @endcode * * @par Concepts: @@ -177,7 +210,7 @@ public: /** * Implements the SOL_SOCKET/SO_SNDBUF socket option. * - * @par Examples: + * @par Examples * Setting the option: * @code * asio::ip::tcp::socket socket(io_service); @@ -193,7 +226,7 @@ public: * ... * asio::socket_base::send_buffer_size option; * socket.get_option(option); - * int size = option.get(); + * int size = option.value(); * @endcode * * @par Concepts: @@ -210,7 +243,7 @@ public: /** * Implements the SOL_SOCKET/SO_SNDLOWAT socket option. * - * @par Examples: + * @par Examples * Setting the option: * @code * asio::ip::tcp::socket socket(io_service); @@ -226,7 +259,7 @@ public: * ... * asio::socket_base::send_low_watermark option; * socket.get_option(option); - * int size = option.get(); + * int size = option.value(); * @endcode * * @par Concepts: @@ -243,7 +276,7 @@ public: /** * Implements the SOL_SOCKET/SO_RCVBUF socket option. * - * @par Examples: + * @par Examples * Setting the option: * @code * asio::ip::tcp::socket socket(io_service); @@ -259,7 +292,7 @@ public: * ... * asio::socket_base::receive_buffer_size option; * socket.get_option(option); - * int size = option.get(); + * int size = option.value(); * @endcode * * @par Concepts: @@ -276,7 +309,7 @@ public: /** * Implements the SOL_SOCKET/SO_RCVLOWAT socket option. * - * @par Examples: + * @par Examples * Setting the option: * @code * asio::ip::tcp::socket socket(io_service); @@ -292,7 +325,7 @@ public: * ... * asio::socket_base::receive_low_watermark option; * socket.get_option(option); - * int size = option.get(); + * int size = option.value(); * @endcode * * @par Concepts: @@ -310,7 +343,7 @@ public: /** * Implements the SOL_SOCKET/SO_REUSEADDR socket option. * - * @par Examples: + * @par Examples * Setting the option: * @code * asio::ip::tcp::acceptor acceptor(io_service); @@ -326,7 +359,7 @@ public: * ... * asio::socket_base::reuse_address option; * acceptor.get_option(option); - * bool is_set = option.get(); + * bool is_set = option.value(); * @endcode * * @par Concepts: @@ -344,7 +377,7 @@ public: /** * Implements the SOL_SOCKET/SO_LINGER socket option. * - * @par Examples: + * @par Examples * Setting the option: * @code * asio::ip::tcp::socket socket(io_service); @@ -380,7 +413,7 @@ public: * operation is permitted to fail with asio::error::connection_aborted. * By default the option is false. * - * @par Examples: + * @par Examples * Setting the option: * @code * asio::ip::tcp::acceptor acceptor(io_service); @@ -396,7 +429,7 @@ public: * ... * asio::socket_base::enable_connection_aborted option; * acceptor.get_option(option); - * bool is_set = option.get(); + * bool is_set = option.value(); * @endcode * * @par Concepts: @@ -415,7 +448,7 @@ public: /** * Implements the FIONBIO IO control command. * - * @par Example: + * @par Example * @code * asio::ip::tcp::socket socket(io_service); * ... @@ -437,7 +470,7 @@ public: /** * Implements the FIONREAD IO control command. * - * @par Example: + * @par Example * @code * asio::ip::tcp::socket socket(io_service); * ... diff --git a/libtorrent/include/libtorrent/asio/ssl.hpp b/libtorrent/include/libtorrent/asio/ssl.hpp index 2d4621340..3f2d2750c 100644 --- a/libtorrent/include/libtorrent/asio/ssl.hpp +++ b/libtorrent/include/libtorrent/asio/ssl.hpp @@ -2,7 +2,7 @@ // ssl.hpp // ~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/ssl/basic_context.hpp b/libtorrent/include/libtorrent/asio/ssl/basic_context.hpp index 2c25e81a8..b85a01c1d 100644 --- a/libtorrent/include/libtorrent/asio/ssl/basic_context.hpp +++ b/libtorrent/include/libtorrent/asio/ssl/basic_context.hpp @@ -23,9 +23,10 @@ #include #include "asio/detail/pop_options.hpp" -#include "asio/error_handler.hpp" +#include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/ssl/context_base.hpp" +#include "asio/detail/throw_error.hpp" namespace asio { namespace ssl { @@ -76,11 +77,13 @@ public: * the context_base class. The options are bitwise-ored with any existing * value for the options. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ void set_options(options o) { - service_.set_options(impl_, o, throw_error()); + asio::error_code ec; + service_.set_options(impl_, o, ec); + asio::detail::throw_error(ec); } /// Set options on the context. @@ -91,17 +94,12 @@ public: * the context_base class. The options are bitwise-ored with any existing * value for the options. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. */ - template - void set_options(options o, Error_Handler error_handler) + asio::error_code set_options(options o, + asio::error_code& ec) { - service_.set_options(impl_, o, error_handler); + return service_.set_options(impl_, o, ec); } /// Set the peer verification mode. @@ -112,11 +110,13 @@ public: * @param v A bitmask of peer verification modes. The available verify_mode * values are defined in the context_base class. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ void set_verify_mode(verify_mode v) { - service_.set_verify_mode(impl_, v, throw_error()); + asio::error_code ec; + service_.set_verify_mode(impl_, v, ec); + asio::detail::throw_error(ec); } /// Set the peer verification mode. @@ -127,17 +127,12 @@ public: * @param v A bitmask of peer verification modes. The available verify_mode * values are defined in the context_base class. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. */ - template - void set_verify_mode(verify_mode v, Error_Handler error_handler) + asio::error_code set_verify_mode(verify_mode v, + asio::error_code& ec) { - service_.set_verify_mode(impl_, v, error_handler); + return service_.set_verify_mode(impl_, v, ec); } /// Load a certification authority file for performing verification. @@ -148,11 +143,13 @@ public: * @param filename The name of a file containing certification authority * certificates in PEM format. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ void load_verify_file(const std::string& filename) { - service_.load_verify_file(impl_, filename, throw_error()); + asio::error_code ec; + service_.load_verify_file(impl_, filename, ec); + asio::detail::throw_error(ec); } /// Load a certification authority file for performing verification. @@ -163,18 +160,12 @@ public: * @param filename The name of a file containing certification authority * certificates in PEM format. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. */ - template - void load_verify_file(const std::string& filename, - Error_Handler error_handler) + asio::error_code load_verify_file(const std::string& filename, + asio::error_code& ec) { - service_.load_verify_file(impl_, filename, error_handler); + return service_.load_verify_file(impl_, filename, ec); } /// Add a directory containing certificate authority files to be used for @@ -187,11 +178,13 @@ public: * * @param path The name of a directory containing the certificates. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ void add_verify_path(const std::string& path) { - service_.add_verify_path(impl_, path, throw_error()); + asio::error_code ec; + service_.add_verify_path(impl_, path, ec); + asio::detail::throw_error(ec); } /// Add a directory containing certificate authority files to be used for @@ -204,17 +197,12 @@ public: * * @param path The name of a directory containing the certificates. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. */ - template - void add_verify_path(const std::string& path, Error_Handler error_handler) + asio::error_code add_verify_path(const std::string& path, + asio::error_code& ec) { - service_.add_verify_path(impl_, path, error_handler); + return service_.add_verify_path(impl_, path, ec); } /// Use a certificate from a file. @@ -225,11 +213,13 @@ public: * * @param format The file format (ASN.1 or PEM). * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ void use_certificate_file(const std::string& filename, file_format format) { - service_.use_certificate_file(impl_, filename, format, throw_error()); + asio::error_code ec; + service_.use_certificate_file(impl_, filename, format, ec); + asio::detail::throw_error(ec); } /// Use a certificate from a file. @@ -240,18 +230,12 @@ public: * * @param format The file format (ASN.1 or PEM). * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. */ - template - void use_certificate_file(const std::string& filename, file_format format, - Error_Handler error_handler) + asio::error_code use_certificate_file(const std::string& filename, + file_format format, asio::error_code& ec) { - service_.use_certificate_file(impl_, filename, format, error_handler); + return service_.use_certificate_file(impl_, filename, format, ec); } /// Use a certificate chain from a file. @@ -262,11 +246,13 @@ public: * @param filename The name of the file containing the certificate. The file * must use the PEM format. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ void use_certificate_chain_file(const std::string& filename) { - service_.use_certificate_chain_file(impl_, filename, throw_error()); + asio::error_code ec; + service_.use_certificate_chain_file(impl_, filename, ec); + asio::detail::throw_error(ec); } /// Use a certificate chain from a file. @@ -277,18 +263,12 @@ public: * @param filename The name of the file containing the certificate. The file * must use the PEM format. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. */ - template - void use_certificate_chain_file(const std::string& filename, - Error_Handler error_handler) + asio::error_code use_certificate_chain_file( + const std::string& filename, asio::error_code& ec) { - service_.use_certificate_chain_file(impl_, filename, error_handler); + return service_.use_certificate_chain_file(impl_, filename, ec); } /// Use a private key from a file. @@ -299,11 +279,13 @@ public: * * @param format The file format (ASN.1 or PEM). * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ void use_private_key_file(const std::string& filename, file_format format) { - service_.use_private_key_file(impl_, filename, format, throw_error()); + asio::error_code ec; + service_.use_private_key_file(impl_, filename, format, ec); + asio::detail::throw_error(ec); } /// Use a private key from a file. @@ -314,18 +296,12 @@ public: * * @param format The file format (ASN.1 or PEM). * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. */ - template - void use_private_key_file(const std::string& filename, file_format format, - Error_Handler error_handler) + asio::error_code use_private_key_file(const std::string& filename, + file_format format, asio::error_code& ec) { - service_.use_private_key_file(impl_, filename, format, error_handler); + return service_.use_private_key_file(impl_, filename, format, ec); } /// Use an RSA private key from a file. @@ -337,11 +313,13 @@ public: * * @param format The file format (ASN.1 or PEM). * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ void use_rsa_private_key_file(const std::string& filename, file_format format) { - service_.use_rsa_private_key_file(impl_, filename, format, throw_error()); + asio::error_code ec; + service_.use_rsa_private_key_file(impl_, filename, format, ec); + asio::detail::throw_error(ec); } /// Use an RSA private key from a file. @@ -353,18 +331,13 @@ public: * * @param format The file format (ASN.1 or PEM). * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. */ - template - void use_rsa_private_key_file(const std::string& filename, file_format format, - Error_Handler error_handler) + asio::error_code use_rsa_private_key_file( + const std::string& filename, file_format format, + asio::error_code& ec) { - service_.use_rsa_private_key_file(impl_, filename, format, error_handler); + return service_.use_rsa_private_key_file(impl_, filename, format, ec); } /// Use the specified file to obtain the temporary Diffie-Hellman parameters. @@ -375,11 +348,13 @@ public: * @param filename The name of the file containing the Diffie-Hellman * parameters. The file must use the PEM format. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ void use_tmp_dh_file(const std::string& filename) { - service_.use_tmp_dh_file(impl_, filename, throw_error()); + asio::error_code ec; + service_.use_tmp_dh_file(impl_, filename, ec); + asio::detail::throw_error(ec); } /// Use the specified file to obtain the temporary Diffie-Hellman parameters. @@ -390,17 +365,12 @@ public: * @param filename The name of the file containing the Diffie-Hellman * parameters. The file must use the PEM format. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. */ - template - void use_tmp_dh_file(const std::string& filename, Error_Handler error_handler) + asio::error_code use_tmp_dh_file(const std::string& filename, + asio::error_code& ec) { - service_.use_tmp_dh_file(impl_, filename, error_handler); + return service_.use_tmp_dh_file(impl_, filename, ec); } /// Set the password callback. @@ -416,12 +386,14 @@ public: * ); @endcode * The return value of the callback is a string containing the password. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ - template - void set_password_callback(Password_Callback callback) + template + void set_password_callback(PasswordCallback callback) { - service_.set_password_callback(impl_, callback, throw_error()); + asio::error_code ec; + service_.set_password_callback(impl_, callback, ec); + asio::detail::throw_error(ec); } /// Set the password callback. @@ -437,18 +409,13 @@ public: * ); @endcode * The return value of the callback is a string containing the password. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. */ - template - void set_password_callback(Password_Callback callback, - Error_Handler error_handler) + template + asio::error_code set_password_callback(PasswordCallback callback, + asio::error_code& ec) { - service_.set_password_callback(impl_, callback, error_handler); + return service_.set_password_callback(impl_, callback, ec); } private: diff --git a/libtorrent/include/libtorrent/asio/ssl/context_service.hpp b/libtorrent/include/libtorrent/asio/ssl/context_service.hpp index 636b970c3..f0698a58f 100644 --- a/libtorrent/include/libtorrent/asio/ssl/context_service.hpp +++ b/libtorrent/include/libtorrent/asio/ssl/context_service.hpp @@ -23,7 +23,9 @@ #include #include "asio/detail/pop_options.hpp" +#include "asio/error.hpp" #include "asio/io_service.hpp" +#include "asio/detail/service_base.hpp" #include "asio/ssl/context_base.hpp" #include "asio/ssl/detail/openssl_context_service.hpp" @@ -32,13 +34,22 @@ namespace ssl { /// Default service implementation for a context. class context_service +#if defined(GENERATING_DOCUMENTATION) : public asio::io_service::service +#else + : public asio::detail::service_base +#endif { private: // The type of the platform-specific implementation. typedef detail::openssl_context_service service_impl_type; public: +#if defined(GENERATING_DOCUMENTATION) + /// The unique service identifier. + static asio::io_service::id id; +#endif + /// The type of the context. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined impl_type; @@ -48,7 +59,7 @@ public: /// Constructor. explicit context_service(asio::io_service& io_service) - : asio::io_service::service(io_service), + : asio::detail::service_base(io_service), service_impl_(asio::use_service(io_service)) { } @@ -77,85 +88,78 @@ public: } /// Set options on the context. - template - void set_options(impl_type& impl, context_base::options o, - Error_Handler error_handler) + asio::error_code set_options(impl_type& impl, + context_base::options o, asio::error_code& ec) { - service_impl_.set_options(impl, o, error_handler); + return service_impl_.set_options(impl, o, ec); } /// Set peer verification mode. - template - void set_verify_mode(impl_type& impl, context_base::verify_mode v, - Error_Handler error_handler) + asio::error_code set_verify_mode(impl_type& impl, + context_base::verify_mode v, asio::error_code& ec) { - service_impl_.set_verify_mode(impl, v, error_handler); + return service_impl_.set_verify_mode(impl, v, ec); } /// Load a certification authority file for performing verification. - template - void load_verify_file(impl_type& impl, const std::string& filename, - Error_Handler error_handler) + asio::error_code load_verify_file(impl_type& impl, + const std::string& filename, asio::error_code& ec) { - service_impl_.load_verify_file(impl, filename, error_handler); + return service_impl_.load_verify_file(impl, filename, ec); } /// Add a directory containing certification authority files to be used for /// performing verification. - template - void add_verify_path(impl_type& impl, const std::string& path, - Error_Handler error_handler) + asio::error_code add_verify_path(impl_type& impl, + const std::string& path, asio::error_code& ec) { - service_impl_.add_verify_path(impl, path, error_handler); + return service_impl_.add_verify_path(impl, path, ec); } /// Use a certificate from a file. - template - void use_certificate_file(impl_type& impl, const std::string& filename, - context_base::file_format format, Error_Handler error_handler) + asio::error_code use_certificate_file(impl_type& impl, + const std::string& filename, context_base::file_format format, + asio::error_code& ec) { - service_impl_.use_certificate_file(impl, filename, format, error_handler); + return service_impl_.use_certificate_file(impl, filename, format, ec); } /// Use a certificate chain from a file. - template - void use_certificate_chain_file(impl_type& impl, const std::string& filename, - Error_Handler error_handler) + asio::error_code use_certificate_chain_file(impl_type& impl, + const std::string& filename, asio::error_code& ec) { - service_impl_.use_certificate_chain_file(impl, filename, error_handler); + return service_impl_.use_certificate_chain_file(impl, filename, ec); } /// Use a private key from a file. - template - void use_private_key_file(impl_type& impl, const std::string& filename, - context_base::file_format format, Error_Handler error_handler) + asio::error_code use_private_key_file(impl_type& impl, + const std::string& filename, context_base::file_format format, + asio::error_code& ec) { - service_impl_.use_private_key_file(impl, filename, format, error_handler); + return service_impl_.use_private_key_file(impl, filename, format, ec); } /// Use an RSA private key from a file. - template - void use_rsa_private_key_file(impl_type& impl, const std::string& filename, - context_base::file_format format, Error_Handler error_handler) + asio::error_code use_rsa_private_key_file(impl_type& impl, + const std::string& filename, context_base::file_format format, + asio::error_code& ec) { - service_impl_.use_rsa_private_key_file(impl, filename, format, - error_handler); + return service_impl_.use_rsa_private_key_file(impl, filename, format, ec); } /// Use the specified file to obtain the temporary Diffie-Hellman parameters. - template - void use_tmp_dh_file(impl_type& impl, const std::string& filename, - Error_Handler error_handler) + asio::error_code use_tmp_dh_file(impl_type& impl, + const std::string& filename, asio::error_code& ec) { - service_impl_.use_tmp_dh_file(impl, filename, error_handler); + return service_impl_.use_tmp_dh_file(impl, filename, ec); } /// Set the password callback. - template - void set_password_callback(impl_type& impl, Password_Callback callback, - Error_Handler error_handler) + template + asio::error_code set_password_callback(impl_type& impl, + PasswordCallback callback, asio::error_code& ec) { - service_impl_.set_password_callback(impl, callback, error_handler); + return service_impl_.set_password_callback(impl, callback, ec); } private: diff --git a/libtorrent/include/libtorrent/asio/ssl/detail/openssl_context_service.hpp b/libtorrent/include/libtorrent/asio/ssl/detail/openssl_context_service.hpp index 723bcadf2..96d610801 100644 --- a/libtorrent/include/libtorrent/asio/ssl/detail/openssl_context_service.hpp +++ b/libtorrent/include/libtorrent/asio/ssl/detail/openssl_context_service.hpp @@ -26,6 +26,7 @@ #include "asio/error.hpp" #include "asio/io_service.hpp" +#include "asio/detail/service_base.hpp" #include "asio/ssl/context_base.hpp" #include "asio/ssl/detail/openssl_init.hpp" #include "asio/ssl/detail/openssl_types.hpp" @@ -35,7 +36,7 @@ namespace ssl { namespace detail { class openssl_context_service - : public asio::io_service::service + : public asio::detail::service_base { public: // The native type of the context. @@ -47,7 +48,7 @@ public: // Constructor. openssl_context_service(asio::io_service& io_service) - : asio::io_service::service(io_service) + : asio::detail::service_base(io_service) { } @@ -130,64 +131,58 @@ public: } // Set options on the context. - template - void set_options(impl_type& impl, context_base::options o, - Error_Handler error_handler) + asio::error_code set_options(impl_type& impl, + context_base::options o, asio::error_code& ec) { ::SSL_CTX_set_options(impl, o); - asio::error e; - error_handler(e); + ec = asio::error_code(); + return ec; } // Set peer verification mode. - template - void set_verify_mode(impl_type& impl, context_base::verify_mode v, - Error_Handler error_handler) + asio::error_code set_verify_mode(impl_type& impl, + context_base::verify_mode v, asio::error_code& ec) { ::SSL_CTX_set_verify(impl, v, 0); - asio::error e; - error_handler(e); + ec = asio::error_code(); + return ec; } // Load a certification authority file for performing verification. - template - void load_verify_file(impl_type& impl, const std::string& filename, - Error_Handler error_handler) + asio::error_code load_verify_file(impl_type& impl, + const std::string& filename, asio::error_code& ec) { if (::SSL_CTX_load_verify_locations(impl, filename.c_str(), 0) != 1) { - asio::error e(asio::error::invalid_argument); - error_handler(e); - return; + ec = asio::error::invalid_argument; + return ec; } - asio::error e; - error_handler(e); + ec = asio::error_code(); + return ec; } // Add a directory containing certification authority files to be used for // performing verification. - template - void add_verify_path(impl_type& impl, const std::string& path, - Error_Handler error_handler) + asio::error_code add_verify_path(impl_type& impl, + const std::string& path, asio::error_code& ec) { if (::SSL_CTX_load_verify_locations(impl, 0, path.c_str()) != 1) { - asio::error e(asio::error::invalid_argument); - error_handler(e); - return; + ec = asio::error::invalid_argument; + return ec; } - asio::error e; - error_handler(e); + ec = asio::error_code(); + return ec; } // Use a certificate from a file. - template - void use_certificate_file(impl_type& impl, const std::string& filename, - context_base::file_format format, Error_Handler error_handler) + asio::error_code use_certificate_file(impl_type& impl, + const std::string& filename, context_base::file_format format, + asio::error_code& ec) { int file_type; switch (format) @@ -200,43 +195,39 @@ public: break; default: { - asio::error e(asio::error::invalid_argument); - error_handler(e); - return; + ec = asio::error::invalid_argument; + return ec; } } if (::SSL_CTX_use_certificate_file(impl, filename.c_str(), file_type) != 1) { - asio::error e(asio::error::invalid_argument); - error_handler(e); - return; + ec = asio::error::invalid_argument; + return ec; } - asio::error e; - error_handler(e); + ec = asio::error_code(); + return ec; } // Use a certificate chain from a file. - template - void use_certificate_chain_file(impl_type& impl, const std::string& filename, - Error_Handler error_handler) + asio::error_code use_certificate_chain_file(impl_type& impl, + const std::string& filename, asio::error_code& ec) { if (::SSL_CTX_use_certificate_chain_file(impl, filename.c_str()) != 1) { - asio::error e(asio::error::invalid_argument); - error_handler(e); - return; + ec = asio::error::invalid_argument; + return ec; } - asio::error e; - error_handler(e); + ec = asio::error_code(); + return ec; } // Use a private key from a file. - template - void use_private_key_file(impl_type& impl, const std::string& filename, - context_base::file_format format, Error_Handler error_handler) + asio::error_code use_private_key_file(impl_type& impl, + const std::string& filename, context_base::file_format format, + asio::error_code& ec) { int file_type; switch (format) @@ -249,27 +240,25 @@ public: break; default: { - asio::error e(asio::error::invalid_argument); - error_handler(e); - return; + ec = asio::error::invalid_argument; + return ec; } } if (::SSL_CTX_use_PrivateKey_file(impl, filename.c_str(), file_type) != 1) { - asio::error e(asio::error::invalid_argument); - error_handler(e); - return; + ec = asio::error::invalid_argument; + return ec; } - asio::error e; - error_handler(e); + ec = asio::error_code(); + return ec; } // Use an RSA private key from a file. - template - void use_rsa_private_key_file(impl_type& impl, const std::string& filename, - context_base::file_format format, Error_Handler error_handler) + asio::error_code use_rsa_private_key_file(impl_type& impl, + const std::string& filename, context_base::file_format format, + asio::error_code& ec) { int file_type; switch (format) @@ -282,44 +271,39 @@ public: break; default: { - asio::error e(asio::error::invalid_argument); - error_handler(e); - return; + ec = asio::error::invalid_argument; + return ec; } } if (::SSL_CTX_use_RSAPrivateKey_file( impl, filename.c_str(), file_type) != 1) { - asio::error e(asio::error::invalid_argument); - error_handler(e); - return; + ec = asio::error::invalid_argument; + return ec; } - asio::error e; - error_handler(e); + ec = asio::error_code(); + return ec; } // Use the specified file to obtain the temporary Diffie-Hellman parameters. - template - void use_tmp_dh_file(impl_type& impl, const std::string& filename, - Error_Handler error_handler) + asio::error_code use_tmp_dh_file(impl_type& impl, + const std::string& filename, asio::error_code& ec) { ::BIO* bio = ::BIO_new_file(filename.c_str(), "r"); if (!bio) { - asio::error e(asio::error::invalid_argument); - error_handler(e); - return; + ec = asio::error::invalid_argument; + return ec; } ::DH* dh = ::PEM_read_bio_DHparams(bio, 0, 0, 0); if (!dh) { ::BIO_free(bio); - asio::error e(asio::error::invalid_argument); - error_handler(e); - return; + ec = asio::error::invalid_argument; + return ec; } ::BIO_free(bio); @@ -327,13 +311,12 @@ public: if (result != 1) { ::DH_free(dh); - asio::error e(asio::error::invalid_argument); - error_handler(e); - return; + ec = asio::error::invalid_argument; + return ec; } - asio::error e; - error_handler(e); + ec = asio::error_code(); + return ec; } static int password_callback(char* buf, int size, int purpose, void* data) @@ -355,9 +338,9 @@ public: } // Set the password callback. - template - void set_password_callback(impl_type& impl, Password_Callback callback, - Error_Handler error_handler) + template + asio::error_code set_password_callback(impl_type& impl, + Password_Callback callback, asio::error_code& ec) { // Allocate callback function object if not already present. if (impl->default_passwd_callback_userdata) @@ -378,8 +361,8 @@ public: SSL_CTX_set_default_passwd_cb(impl, &openssl_context_service::password_callback); - asio::error e; - error_handler(e); + ec = asio::error_code(); + return ec; } private: diff --git a/libtorrent/include/libtorrent/asio/ssl/detail/openssl_init.hpp b/libtorrent/include/libtorrent/asio/ssl/detail/openssl_init.hpp index 60d19b787..06fbf86fe 100644 --- a/libtorrent/include/libtorrent/asio/ssl/detail/openssl_init.hpp +++ b/libtorrent/include/libtorrent/asio/ssl/detail/openssl_init.hpp @@ -45,13 +45,12 @@ private: { ::SSL_library_init(); ::SSL_load_error_strings(); + ::OpenSSL_add_ssl_algorithms(); mutexes_.resize(::CRYPTO_num_locks()); for (size_t i = 0; i < mutexes_.size(); ++i) mutexes_[i].reset(new asio::detail::mutex); ::CRYPTO_set_locking_callback(&do_init::openssl_locking_func); - - ::OpenSSL_add_ssl_algorithms(); } } diff --git a/libtorrent/include/libtorrent/asio/ssl/detail/openssl_operation.hpp b/libtorrent/include/libtorrent/asio/ssl/detail/openssl_operation.hpp index 1497638f1..b7a564464 100644 --- a/libtorrent/include/libtorrent/asio/ssl/detail/openssl_operation.hpp +++ b/libtorrent/include/libtorrent/asio/ssl/detail/openssl_operation.hpp @@ -33,7 +33,8 @@ namespace ssl { namespace detail { typedef boost::function ssl_primitive_func; -typedef boost::function user_handler_func; +typedef boost::function + user_handler_func; // Network send_/recv buffer implementation // @@ -155,15 +156,15 @@ public: if (is_shut_down_sent && is_shut_down_received && is_operation_done) // SSL connection is shut down cleanly - return handler_(asio::error(), 1); + return handler_(asio::error_code(), 1); if (is_shut_down_received && !is_write_needed) - return handler_(asio::error(asio::error::eof), 0); + return handler_(asio::error::eof, 0); if (is_shut_down_received) // Shutdown has been requested, while we were reading or writing... // abort our action... - return handler_(asio::error(asio::error::shut_down), 0); + return handler_(asio::error::shut_down, 0); if (!is_operation_done && !is_read_needed && !is_write_needed && !is_shut_down_sent) @@ -171,9 +172,15 @@ public: // The operation has failed... It is not completed and does // not want network communication nor does want to send shutdown out... if (error_code == SSL_ERROR_SYSCALL) - return handler_(asio::error(sys_error_code), rc); + { + return handler_(asio::error_code( + sys_error_code, asio::native_ecat), rc); + } else - return handler_(asio::error(error_code + 1000000), rc); + { + return handler_(asio::error_code( + error_code, asio::ssl_ecat), rc); + } } if (!is_operation_done && !is_write_needed) @@ -198,7 +205,7 @@ public: if (!BIO_should_retry(ssl_bio_)) { // Some serios error with BIO.... - return handler_(asio::error(asio::error::no_recovery), 0); + return handler_(asio::error::no_recovery, 0); } } @@ -212,7 +219,7 @@ public: // Private implementation private: - typedef boost::function + typedef boost::function int_handler_func; typedef boost::function write_func; @@ -234,15 +241,15 @@ private: SSL* session_; // - int sync_user_handler(const asio::error& error, int rc) + int sync_user_handler(const asio::error_code& error, int rc) { if (!error) return rc; - throw error; + throw asio::system_error(error); } - int async_user_handler(const asio::error& error, int rc) + int async_user_handler(const asio::error_code& error, int rc) { user_handler_(error, rc); return 0; @@ -295,7 +302,7 @@ private: { // Seems like fatal error // reading from SSL BIO has failed... - handler_(asio::error(asio::error::no_recovery), 0); + handler_(asio::error::no_recovery, 0); return 0; } } @@ -303,7 +310,7 @@ private: if (is_operation_done) { // Finish the operation, with success - handler_(asio::error(), rc); + handler_(asio::error_code(), rc); return 0; } @@ -315,7 +322,7 @@ private: } void async_write_handler(bool is_operation_done, int rc, - const asio::error& error, size_t bytes_sent) + const asio::error_code& error, size_t bytes_sent) { if (!error) { @@ -323,7 +330,7 @@ private: send_buf_.data_removed(bytes_sent); if (is_operation_done) - handler_(asio::error(), rc); + handler_(asio::error_code(), rc); else // Since the operation was not completed, try it again... start(); @@ -349,7 +356,8 @@ private: ); } - void async_read_handler(const asio::error& error, size_t bytes_recvd) + void async_read_handler(const asio::error_code& error, + size_t bytes_recvd) { if (!error) { @@ -372,7 +380,7 @@ private: if (!BIO_should_retry(ssl_bio_)) { // Some serios error with BIO.... - handler_(asio::error(asio::error::no_recovery), 0); + handler_(asio::error::no_recovery, 0); return; } } @@ -416,7 +424,7 @@ private: { // Seems like fatal error // reading from SSL BIO has failed... - throw asio::error(asio::error::no_recovery); + throw asio::system_error(asio::error::no_recovery); } } @@ -456,7 +464,7 @@ private: if (!BIO_should_retry(ssl_bio_)) { // Some serios error with BIO.... - throw asio::error(asio::error::no_recovery); + throw asio::system_error(asio::error::no_recovery); } } diff --git a/libtorrent/include/libtorrent/asio/ssl/detail/openssl_stream_service.hpp b/libtorrent/include/libtorrent/asio/ssl/detail/openssl_stream_service.hpp index d190ce937..d90b588ef 100644 --- a/libtorrent/include/libtorrent/asio/ssl/detail/openssl_stream_service.hpp +++ b/libtorrent/include/libtorrent/asio/ssl/detail/openssl_stream_service.hpp @@ -26,7 +26,9 @@ #include #include "asio/detail/pop_options.hpp" +#include "asio/error.hpp" #include "asio/io_service.hpp" +#include "asio/detail/service_base.hpp" #include "asio/ssl/basic_context.hpp" #include "asio/ssl/stream_base.hpp" #include "asio/ssl/detail/openssl_operation.hpp" @@ -37,7 +39,7 @@ namespace ssl { namespace detail { class openssl_stream_service - : public asio::io_service::service + : public asio::detail::service_base { private: //Base handler for asyncrhonous operations @@ -45,7 +47,8 @@ private: class base_handler { public: - typedef boost::function func_t; + typedef boost::function< + void (const asio::error_code&, size_t)> func_t; base_handler(asio::io_service& io_service) : op_(NULL) @@ -53,7 +56,7 @@ private: , work_(io_service) {} - void do_func(const asio::error& error, size_t size) + void do_func(const asio::error_code& error, size_t size) { func_(error, size); } @@ -90,7 +93,7 @@ private: private: Handler handler_; - void handler_impl(const asio::error& error, size_t size) + void handler_impl(const asio::error_code& error, size_t size) { handler_(error, size); delete this; @@ -114,7 +117,7 @@ private: private: Handler handler_; - void handler_impl(const asio::error& error, size_t) + void handler_impl(const asio::error_code& error, size_t) { handler_(error); delete this; @@ -139,7 +142,7 @@ private: private: Handler handler_; - void handler_impl(const asio::error& error, size_t) + void handler_impl(const asio::error_code& error, size_t) { handler_(error); delete this; @@ -157,7 +160,7 @@ public: // Construct a new stream socket service for the specified io_service. explicit openssl_stream_service(asio::io_service& io_service) - : asio::io_service::service(io_service) + : asio::detail::service_base(io_service) { } @@ -201,9 +204,9 @@ public: } // Perform SSL handshaking. - template - void handshake(impl_type& impl, Stream& next_layer, - stream_base::handshake_type type, Error_Handler error_handler) + template + asio::error_code handshake(impl_type& impl, Stream& next_layer, + stream_base::handshake_type type, asio::error_code& ec) { try { @@ -217,14 +220,14 @@ public: impl->ext_bio); op.start(); } - catch (asio::error& e) + catch (asio::system_error& e) { - error_handler(e); - return; + ec = e.code(); + return ec; } - asio::error e; - error_handler(e); + ec = asio::error_code(); + return ec; } // Start an asynchronous SSL handshake. @@ -260,9 +263,9 @@ public: } // Shut down SSL on the stream. - template - void shutdown(impl_type& impl, Stream& next_layer, - Error_Handler error_handler) + template + asio::error_code shutdown(impl_type& impl, Stream& next_layer, + asio::error_code& ec) { try { @@ -274,14 +277,14 @@ public: impl->ext_bio); op.start(); } - catch (asio::error& e) + catch (asio::system_error& e) { - error_handler(e); - return; + ec = e.code(); + return ec; } - asio::error e; - error_handler(e); + ec = asio::error_code(); + return ec; } // Asynchronously shut down SSL on the stream. @@ -314,9 +317,9 @@ public: } // Write some data to the stream. - template + template std::size_t write_some(impl_type& impl, Stream& next_layer, - const Const_Buffers& buffers, Error_Handler error_handler) + const Const_Buffers& buffers, asio::error_code& ec) { size_t bytes_transferred = 0; try @@ -334,14 +337,13 @@ public: ); bytes_transferred = static_cast(op.start()); } - catch (asio::error& e) + catch (asio::system_error& e) { - error_handler(e); + ec = e.code(); return 0; } - asio::error e; - error_handler(e); + ec = asio::error_code(); return bytes_transferred; } @@ -380,9 +382,9 @@ public: } // Read some data from the stream. - template + template std::size_t read_some(impl_type& impl, Stream& next_layer, - const Mutable_Buffers& buffers, Error_Handler error_handler) + const Mutable_Buffers& buffers, asio::error_code& ec) { size_t bytes_transferred = 0; try @@ -400,14 +402,13 @@ public: bytes_transferred = static_cast(op.start()); } - catch (asio::error& e) + catch (asio::system_error& e) { - error_handler(e); + ec = e.code(); return 0; } - asio::error e; - error_handler(e); + ec = asio::error_code(); return bytes_transferred; } @@ -446,22 +447,20 @@ public: } // Peek at the incoming data on the stream. - template + template std::size_t peek(impl_type& impl, Stream& next_layer, - const Mutable_Buffers& buffers, Error_Handler error_handler) + const Mutable_Buffers& buffers, asio::error_code& ec) { - asio::error e; - error_handler(e); + ec = asio::error_code(); return 0; } // Determine the amount of data that may be read without blocking. - template + template std::size_t in_avail(impl_type& impl, Stream& next_layer, - Error_Handler error_handler) + asio::error_code& ec) { - asio::error e; - error_handler(e); + ec = asio::error_code(); return 0; } diff --git a/libtorrent/include/libtorrent/asio/ssl/stream.hpp b/libtorrent/include/libtorrent/asio/ssl/stream.hpp index 451b02e32..a6af16101 100644 --- a/libtorrent/include/libtorrent/asio/ssl/stream.hpp +++ b/libtorrent/include/libtorrent/asio/ssl/stream.hpp @@ -26,10 +26,10 @@ #include "asio/detail/pop_options.hpp" #include "asio/error.hpp" -#include "asio/error_handler.hpp" #include "asio/ssl/basic_context.hpp" #include "asio/ssl/stream_base.hpp" #include "asio/ssl/stream_service.hpp" +#include "asio/detail/throw_error.hpp" namespace asio { namespace ssl { @@ -39,11 +39,11 @@ namespace ssl { * The stream class template provides asynchronous and blocking stream-oriented * functionality using SSL. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * - * @par Example: + * @par Example * To use the SSL stream template with a stream_socket, you would write: * @code * asio::io_service io_service; @@ -67,9 +67,6 @@ public: /// The type of the lowest layer. typedef typename next_layer_type::lowest_layer_type lowest_layer_type; - /// The type used for reporting errors. - typedef typename next_layer_type::error_type error_type; - /// The type of the service that will be used to provide stream operations. typedef Service service_type; @@ -158,11 +155,13 @@ public: * @param type The type of handshaking to be performed, i.e. as a client or as * a server. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ void handshake(handshake_type type) { - service_.handshake(impl_, next_layer_, type, throw_error()); + asio::error_code ec; + service_.handshake(impl_, next_layer_, type, ec); + asio::detail::throw_error(ec); } /// Perform SSL handshaking. @@ -173,17 +172,12 @@ public: * @param type The type of handshaking to be performed, i.e. as a client or as * a server. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. */ - template - void handshake(handshake_type type, Error_Handler error_handler) + asio::error_code handshake(handshake_type type, + asio::error_code& ec) { - service_.handshake(impl_, next_layer_, type, error_handler); + return service_.handshake(impl_, next_layer_, type, ec); } /// Start an asynchronous SSL handshake. @@ -198,11 +192,11 @@ public: * completes. Copies will be made of the handler as required. The equivalent * function signature of the handler must be: * @code void handler( - * const asio::error& error, // Result of operation + * const asio::error_code& error // Result of operation. * ); @endcode */ - template - void async_handshake(handshake_type type, Handler handler) + template + void async_handshake(handshake_type type, HandshakeHandler handler) { service_.async_handshake(impl_, next_layer_, type, handler); } @@ -212,11 +206,13 @@ public: * This function is used to shut down SSL on the stream. The function call * will block until SSL has been shut down or an error occurs. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ void shutdown() { - service_.shutdown(impl_, next_layer_, throw_error()); + asio::error_code ec; + service_.shutdown(impl_, next_layer_, ec); + asio::detail::throw_error(ec); } /// Shut down SSL on the stream. @@ -224,17 +220,11 @@ public: * This function is used to shut down SSL on the stream. The function call * will block until SSL has been shut down or an error occurs. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. */ - template - void shutdown(Error_Handler error_handler) + asio::error_code shutdown(asio::error_code& ec) { - service_.shutdown(impl_, next_layer_, error_handler); + return service_.shutdown(impl_, next_layer_, ec); } /// Asynchronously shut down SSL on the stream. @@ -246,11 +236,11 @@ public: * completes. Copies will be made of the handler as required. The equivalent * function signature of the handler must be: * @code void handler( - * const asio::error& error, // Result of operation + * const asio::error_code& error // Result of operation. * ); @endcode */ - template - void async_shutdown(Handler handler) + template + void async_shutdown(ShutdownHandler handler) { service_.async_shutdown(impl_, next_layer_, handler); } @@ -265,16 +255,19 @@ public: * * @returns The number of bytes written. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * * @note The write_some operation may not transmit all of the data to the * peer. Consider using the @ref write function if you need to ensure that all * data is written before the blocking operation completes. */ - template - std::size_t write_some(const Const_Buffers& buffers) + template + std::size_t write_some(const ConstBufferSequence& buffers) { - return service_.write_some(impl_, next_layer_, buffers, throw_error()); + asio::error_code ec; + std::size_t s = service_.write_some(impl_, next_layer_, buffers, ec); + asio::detail::throw_error(ec); + return s; } /// Write some data to the stream. @@ -285,25 +278,19 @@ public: * * @param buffers The data to be written to the stream. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation. - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @returns The number of bytes written. Returns 0 if an error occurred and - * the error handler did not throw an exception. + * @returns The number of bytes written. Returns 0 if an error occurred. * * @note The write_some operation may not transmit all of the data to the * peer. Consider using the @ref write function if you need to ensure that all * data is written before the blocking operation completes. */ - template - std::size_t write_some(const Const_Buffers& buffers, - Error_Handler error_handler) + template + std::size_t write_some(const ConstBufferSequence& buffers, + asio::error_code& ec) { - return service_.write_some(impl_, next_layer_, buffers, error_handler); + return service_.write_some(impl_, next_layer_, buffers, ec); } /// Start an asynchronous write. @@ -320,16 +307,17 @@ public: * Copies will be made of the handler as required. The equivalent function * signature of the handler must be: * @code void handler( - * const asio::error& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes written. + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes written. * ); @endcode * * @note The async_write_some operation may not transmit all of the data to * the peer. Consider using the @ref async_write function if you need to * ensure that all data is written before the blocking operation completes. */ - template - void async_write_some(const Const_Buffers& buffers, Handler handler) + template + void async_write_some(const ConstBufferSequence& buffers, + WriteHandler handler) { service_.async_write_some(impl_, next_layer_, buffers, handler); } @@ -344,16 +332,19 @@ public: * * @returns The number of bytes read. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. * * @note The read_some operation may not read all of the requested number of * bytes. Consider using the @ref read function if you need to ensure that the * requested amount of data is read before the blocking operation completes. */ - template - std::size_t read_some(const Mutable_Buffers& buffers) + template + std::size_t read_some(const MutableBufferSequence& buffers) { - return service_.read_some(impl_, next_layer_, buffers, throw_error()); + asio::error_code ec; + std::size_t s = service_.read_some(impl_, next_layer_, buffers, ec); + asio::detail::throw_error(ec); + return s; } /// Read some data from the stream. @@ -364,25 +355,19 @@ public: * * @param buffers The buffers into which the data will be read. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation. - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @returns The number of bytes read. Returns 0 if an error occurred and the - * error handler did not throw an exception. + * @returns The number of bytes read. Returns 0 if an error occurred. * * @note The read_some operation may not read all of the requested number of * bytes. Consider using the @ref read function if you need to ensure that the * requested amount of data is read before the blocking operation completes. */ - template - std::size_t read_some(const Mutable_Buffers& buffers, - Error_Handler error_handler) + template + std::size_t read_some(const MutableBufferSequence& buffers, + asio::error_code& ec) { - return service_.read_some(impl_, next_layer_, buffers, error_handler); + return service_.read_some(impl_, next_layer_, buffers, ec); } /// Start an asynchronous read. @@ -399,8 +384,8 @@ public: * Copies will be made of the handler as required. The equivalent function * signature of the handler must be: * @code void handler( - * const asio::error& error, // Result of operation. - * std::size_t bytes_transferred // Number of bytes read. + * const asio::error_code& error, // Result of operation. + * std::size_t bytes_transferred // Number of bytes read. * ); @endcode * * @note The async_read_some operation may not read all of the requested @@ -408,8 +393,9 @@ public: * ensure that the requested amount of data is read before the asynchronous * operation completes. */ - template - void async_read_some(const Mutable_Buffers& buffers, Handler handler) + template + void async_read_some(const MutableBufferSequence& buffers, + ReadHandler handler) { service_.async_read_some(impl_, next_layer_, buffers, handler); } @@ -424,12 +410,15 @@ public: * * @returns The number of bytes read. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ - template - std::size_t peek(const Mutable_Buffers& buffers) + template + std::size_t peek(const MutableBufferSequence& buffers) { - return service_.peek(impl_, next_layer_, buffers, throw_error()); + asio::error_code ec; + std::size_t s = service_.peek(impl_, next_layer_, buffers, ec); + asio::detail::throw_error(ec); + return s; } /// Peek at the incoming data on the stream. @@ -440,20 +429,15 @@ public: * * @param buffers The buffers into which the data will be read. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation. - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @returns The number of bytes read. Returns 0 if an error occurred and the - * error handler did not throw an exception. + * @returns The number of bytes read. Returns 0 if an error occurred. */ - template - std::size_t peek(const Mutable_Buffers& buffers, Error_Handler error_handler) + template + std::size_t peek(const MutableBufferSequence& buffers, + asio::error_code& ec) { - return service_.peek(impl_, next_layer_, buffers, error_handler); + return service_.peek(impl_, next_layer_, buffers, ec); } /// Determine the amount of data that may be read without blocking. @@ -463,11 +447,14 @@ public: * * @returns The number of bytes of data that can be read without blocking. * - * @throws asio::error Thrown on failure. + * @throws asio::system_error Thrown on failure. */ std::size_t in_avail() { - return service_.in_avail(impl_, next_layer_, throw_error()); + asio::error_code ec; + std::size_t s = service_.in_avail(impl_, next_layer_, ec); + asio::detail::throw_error(ec); + return s; } /// Determine the amount of data that may be read without blocking. @@ -475,19 +462,13 @@ public: * This function is used to determine the amount of data, in bytes, that may * be read from the stream without blocking. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const asio::error& error // Result of operation - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * * @returns The number of bytes of data that can be read without blocking. */ - template - std::size_t in_avail(Error_Handler error_handler) + std::size_t in_avail(asio::error_code& ec) { - return service_.in_avail(impl_, next_layer_, error_handler); + return service_.in_avail(impl_, next_layer_, ec); } private: diff --git a/libtorrent/include/libtorrent/asio/ssl/stream_service.hpp b/libtorrent/include/libtorrent/asio/ssl/stream_service.hpp index 5ad5165cc..d96e68aec 100644 --- a/libtorrent/include/libtorrent/asio/ssl/stream_service.hpp +++ b/libtorrent/include/libtorrent/asio/ssl/stream_service.hpp @@ -25,6 +25,7 @@ #include "asio/detail/pop_options.hpp" #include "asio/io_service.hpp" +#include "asio/detail/service_base.hpp" #include "asio/ssl/basic_context.hpp" #include "asio/ssl/stream_base.hpp" #include "asio/ssl/detail/openssl_stream_service.hpp" @@ -34,13 +35,22 @@ namespace ssl { /// Default service implementation for an SSL stream. class stream_service +#if defined(GENERATING_DOCUMENTATION) : public asio::io_service::service +#else + : public asio::detail::service_base +#endif { private: // The type of the platform-specific implementation. typedef detail::openssl_stream_service service_impl_type; public: +#if defined(GENERATING_DOCUMENTATION) + /// The unique service identifier. + static asio::io_service::id id; +#endif + /// The type of a stream implementation. #if defined(GENERATING_DOCUMENTATION) typedef implementation_defined impl_type; @@ -50,7 +60,7 @@ public: /// Construct a new stream service for the specified io_service. explicit stream_service(asio::io_service& io_service) - : asio::io_service::service(io_service), + : asio::detail::service_base(io_service), service_impl_(asio::use_service(io_service)) { } @@ -82,82 +92,85 @@ public: } /// Perform SSL handshaking. - template - void handshake(impl_type& impl, Stream& next_layer, - stream_base::handshake_type type, Error_Handler error_handler) + template + asio::error_code handshake(impl_type& impl, Stream& next_layer, + stream_base::handshake_type type, asio::error_code& ec) { - service_impl_.handshake(impl, next_layer, type, error_handler); + return service_impl_.handshake(impl, next_layer, type, ec); } /// Start an asynchronous SSL handshake. - template + template void async_handshake(impl_type& impl, Stream& next_layer, - stream_base::handshake_type type, Handler handler) + stream_base::handshake_type type, HandshakeHandler handler) { service_impl_.async_handshake(impl, next_layer, type, handler); } /// Shut down SSL on the stream. - template - void shutdown(impl_type& impl, Stream& next_layer, - Error_Handler error_handler) + template + asio::error_code shutdown(impl_type& impl, Stream& next_layer, + asio::error_code& ec) { - service_impl_.shutdown(impl, next_layer, error_handler); + return service_impl_.shutdown(impl, next_layer, ec); } /// Asynchronously shut down SSL on the stream. - template - void async_shutdown(impl_type& impl, Stream& next_layer, Handler handler) + template + void async_shutdown(impl_type& impl, Stream& next_layer, + ShutdownHandler handler) { service_impl_.async_shutdown(impl, next_layer, handler); } /// Write some data to the stream. - template + template std::size_t write_some(impl_type& impl, Stream& next_layer, - const Const_Buffers& buffers, Error_Handler error_handler) + const ConstBufferSequence& buffers, asio::error_code& ec) { - return service_impl_.write_some(impl, next_layer, buffers, error_handler); + return service_impl_.write_some(impl, next_layer, buffers, ec); } /// Start an asynchronous write. - template + template void async_write_some(impl_type& impl, Stream& next_layer, - const Const_Buffers& buffers, Handler handler) + const ConstBufferSequence& buffers, WriteHandler handler) { service_impl_.async_write_some(impl, next_layer, buffers, handler); } /// Read some data from the stream. - template + template std::size_t read_some(impl_type& impl, Stream& next_layer, - const Mutable_Buffers& buffers, Error_Handler error_handler) + const MutableBufferSequence& buffers, asio::error_code& ec) { - return service_impl_.read_some(impl, next_layer, buffers, error_handler); + return service_impl_.read_some(impl, next_layer, buffers, ec); } /// Start an asynchronous read. - template + template void async_read_some(impl_type& impl, Stream& next_layer, - const Mutable_Buffers& buffers, Handler handler) + const MutableBufferSequence& buffers, ReadHandler handler) { service_impl_.async_read_some(impl, next_layer, buffers, handler); } /// Peek at the incoming data on the stream. - template + template std::size_t peek(impl_type& impl, Stream& next_layer, - const Mutable_Buffers& buffers, Error_Handler error_handler) + const MutableBufferSequence& buffers, asio::error_code& ec) { - return service_impl_.peek(impl, next_layer, buffers, error_handler); + return service_impl_.peek(impl, next_layer, buffers, ec); } /// Determine the amount of data that may be read without blocking. - template + template std::size_t in_avail(impl_type& impl, Stream& next_layer, - Error_Handler error_handler) + asio::error_code& ec) { - return service_impl_.in_avail(impl, next_layer, error_handler); + return service_impl_.in_avail(impl, next_layer, ec); } private: diff --git a/libtorrent/include/libtorrent/asio/strand.hpp b/libtorrent/include/libtorrent/asio/strand.hpp index e378bfd32..948921e10 100644 --- a/libtorrent/include/libtorrent/asio/strand.hpp +++ b/libtorrent/include/libtorrent/asio/strand.hpp @@ -2,7 +2,7 @@ // strand.hpp // ~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -29,7 +29,7 @@ namespace asio { * handlers with the guarantee that none of those handlers will execute * concurrently. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Safe. * diff --git a/libtorrent/include/libtorrent/asio/stream_socket_service.hpp b/libtorrent/include/libtorrent/asio/stream_socket_service.hpp index bb604b764..d7915aaf4 100644 --- a/libtorrent/include/libtorrent/asio/stream_socket_service.hpp +++ b/libtorrent/include/libtorrent/asio/stream_socket_service.hpp @@ -2,7 +2,7 @@ // stream_socket_service.hpp // ~~~~~~~~~~~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -22,10 +22,12 @@ #include #include "asio/detail/pop_options.hpp" +#include "asio/error.hpp" #include "asio/io_service.hpp" #include "asio/detail/epoll_reactor.hpp" #include "asio/detail/kqueue_reactor.hpp" #include "asio/detail/select_reactor.hpp" +#include "asio/detail/service_base.hpp" #include "asio/detail/win_iocp_socket_service.hpp" #include "asio/detail/reactive_socket_service.hpp" @@ -34,9 +36,18 @@ namespace asio { /// Default service implementation for a stream socket. template class stream_socket_service +#if defined(GENERATING_DOCUMENTATION) : public asio::io_service::service +#else + : public asio::detail::service_base > +#endif { public: +#if defined(GENERATING_DOCUMENTATION) + /// The unique service identifier. + static asio::io_service::id id; +#endif + /// The protocol type. typedef Protocol protocol_type; @@ -75,7 +86,8 @@ public: /// Construct a new stream socket service for the specified io_service. explicit stream_socket_service(asio::io_service& io_service) - : asio::io_service::service(io_service), + : asio::detail::service_base< + stream_socket_service >(io_service), service_impl_(asio::use_service(io_service)) { } @@ -98,29 +110,35 @@ public: } /// Open a stream socket. - template - void open(implementation_type& impl, const protocol_type& protocol, - Error_Handler error_handler) + asio::error_code open(implementation_type& impl, + const protocol_type& protocol, asio::error_code& ec) { if (protocol.type() == SOCK_STREAM) - service_impl_.open(impl, protocol, error_handler); + service_impl_.open(impl, protocol, ec); else - error_handler(asio::error(asio::error::invalid_argument)); + ec = asio::error::invalid_argument; + return ec; } /// Assign an existing native socket to a stream socket. - template - void assign(implementation_type& impl, const protocol_type& protocol, - const native_type& native_socket, Error_Handler error_handler) + asio::error_code assign(implementation_type& impl, + const protocol_type& protocol, const native_type& native_socket, + asio::error_code& ec) { - service_impl_.assign(impl, protocol, native_socket, error_handler); + return service_impl_.assign(impl, protocol, native_socket, ec); + } + + /// Determine whether the socket is open. + bool is_open(const implementation_type& impl) const + { + return service_impl_.is_open(impl); } /// Close a stream socket implementation. - template - void close(implementation_type& impl, Error_Handler error_handler) + asio::error_code close(implementation_type& impl, + asio::error_code& ec) { - service_impl_.close(impl, error_handler); + return service_impl_.close(impl, ec); } /// Get the native socket implementation. @@ -130,116 +148,125 @@ public: } /// Cancel all asynchronous operations associated with the socket. - template - void cancel(implementation_type& impl, Error_Handler error_handler) + asio::error_code cancel(implementation_type& impl, + asio::error_code& ec) { - service_impl_.cancel(impl, error_handler); + return service_impl_.cancel(impl, ec); + } + + /// Determine whether the socket is at the out-of-band data mark. + bool at_mark(const implementation_type& impl, + asio::error_code& ec) const + { + return service_impl_.at_mark(impl, ec); + } + + /// Determine the number of bytes available for reading. + std::size_t available(const implementation_type& impl, + asio::error_code& ec) const + { + return service_impl_.available(impl, ec); } /// Bind the stream socket to the specified local endpoint. - template - void bind(implementation_type& impl, const endpoint_type& endpoint, - Error_Handler error_handler) + asio::error_code bind(implementation_type& impl, + const endpoint_type& endpoint, asio::error_code& ec) { - service_impl_.bind(impl, endpoint, error_handler); + return service_impl_.bind(impl, endpoint, ec); } /// Connect the stream socket to the specified endpoint. - template - void connect(implementation_type& impl, const endpoint_type& peer_endpoint, - Error_Handler error_handler) + asio::error_code connect(implementation_type& impl, + const endpoint_type& peer_endpoint, asio::error_code& ec) { - service_impl_.connect(impl, peer_endpoint, error_handler); + return service_impl_.connect(impl, peer_endpoint, ec); } /// Start an asynchronous connect. - template + template void async_connect(implementation_type& impl, - const endpoint_type& peer_endpoint, Handler handler) + const endpoint_type& peer_endpoint, ConnectHandler handler) { service_impl_.async_connect(impl, peer_endpoint, handler); } /// Set a socket option. - template - void set_option(implementation_type& impl, const Option& option, - Error_Handler error_handler) + template + asio::error_code set_option(implementation_type& impl, + const SettableSocketOption& option, asio::error_code& ec) { - service_impl_.set_option(impl, option, error_handler); + return service_impl_.set_option(impl, option, ec); } /// Get a socket option. - template - void get_option(const implementation_type& impl, Option& option, - Error_Handler error_handler) const + template + asio::error_code get_option(const implementation_type& impl, + GettableSocketOption& option, asio::error_code& ec) const { - service_impl_.get_option(impl, option, error_handler); + return service_impl_.get_option(impl, option, ec); } /// Perform an IO control command on the socket. - template - void io_control(implementation_type& impl, IO_Control_Command& command, - Error_Handler error_handler) + template + asio::error_code io_control(implementation_type& impl, + IoControlCommand& command, asio::error_code& ec) { - service_impl_.io_control(impl, command, error_handler); + return service_impl_.io_control(impl, command, ec); } /// Get the local endpoint. - template endpoint_type local_endpoint(const implementation_type& impl, - Error_Handler error_handler) const + asio::error_code& ec) const { - endpoint_type endpoint; - service_impl_.get_local_endpoint(impl, endpoint, error_handler); - return endpoint; + return service_impl_.local_endpoint(impl, ec); } /// Get the remote endpoint. - template endpoint_type remote_endpoint(const implementation_type& impl, - Error_Handler error_handler) const + asio::error_code& ec) const { - endpoint_type endpoint; - service_impl_.get_remote_endpoint(impl, endpoint, error_handler); - return endpoint; + return service_impl_.remote_endpoint(impl, ec); } /// Disable sends or receives on the socket. - template - void shutdown(implementation_type& impl, socket_base::shutdown_type what, - Error_Handler error_handler) + asio::error_code shutdown(implementation_type& impl, + socket_base::shutdown_type what, asio::error_code& ec) { - service_impl_.shutdown(impl, what, error_handler); + return service_impl_.shutdown(impl, what, ec); } /// Send the given data to the peer. - template - std::size_t send(implementation_type& impl, const Const_Buffers& buffers, - socket_base::message_flags flags, Error_Handler error_handler) + template + std::size_t send(implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) { - return service_impl_.send(impl, buffers, flags, error_handler); + return service_impl_.send(impl, buffers, flags, ec); } /// Start an asynchronous send. - template - void async_send(implementation_type& impl, const Const_Buffers& buffers, - socket_base::message_flags flags, Handler handler) + template + void async_send(implementation_type& impl, + const ConstBufferSequence& buffers, + socket_base::message_flags flags, WriteHandler handler) { service_impl_.async_send(impl, buffers, flags, handler); } /// Receive some data from the peer. - template - std::size_t receive(implementation_type& impl, const Mutable_Buffers& buffers, - socket_base::message_flags flags, Error_Handler error_handler) + template + std::size_t receive(implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, asio::error_code& ec) { - return service_impl_.receive(impl, buffers, flags, error_handler); + return service_impl_.receive(impl, buffers, flags, ec); } /// Start an asynchronous receive. - template - void async_receive(implementation_type& impl, const Mutable_Buffers& buffers, - socket_base::message_flags flags, Handler handler) + template + void async_receive(implementation_type& impl, + const MutableBufferSequence& buffers, + socket_base::message_flags flags, ReadHandler handler) { service_impl_.async_receive(impl, buffers, flags, handler); } diff --git a/libtorrent/include/libtorrent/asio/streambuf.hpp b/libtorrent/include/libtorrent/asio/streambuf.hpp index d20c957da..fdcc94a00 100644 --- a/libtorrent/include/libtorrent/asio/streambuf.hpp +++ b/libtorrent/include/libtorrent/asio/streambuf.hpp @@ -2,7 +2,7 @@ // streambuf.hpp // ~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/system_error.hpp b/libtorrent/include/libtorrent/asio/system_error.hpp new file mode 100644 index 000000000..95f9f540e --- /dev/null +++ b/libtorrent/include/libtorrent/asio/system_error.hpp @@ -0,0 +1,117 @@ +// +// system_error.hpp +// ~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_SYSTEM_ERROR_HPP +#define ASIO_SYSTEM_ERROR_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +#include "asio/detail/push_options.hpp" +#include +#include +#include +#include +#include +#include "asio/detail/pop_options.hpp" + +#include "asio/error_code.hpp" + +namespace asio { + +/// The system_error class is used to represent system conditions that +/// prevent the library from operating correctly. +class system_error + : public std::exception +{ +public: + /// Construct with an error code. + system_error(const error_code& code) + : code_(code), + context_() + { + } + + /// Construct with an error code and context. + system_error(const error_code& code, const std::string& context) + : code_(code), + context_(context) + { + } + + /// Copy constructor. + system_error(const system_error& other) + : std::exception(other), + code_(other.code_), + context_(other.context_), + what_() + { + } + + /// Destructor. + virtual ~system_error() throw () + { + } + + /// Assignment operator. + system_error& operator=(const system_error& e) + { + context_ = e.context_; + code_ = e.code_; + what_.reset(); + return *this; + } + + /// Get a string representation of the exception. + virtual const char* what() const throw () + { + try + { + if (!what_) + { + std::string tmp(context_); + if (tmp.length()) + tmp += ": "; + tmp += code_.message(); + what_.reset(new std::string(tmp)); + } + return what_->c_str(); + } + catch (std::exception&) + { + return "system_error"; + } + } + + /// Get the error code associated with the exception. + error_code code() const + { + return code_; + } + +private: + // The code associated with the error. + error_code code_; + + // The context associated with the error. + std::string context_; + + // The string representation of the error. + mutable boost::scoped_ptr what_; +}; + +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_SYSTEM_ERROR_HPP diff --git a/libtorrent/include/libtorrent/asio/thread.hpp b/libtorrent/include/libtorrent/asio/thread.hpp index 72b2510ca..b8bc81bab 100644 --- a/libtorrent/include/libtorrent/asio/thread.hpp +++ b/libtorrent/include/libtorrent/asio/thread.hpp @@ -2,7 +2,7 @@ // thread.hpp // ~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -29,11 +29,11 @@ namespace asio { * a thread and waiting for it to exit. If more extensive threading * capabilities are required, you are strongly advised to use something else. * - * @par Thread Safety: + * @par Thread Safety * @e Distinct @e objects: Safe.@n * @e Shared @e objects: Unsafe. * - * @par Example: + * @par Example * A typical use of asio::thread would be to launch a thread to run an * io_service's event processing loop: * diff --git a/libtorrent/include/libtorrent/asio/time_traits.hpp b/libtorrent/include/libtorrent/asio/time_traits.hpp index 7b459944c..d3c910e53 100644 --- a/libtorrent/include/libtorrent/asio/time_traits.hpp +++ b/libtorrent/include/libtorrent/asio/time_traits.hpp @@ -2,7 +2,7 @@ // time_traits.hpp // ~~~~~~~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/libtorrent/include/libtorrent/asio/write.hpp b/libtorrent/include/libtorrent/asio/write.hpp index 7bebecf49..5d643626a 100644 --- a/libtorrent/include/libtorrent/asio/write.hpp +++ b/libtorrent/include/libtorrent/asio/write.hpp @@ -2,7 +2,7 @@ // write.hpp // ~~~~~~~~~ // -// Copyright (c) 2003-2006 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -23,6 +23,7 @@ #include "asio/detail/pop_options.hpp" #include "asio/basic_streambuf.hpp" +#include "asio/error.hpp" namespace asio { @@ -45,7 +46,7 @@ namespace asio { * write_some function. * * @param s The stream to which the data is to be written. The type must support - * the Sync_Write_Stream concept. + * the SyncWriteStream concept. * * @param buffers One or more buffers containing the data to be written. The sum * of the buffer sizes indicates the maximum number of bytes to write to the @@ -53,9 +54,9 @@ namespace asio { * * @returns The number of bytes transferred. * - * @throws Sync_Write_Stream::error_type Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @par Example: + * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code asio::write(s, asio::buffer(data, size)); @endcode * See the @ref buffer documentation for information on writing multiple @@ -65,11 +66,10 @@ namespace asio { * @note This overload is equivalent to calling: * @code asio::write( * s, buffers, - * asio::transfer_all(), - * asio::throw_error()); @endcode + * asio::transfer_all()); @endcode */ -template -std::size_t write(Sync_Write_Stream& s, const Const_Buffers& buffers); +template +std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers); /// Write a certain amount of data to a stream before returning. /** @@ -85,7 +85,7 @@ std::size_t write(Sync_Write_Stream& s, const Const_Buffers& buffers); * write_some function. * * @param s The stream to which the data is to be written. The type must support - * the Sync_Write_Stream concept. + * the SyncWriteStream concept. * * @param buffers One or more buffers containing the data to be written. The sum * of the buffer sizes indicates the maximum number of bytes to write to the @@ -95,11 +95,11 @@ std::size_t write(Sync_Write_Stream& s, const Const_Buffers& buffers); * whether the write operation is complete. The signature of the function object * must be: * @code bool completion_condition( - * const Sync_Write_Stream::error_type& error, // Result of latest write_some - * // operation. + * const asio::error_code& error, // Result of latest write_some + * // operation. * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * std::size_t bytes_transferred // Number of bytes transferred + * // so far. * ); @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 @@ -107,26 +107,20 @@ std::size_t write(Sync_Write_Stream& s, const Const_Buffers& buffers); * * @returns The number of bytes transferred. * - * @throws Sync_Write_Stream::error_type Thrown on failure. + * @throws asio::system_error Thrown on failure. * - * @par Example: + * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code asio::write(s, asio::buffer(data, size), * asio::transfer_at_least(32)); @endcode * See the @ref buffer documentation for information on writing multiple * buffers in one go, and how to use it with arrays, boost::array or * std::vector. - * - * @note This overload is equivalent to calling: - * @code asio::write( - * s, buffers, - * completion_condition, - * asio::throw_error()); @endcode */ -template -std::size_t write(Sync_Write_Stream& s, const Const_Buffers& buffers, - Completion_Condition completion_condition); +template +std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition); /// Write a certain amount of data to a stream before returning. /** @@ -142,7 +136,7 @@ std::size_t write(Sync_Write_Stream& s, const Const_Buffers& buffers, * write_some function. * * @param s The stream to which the data is to be written. The type must support - * the Sync_Write_Stream concept. + * the SyncWriteStream concept. * * @param buffers One or more buffers containing the data to be written. The sum * of the buffer sizes indicates the maximum number of bytes to write to the @@ -152,31 +146,25 @@ std::size_t write(Sync_Write_Stream& s, const Const_Buffers& buffers, * whether the write operation is complete. The signature of the function object * must be: * @code bool completion_condition( - * const Sync_Write_Stream::error_type& error, // Result of latest write_some - * // operation. + * const asio::error_code& error, // Result of latest write_some + * // operation. * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * std::size_t bytes_transferred // Number of bytes transferred + * // so far. * ); @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. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const Sync_Write_Stream::error_type& error // Result of operation. - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @returns The number of bytes written. If an error occurs, and the error - * handler does not throw an exception, returns the total number of bytes - * successfully transferred prior to the error. + * @returns The number of bytes written. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. */ -template -std::size_t write(Sync_Write_Stream& s, const Const_Buffers& buffers, - Completion_Condition completion_condition, Error_Handler error_handler); +template +std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, asio::error_code& ec); /// Write a certain amount of data to a stream before returning. /** @@ -191,22 +179,21 @@ std::size_t write(Sync_Write_Stream& s, const Const_Buffers& buffers, * write_some function. * * @param s The stream to which the data is to be written. The type must support - * the Sync_Write_Stream concept. + * the SyncWriteStream concept. * * @param b The basic_streambuf object from which data will be written. * * @returns The number of bytes transferred. * - * @throws Sync_Write_Stream::error_type Thrown on failure. + * @throws asio::system_error Thrown on failure. * * @note This overload is equivalent to calling: * @code asio::write( * s, b, - * asio::transfer_all(), - * asio::throw_error()); @endcode + * asio::transfer_all()); @endcode */ -template -std::size_t write(Sync_Write_Stream& s, basic_streambuf& b); +template +std::size_t write(SyncWriteStream& s, basic_streambuf& b); /// Write a certain amount of data to a stream before returning. /** @@ -221,7 +208,7 @@ std::size_t write(Sync_Write_Stream& s, basic_streambuf& b); * write_some function. * * @param s The stream to which the data is to be written. The type must support - * the Sync_Write_Stream concept. + * the SyncWriteStream concept. * * @param b The basic_streambuf object from which data will be written. * @@ -229,11 +216,11 @@ std::size_t write(Sync_Write_Stream& s, basic_streambuf& b); * whether the write operation is complete. The signature of the function object * must be: * @code bool completion_condition( - * const Sync_Write_Stream::error_type& error, // Result of latest write_some - * // operation. + * const asio::error_code& error, // Result of latest write_some + * // operation. * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * std::size_t bytes_transferred // Number of bytes transferred + * // so far. * ); @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 @@ -241,18 +228,12 @@ std::size_t write(Sync_Write_Stream& s, basic_streambuf& b); * * @returns The number of bytes transferred. * - * @throws Sync_Write_Stream::error_type Thrown on failure. - * - * @note This overload is equivalent to calling: - * @code asio::write( - * s, b, - * completion_condition, - * asio::throw_error()); @endcode + * @throws asio::system_error Thrown on failure. */ -template -std::size_t write(Sync_Write_Stream& s, basic_streambuf& b, - Completion_Condition completion_condition); +template +std::size_t write(SyncWriteStream& s, basic_streambuf& b, + CompletionCondition completion_condition); /// Write a certain amount of data to a stream before returning. /** @@ -267,7 +248,7 @@ std::size_t write(Sync_Write_Stream& s, basic_streambuf& b, * write_some function. * * @param s The stream to which the data is to be written. The type must support - * the Sync_Write_Stream concept. + * the SyncWriteStream concept. * * @param b The basic_streambuf object from which data will be written. * @@ -275,31 +256,25 @@ std::size_t write(Sync_Write_Stream& s, basic_streambuf& b, * whether the write operation is complete. The signature of the function object * must be: * @code bool completion_condition( - * const Sync_Write_Stream::error_type& error, // Result of latest write_some - * // operation. + * const asio::error_code& error, // Result of latest write_some + * // operation. * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * std::size_t bytes_transferred // Number of bytes transferred + * // so far. * ); @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. * - * @param error_handler A handler to be called when the operation completes, - * to indicate whether or not an error has occurred. Copies will be made of - * the handler as required. The function signature of the handler must be: - * @code void error_handler( - * const Sync_Write_Stream::error_type& error // Result of operation. - * ); @endcode + * @param ec Set to indicate what error occurred, if any. * - * @returns The number of bytes written. If an error occurs, and the error - * handler does not throw an exception, returns the total number of bytes - * successfully transferred prior to the error. + * @returns The number of bytes written. If an error occurs, returns the total + * number of bytes successfully transferred prior to the error. */ -template -std::size_t write(Sync_Write_Stream& s, basic_streambuf& b, - Completion_Condition completion_condition, Error_Handler error_handler); +template +std::size_t write(SyncWriteStream& s, basic_streambuf& b, + CompletionCondition completion_condition, asio::error_code& ec); /*@}*/ /** @@ -324,7 +299,7 @@ std::size_t write(Sync_Write_Stream& s, basic_streambuf& b, * async_write_some function. * * @param s The stream to which the data is to be written. The type must support - * the Async_Write_Stream concept. + * the AsyncWriteStream concept. * * @param buffers One or more buffers containing the data to be written. * Although the buffers object may be copied as necessary, ownership of the @@ -335,20 +310,19 @@ std::size_t write(Sync_Write_Stream& s, basic_streambuf& b, * Copies will be made of the handler as required. The function signature of * the handler must be: * @code void handler( - * const Async_Write_Stream::error_type& error, // Result of operation. + * const asio::error_code& error, // Result of operation. * - * std::size_t bytes_transferred // Number of bytes written - * // from the buffers. If an - * // error occurred, this will - * // be less than the sum of the - * // buffer sizes. + * std::size_t bytes_transferred // Number of bytes written from the + * // buffers. If an error occurred, + * // this will be less than the sum + * // of the buffer sizes. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * - * @par Example: + * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code * asio::async_write(s, asio::buffer(data, size), handler); @@ -357,9 +331,10 @@ std::size_t write(Sync_Write_Stream& s, basic_streambuf& b, * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ -template -void async_write(Async_Write_Stream& s, const Const_Buffers& buffers, - Handler handler); +template +void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, + WriteHandler handler); /// Start an asynchronous operation to write a certain amount of data to a /// stream. @@ -378,7 +353,7 @@ void async_write(Async_Write_Stream& s, const Const_Buffers& buffers, * async_write_some function. * * @param s The stream to which the data is to be written. The type must support - * the Async_Write_Stream concept. + * the AsyncWriteStream concept. * * @param buffers One or more buffers containing the data to be written. * Although the buffers object may be copied as necessary, ownership of the @@ -389,11 +364,11 @@ void async_write(Async_Write_Stream& s, const Const_Buffers& buffers, * whether the write operation is complete. The signature of the function object * must be: * @code bool completion_condition( - * const Async_Write_Stream::error_type& error, // Result of latest write_some - * // operation. + * const asio::error_code& error, // Result of latest write_some + * // operation. * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * std::size_t bytes_transferred // Number of bytes transferred + * // so far. * ); @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 @@ -403,20 +378,19 @@ void async_write(Async_Write_Stream& s, const Const_Buffers& buffers, * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( - * const Async_Write_Stream::error_type& error, // Result of operation. + * const asio::error_code& error, // Result of operation. * - * std::size_t bytes_transferred // Number of bytes written - * // from the buffers. If an - * // error occurred, this will - * // be less than the sum of the - * // buffer sizes. + * std::size_t bytes_transferred // Number of bytes written from the + * // buffers. If an error occurred, + * // this will be less than the sum + * // of the buffer sizes. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). * - * @par Example: + * @par Example * To write a single data buffer use the @ref buffer function as follows: * @code asio::async_write(s, * asio::buffer(data, size), @@ -426,10 +400,10 @@ void async_write(Async_Write_Stream& s, const Const_Buffers& buffers, * buffers in one go, and how to use it with arrays, boost::array or * std::vector. */ -template -void async_write(Async_Write_Stream& s, const Const_Buffers& buffers, - Completion_Condition completion_condition, Handler handler); +template +void async_write(AsyncWriteStream& s, const ConstBufferSequence& buffers, + CompletionCondition completion_condition, WriteHandler handler); /// Start an asynchronous operation to write a certain amount of data to a /// stream. @@ -447,7 +421,7 @@ void async_write(Async_Write_Stream& s, const Const_Buffers& buffers, * async_write_some function. * * @param s The stream to which the data is to be written. The type must support - * the Async_Write_Stream concept. + * the AsyncWriteStream concept. * * @param b A basic_streambuf object from which data will be written. Ownership * of the streambuf is retained by the caller, which must guarantee that it @@ -457,22 +431,21 @@ void async_write(Async_Write_Stream& s, const Const_Buffers& buffers, * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( - * const Async_Write_Stream::error_type& error, // Result of operation. + * const asio::error_code& error, // Result of operation. * - * std::size_t bytes_transferred // Number of bytes written - * // from the buffers. If an - * // error occurred, this will - * // be less than the sum of the - * // buffer sizes. + * std::size_t bytes_transferred // Number of bytes written from the + * // buffers. If an error occurred, + * // this will be less than the sum + * // of the buffer sizes. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). */ -template -void async_write(Async_Write_Stream& s, basic_streambuf& b, - Handler handler); +template +void async_write(AsyncWriteStream& s, basic_streambuf& b, + WriteHandler handler); /// Start an asynchronous operation to write a certain amount of data to a /// stream. @@ -490,7 +463,7 @@ void async_write(Async_Write_Stream& s, basic_streambuf& b, * async_write_some function. * * @param s The stream to which the data is to be written. The type must support - * the Async_Write_Stream concept. + * the AsyncWriteStream concept. * * @param b A basic_streambuf object from which data will be written. Ownership * of the streambuf is retained by the caller, which must guarantee that it @@ -500,11 +473,11 @@ void async_write(Async_Write_Stream& s, basic_streambuf& b, * whether the write operation is complete. The signature of the function object * must be: * @code bool completion_condition( - * const Async_Write_Stream::error_type& error, // Result of latest write_some - * // operation. + * const asio::error_code& error, // Result of latest write_some + * // operation. * - * std::size_t bytes_transferred // Number of bytes transferred - * // so far. + * std::size_t bytes_transferred // Number of bytes transferred + * // so far. * ); @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 @@ -514,23 +487,22 @@ void async_write(Async_Write_Stream& s, basic_streambuf& b, * Copies will be made of the handler as required. The function signature of the * handler must be: * @code void handler( - * const Async_Write_Stream::error_type& error, // Result of operation. + * const asio::error_code& error, // Result of operation. * - * std::size_t bytes_transferred // Number of bytes written - * // from the buffers. If an - * // error occurred, this will - * // be less than the sum of the - * // buffer sizes. + * std::size_t bytes_transferred // Number of bytes written from the + * // buffers. If an error occurred, + * // this will be less than the sum + * // of the buffer sizes. * ); @endcode * Regardless of whether the asynchronous operation completes immediately or * not, the handler will not be invoked from within this function. Invocation of * the handler will be performed in a manner equivalent to using * asio::io_service::post(). */ -template -void async_write(Async_Write_Stream& s, basic_streambuf& b, - Completion_Condition completion_condition, Handler handler); +template +void async_write(AsyncWriteStream& s, basic_streambuf& b, + CompletionCondition completion_condition, WriteHandler handler); /*@}*/ diff --git a/libtorrent/include/libtorrent/aux_/allocate_resources_impl.hpp b/libtorrent/include/libtorrent/aux_/allocate_resources_impl.hpp index 4be3d8a1e..31865d40a 100644 --- a/libtorrent/include/libtorrent/aux_/allocate_resources_impl.hpp +++ b/libtorrent/include/libtorrent/aux_/allocate_resources_impl.hpp @@ -74,6 +74,11 @@ namespace libtorrent return accepted; } + inline int div_round_up(int numerator, int denominator) + { + return (numerator + denominator - 1) / denominator; + } + #ifndef NDEBUG template @@ -120,7 +125,11 @@ namespace libtorrent sum_max = saturated_add(sum_max, ((*i).*m_res).max); sum_min = saturated_add(sum_min, ((*i).*m_res).min); } - assert(sum_given == (std::min)(std::max(m_resources, sum_min), sum_max)); + if (sum_given != (std::min)(std::max(m_resources, sum_min), sum_max)) + { + std::cerr << sum_given << " " << m_resources << " " << sum_min << " " << sum_max << std::endl; + assert(false); + } } }; @@ -142,6 +151,12 @@ namespace libtorrent , res); #endif + for (It i = start; i != end; ++i) + { + resource_request& r = (*i).*res; + r.leftovers = (std::max)(r.used - r.given, 0); + } + if (resources == resource_request::inf) { // No competition for resources. @@ -157,18 +172,86 @@ namespace libtorrent int sum_max = 0; int sum_min = 0; + // the number of consumer that saturated their + // quota last time slice + int num_saturated = 0; + // the total resources that those saturated their + // quota used. This is used to calculate the mean + // of the saturating consumers, in order to + // balance their quotas for the next time slice. + size_type saturated_sum = 0; for (It i = start; i != end; ++i) { - sum_max = saturated_add(sum_max, ((*i).*res).max); - assert(((*i).*res).min < resource_request::inf); - assert(((*i).*res).min >= 0); - assert(((*i).*res).min <= ((*i).*res).max); - sum_min += ((*i).*res).min; - ((*i).*res).given = ((*i).*res).min; + resource_request& r = (*i).*res; + sum_max = saturated_add(sum_max, r.max); + assert(r.min < resource_request::inf); + assert(r.min >= 0); + assert(r.min <= r.max); + sum_min += r.min; + + // a consumer that uses 95% or more of its assigned + // quota is considered saturating + size_type used = r.used; + if (r.given == 0) continue; + if (used * 20 / r.given >= 19) + { + ++num_saturated; + saturated_sum += r.given; + } } - if (resources == 0 || sum_max == 0) + if (sum_max <= resources) + { + // it turns out that there's no competition for resources + // after all. + for (It i = start; i != end; ++i) + { + ((*i).*res).given = ((*i).*res).max; + } return; + } + + if (sum_min >= resources) + { + // the amount of resources is smaller than + // the minimum resources to distribute, so + // give everyone the minimum + for (It i = start; i != end; ++i) + { + ((*i).*res).given = ((*i).*res).min; + } + return; + } + + // now, the "used" field will be used as a target value. + // the algorithm following this loop will then scale the + // used values to fit the available resources and store + // the scaled values as given. So, the ratios of the + // used values will be maintained. + for (It i = start; i != end; ++i) + { + resource_request& r = (*i).*res; + + int target; + size_type used = r.used; + if (r.given > 0 && used * 20 / r.given >= 19) + { + assert(num_saturated > 0); + target = div_round_up(saturated_sum, num_saturated); + target += div_round_up(target, 10); + } + else + { + target = r.used; + } + if (target > r.max) target = r.max; + else if (target < r.min) target = r.min; + + // move 12.5% towards the the target value + r.used = r.given + div_round_up(target - r.given, 8); + r.given = r.min; + } + resources = (std::max)(resources, sum_min); int resources_to_distribute = (std::min)(resources, sum_max) - sum_min; @@ -178,12 +261,14 @@ namespace libtorrent #endif while (resources_to_distribute > 0) { + // in order to scale, we need to calculate the sum of + // all the used values. size_type total_used = 0; size_type max_used = 0; for (It i = start; i != end; ++i) { resource_request& r = (*i).*res; - if(r.given == r.max) continue; + if (r.given == r.max) continue; assert(r.given < r.max); @@ -191,19 +276,18 @@ namespace libtorrent total_used += (size_type)r.used + 1; } + size_type kNumer = resources_to_distribute; size_type kDenom = total_used; assert(kNumer >= 0); assert(kDenom >= 0); assert(kNumer <= (std::numeric_limits::max)()); - assert(total_used < (std::numeric_limits::max)()); if (kNumer * max_used <= kDenom) { kNumer = 1; kDenom = max_used; assert(kDenom >= 0); - assert(kDenom <= (std::numeric_limits::max)()); } for (It i = start; i != end && resources_to_distribute > 0; ++i) @@ -220,7 +304,11 @@ namespace libtorrent to_give = resources_to_distribute; assert(to_give >= 0); assert(to_give <= resources_to_distribute); +#ifndef NDEBUG + int tmp = resources_to_distribute; +#endif resources_to_distribute -= give(r, (int)to_give); + assert(resources_to_distribute <= tmp); assert(resources_to_distribute >= 0); } @@ -230,6 +318,7 @@ namespace libtorrent prev_resources_to_distribute = resources_to_distribute; #endif } + assert(resources_to_distribute == 0); } } // namespace libtorrent::aux diff --git a/libtorrent/include/libtorrent/aux_/session_impl.hpp b/libtorrent/include/libtorrent/aux_/session_impl.hpp index 2712e7078..04d71885c 100644 --- a/libtorrent/include/libtorrent/aux_/session_impl.hpp +++ b/libtorrent/include/libtorrent/aux_/session_impl.hpp @@ -75,6 +75,8 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/session_status.hpp" #include "libtorrent/session.hpp" #include "libtorrent/stat.hpp" +#include "libtorrent/file_pool.hpp" +#include "libtorrent/bandwidth_manager.hpp" namespace libtorrent { @@ -148,6 +150,10 @@ namespace libtorrent bool m_abort; }; +#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) + struct tracker_logger; +#endif + // this is the link between the main thread and the // thread started to run the main downloader loop struct session_impl: boost::noncopyable @@ -155,7 +161,7 @@ namespace libtorrent #ifndef NDEBUG friend class ::libtorrent::peer_connection; #endif - friend class checker_impl; + friend struct checker_impl; friend class invariant_access; typedef std::map , boost::intrusive_ptr > @@ -170,13 +176,16 @@ namespace libtorrent , char const* listen_interface = "0.0.0.0"); ~session_impl(); +#ifndef TORRENT_DISABLE_EXTENSIONS + void add_extension(boost::function(torrent*)> ext); +#endif void operator()(); void open_listen_port(); void async_accept(); void on_incoming_connection(boost::shared_ptr const& s - , boost::weak_ptr const& as, asio::error const& e); + , boost::weak_ptr const& as, asio::error_code const& e); // must be locked to access the data // in this struct @@ -228,6 +237,7 @@ namespace libtorrent torrent_handle add_torrent( char const* tracker_url , sha1_hash const& info_hash + , char const* name , boost::filesystem::path const& save_path , entry const& resume_data , bool compact_mode @@ -235,22 +245,22 @@ namespace libtorrent void remove_torrent(torrent_handle const& h); - void disable_extensions(); - void enable_extension(extension_index i); - bool extensions_enabled() const; - bool extension_enabled(int i) const - { return m_extension_enabled[i]; } - std::vector get_torrents(); void set_severity_level(alert::severity_t s); std::auto_ptr pop_alert(); + + int upload_rate_limit() const; + int download_rate_limit() const; + void set_download_rate_limit(int bytes_per_second); void set_upload_rate_limit(int bytes_per_second); void set_max_half_open_connections(int limit); void set_max_connections(int limit); void set_max_uploads(int limit); + int num_uploads() const; + int num_connections() const; session_status status() const; void set_peer_id(peer_id const& id); @@ -259,6 +269,9 @@ namespace libtorrent void abort(); + torrent_handle find_torrent_handle(sha1_hash const& info_hash); + + // handles delayed alerts alert_manager m_alerts; @@ -267,7 +280,15 @@ namespace libtorrent // this is where all active sockets are stored. // the selector can sleep while there's no activity on // them - demuxer m_selector; + io_service m_io_service; + asio::strand m_strand; + + // the bandwidth manager is responsible for + // handing out bandwidth to connections that + // asks for it, it can also throttle the + // rate. + bandwidth_manager m_dl_bandwidth_manager; + bandwidth_manager m_ul_bandwidth_manager; tracker_manager m_tracker_manager; torrent_map m_torrents; @@ -310,10 +331,6 @@ namespace libtorrent boost::shared_ptr m_listen_socket; - // the entries in this array maps the - // extension index (as specified in peer_connection) - bool m_extension_enabled[num_supported_extensions]; - // the settings for the client session_settings m_settings; @@ -322,11 +339,6 @@ namespace libtorrent // should exit volatile bool m_abort; - // maximum upload rate given in - // bytes per second. -1 means - // unlimited - int m_upload_rate; - int m_download_rate; int m_max_uploads; int m_max_connections; // the number of simultaneous half-open tcp @@ -341,14 +353,17 @@ namespace libtorrent // this is used to know if the client is behind // NAT or not. bool m_incoming_connection; + + // the file pool that all storages in this session's + // torrents uses. It sets a limit on the number of + // open files by this session. + file_pool m_files; - // does the actual disconnections - // that are queued up in m_disconnect_peer - void second_tick(asio::error const& e); + void second_tick(asio::error_code const& e); boost::posix_time::ptime m_last_tick; #ifndef TORRENT_DISABLE_DHT - boost::scoped_ptr m_dht; + boost::intrusive_ptr m_dht; dht_settings m_dht_settings; #endif // the timer used to fire the second_tick @@ -357,12 +372,29 @@ namespace libtorrent void check_invariant(const char *place = 0); #endif #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - boost::shared_ptr create_log(std::string const& name, bool append = true); + boost::shared_ptr create_log(std::string const& name + , int instance, bool append = true); + + // this list of tracker loggers serves as tracker_callbacks when + // shutting down. This list is just here to keep them alive during + // whe shutting down process + std::list > m_tracker_loggers; + + // logger used to write bandwidth usage statistics + boost::shared_ptr m_stats_logger; + int m_second_counter; public: boost::shared_ptr m_logger; private: #endif +#ifndef TORRENT_DISABLE_EXTENSIONS + typedef std::list(torrent*)> > extension_list_t; + + extension_list_t m_extensions; +#endif + // data shared between the main thread // and the checker thread checker_impl m_checker_impl; @@ -374,6 +406,61 @@ namespace libtorrent // on all torrents before they start downloading boost::scoped_ptr m_checker_thread; }; + +#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) + struct tracker_logger : request_callback + { + tracker_logger(session_impl& ses): m_ses(ses) {} + void tracker_warning(std::string const& str) + { + debug_log("*** tracker warning: " + str); + } + + void tracker_response(tracker_request const& + , std::vector& peers + , int interval + , int complete + , int incomplete) + { + std::stringstream s; + s << "TRACKER RESPONSE:\n" + "interval: " << interval << "\n" + "peers:\n"; + for (std::vector::const_iterator i = peers.begin(); + i != peers.end(); ++i) + { + s << " " << std::setfill(' ') << std::setw(16) << i->ip + << " " << std::setw(5) << std::dec << i->port << " "; + if (!i->pid.is_all_zeros()) s << " " << i->pid; + s << "\n"; + } + debug_log(s.str()); + } + + void tracker_request_timed_out( + tracker_request const&) + { + debug_log("*** tracker timed out"); + } + + void tracker_request_error( + tracker_request const& + , int response_code + , const std::string& str) + { + debug_log(std::string("*** tracker error: ") + + boost::lexical_cast(response_code) + ": " + + str); + } + + void debug_log(const std::string& line) + { + (*m_ses.m_logger) << line << "\n"; + } + session_impl& m_ses; + }; +#endif + } } diff --git a/libtorrent/include/libtorrent/bandwidth_manager.hpp b/libtorrent/include/libtorrent/bandwidth_manager.hpp new file mode 100644 index 000000000..32d1b510d --- /dev/null +++ b/libtorrent/include/libtorrent/bandwidth_manager.hpp @@ -0,0 +1,228 @@ +/* + +Copyright (c) 2007, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef TORRENT_BANDWIDTH_MANAGER_HPP_INCLUDED +#define TORRENT_BANDWIDTH_MANAGER_HPP_INCLUDED + +#include "libtorrent/socket.hpp" +#include +#include +#include +#include +#include +#include +#include + +namespace pt = boost::posix_time; +using boost::weak_ptr; +using boost::shared_ptr; +using boost::intrusive_ptr; +using boost::bind; + +namespace libtorrent +{ + + class peer_connection; + class torrent; + + // the maximum block of bandwidth quota to + // hand out is 33kB. The block size may + // be smaller on lower limits + const int max_bandwidth_block_size = 33000; + const int min_bandwidth_block_size = 4000; + +#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING + namespace aux + { + struct session_impl; + } +#endif + +struct history_entry +{ + history_entry(intrusive_ptr p, weak_ptr t + , int a, pt::ptime exp); + pt::ptime expires_at; + int amount; + intrusive_ptr peer; + weak_ptr tor; +}; + +struct bw_queue_entry +{ + bw_queue_entry(boost::intrusive_ptr const& pe, bool no_prio); + boost::intrusive_ptr peer; + bool non_prioritized; +}; + +// member of peer_connection +struct bandwidth_limit +{ + static const int inf = boost::integer_traits::const_max; + + bandwidth_limit() + : m_quota_left(0) + , m_local_limit(inf) + , m_current_rate(0) + {} + + void throttle(int limit) + { + m_local_limit = limit; + } + + int throttle() const + { + return m_local_limit; + } + + void assign(int amount) + { + assert(amount > 0); + m_current_rate += amount; + m_quota_left += amount; + } + + void use_quota(int amount) + { + assert(amount <= m_quota_left); + m_quota_left -= amount; + } + + int quota_left() const + { + return (std::max)(m_quota_left, 0); + } + + void expire(int amount) + { + assert(amount >= 0); + m_current_rate -= amount; + } + + int max_assignable() const + { + if (m_local_limit == inf) return inf; + if (m_local_limit <= m_current_rate) return 0; + return m_local_limit - m_current_rate; + } + +private: + + // this is the amount of bandwidth we have + // been assigned without using yet. i.e. + // the bandwidth that we use up every time + // we receive or send a message. Once this + // hits zero, we need to request more + // bandwidth from the torrent which + // in turn will request bandwidth from + // the bandwidth manager + int m_quota_left; + + // the local limit is the number of bytes + // per window size we are allowed to use. + int m_local_limit; + + // the current rate is the number of + // bytes we have been assigned within + // the window size. + int m_current_rate; +}; + +struct bandwidth_manager +{ + bandwidth_manager(io_service& ios, int channel); + + void throttle(int limit) + { + mutex_t::scoped_lock l(m_mutex); + assert(limit >= 0); + m_limit = limit; + } + + int throttle() const + { + mutex_t::scoped_lock l(m_mutex); + return m_limit; + } + + // non prioritized means that, if there's a line for bandwidth, + // others will cut in front of the non-prioritized peers. + // this is used by web seeds + void request_bandwidth(intrusive_ptr peer + , bool non_prioritized); + +#ifndef NDEBUG + void check_invariant() const; +#endif +#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING + aux::session_impl* m_ses; +#endif + +private: + + void add_history_entry(history_entry const& e); + void on_history_expire(asio::error_code const& e); + void hand_out_bandwidth(); + + typedef boost::mutex mutex_t; + mutable mutex_t m_mutex; + + // the io_service used for the timer + io_service& m_ios; + + // the timer that is waiting for the entries + // in the history queue to expire (slide out + // of the history window) + deadline_timer m_history_timer; + + // the rate limit (bytes per second) + int m_limit; + + // the sum of all recently handed out bandwidth blocks + int m_current_quota; + + // these are the consumers that want bandwidth + std::deque m_queue; + + // these are the consumers that have received bandwidth + // that will expire + std::deque m_history; + + // this is the channel within the consumers + // that bandwidth is assigned to (upload or download) + int m_channel; +}; + +} + +#endif diff --git a/libtorrent/include/libtorrent/bt_peer_connection.hpp b/libtorrent/include/libtorrent/bt_peer_connection.hpp index d02614c52..f68a5d1fa 100644 --- a/libtorrent/include/libtorrent/bt_peer_connection.hpp +++ b/libtorrent/include/libtorrent/bt_peer_connection.hpp @@ -102,22 +102,51 @@ namespace libtorrent ~bt_peer_connection(); + enum message_type + { + // standard messages + msg_choke = 0, + msg_unchoke, + msg_interested, + msg_not_interested, + msg_have, + msg_bitfield, + msg_request, + msg_piece, + msg_cancel, + msg_dht_port, + // extension protocol message + msg_extended = 20, + + num_supported_messages + }; + // called from the main loop when this connection has any // work to do. - void on_sent(asio::error const& error + void on_sent(asio::error_code const& error , std::size_t bytes_transferred); - void on_receive(asio::error const& error + void on_receive(asio::error_code const& error , std::size_t bytes_transferred); virtual void get_peer_info(peer_info& p) const; + virtual bool in_handshake() const; +#ifndef TORRENT_DISABLE_EXTENSIONS bool support_extensions() const { return m_supports_extensions; } - bool supports_extension(extension_index ex) const - { return m_extension_messages[ex] > 0; } - - bool has_metadata() const; + template + T* supports_extension() const + { + for (extension_list_t::const_iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + T* ret = dynamic_cast(i->get()); + if (ret) return ret; + } + return 0; + } +#endif // the message handlers are called // each time a recv() returns some new @@ -142,9 +171,6 @@ namespace libtorrent void on_extended(int received); void on_extended_handshake(); - void on_chat(); - void on_metadata(); - void on_peer_exchange(); typedef void (bt_peer_connection::*message_handler)(int received); @@ -160,14 +186,16 @@ namespace libtorrent void write_have(int index); void write_piece(peer_request const& r); void write_handshake(); +#ifndef TORRENT_DISABLE_EXTENSIONS void write_extensions(); +#endif void write_chat_message(const std::string& msg); void write_metadata(std::pair req); void write_metadata_request(std::pair req); void write_keepalive(); void write_dht_port(int listen_port); void on_connected() {} - void on_tick(); + void on_metadata(); #ifndef NDEBUG void check_invariant() const; @@ -184,11 +212,6 @@ namespace libtorrent // will be invalid. boost::optional downloading_piece_progress() const; - // if we don't have all metadata - // this function will request a part of it - // from this peer - void request_metadata(); - enum state { read_protocol_length = 0, @@ -207,25 +230,6 @@ namespace libtorrent // the timeout in seconds int m_timeout; - enum message_type - { - // standard messages - msg_choke = 0, - msg_unchoke, - msg_interested, - msg_not_interested, - msg_have, - msg_bitfield, - msg_request, - msg_piece, - msg_cancel, - msg_dht_port, - // extension protocol message - msg_extended = 20, - - num_supported_messages - }; - static const message_handler m_message_handler[num_supported_messages]; // this is a queue of ranges that describes @@ -249,43 +253,19 @@ namespace libtorrent { return r.start < 0; } std::deque m_payloads; +#ifndef TORRENT_DISABLE_EXTENSIONS // this is set to true if the handshake from // the peer indicated that it supports the // extension protocol bool m_supports_extensions; +#endif bool m_supports_dht_port; - static const char* extension_names[num_supported_extensions]; - // contains the indices of the extension messages for each extension - // supported by the other end. A value of <= 0 means that the extension - // is not supported. - int m_extension_messages[num_supported_extensions]; - - // this is set to the current time each time we get a - // "I don't have metadata" message. - boost::posix_time::ptime m_no_metadata; - - // this is set to the time when we last sent - // a request for metadata to this peer - boost::posix_time::ptime m_metadata_request; - - // this is set to true when we send a metadata - // request to this peer, and reset to false when - // we receive a reply to our request. - bool m_waiting_metadata_request; - - // if we're waiting for a metadata request - // this was the request we sent - std::pair m_last_metadata_request; - - // the number of bytes of metadata we have received - // so far from this per, only counting the current - // request. Any previously finished requests - // that have been forwarded to the torrent object - // do not count. - int m_metadata_progress; - #ifndef NDEBUG + // this is set to true when the client's + // bitfield is sent to this peer + bool m_sent_bitfield; + bool m_in_constructor; #endif }; diff --git a/libtorrent/include/libtorrent/buffer.hpp b/libtorrent/include/libtorrent/buffer.hpp index 5dc2e558a..91ef58874 100644 --- a/libtorrent/include/libtorrent/buffer.hpp +++ b/libtorrent/include/libtorrent/buffer.hpp @@ -55,7 +55,7 @@ public: return begin[index]; } - int left() const { assert(end > begin); return end - begin; } + int left() const { assert(end >= begin); return end - begin; } char* begin; char* end; @@ -74,7 +74,7 @@ public: return begin[index]; } - int left() const { assert(end > begin); return end - begin; } + int left() const { assert(end >= begin); return end - begin; } char const* begin; char const* end; diff --git a/libtorrent/include/libtorrent/debug.hpp b/libtorrent/include/libtorrent/debug.hpp index 8aeeeb544..78df16b7a 100644 --- a/libtorrent/include/libtorrent/debug.hpp +++ b/libtorrent/include/libtorrent/debug.hpp @@ -67,10 +67,10 @@ namespace libtorrent struct logger { - logger(boost::filesystem::path const& filename, bool append = true) + logger(boost::filesystem::path const& filename, int instance, bool append = true) { using namespace boost::filesystem; - path dir(complete("libtorrent_logs")); + path dir(complete("libtorrent_logs" + boost::lexical_cast(instance))); if (!exists(dir)) create_directories(dir); m_file.open(dir / filename, std::ios_base::out | (append ? std::ios_base::app : std::ios_base::out)); *this << "\n\n\n*** starting log ***\n"; diff --git a/libtorrent/include/libtorrent/entry.hpp b/libtorrent/include/libtorrent/entry.hpp index 85c5462a2..31a78b972 100644 --- a/libtorrent/include/libtorrent/entry.hpp +++ b/libtorrent/include/libtorrent/entry.hpp @@ -128,14 +128,14 @@ namespace libtorrent data_type type() const; - entry(const dictionary_type&); - entry(const string_type&); - entry(const list_type&); - entry(const integer_type&); + entry(dictionary_type const&); + entry(string_type const&); + entry(list_type const&); + entry(integer_type const&); entry(); entry(data_type t); - entry(const entry& e); + entry(entry const& e); ~entry(); bool operator==(entry const& e) const; @@ -221,6 +221,7 @@ namespace libtorrent inline entry::integer_type& entry::integer() { + if (m_type == undefined_t) construct(int_t); if (m_type != int_t) throw type_error("invalid type requested from entry"); return *reinterpret_cast(data); } @@ -233,6 +234,7 @@ namespace libtorrent inline entry::string_type& entry::string() { + if (m_type == undefined_t) construct(string_t); if (m_type != string_t) throw type_error("invalid type requested from entry"); return *reinterpret_cast(data); } @@ -245,6 +247,7 @@ namespace libtorrent inline entry::list_type& entry::list() { + if (m_type == undefined_t) construct(list_t); if (m_type != list_t) throw type_error("invalid type requested from entry"); return *reinterpret_cast(data); } @@ -257,6 +260,7 @@ namespace libtorrent inline entry::dictionary_type& entry::dict() { + if (m_type == undefined_t) construct(dictionary_t); if (m_type != dictionary_t) throw type_error("invalid type requested from entry"); return *reinterpret_cast(data); } diff --git a/libtorrent/include/libtorrent/extensions.hpp b/libtorrent/include/libtorrent/extensions.hpp new file mode 100644 index 000000000..9068aa62a --- /dev/null +++ b/libtorrent/include/libtorrent/extensions.hpp @@ -0,0 +1,167 @@ +/* + +Copyright (c) 2006, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef TORRENT_EXTENSIONS_HPP_INCLUDED +#define TORRENT_EXTENSIONS_HPP_INCLUDED + +#ifndef TORRENT_DISABLE_EXTENSIONS + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include +#include "libtorrent/config.hpp" +#include "libtorrent/buffer.hpp" + +namespace libtorrent +{ + struct peer_plugin; + class bt_peer_connection; + struct peer_request; + class peer_connection; + class entry; + + struct TORRENT_EXPORT torrent_plugin + { + virtual ~torrent_plugin() {} + // throwing an exception closes the connection + // returning a 0 pointer is valid and will not add + // the peer_plugin to the peer_connection + virtual boost::shared_ptr new_connection(peer_connection*) + { return boost::shared_ptr(); } + + virtual void on_piece_pass(int index) {} + virtual void on_piece_failed(int index) {} + + // called aproximately once every second + virtual void tick() {} + + // if true is returned, it means the handler handled the event, + // and no other plugins will have their handlers called, and the + // default behavior will be skipped + virtual bool on_pause() { return false; } + virtual bool on_resume() { return false;} + }; + + struct TORRENT_EXPORT peer_plugin + { + virtual ~peer_plugin() {} + + // can add entries to the extension handshake + virtual void add_handshake(entry&) {} + + // throwing an exception from any of the handlers (except add_handshake) + // closes the connection + + // this is called when the initial BT handshake is received. Returning false + // means that the other end doesn't support this extension and will remove + // it from the list of plugins. + virtual bool on_handshake() { return true; } + + // called when the extension handshake from the other end is received + // if this returns false, it means that this extension isn't + // supported by this peer. It will result in this peer_plugin + // being removed from the peer_connection and destructed. + virtual bool on_extension_handshake(entry const& h) { return true; } + + // returning true from any of the message handlers + // indicates that the plugin has handeled the message. + // it will break the plugin chain traversing and not let + // anyone else handle the message, including the default + // handler. + + virtual bool on_choke() + { return false; } + + virtual bool on_unchoke() + { return false; } + + virtual bool on_interested() + { return false; } + + virtual bool on_not_interested() + { return false; } + + virtual bool on_have(int index) + { return false; } + + virtual bool on_bitfield(std::vector const& bitfield) + { return false; } + + virtual bool on_request(peer_request const& req) + { return false; } + + virtual bool on_piece(peer_request const& piece, char const* data) + { return false; } + + virtual bool on_cancel(peer_request const& req) + { return false; } + + // called when an extended message is received. If returning true, + // the message is not processed by any other plugin and if false + // is returned the next plugin in the chain will receive it to + // be able to handle it + virtual bool on_extended(int length + , int msg, buffer::const_interval body) + { return false; } + + virtual bool on_unknown_message(int length, int msg + , buffer::const_interval body) + { return false; } + + // called when a piece that this peer participated in either + // fails or passes the hash_check + virtual void on_piece_pass(int index) {} + virtual void on_piece_failed(int index) {} + + // called aproximately once every second + virtual void tick() {} + + // called each time a request message is to be sent. If true + // is returned, the original request message won't be sent and + // no other plugin will have this function called. + virtual bool write_request(peer_request const& r) { return false; } + }; + +} + +#endif + +#endif // TORRENT_EXTENSIONS_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/extensions/logger.hpp b/libtorrent/include/libtorrent/extensions/logger.hpp new file mode 100644 index 000000000..42e08fcf6 --- /dev/null +++ b/libtorrent/include/libtorrent/extensions/logger.hpp @@ -0,0 +1,54 @@ +/* + +Copyright (c) 2006, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef TORRENT_LOGGER_HPP_INCLUDED +#define TORRENT_LOGGER_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +namespace libtorrent +{ + struct torrent_plugin; + class torrent; + boost::shared_ptr create_logger_plugin(torrent*); +} + +#endif // TORRENT_LOGGER_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/extensions/metadata_transfer.hpp b/libtorrent/include/libtorrent/extensions/metadata_transfer.hpp new file mode 100644 index 000000000..6e11eb5b1 --- /dev/null +++ b/libtorrent/include/libtorrent/extensions/metadata_transfer.hpp @@ -0,0 +1,54 @@ +/* + +Copyright (c) 2006, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef TORRENT_METADATA_TRANSFER_HPP_INCLUDED +#define TORRENT_METADATA_TRANSFER_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +namespace libtorrent +{ + struct torrent_plugin; + class torrent; + boost::shared_ptr create_metadata_plugin(torrent*); +} + +#endif // TORRENT_METADATA_TRANSFER_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/extensions/ut_pex.hpp b/libtorrent/include/libtorrent/extensions/ut_pex.hpp new file mode 100644 index 000000000..c21c56816 --- /dev/null +++ b/libtorrent/include/libtorrent/extensions/ut_pex.hpp @@ -0,0 +1,53 @@ +/* + +Copyright (c) 2006, MassaRoddel +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef TORRENT_UT_PEX_EXTENSION_HPP_INCLUDED +#define TORRENT_UT_PEX_EXTENSION_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +namespace libtorrent +{ + struct torrent_plugin; + class torrent; + boost::shared_ptr create_ut_pex_plugin(torrent*); +} + +#endif // TORRENT_UT_PEX_EXTENSION_HPP_INCLUDED diff --git a/libtorrent/include/libtorrent/file_pool.hpp b/libtorrent/include/libtorrent/file_pool.hpp new file mode 100644 index 000000000..1da47fc85 --- /dev/null +++ b/libtorrent/include/libtorrent/file_pool.hpp @@ -0,0 +1,104 @@ +/* + +Copyright (c) 2006, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef TORRENT_FILE_POOL_HPP +#define TORRENT_FILE_POOL_HPP + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/file.hpp" + +namespace libtorrent +{ + + using boost::multi_index::multi_index_container; + using boost::multi_index::ordered_non_unique; + using boost::multi_index::ordered_unique; + using boost::multi_index::indexed_by; + using boost::multi_index::member; + namespace pt = boost::posix_time; + namespace fs = boost::filesystem; + + struct TORRENT_EXPORT file_pool : boost::noncopyable + { + file_pool(int size = 40): m_size(size) {} + + boost::shared_ptr open_file(void* st, fs::path const& p, file::open_mode m); + void release(void* st); + void resize(int size); + + private: + int m_size; + + struct lru_file_entry + { + lru_file_entry(boost::shared_ptr const& f) + : file_ptr(f) + , last_use(pt::second_clock::universal_time()) {} + mutable boost::shared_ptr file_ptr; + fs::path file_path; + void* key; + pt::ptime last_use; + file::open_mode mode; + }; + + typedef multi_index_container< + lru_file_entry, indexed_by< + ordered_unique > + , ordered_non_unique > + , ordered_non_unique > + > + > file_set; + + file_set m_files; + boost::mutex m_mutex; + }; +} + +#endif diff --git a/libtorrent/include/libtorrent/http_tracker_connection.hpp b/libtorrent/include/libtorrent/http_tracker_connection.hpp index b66d4349d..589f62fbb 100644 --- a/libtorrent/include/libtorrent/http_tracker_connection.hpp +++ b/libtorrent/include/libtorrent/http_tracker_connection.hpp @@ -72,11 +72,14 @@ namespace libtorrent std::string const& protocol() const { return m_protocol; } int status_code() const { return m_status_code; } std::string message() const { return m_server_message; } - buffer::const_interval get_body(); + buffer::const_interval get_body() const; bool header_finished() const { return m_state == read_body; } bool finished() const { return m_finished; } boost::tuple incoming(buffer::const_interval recv_buffer); int body_start() const { return m_body_start_pos; } + int content_length() const { return m_content_length; } + + void reset(); private: int m_recv_pos; int m_status_code; @@ -84,7 +87,6 @@ namespace libtorrent std::string m_server_message; int m_content_length; - enum { plain, gzip } m_content_encoding; enum { read_status, read_header, read_body } m_state; @@ -111,12 +113,13 @@ namespace libtorrent public: http_tracker_connection( - demuxer& d + asio::strand& str , tracker_manager& man , tracker_request const& req , std::string const& hostname , unsigned short port , std::string request + , address bind_infc , boost::weak_ptr c , session_settings const& stn , std::string const& password = ""); @@ -132,10 +135,10 @@ namespace libtorrent std::string const& hostname , std::string const& request); - void name_lookup(asio::error const& error, tcp::resolver::iterator i); - void connected(asio::error const& error); - void sent(asio::error const& error); - void receive(asio::error const& error + void name_lookup(asio::error_code const& error, tcp::resolver::iterator i); + void connected(asio::error_code const& error); + void sent(asio::error_code const& error); + void receive(asio::error_code const& error , std::size_t bytes_transferred); virtual void on_timeout(); @@ -144,12 +147,9 @@ namespace libtorrent peer_entry extract_peer_info(const entry& e); tracker_manager& m_man; - enum { read_status, read_header, read_body } m_state; - - enum { plain, gzip } m_content_encoding; - int m_content_length; - std::string m_location; + http_parser m_parser; + asio::strand& m_strand; tcp::resolver m_name_lookup; int m_port; boost::shared_ptr m_socket; @@ -157,16 +157,9 @@ namespace libtorrent std::vector m_buffer; std::string m_send_buffer; - std::string m_server_message; - std::string m_server_protocol; - session_settings const& m_settings; std::string m_password; - int m_code; - // server string in http-reply - std::string m_server; - bool m_timed_out; }; diff --git a/libtorrent/include/libtorrent/kademlia/dht_tracker.hpp b/libtorrent/include/libtorrent/kademlia/dht_tracker.hpp index d447d4b23..d1a3a8247 100644 --- a/libtorrent/include/libtorrent/kademlia/dht_tracker.hpp +++ b/libtorrent/include/libtorrent/kademlia/dht_tracker.hpp @@ -45,6 +45,8 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include +#include #include "libtorrent/kademlia/node.hpp" #include "libtorrent/kademlia/node_id.hpp" @@ -60,10 +62,18 @@ namespace libtorrent { namespace dht TORRENT_DECLARE_LOG(dht_tracker); #endif + struct dht_tracker; + + TORRENT_EXPORT void intrusive_ptr_add_ref(dht_tracker const*); + TORRENT_EXPORT void intrusive_ptr_release(dht_tracker const*); + struct dht_tracker { - dht_tracker(asio::io_service& d, dht_settings const& settings + friend void intrusive_ptr_add_ref(dht_tracker const*); + friend void intrusive_ptr_release(dht_tracker const*); + dht_tracker(asio::io_service& ios, dht_settings const& settings , asio::ip::address listen_interface, entry const& bootstrap); + void stop(); void add_node(udp::endpoint node); void add_node(std::pair const& node); @@ -80,22 +90,25 @@ namespace libtorrent { namespace dht void dht_status(session_status& s); private: + + boost::intrusive_ptr self() + { return boost::intrusive_ptr(this); } - void on_name_lookup(asio::error const& e + void on_name_lookup(asio::error_code const& e , udp::resolver::iterator host); - void on_router_name_lookup(asio::error const& e + void on_router_name_lookup(asio::error_code const& e , udp::resolver::iterator host); - void connection_timeout(asio::error const& e); - void refresh_timeout(asio::error const& e); - void tick(asio::error const& e); + void connection_timeout(asio::error_code const& e); + void refresh_timeout(asio::error_code const& e); + void tick(asio::error_code const& e); - // translate bittorrent kademlia message into the generice kademlia message + // translate bittorrent kademlia message into the generic kademlia message // used by the library - void on_receive(asio::error const& error, size_t bytes_transferred); + void on_receive(asio::error_code const& error, size_t bytes_transferred); void on_bootstrap(); void send_packet(msg const& m); - asio::io_service& m_demuxer; + asio::strand m_strand; asio::ip::udp::socket m_socket; node_impl m_dht; @@ -116,6 +129,9 @@ namespace libtorrent { namespace dht // used to resolve hostnames for nodes udp::resolver m_host_resolver; + + // reference counter for intrusive_ptr + mutable boost::detail::atomic_count m_refs; #ifdef TORRENT_DHT_VERBOSE_LOGGING int m_replies_sent[5]; @@ -131,6 +147,7 @@ namespace libtorrent { namespace dht int m_lt_message_input; int m_mp_message_input; int m_gr_message_input; + int m_mo_message_input; int m_total_in_bytes; int m_total_out_bytes; diff --git a/libtorrent/include/libtorrent/kademlia/logging.hpp b/libtorrent/include/libtorrent/kademlia/logging.hpp index 8bd488f1a..c0cbb31a4 100644 --- a/libtorrent/include/libtorrent/kademlia/logging.hpp +++ b/libtorrent/include/libtorrent/kademlia/logging.hpp @@ -133,7 +133,7 @@ public: #define TORRENT_DEFINE_LOG(name) \ libtorrent::dht::log& name ## _log() \ { \ - static std::ofstream log_file("libtorrent_logs/dht.log", std::ios::app); \ + static std::ofstream log_file("dht.log", std::ios::app); \ static libtorrent::dht::log instance(#name, log_file); \ return instance; \ } diff --git a/libtorrent/include/libtorrent/kademlia/refresh.hpp b/libtorrent/include/libtorrent/kademlia/refresh.hpp index f47b80462..7231b26f2 100644 --- a/libtorrent/include/libtorrent/kademlia/refresh.hpp +++ b/libtorrent/include/libtorrent/kademlia/refresh.hpp @@ -69,7 +69,7 @@ public: ); void ping_reply(node_id id); - void ping_timeout(node_id id); + void ping_timeout(node_id id, bool prevent_request = false); private: template @@ -88,7 +88,7 @@ private: void done(); void invoke(node_id const& id, udp::endpoint addr); - void invoke_pings_or_finish(); + void invoke_pings_or_finish(bool prevent_request = false); int m_max_active_pings; int m_active_pings; diff --git a/libtorrent/include/libtorrent/kademlia/rpc_manager.hpp b/libtorrent/include/libtorrent/kademlia/rpc_manager.hpp index 5aa850e95..2603071fc 100644 --- a/libtorrent/include/libtorrent/kademlia/rpc_manager.hpp +++ b/libtorrent/include/libtorrent/kademlia/rpc_manager.hpp @@ -128,6 +128,12 @@ struct observer : boost::noncopyable // this is called when no reply has been received within // some timeout virtual void timeout() = 0; + + // if this is called the destructor should + // not invoke any new messages, and should + // only clean up. It means the rpc-manager + // is being destructed + virtual void abort() = 0; udp::endpoint target_addr; boost::posix_time::ptime sent; @@ -162,7 +168,8 @@ public: private: enum { max_transactions = 2048 }; - unsigned int new_transaction_id(); + + unsigned int new_transaction_id(boost::shared_ptr o); void update_oldest_transaction_id(); boost::uint32_t calc_connection_id(udp::endpoint addr); @@ -170,6 +177,7 @@ private: typedef boost::array, max_transactions> transactions_t; transactions_t m_transactions; + std::vector > m_aborted_transactions; // this is the next transaction id to be used int m_next_transaction_id; @@ -185,6 +193,7 @@ private: routing_table& m_table; boost::posix_time::ptime m_timer; node_id m_random_number; + bool m_destructing; }; } } // namespace libtorrent::dht diff --git a/libtorrent/include/libtorrent/kademlia/traversal_algorithm.hpp b/libtorrent/include/libtorrent/kademlia/traversal_algorithm.hpp index a99a9c6ea..6fa647ba4 100644 --- a/libtorrent/include/libtorrent/kademlia/traversal_algorithm.hpp +++ b/libtorrent/include/libtorrent/kademlia/traversal_algorithm.hpp @@ -58,7 +58,7 @@ class traversal_algorithm : boost::noncopyable public: void traverse(node_id const& id, udp::endpoint addr); void finished(node_id const& id); - void failed(node_id const& id); + void failed(node_id const& id, bool prevent_request = false); virtual ~traversal_algorithm() {} protected: @@ -73,7 +73,6 @@ protected: , InIt end ); - void add_request(node_id const& id, udp::endpoint addr); void add_requests(); void add_entry(node_id const& id, udp::endpoint addr, unsigned char flags); diff --git a/libtorrent/include/libtorrent/peer_connection.hpp b/libtorrent/include/libtorrent/peer_connection.hpp index a7f9b7e53..0763ed56c 100644 --- a/libtorrent/include/libtorrent/peer_connection.hpp +++ b/libtorrent/include/libtorrent/peer_connection.hpp @@ -71,6 +71,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/piece_block_progress.hpp" #include "libtorrent/config.hpp" #include "libtorrent/session.hpp" +#include "libtorrent/bandwidth_manager.hpp" // TODO: each time a block is 'taken over' // from another peer. That peer must be given @@ -79,6 +80,7 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { class torrent; + struct peer_plugin; namespace detail { @@ -101,6 +103,13 @@ namespace libtorrent friend void intrusive_ptr_release(peer_connection const*); public: + enum channels + { + upload_channel, + download_channel, + num_channels + }; + // this is the constructor where the we are the active part. // The peer_conenction should handshake and verify that the // other end has the correct id @@ -108,7 +117,8 @@ namespace libtorrent aux::session_impl& ses , boost::weak_ptr t , boost::shared_ptr s - , tcp::endpoint const& remote); + , tcp::endpoint const& remote + , tcp::endpoint const& proxy); // with this constructor we have been contacted and we still don't // know which torrent the connection belongs to @@ -116,16 +126,39 @@ namespace libtorrent aux::session_impl& ses , boost::shared_ptr s); + virtual ~peer_connection(); + +#ifndef TORRENT_DISABLE_EXTENSIONS + void add_extension(boost::shared_ptr); +#endif + // this function is called once the torrent associated // with this peer connection has retrieved the meta- // data. If the torrent was spawned with metadata // this is called from the constructor. void init(); + // this is called when the metadata is retrieved + // and the files has been checked + virtual void on_metadata() {} + void set_upload_limit(int limit); void set_download_limit(int limit); - virtual ~peer_connection(); + bool prefer_whole_pieces() const + { return m_prefer_whole_pieces; } + + void prefer_whole_pieces(bool b) + { m_prefer_whole_pieces = b; } + + bool request_large_blocks() const + { return m_request_large_blocks; } + + void request_large_blocks(bool b) + { m_request_large_blocks = b; } + + void set_non_prioritized(bool b) + { m_non_prioritized = b; } // this adds an announcement in the announcement queue // it will let the peer know that we have the given piece @@ -172,20 +205,18 @@ namespace libtorrent boost::shared_ptr get_socket() const { return m_socket; } tcp::endpoint const& remote() const { return m_remote; } + tcp::endpoint const& proxy() const { return m_remote_proxy; } std::vector const& get_bitfield() const; // this will cause this peer_connection to be disconnected. - // what it does is that it puts a reference to it in - // m_ses.m_disconnect_peer list, which will be scanned in the - // mainloop to disconnect peers. void disconnect(); bool is_disconnecting() const { return m_disconnecting; } // this is called when the connection attempt has succeeded // and the peer_connection is supposed to set m_connecting // to false, and stop monitor writability - void on_connection_complete(asio::error const& e); + void on_connection_complete(asio::error_code const& e); // returns true if this connection is still waiting to // finish the connection attempt @@ -212,8 +243,8 @@ namespace libtorrent void add_free_upload(size_type free_upload); // trust management. - void received_valid_data(); - void received_invalid_data(); + void received_valid_data(int index); + void received_invalid_data(int index); int trust_points() const; size_type share_diff() const; @@ -261,13 +292,20 @@ namespace libtorrent // adds a block to the request queue void add_request(piece_block const& b); + // removes a block from the request queue or download queue + // sends a cancel message if appropriate + // refills the request queue, and possibly ignoring pieces requested + // by peers in the ignore list (to avoid recursion) void cancel_request(piece_block const& b); void send_block_requests(); - // how much bandwidth we're using, how much we want, - // and how much we are allowed to use. - resource_request m_ul_bandwidth_quota; - resource_request m_dl_bandwidth_quota; + int max_assignable_bandwidth(int channel) const + { + return m_bandwidth_limit[channel].max_assignable(); + } + + void assign_bandwidth(int channel, int amount); + void expire_bandwidth(int channel, int amount); #ifndef NDEBUG void check_invariant() const; @@ -276,6 +314,10 @@ namespace libtorrent virtual void get_peer_info(peer_info& p) const = 0; + // is true until we can be sure that the other end + // speaks our protocol (be it bittorrent or http). + virtual bool in_handshake() const = 0; + // returns the block currently being // downloaded. And the progress of that // block. If the peer isn't downloading @@ -290,6 +332,18 @@ namespace libtorrent return boost::optional(); } + void send_buffer(char const* begin, char const* end); + buffer::interval allocate_send_buffer(int size); + void setup_send(); + + void set_country(char const* c) + { + assert(strlen(c) == 2); + m_country[0] = c[0]; + m_country[1] = c[1]; + } + bool has_country() const { return m_country[0] != 0; } + protected: virtual void write_choke() = 0; @@ -305,13 +359,11 @@ namespace libtorrent virtual void on_connected() = 0; virtual void on_tick() {} - virtual void on_receive(asio::error const& error + virtual void on_receive(asio::error_code const& error , std::size_t bytes_transferred) = 0; - virtual void on_sent(asio::error const& error + virtual void on_sent(asio::error_code const& error , std::size_t bytes_transferred) = 0; - void send_buffer(char const* begin, char const* end); - buffer::interval allocate_send_buffer(int size); int send_buffer_size() const { return (int)m_send_buffer[0].size() @@ -333,16 +385,19 @@ namespace libtorrent bool packet_finished() const { assert(m_recv_pos <= m_packet_size); - return m_packet_size == m_recv_pos; + return m_packet_size <= m_recv_pos; } - void setup_send(); void setup_receive(); void attach_to_torrent(sha1_hash const& ih); bool verify_piece(peer_request const& p) const; + // the bandwidth channels, upload and download + // keeps track of the current quotas + bandwidth_limit m_bandwidth_limit[num_channels]; + // statistics about upload and download speeds // and total amount of uploads and downloads for // this peer @@ -357,9 +412,9 @@ namespace libtorrent // called from the main loop when this connection has any // work to do. - void on_send_data(asio::error const& error + void on_send_data(asio::error_code const& error , std::size_t bytes_transferred); - void on_receive_data(asio::error const& error + void on_receive_data(asio::error_code const& error , std::size_t bytes_transferred); // this is the limit on the number of outstanding requests @@ -372,6 +427,17 @@ namespace libtorrent void set_timeout(int s) { m_timeout = s; } +#ifndef TORRENT_DISABLE_EXTENSIONS + typedef std::list > extension_list_t; + extension_list_t m_extensions; +#endif + + // in case the session settings is set + // to resolve countries, this is set to + // the two character country code this + // peer resides in. + char m_country[2]; + private: void fill_send_buffer(); @@ -412,7 +478,13 @@ namespace libtorrent boost::posix_time::ptime m_last_sent; boost::shared_ptr m_socket; + // this is the peer we're actually talking to + // it may not necessarily be the peer we're + // connected to, in case we use a proxy tcp::endpoint m_remote; + + // if we use a proxy, this is the address to it + tcp::endpoint m_remote_proxy; // this is the torrent this connection is // associated with. If the connection is an @@ -535,16 +607,34 @@ namespace libtorrent // these are true when there's a asynchronous write // or read operation running. bool m_writing; - // this is the number of bytes sent to the socket last - // time it was invoked. This is compared against the - // bytes_transferred in the callback function that tells - // how much actually was sent. Then the quota can be - // corrected according to the actual number of bytes sent - int m_last_write_size; bool m_reading; - int m_last_read_size; + + // if set to true, this peer will always prefer + // to request entire pieces, rather than blocks. + // if it is false, the download rate limit setting + // will be used to determine if whole pieces + // are preferred. + bool m_prefer_whole_pieces; + + // if this is true, the blocks picked by the piece + // picker will be merged before passed to the + // request function. i.e. subsequent blocks are + // merged into larger blocks. This is used by + // the http-downloader, to request whole pieces + // at a time. + bool m_request_large_blocks; + + // if this is true, other (prioritized) peers will + // skip ahead of it in the queue for bandwidth. The + // effect is that non prioritized peers will only use + // the left-over bandwidth (suitable for web seeds). + bool m_non_prioritized; + // reference counter for intrusive_ptr mutable boost::detail::atomic_count m_refs; + + int m_upload_limit; + int m_download_limit; #ifndef NDEBUG public: diff --git a/libtorrent/include/libtorrent/peer_id.hpp b/libtorrent/include/libtorrent/peer_id.hpp index d3bf624b7..e5a224bc4 100644 --- a/libtorrent/include/libtorrent/peer_id.hpp +++ b/libtorrent/include/libtorrent/peer_id.hpp @@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "libtorrent/config.hpp" @@ -55,6 +56,12 @@ namespace libtorrent big_number() {} + big_number(std::string const& s) + { + int sl = int(s.size()) < size ? int(s.size()) : size; + std::memcpy(m_number, &s[0], sl); + } + // when initialized with 0 big_number(private_pointer*) { clear(); } diff --git a/libtorrent/include/libtorrent/peer_info.hpp b/libtorrent/include/libtorrent/peer_info.hpp index 7a6e50834..c293fd345 100644 --- a/libtorrent/include/libtorrent/peer_info.hpp +++ b/libtorrent/include/libtorrent/peer_info.hpp @@ -69,6 +69,12 @@ namespace libtorrent bool seed; // true if this is a seed int upload_limit; int download_limit; + + // in case the session settings is set + // to resolve countries, this is set to + // the two character country code this + // peer resides in. + char country[2]; size_type load_balancing; diff --git a/libtorrent/include/libtorrent/piece_picker.hpp b/libtorrent/include/libtorrent/piece_picker.hpp index 23f20a79a..429ec34f6 100644 --- a/libtorrent/include/libtorrent/piece_picker.hpp +++ b/libtorrent/include/libtorrent/piece_picker.hpp @@ -199,7 +199,7 @@ namespace libtorrent void get_downloaders(std::vector& d, int index) const; - const std::vector& get_download_queue() const + std::vector const& get_download_queue() const { return m_downloads; } boost::optional get_downloader(piece_block block) const; @@ -337,6 +337,9 @@ namespace libtorrent // the required popularity of a piece in order to download // it in sequence instead of random order. int m_sequenced_download_threshold; +#ifndef NDEBUG + bool m_files_checked_called; +#endif }; inline int piece_picker::blocks_in_piece(int index) const diff --git a/libtorrent/include/libtorrent/policy.hpp b/libtorrent/include/libtorrent/policy.hpp index 1358e2bdf..82d04eecc 100644 --- a/libtorrent/include/libtorrent/policy.hpp +++ b/libtorrent/include/libtorrent/policy.hpp @@ -69,6 +69,10 @@ namespace libtorrent free_upload_amount = 4 * 16 * 1024 }; + void request_a_block( + torrent& t + , peer_connection& c + , std::vector ignore = std::vector()); class TORRENT_EXPORT policy { @@ -85,7 +89,6 @@ namespace libtorrent void peer_from_tracker(const tcp::endpoint& remote, const peer_id& pid); // called when an incoming connection is accepted - // return false if the connection closed void new_connection(peer_connection& c); // this is called if a peer timed-out or diff --git a/libtorrent/include/libtorrent/random_sample.hpp b/libtorrent/include/libtorrent/random_sample.hpp index 741576fd9..8d85080df 100644 --- a/libtorrent/include/libtorrent/random_sample.hpp +++ b/libtorrent/include/libtorrent/random_sample.hpp @@ -36,6 +36,8 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#include "libtorrent/config.hpp" + namespace libtorrent { @@ -51,7 +53,7 @@ namespace libtorrent while (m < n) { - if ((rand() / (RAND_MAX + 1.f)) * (N - t) >= n - m) + if ((std::rand() / (RAND_MAX + 1.f)) * (N - t) >= n - m) { ++start; ++t; diff --git a/libtorrent/include/libtorrent/resource_request.hpp b/libtorrent/include/libtorrent/resource_request.hpp index 046b49df9..1e41b9cbb 100644 --- a/libtorrent/include/libtorrent/resource_request.hpp +++ b/libtorrent/include/libtorrent/resource_request.hpp @@ -54,6 +54,7 @@ namespace libtorrent , min(0) , max(0) , given(0) + , leftovers(0) {} resource_request(int used_, int min_, int max_, int given_) @@ -61,16 +62,18 @@ namespace libtorrent , min(min_) , max(max_) , given(given_) + , leftovers(0) {} int left() const { assert(given <= max); assert(given >= min); - if (used < 0 && (given - used < 0)) - return boost::integer_traits::const_max; - return given - used; + assert(used >= 0); + return (std::max)(given - used, 0); } + + void reset() { used = leftovers; leftovers = 0; } static const int inf = boost::integer_traits::const_max; @@ -84,6 +87,11 @@ namespace libtorrent // Reply: Okay, you're allowed to use this amount (a compromise): int given; + + // this is the amount of resources that exceeded the + // given limit. When the used field is reset (after resources + // have been distributed), it is reset to this number. + int leftovers; }; } diff --git a/libtorrent/include/libtorrent/session.hpp b/libtorrent/include/libtorrent/session.hpp index d62d69493..454b34f7e 100644 --- a/libtorrent/include/libtorrent/session.hpp +++ b/libtorrent/include/libtorrent/session.hpp @@ -60,41 +60,30 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/version.hpp" #include "libtorrent/fingerprint.hpp" +#include "libtorrent/resource_request.hpp" -#if !defined(NDEBUG) && defined(_MSC_VER) -# include +#ifdef _MSC_VER # include #endif namespace libtorrent { + struct torrent_plugin; class torrent; class ip_filter; - enum extension_index - { - extended_handshake, - extended_chat_message, - extended_metadata_message, - extended_peer_exchange_message, - num_supported_extensions - }; namespace aux { // workaround for microsofts // hardware exceptions that makes // it hard to debug stuff -#if defined(_MSC_VER) +#ifdef _MSC_VER struct eh_initializer { eh_initializer() { -#ifndef NDEBUG - _clearfp(); - _controlfp(_EM_INEXACT | _EM_UNDERFLOW, _MCW_EM ); ::_set_se_translator(straight_to_debugger); -#endif } static void straight_to_debugger(unsigned int, _EXCEPTION_POINTERS*) @@ -104,6 +93,12 @@ namespace libtorrent struct eh_initializer {}; #endif struct session_impl; + + struct filesystem_init + { + filesystem_init(); + }; + } class TORRENT_EXPORT session_proxy @@ -130,7 +125,11 @@ namespace libtorrent ~session(); + // returns a list of all torrents in this session std::vector get_torrents() const; + + // returns an invalid handle in case the torrent doesn't exist + torrent_handle find_torrent(sha1_hash const& info_hash) const; // all torrent_handles must be destructed before the session is destructed! torrent_handle add_torrent( @@ -155,6 +154,7 @@ namespace libtorrent torrent_handle add_torrent( char const* tracker_url , sha1_hash const& info_hash + , char const* name , boost::filesystem::path const& save_path , entry const& resume_data = entry() , bool compact_mode = true @@ -173,8 +173,11 @@ namespace libtorrent void add_dht_router(std::pair const& node); #endif - void enable_extension(extension_index i); - void disable_extensions(); +#ifndef TORRENT_DISABLE_EXTENSIONS + + void add_extension(boost::function(torrent*)> ext); + +#endif void set_ip_filter(ip_filter const& f); void set_peer_id(peer_id const& pid); @@ -200,10 +203,21 @@ namespace libtorrent // returns the port we ended up listening on unsigned short listen_port() const; + // Get the number of uploads. + int num_uploads() const; + + // Get the number of connections. This number also contains the + // number of half open connections. + int num_connections() const; + void remove_torrent(const torrent_handle& h); void set_settings(session_settings const& s); session_settings const& settings(); + + int upload_rate_limit() const; + int download_rate_limit() const; + void set_upload_rate_limit(int bytes_per_second); void set_download_rate_limit(int bytes_per_second); void set_max_uploads(int limit); @@ -213,8 +227,18 @@ namespace libtorrent std::auto_ptr pop_alert(); void set_severity_level(alert::severity_t s); + // Resource management used for global limits. + resource_request m_ul_bandwidth_quota; + resource_request m_dl_bandwidth_quota; + resource_request m_uploads_quota; + resource_request m_connections_quota; + private: + // just a way to initialize boost.filesystem + // before the session_impl is created + aux::filesystem_init m_dummy; + // data shared between the main thread // and the working thread boost::shared_ptr m_impl; diff --git a/libtorrent/include/libtorrent/session_settings.hpp b/libtorrent/include/libtorrent/session_settings.hpp index 80d328611..7f6418d74 100644 --- a/libtorrent/include/libtorrent/session_settings.hpp +++ b/libtorrent/include/libtorrent/session_settings.hpp @@ -56,6 +56,11 @@ namespace libtorrent , peer_timeout(120) , urlseed_timeout(20) , urlseed_pipeline_size(5) + , file_pool_size(40) + , allow_multiple_connections_per_ip(false) +#ifndef TORRENT_DISABLE_DHT + , use_dht_as_fallback(true) +#endif {} std::string proxy_ip; @@ -130,6 +135,30 @@ namespace libtorrent // controls the pipelining size of url-seeds int urlseed_pipeline_size; + + // sets the upper limit on the total number of files this + // session will keep open. The reason why files are + // left open at all is that some anti virus software + // hooks on every file close, and scans the file for + // viruses. deferring the closing of the files will + // be the difference between a usable system and + // a completely hogged down system. Most operating + // systems also has a limit on the total number of + // file descriptors a process may have open. It is + // usually a good idea to find this limit and set the + // number of connections and the number of files + // limits so their sum is slightly below it. + int file_pool_size; + + // false to not allow multiple connections from the same + // IP address. true will allow it. + bool allow_multiple_connections_per_ip; + +#ifndef TORRENT_DISABLE_DHT + // while this is true, the dht will note be used unless the + // tracker is online + bool use_dht_as_fallback; +#endif }; #ifndef TORRENT_DISABLE_DHT diff --git a/libtorrent/include/libtorrent/session_status.hpp b/libtorrent/include/libtorrent/session_status.hpp index 7d12674fd..834044e36 100644 --- a/libtorrent/include/libtorrent/session_status.hpp +++ b/libtorrent/include/libtorrent/session_status.hpp @@ -56,9 +56,9 @@ namespace libtorrent int num_peers; #ifndef TORRENT_DISABLE_DHT - int m_dht_nodes; - int m_dht_node_cache; - int m_dht_torrents; + int dht_nodes; + int dht_node_cache; + int dht_torrents; #endif }; diff --git a/libtorrent/include/libtorrent/socket.hpp b/libtorrent/include/libtorrent/socket.hpp index 394c2a133..5df7a4579 100644 --- a/libtorrent/include/libtorrent/socket.hpp +++ b/libtorrent/include/libtorrent/socket.hpp @@ -50,6 +50,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #ifdef __OBJC__ #undef Protocol @@ -71,7 +72,7 @@ namespace libtorrent using boost::asio::stream_socket; using boost::asio::datagram_socket; using boost::asio::socket_acceptor; - using boost::asio::demuxer; + using boost::asio::io_service; using boost::asio::ipv4::host_resolver; using boost::asio::async_write; using boost::asio::ipv4::host; @@ -87,7 +88,7 @@ namespace libtorrent typedef asio::ip::address_v6 address_v6; typedef asio::ip::udp::socket datagram_socket; typedef asio::ip::tcp::acceptor socket_acceptor; - typedef asio::io_service demuxer; + typedef asio::io_service io_service; using asio::async_write; using asio::deadline_timer; diff --git a/libtorrent/include/libtorrent/storage.hpp b/libtorrent/include/libtorrent/storage.hpp index 44f956786..808e90a1a 100644 --- a/libtorrent/include/libtorrent/storage.hpp +++ b/libtorrent/include/libtorrent/storage.hpp @@ -61,6 +61,7 @@ namespace libtorrent } class session; + struct file_pool; #if defined(_WIN32) && defined(UNICODE) @@ -91,7 +92,8 @@ namespace libtorrent public: storage( const torrent_info& info - , const boost::filesystem::path& path); + , const boost::filesystem::path& path + , file_pool& fp); void swap(storage&); @@ -125,14 +127,15 @@ namespace libtorrent piece_manager( const torrent_info& info - , const boost::filesystem::path& path); + , const boost::filesystem::path& path + , file_pool& fp); ~piece_manager(); bool check_fastresume(aux::piece_checker_data& d , std::vector& pieces, int& num_pieces, bool compact_mode); std::pair check_files(std::vector& pieces - , int& num_pieces); + , int& num_pieces, boost::recursive_mutex& mutex); void release_files(); diff --git a/libtorrent/include/libtorrent/torrent.hpp b/libtorrent/include/libtorrent/torrent.hpp index 17bdc50d7..56a4f54be 100644 --- a/libtorrent/include/libtorrent/torrent.hpp +++ b/libtorrent/include/libtorrent/torrent.hpp @@ -49,6 +49,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #ifdef _MSC_VER #pragma warning(pop) @@ -66,6 +67,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/piece_picker.hpp" #include "libtorrent/config.hpp" #include "libtorrent/escape_string.hpp" +#include "libtorrent/bandwidth_manager.hpp" namespace libtorrent { @@ -74,6 +76,7 @@ namespace libtorrent #endif class piece_manager; + struct torrent_plugin; namespace aux { @@ -81,10 +84,6 @@ namespace libtorrent struct piece_checker_data; } - int div_round_up(int numerator, int denominator); - std::pair req_to_offset(std::pair req, int total_size); - std::pair offset_to_req(std::pair offset, int total_size); - // a torrent is a class that holds information // for a specific download. It updates itself against // the tracker @@ -110,6 +109,7 @@ namespace libtorrent , aux::checker_impl& checker , char const* tracker_url , sha1_hash const& info_hash + , char const* name , boost::filesystem::path const& save_path , tcp::endpoint const& net_interface , bool compact_mode @@ -118,6 +118,10 @@ namespace libtorrent ~torrent(); +#ifndef TORRENT_DISABLE_EXTENSIONS + void add_extension(boost::shared_ptr); +#endif + // this is called when the torrent has metadata. // it will initialize the storage and the piece-picker void init(); @@ -135,6 +139,8 @@ namespace libtorrent session_settings const& settings() const; + aux::session_impl& session() { return m_ses; } + void set_sequenced_download_threshold(int threshold); // is called every second by session. This will @@ -146,10 +152,8 @@ namespace libtorrent // debug purpose only void print(std::ostream& os) const; - // this is called from the peer_connection for - // each piece of metadata it receives - void metadata_progress(int total_size, int received); - + std::string name() const; + bool check_fastresume(aux::piece_checker_data&); std::pair check_files(); void files_checked(std::vector const& @@ -186,6 +190,25 @@ namespace libtorrent float ratio() const { return m_ratio; } + void resolve_countries(bool r) + { m_resolve_countries = r; } + + bool resolving_countries() const { return m_resolve_countries; } + +// -------------------------------------------- + // BANDWIDTH MANAGEMENT + + bandwidth_limit m_bandwidth_limit[2]; + + void request_bandwidth(int channel + , boost::intrusive_ptr p + , bool non_prioritized); + + void expire_bandwidth(int channel, int amount); + void assign_bandwidth(int channel, int amount); + + int bandwidth_throttle(int channel) const; + // -------------------------------------------- // PEER MANAGEMENT @@ -227,6 +250,7 @@ namespace libtorrent peer_iterator begin() { return m_connections.begin(); } peer_iterator end() { return m_connections.end(); } + void resolve_peer_country(boost::intrusive_ptr const& p) const; // -------------------------------------------- // TRACKER MANAGEMENT @@ -295,17 +319,35 @@ namespace libtorrent // piece a peer has gained. void peer_has(int index) { - assert(m_picker.get()); - assert(index >= 0 && index < (signed)m_have_pieces.size()); - m_picker->inc_refcount(index); + if (m_picker.get()) + { + assert(!is_seed()); + assert(index >= 0 && index < (signed)m_have_pieces.size()); + m_picker->inc_refcount(index); + } +#ifndef NDEBUG + else + { + assert(is_seed()); + } +#endif } // when peer disconnects, this is called for every piece it had void peer_lost(int index) { - assert(m_picker.get()); - assert(index >= 0 && index < (signed)m_have_pieces.size()); - m_picker->dec_refcount(index); + if (m_picker.get()) + { + assert(!is_seed()); + assert(index >= 0 && index < (signed)m_have_pieces.size()); + m_picker->dec_refcount(index); + } +#ifndef NDEBUG + else + { + assert(is_seed()); + } +#endif } int block_size() const { assert(m_block_size > 0); return m_block_size; } @@ -321,10 +363,20 @@ namespace libtorrent // the download. It will post an event, disconnect // all seeds and let the tracker know we're finished. void completed(); - + // this is the asio callback that is called when a name - // lookup for a web seed is completed. - void on_name_lookup(asio::error const& e, tcp::resolver::iterator i + // lookup for a PEER is completed. + void on_peer_name_lookup(asio::error_code const& e, tcp::resolver::iterator i + , peer_id pid); + + // this is the asio callback that is called when a name + // lookup for a WEB SEED is completed. + void on_name_lookup(asio::error_code const& e, tcp::resolver::iterator i + , std::string url, tcp::endpoint proxy); + + // this is the asio callback that is called when a name + // lookup for a proxy for a web seed is completed. + void on_proxy_name_lookup(asio::error_code const& e, tcp::resolver::iterator i , std::string url); // this is called when the torrent has finished. i.e. @@ -342,15 +394,6 @@ namespace libtorrent void received_redundant_data(int num_bytes) { assert(num_bytes > 0); m_total_redundant_bytes += num_bytes; } - float priority() const - { return m_priority; } - - void set_priority(float p) - { - assert(p >= 0.f && p <= 1.f); - m_priority = p; - } - bool is_seed() const { return valid_metadata() @@ -382,8 +425,6 @@ namespace libtorrent // LOGGING #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - logger* spawn_logger(const char* title); - virtual void debug_log(const std::string& line); #endif @@ -395,12 +436,8 @@ namespace libtorrent // -------------------------------------------- // RESOURCE MANAGEMENT - // this will distribute the given upload/download - // quotas and number of connections, among the peers - void distribute_resources(); + void distribute_resources(float tick_interval); - resource_request m_ul_bandwidth_quota; - resource_request m_dl_bandwidth_quota; resource_request m_uploads_quota; resource_request m_connections_quota; @@ -419,23 +456,20 @@ namespace libtorrent { return m_connections_initialized; } bool valid_metadata() const { return m_storage.get() != 0; } - std::vector const& metadata() const; - - bool received_metadata( - char const* buf - , int size - , int offset - , int total_size); - - // returns a range of the metadata that - // we should request. - std::pair metadata_request(); - void cancel_metadata_request(std::pair req); + // parses the info section from the given + // bencoded tree and moves the torrent + // to the checker thread for initial checking + // of the storage. + void set_metadata(entry const&); + private: - + void try_next_tracker(); int prioritize_tracker(int tracker_index); + void on_country_lookup(asio::error_code const& error, tcp::resolver::iterator i + , boost::intrusive_ptr p) const; + bool request_bandwidth_from_session(int channel) const; torrent_info m_torrent_file; @@ -495,20 +529,35 @@ namespace libtorrent std::set m_resolving_web_seeds; // used to resolve the names of web seeds - tcp::resolver m_host_resolver; + mutable tcp::resolver m_host_resolver; + // this is true while there is a country + // resolution in progress. To avoid flodding + // the DNS request queue, only one ip is reolved + // at a time. + mutable bool m_resolving_country; + + // this is true if the user has enabled + // country resolution in this torrent + bool m_resolve_countries; + #ifndef TORRENT_DISABLE_DHT static void on_dht_announce_response_disp(boost::weak_ptr t , std::vector const& peers); deadline_timer m_dht_announce_timer; - void on_dht_announce(asio::error const& e); + void on_dht_announce(asio::error_code const& e); void on_dht_announce_response(std::vector const& peers); + bool should_announce_dht() const; #endif // this is the upload and download statistics for the whole torrent. // it's updated from all its peers once every second. libtorrent::stat m_stat; + // this is the stats for web seeds in this torrent only. It is updated + // once every second. + libtorrent::stat m_web_stat; + // ----------------------------- boost::shared_ptr m_policy; @@ -520,6 +569,9 @@ namespace libtorrent boost::scoped_ptr m_picker; + // the queue of peer_connections that want more bandwidth + std::deque m_bandwidth_queue[2]; + std::vector m_trackers; // this is an index into m_torrent_file.trackers() int m_last_working_tracker; @@ -534,11 +586,6 @@ namespace libtorrent // is called and the time scaler is reset to 0. int m_time_scaler; - // this is the priority of this torrent. It is used - // to weight the assigned upload bandwidth between peers - // it should be within the range [0, 1] - float m_priority; - // the bitmask that says which pieces we have std::vector m_have_pieces; @@ -569,35 +616,11 @@ namespace libtorrent // are opened through tcp::endpoint m_net_interface; - // the max number of bytes this torrent - // can upload per second - int m_upload_bandwidth_limit; - int m_download_bandwidth_limit; - - // this buffer is filled with the info-section of - // the metadata file while downloading it from - // peers, and while sending it. - // it is mutable because it's generated lazily - mutable std::vector m_metadata; - - // this is a bitfield of size 256, each bit represents - // a piece of the metadata. It is set to one if we - // have that piece. This vector may be empty - // (size 0) if we haven't received any metadata - // or if we already have all metadata - std::vector m_have_metadata; - // this vector keeps track of how many times each meatdata - // block has been requested - std::vector m_requested_metadata; - boost::filesystem::path m_save_path; // determines the storage state for this torrent. const bool m_compact_mode; - int m_metadata_progress; - int m_metadata_size; - // defaults to 16 kiB, but can be set by the user // when creating the torrent const int m_default_block_size; @@ -613,7 +636,18 @@ namespace libtorrent // has been initialized with files_checked(). bool m_connections_initialized; + // if the torrent is started without metadata, it may + // still be given a name until the metadata is received + // once the metadata is received this field will no + // longer be used and will be reset + boost::scoped_ptr m_name; + session_settings const& m_settings; + +#ifndef TORRENT_DISABLE_EXTENSIONS + typedef std::list > extension_list_t; + extension_list_t m_extensions; +#endif #ifndef NDEBUG // this is the amount downloaded when this torrent @@ -621,6 +655,16 @@ namespace libtorrent // total_done - m_initial_done <= total_payload_download size_type m_initial_done; #endif + +#ifdef TORRENT_LOGGING + boost::shared_ptr m_log; + boost::shared_ptr m_peer_log; + int m_second_count; + + enum { debug_bw_history_size = 10 }; + int m_ul_history[debug_bw_history_size]; + int m_dl_history[debug_bw_history_size]; +#endif }; inline boost::posix_time::ptime torrent::next_announce() const diff --git a/libtorrent/include/libtorrent/torrent_handle.hpp b/libtorrent/include/libtorrent/torrent_handle.hpp index 80d57fec7..92dbdf34b 100644 --- a/libtorrent/include/libtorrent/torrent_handle.hpp +++ b/libtorrent/include/libtorrent/torrent_handle.hpp @@ -218,7 +218,7 @@ namespace libtorrent friend struct aux::session_impl; friend class torrent; - torrent_handle(): m_ses(0), m_chk(0) {} + torrent_handle(): m_ses(0), m_chk(0), m_info_hash(0) {} void get_peer_info(std::vector& v) const; bool send_chat_message(tcp::endpoint ip, std::string message) const; @@ -243,6 +243,9 @@ namespace libtorrent bool is_paused() const; void pause() const; void resume() const; + + void resolve_countries(bool r); + bool resolve_countries() const; // marks the piece with the given index as filtered // it will not be downloaded @@ -261,13 +264,6 @@ namespace libtorrent entry write_resume_data() const; - // kind of similar to get_torrent_info() but this - // is lower level, returning the exact info-part of - // the .torrent file. When hashed, this buffer - // will produce the info hash. The reference is valid - // only as long as the torrent is running. - std::vector const& metadata() const; - // forces this torrent to reannounce // (make a rerequest from the tracker) void force_reannounce() const; @@ -278,6 +274,11 @@ namespace libtorrent // timed out. void force_reannounce(boost::posix_time::time_duration) const; + // returns the name of this torrent, in case it doesn't + // have metadata it returns the name assigned to it + // when it was added. + std::string name() const; + // TODO: add a feature where the user can tell the torrent // to finish all pieces currently in the pipeline, and then // abort the torrent. diff --git a/libtorrent/include/libtorrent/tracker_manager.hpp b/libtorrent/include/libtorrent/tracker_manager.hpp index a45f88b59..5bac57e6e 100644 --- a/libtorrent/include/libtorrent/tracker_manager.hpp +++ b/libtorrent/include/libtorrent/tracker_manager.hpp @@ -82,6 +82,7 @@ namespace libtorrent { tracker_request() : kind(announce_request) + , web_downloaded(0) , event(none) , key(0) , num_want(0) @@ -106,6 +107,7 @@ namespace libtorrent size_type downloaded; size_type uploaded; size_type left; + size_type web_downloaded; unsigned short listen_port; event_t event; std::string url; @@ -156,7 +158,7 @@ namespace libtorrent friend void intrusive_ptr_add_ref(timeout_handler const*); friend void intrusive_ptr_release(timeout_handler const*); - timeout_handler(demuxer& d); + timeout_handler(asio::strand& str); void set_timeout(int completion_timeout, int read_timeout); void restart_read_timeout(); @@ -167,12 +169,12 @@ namespace libtorrent private: - void timeout_callback(asio::error const&); + void timeout_callback(asio::error_code const&); boost::intrusive_ptr self() { return boost::intrusive_ptr(this); } - demuxer& m_demuxer; + asio::strand& m_strand; // used for timeouts // this is set when the request has been sent boost::posix_time::ptime m_start_time; @@ -194,7 +196,8 @@ namespace libtorrent { tracker_connection(tracker_manager& man , tracker_request req - , demuxer& d + , asio::strand& str + , address bind_interface , boost::weak_ptr r); request_callback& requester(); @@ -206,10 +209,12 @@ namespace libtorrent void fail(int code, char const* msg); void fail_timeout(); void close(); + address const& bind_interface() const { return m_bind_interface; } protected: boost::weak_ptr m_requester; private: + address m_bind_interface; tracker_manager& m_man; const tracker_request m_req; }; @@ -222,9 +227,10 @@ namespace libtorrent : m_settings(s) {} void queue_request( - demuxer& d + asio::strand& str , tracker_request r , std::string const& auth + , address bind_infc , boost::weak_ptr c = boost::weak_ptr()); void abort_all_requests(); diff --git a/libtorrent/include/libtorrent/udp_tracker_connection.hpp b/libtorrent/include/libtorrent/udp_tracker_connection.hpp index 43671ed86..bf87bea77 100644 --- a/libtorrent/include/libtorrent/udp_tracker_connection.hpp +++ b/libtorrent/include/libtorrent/udp_tracker_connection.hpp @@ -66,11 +66,12 @@ namespace libtorrent public: udp_tracker_connection( - demuxer& d + asio::strand& str , tracker_manager& man , tracker_request const& req , std::string const& hostname , unsigned short port + , address bind_infc , boost::weak_ptr c , session_settings const& stn); @@ -87,24 +88,24 @@ namespace libtorrent boost::intrusive_ptr self() { return boost::intrusive_ptr(this); } - void name_lookup(asio::error const& error, tcp::resolver::iterator i); - void timeout(asio::error const& error); + void name_lookup(asio::error_code const& error, udp::resolver::iterator i); + void timeout(asio::error_code const& error); void send_udp_connect(); - void connect_response(asio::error const& error, std::size_t bytes_transferred); + void connect_response(asio::error_code const& error, std::size_t bytes_transferred); void send_udp_announce(); - void announce_response(asio::error const& error, std::size_t bytes_transferred); + void announce_response(asio::error_code const& error, std::size_t bytes_transferred); void send_udp_scrape(); - void scrape_response(asio::error const& error, std::size_t bytes_transferred); + void scrape_response(asio::error_code const& error, std::size_t bytes_transferred); virtual void on_timeout(); tracker_manager& m_man; - tcp::resolver m_name_lookup; - int m_port; + asio::strand& m_strand; + udp::resolver m_name_lookup; boost::shared_ptr m_socket; udp::endpoint m_target; udp::endpoint m_sender; diff --git a/libtorrent/include/libtorrent/utf8.hpp b/libtorrent/include/libtorrent/utf8.hpp index 7a31af804..157a7fdba 100644 --- a/libtorrent/include/libtorrent/utf8.hpp +++ b/libtorrent/include/libtorrent/utf8.hpp @@ -26,6 +26,7 @@ #include #include #include +#include namespace libtorrent { namespace detail { @@ -132,7 +133,7 @@ OutputIterator wchar_utf8(InputIterator first, InputIterator last, OutputIterato inline void utf8_wchar(const std::string &utf8, std::wstring &wide) { wide.clear(); - detail::utf8_wchar(utf8.begin(), utf8.end(), std::insert_iterator(wide, wide.end())); + detail::utf8_wchar(utf8.begin(), utf8.end(), std::back_inserter(wide)); } inline std::wstring utf8_wchar(const std::string &str) @@ -145,7 +146,7 @@ inline std::wstring utf8_wchar(const std::string &str) inline void wchar_utf8(const std::wstring &wide, std::string &utf8) { utf8.clear(); - detail::wchar_utf8(wide.begin(), wide.end(), std::insert_iterator(utf8, utf8.end())); + detail::wchar_utf8(wide.begin(), wide.end(), std::back_inserter(utf8)); } inline std::string wchar_utf8(const std::wstring &str) diff --git a/libtorrent/include/libtorrent/version.hpp b/libtorrent/include/libtorrent/version.hpp index 25c7a9f05..a96a4d7a4 100644 --- a/libtorrent/include/libtorrent/version.hpp +++ b/libtorrent/include/libtorrent/version.hpp @@ -34,8 +34,8 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_VERSION_HPP_INCLUDED #define LIBTORRENT_VERSION_MAJOR 0 -#define LIBTORRENT_VERSION_MINOR 11 +#define LIBTORRENT_VERSION_MINOR 12 -#define LIBTORRENT_VERSION "0.11.0.0" +#define LIBTORRENT_VERSION "0.12.0.0" #endif diff --git a/libtorrent/include/libtorrent/web_peer_connection.hpp b/libtorrent/include/libtorrent/web_peer_connection.hpp index 77f840409..a8ed22820 100644 --- a/libtorrent/include/libtorrent/web_peer_connection.hpp +++ b/libtorrent/include/libtorrent/web_peer_connection.hpp @@ -98,21 +98,23 @@ namespace libtorrent , boost::weak_ptr t , boost::shared_ptr s , tcp::endpoint const& remote + , tcp::endpoint const& proxy , std::string const& url); ~web_peer_connection(); // called from the main loop when this connection has any // work to do. - void on_sent(asio::error const& error + void on_sent(asio::error_code const& error , std::size_t bytes_transferred); - void on_receive(asio::error const& error + void on_receive(asio::error_code const& error , std::size_t bytes_transferred); std::string const& url() const { return m_url; } virtual void get_peer_info(peer_info& p) const; - + virtual bool in_handshake() const; + // the following functions appends messages // to the send buffer void write_choke() {} diff --git a/libtorrent/src/Makefile.am b/libtorrent/src/Makefile.am new file mode 100644 index 000000000..6cd77798e --- /dev/null +++ b/libtorrent/src/Makefile.am @@ -0,0 +1,81 @@ +lib_LTLIBRARIES = libtorrent.la + +if USE_DHT +kademlia_sources = kademlia/closest_nodes.cpp \ +kademlia/dht_tracker.cpp \ +kademlia/find_data.cpp \ +kademlia/node.cpp \ +kademlia/node_id.cpp \ +kademlia/refresh.cpp \ +kademlia/routing_table.cpp \ +kademlia/rpc_manager.cpp \ +kademlia/traversal_algorithm.cpp +endif + +libtorrent_la_SOURCES = allocate_resources.cpp \ +bandwidth_manager.cpp entry.cpp escape_string.cpp \ +peer_connection.cpp bt_peer_connection.cpp web_peer_connection.cpp \ +piece_picker.cpp policy.cpp session.cpp session_impl.cpp sha1.cpp stat.cpp \ +storage.cpp torrent.cpp torrent_handle.cpp \ +torrent_info.cpp tracker_manager.cpp \ +http_tracker_connection.cpp udp_tracker_connection.cpp \ +alert.cpp identify_client.cpp ip_filter.cpp file.cpp metadata_transfer.cpp \ +logger.cpp file_pool.cpp ut_pex.cpp $(kademlia_sources) + +noinst_HEADERS = \ +$(top_srcdir)/include/libtorrent/alert.hpp \ +$(top_srcdir)/include/libtorrent/alert_types.hpp \ +$(top_srcdir)/include/libtorrent/allocate_resources.hpp \ +$(top_srcdir)/include/libtorrent/aux_/allocate_resources_impl.hpp \ +$(top_srcdir)/include/libtorrent/aux_/session_impl.hpp \ +$(top_srcdir)/include/libtorrent/bandwidth_manager.hpp \ +$(top_srcdir)/include/libtorrent/bencode.hpp \ +$(top_srcdir)/include/libtorrent/buffer.hpp \ +$(top_srcdir)/include/libtorrent/debug.hpp \ +$(top_srcdir)/include/libtorrent/entry.hpp \ +$(top_srcdir)/include/libtorrent/escape_string.hpp \ +$(top_srcdir)/include/libtorrent/extensions.hpp \ +$(top_srcdir)/include/libtorrent/extensions/metadata_transfer.hpp \ +$(top_srcdir)/include/libtorrent/extensions/logger.hpp \ +$(top_srcdir)/include/libtorrent/extensions/ut_pex.hpp \ +$(top_srcdir)/include/libtorrent/file.hpp \ +$(top_srcdir)/include/libtorrent/file_pool.hpp \ +$(top_srcdir)/include/libtorrent/fingerprint.hpp \ +$(top_srcdir)/include/libtorrent/hasher.hpp \ +$(top_srcdir)/include/libtorrent/session_settings.hpp \ +$(top_srcdir)/include/libtorrent/http_tracker_connection.hpp \ +$(top_srcdir)/include/libtorrent/identify_client.hpp \ +$(top_srcdir)/include/libtorrent/invariant_check.hpp \ +$(top_srcdir)/include/libtorrent/io.hpp \ +$(top_srcdir)/include/libtorrent/ip_filter.hpp \ +$(top_srcdir)/include/libtorrent/peer.hpp \ +$(top_srcdir)/include/libtorrent/peer_connection.hpp \ +$(top_srcdir)/include/libtorrent/bt_peer_connection.hpp \ +$(top_srcdir)/include/libtorrent/web_peer_connection.hpp \ +$(top_srcdir)/include/libtorrent/peer_id.hpp \ +$(top_srcdir)/include/libtorrent/peer_info.hpp \ +$(top_srcdir)/include/libtorrent/peer_request.hpp \ +$(top_srcdir)/include/libtorrent/piece_block_progress.hpp \ +$(top_srcdir)/include/libtorrent/piece_picker.hpp \ +$(top_srcdir)/include/libtorrent/policy.hpp \ +$(top_srcdir)/include/libtorrent/resource_request.hpp \ +$(top_srcdir)/include/libtorrent/session.hpp \ +$(top_srcdir)/include/libtorrent/size_type.hpp \ +$(top_srcdir)/include/libtorrent/socket.hpp \ +$(top_srcdir)/include/libtorrent/stat.hpp \ +$(top_srcdir)/include/libtorrent/storage.hpp \ +$(top_srcdir)/include/libtorrent/torrent.hpp \ +$(top_srcdir)/include/libtorrent/torrent_handle.hpp \ +$(top_srcdir)/include/libtorrent/torrent_info.hpp \ +$(top_srcdir)/include/libtorrent/tracker_manager.hpp \ +$(top_srcdir)/include/libtorrent/udp_tracker_connection.hpp \ +$(top_srcdir)/include/libtorrent/utf8.hpp \ +$(top_srcdir)/include/libtorrent/version.hpp + + +libtorrent_la_LDFLAGS = $(LDFLAGS) -version-info 1:0:1 +libtorrent_la_LIBADD = @ZLIB@ -l@BOOST_DATE_TIME_LIB@ -l@BOOST_FILESYSTEM_LIB@ -l@BOOST_THREAD_LIB@ @PTHREAD_LIBS@ + +AM_CXXFLAGS= -ftemplate-depth-50 -I$(top_srcdir)/include -I$(top_srcdir)/include/libtorrent @ZLIBINCL@ @DEBUGFLAGS@ @PTHREAD_CFLAGS@ +AM_LDFLAGS= $(LDFLAGS) -l@BOOST_DATE_TIME_LIB@ -l@BOOST_FILESYSTEM_LIB@ -l@BOOST_THREAD_LIB@ @PTHREAD_LIBS@ + diff --git a/libtorrent/src/Makefile.in b/libtorrent/src/Makefile.in new file mode 100644 index 000000000..aa318eddc --- /dev/null +++ b/libtorrent/src/Makefile.in @@ -0,0 +1,672 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ac_cxx_namespaces.m4 \ + $(top_srcdir)/m4/acx_pthread.m4 \ + $(top_srcdir)/m4/ax_boost_date-time.m4 \ + $(top_srcdir)/m4/ax_boost_filesystem.m4 \ + $(top_srcdir)/m4/ax_boost_program_options.m4 \ + $(top_srcdir)/m4/ax_boost_regex.m4 \ + $(top_srcdir)/m4/ax_boost_thread.m4 $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(libdir)" +libLTLIBRARIES_INSTALL = $(INSTALL) +LTLIBRARIES = $(lib_LTLIBRARIES) +libtorrent_la_DEPENDENCIES = +am__libtorrent_la_SOURCES_DIST = allocate_resources.cpp \ + bandwidth_manager.cpp entry.cpp escape_string.cpp \ + peer_connection.cpp bt_peer_connection.cpp \ + web_peer_connection.cpp piece_picker.cpp policy.cpp \ + session.cpp session_impl.cpp sha1.cpp stat.cpp storage.cpp \ + torrent.cpp torrent_handle.cpp torrent_info.cpp \ + tracker_manager.cpp http_tracker_connection.cpp \ + udp_tracker_connection.cpp alert.cpp identify_client.cpp \ + ip_filter.cpp file.cpp metadata_transfer.cpp logger.cpp \ + file_pool.cpp ut_pex.cpp kademlia/closest_nodes.cpp \ + kademlia/dht_tracker.cpp kademlia/find_data.cpp \ + kademlia/node.cpp kademlia/node_id.cpp kademlia/refresh.cpp \ + kademlia/routing_table.cpp kademlia/rpc_manager.cpp \ + kademlia/traversal_algorithm.cpp +@USE_DHT_TRUE@am__objects_1 = closest_nodes.lo dht_tracker.lo \ +@USE_DHT_TRUE@ find_data.lo node.lo node_id.lo refresh.lo \ +@USE_DHT_TRUE@ routing_table.lo rpc_manager.lo \ +@USE_DHT_TRUE@ traversal_algorithm.lo +am_libtorrent_la_OBJECTS = allocate_resources.lo bandwidth_manager.lo \ + entry.lo escape_string.lo peer_connection.lo \ + bt_peer_connection.lo web_peer_connection.lo piece_picker.lo \ + policy.lo session.lo session_impl.lo sha1.lo stat.lo \ + storage.lo torrent.lo torrent_handle.lo torrent_info.lo \ + tracker_manager.lo http_tracker_connection.lo \ + udp_tracker_connection.lo alert.lo identify_client.lo \ + ip_filter.lo file.lo metadata_transfer.lo logger.lo \ + file_pool.lo ut_pex.lo $(am__objects_1) +libtorrent_la_OBJECTS = $(am_libtorrent_la_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) --tag=CXX --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libtorrent_la_SOURCES) +DIST_SOURCES = $(am__libtorrent_la_SOURCES_DIST) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BOOST_DATE_TIME_LIB = @BOOST_DATE_TIME_LIB@ +BOOST_FILESYSTEM_LIB = @BOOST_FILESYSTEM_LIB@ +BOOST_PROGRAM_OPTIONS_LIB = @BOOST_PROGRAM_OPTIONS_LIB@ +BOOST_REGEX_LIB = @BOOST_REGEX_LIB@ +BOOST_THREAD_LIB = @BOOST_THREAD_LIB@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CLIENT_TEST_BIN = @CLIENT_TEST_BIN@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEBUGFLAGS = @DEBUGFLAGS@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXAMPLESDIR = @EXAMPLESDIR@ +EXEEXT = @EXEEXT@ +F77 = @F77@ +FFLAGS = @FFLAGS@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PTHREAD_CC = @PTHREAD_CC@ +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_DHT_FALSE = @USE_DHT_FALSE@ +USE_DHT_TRUE = @USE_DHT_TRUE@ +VERSION = @VERSION@ +ZLIB = @ZLIB@ +ZLIBDIR = @ZLIBDIR@ +ZLIBINCL = @ZLIBINCL@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_F77 = @ac_ct_F77@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +acx_pthread_config = @acx_pthread_config@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +lib_LTLIBRARIES = libtorrent.la +@USE_DHT_TRUE@kademlia_sources = kademlia/closest_nodes.cpp \ +@USE_DHT_TRUE@kademlia/dht_tracker.cpp \ +@USE_DHT_TRUE@kademlia/find_data.cpp \ +@USE_DHT_TRUE@kademlia/node.cpp \ +@USE_DHT_TRUE@kademlia/node_id.cpp \ +@USE_DHT_TRUE@kademlia/refresh.cpp \ +@USE_DHT_TRUE@kademlia/routing_table.cpp \ +@USE_DHT_TRUE@kademlia/rpc_manager.cpp \ +@USE_DHT_TRUE@kademlia/traversal_algorithm.cpp + +libtorrent_la_SOURCES = allocate_resources.cpp \ +bandwidth_manager.cpp entry.cpp escape_string.cpp \ +peer_connection.cpp bt_peer_connection.cpp web_peer_connection.cpp \ +piece_picker.cpp policy.cpp session.cpp session_impl.cpp sha1.cpp stat.cpp \ +storage.cpp torrent.cpp torrent_handle.cpp \ +torrent_info.cpp tracker_manager.cpp \ +http_tracker_connection.cpp udp_tracker_connection.cpp \ +alert.cpp identify_client.cpp ip_filter.cpp file.cpp metadata_transfer.cpp \ +logger.cpp file_pool.cpp ut_pex.cpp $(kademlia_sources) + +noinst_HEADERS = \ +$(top_srcdir)/include/libtorrent/alert.hpp \ +$(top_srcdir)/include/libtorrent/alert_types.hpp \ +$(top_srcdir)/include/libtorrent/allocate_resources.hpp \ +$(top_srcdir)/include/libtorrent/aux_/allocate_resources_impl.hpp \ +$(top_srcdir)/include/libtorrent/aux_/session_impl.hpp \ +$(top_srcdir)/include/libtorrent/bandwidth_manager.hpp \ +$(top_srcdir)/include/libtorrent/bencode.hpp \ +$(top_srcdir)/include/libtorrent/buffer.hpp \ +$(top_srcdir)/include/libtorrent/debug.hpp \ +$(top_srcdir)/include/libtorrent/entry.hpp \ +$(top_srcdir)/include/libtorrent/escape_string.hpp \ +$(top_srcdir)/include/libtorrent/extensions.hpp \ +$(top_srcdir)/include/libtorrent/extensions/metadata_transfer.hpp \ +$(top_srcdir)/include/libtorrent/extensions/logger.hpp \ +$(top_srcdir)/include/libtorrent/extensions/ut_pex.hpp \ +$(top_srcdir)/include/libtorrent/file.hpp \ +$(top_srcdir)/include/libtorrent/file_pool.hpp \ +$(top_srcdir)/include/libtorrent/fingerprint.hpp \ +$(top_srcdir)/include/libtorrent/hasher.hpp \ +$(top_srcdir)/include/libtorrent/session_settings.hpp \ +$(top_srcdir)/include/libtorrent/http_tracker_connection.hpp \ +$(top_srcdir)/include/libtorrent/identify_client.hpp \ +$(top_srcdir)/include/libtorrent/invariant_check.hpp \ +$(top_srcdir)/include/libtorrent/io.hpp \ +$(top_srcdir)/include/libtorrent/ip_filter.hpp \ +$(top_srcdir)/include/libtorrent/peer.hpp \ +$(top_srcdir)/include/libtorrent/peer_connection.hpp \ +$(top_srcdir)/include/libtorrent/bt_peer_connection.hpp \ +$(top_srcdir)/include/libtorrent/web_peer_connection.hpp \ +$(top_srcdir)/include/libtorrent/peer_id.hpp \ +$(top_srcdir)/include/libtorrent/peer_info.hpp \ +$(top_srcdir)/include/libtorrent/peer_request.hpp \ +$(top_srcdir)/include/libtorrent/piece_block_progress.hpp \ +$(top_srcdir)/include/libtorrent/piece_picker.hpp \ +$(top_srcdir)/include/libtorrent/policy.hpp \ +$(top_srcdir)/include/libtorrent/resource_request.hpp \ +$(top_srcdir)/include/libtorrent/session.hpp \ +$(top_srcdir)/include/libtorrent/size_type.hpp \ +$(top_srcdir)/include/libtorrent/socket.hpp \ +$(top_srcdir)/include/libtorrent/stat.hpp \ +$(top_srcdir)/include/libtorrent/storage.hpp \ +$(top_srcdir)/include/libtorrent/torrent.hpp \ +$(top_srcdir)/include/libtorrent/torrent_handle.hpp \ +$(top_srcdir)/include/libtorrent/torrent_info.hpp \ +$(top_srcdir)/include/libtorrent/tracker_manager.hpp \ +$(top_srcdir)/include/libtorrent/udp_tracker_connection.hpp \ +$(top_srcdir)/include/libtorrent/utf8.hpp \ +$(top_srcdir)/include/libtorrent/version.hpp + +libtorrent_la_LDFLAGS = $(LDFLAGS) -version-info 1:0:1 +libtorrent_la_LIBADD = @ZLIB@ -l@BOOST_DATE_TIME_LIB@ -l@BOOST_FILESYSTEM_LIB@ -l@BOOST_THREAD_LIB@ @PTHREAD_LIBS@ +AM_CXXFLAGS = -ftemplate-depth-50 -I$(top_srcdir)/include -I$(top_srcdir)/include/libtorrent @ZLIBINCL@ @DEBUGFLAGS@ @PTHREAD_CFLAGS@ +AM_LDFLAGS = $(LDFLAGS) -l@BOOST_DATE_TIME_LIB@ -l@BOOST_FILESYSTEM_LIB@ -l@BOOST_THREAD_LIB@ @PTHREAD_LIBS@ +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + p=$(am__strip_dir) \ + echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ + $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libtorrent.la: $(libtorrent_la_OBJECTS) $(libtorrent_la_DEPENDENCIES) + $(CXXLINK) -rpath $(libdir) $(libtorrent_la_LDFLAGS) $(libtorrent_la_OBJECTS) $(libtorrent_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alert.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/allocate_resources.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bandwidth_manager.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bt_peer_connection.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/closest_nodes.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dht_tracker.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/entry.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/escape_string.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file_pool.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/find_data.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/http_tracker_connection.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/identify_client.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ip_filter.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logger.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/metadata_transfer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node_id.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/peer_connection.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/piece_picker.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/policy.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/refresh.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/routing_table.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpc_manager.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/session.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/session_impl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sha1.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stat.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/storage.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/torrent.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/torrent_handle.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/torrent_info.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tracker_manager.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/traversal_algorithm.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/udp_tracker_connection.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ut_pex.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/web_peer_connection.Plo@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cpp.lo: +@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ $< + +closest_nodes.lo: kademlia/closest_nodes.cpp +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT closest_nodes.lo -MD -MP -MF "$(DEPDIR)/closest_nodes.Tpo" -c -o closest_nodes.lo `test -f 'kademlia/closest_nodes.cpp' || echo '$(srcdir)/'`kademlia/closest_nodes.cpp; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/closest_nodes.Tpo" "$(DEPDIR)/closest_nodes.Plo"; else rm -f "$(DEPDIR)/closest_nodes.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='kademlia/closest_nodes.cpp' object='closest_nodes.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o closest_nodes.lo `test -f 'kademlia/closest_nodes.cpp' || echo '$(srcdir)/'`kademlia/closest_nodes.cpp + +dht_tracker.lo: kademlia/dht_tracker.cpp +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dht_tracker.lo -MD -MP -MF "$(DEPDIR)/dht_tracker.Tpo" -c -o dht_tracker.lo `test -f 'kademlia/dht_tracker.cpp' || echo '$(srcdir)/'`kademlia/dht_tracker.cpp; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/dht_tracker.Tpo" "$(DEPDIR)/dht_tracker.Plo"; else rm -f "$(DEPDIR)/dht_tracker.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='kademlia/dht_tracker.cpp' object='dht_tracker.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o dht_tracker.lo `test -f 'kademlia/dht_tracker.cpp' || echo '$(srcdir)/'`kademlia/dht_tracker.cpp + +find_data.lo: kademlia/find_data.cpp +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT find_data.lo -MD -MP -MF "$(DEPDIR)/find_data.Tpo" -c -o find_data.lo `test -f 'kademlia/find_data.cpp' || echo '$(srcdir)/'`kademlia/find_data.cpp; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/find_data.Tpo" "$(DEPDIR)/find_data.Plo"; else rm -f "$(DEPDIR)/find_data.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='kademlia/find_data.cpp' object='find_data.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o find_data.lo `test -f 'kademlia/find_data.cpp' || echo '$(srcdir)/'`kademlia/find_data.cpp + +node.lo: kademlia/node.cpp +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT node.lo -MD -MP -MF "$(DEPDIR)/node.Tpo" -c -o node.lo `test -f 'kademlia/node.cpp' || echo '$(srcdir)/'`kademlia/node.cpp; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/node.Tpo" "$(DEPDIR)/node.Plo"; else rm -f "$(DEPDIR)/node.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='kademlia/node.cpp' object='node.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o node.lo `test -f 'kademlia/node.cpp' || echo '$(srcdir)/'`kademlia/node.cpp + +node_id.lo: kademlia/node_id.cpp +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT node_id.lo -MD -MP -MF "$(DEPDIR)/node_id.Tpo" -c -o node_id.lo `test -f 'kademlia/node_id.cpp' || echo '$(srcdir)/'`kademlia/node_id.cpp; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/node_id.Tpo" "$(DEPDIR)/node_id.Plo"; else rm -f "$(DEPDIR)/node_id.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='kademlia/node_id.cpp' object='node_id.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o node_id.lo `test -f 'kademlia/node_id.cpp' || echo '$(srcdir)/'`kademlia/node_id.cpp + +refresh.lo: kademlia/refresh.cpp +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT refresh.lo -MD -MP -MF "$(DEPDIR)/refresh.Tpo" -c -o refresh.lo `test -f 'kademlia/refresh.cpp' || echo '$(srcdir)/'`kademlia/refresh.cpp; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/refresh.Tpo" "$(DEPDIR)/refresh.Plo"; else rm -f "$(DEPDIR)/refresh.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='kademlia/refresh.cpp' object='refresh.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o refresh.lo `test -f 'kademlia/refresh.cpp' || echo '$(srcdir)/'`kademlia/refresh.cpp + +routing_table.lo: kademlia/routing_table.cpp +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT routing_table.lo -MD -MP -MF "$(DEPDIR)/routing_table.Tpo" -c -o routing_table.lo `test -f 'kademlia/routing_table.cpp' || echo '$(srcdir)/'`kademlia/routing_table.cpp; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/routing_table.Tpo" "$(DEPDIR)/routing_table.Plo"; else rm -f "$(DEPDIR)/routing_table.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='kademlia/routing_table.cpp' object='routing_table.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o routing_table.lo `test -f 'kademlia/routing_table.cpp' || echo '$(srcdir)/'`kademlia/routing_table.cpp + +rpc_manager.lo: kademlia/rpc_manager.cpp +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT rpc_manager.lo -MD -MP -MF "$(DEPDIR)/rpc_manager.Tpo" -c -o rpc_manager.lo `test -f 'kademlia/rpc_manager.cpp' || echo '$(srcdir)/'`kademlia/rpc_manager.cpp; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/rpc_manager.Tpo" "$(DEPDIR)/rpc_manager.Plo"; else rm -f "$(DEPDIR)/rpc_manager.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='kademlia/rpc_manager.cpp' object='rpc_manager.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o rpc_manager.lo `test -f 'kademlia/rpc_manager.cpp' || echo '$(srcdir)/'`kademlia/rpc_manager.cpp + +traversal_algorithm.lo: kademlia/traversal_algorithm.cpp +@am__fastdepCXX_TRUE@ if $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT traversal_algorithm.lo -MD -MP -MF "$(DEPDIR)/traversal_algorithm.Tpo" -c -o traversal_algorithm.lo `test -f 'kademlia/traversal_algorithm.cpp' || echo '$(srcdir)/'`kademlia/traversal_algorithm.cpp; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/traversal_algorithm.Tpo" "$(DEPDIR)/traversal_algorithm.Plo"; else rm -f "$(DEPDIR)/traversal_algorithm.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='kademlia/traversal_algorithm.cpp' object='traversal_algorithm.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LIBTOOL) --tag=CXX --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o traversal_algorithm.lo `test -f 'kademlia/traversal_algorithm.cpp' || echo '$(srcdir)/'`kademlia/traversal_algorithm.cpp + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(mkdir_p) $(distdir)/../include/libtorrent $(distdir)/../include/libtorrent/aux_ $(distdir)/../include/libtorrent/extensions + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(mkdir_p) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-libtool distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: install-libLTLIBRARIES + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am \ + install-libLTLIBRARIES install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am \ + uninstall-libLTLIBRARIES + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libtorrent/src/allocate_resources.cpp b/libtorrent/src/allocate_resources.cpp index 7d08b036d..7e342ee95 100644 --- a/libtorrent/src/allocate_resources.cpp +++ b/libtorrent/src/allocate_resources.cpp @@ -1,6 +1,6 @@ /* -Copyright (c) 2003, Magnus Jonsson, Arvid Norberg +Copyright (c) 2006, Magnus Jonsson, Arvid Norberg All rights reserved. Redistribution and use in source and binary forms, with or without @@ -163,6 +163,11 @@ namespace libtorrent { return *p.second; } + + session& deref(session* p) + { + return *p; + } } void allocate_resources( @@ -196,6 +201,23 @@ namespace libtorrent , new_iter(c.end(), &aux::pick_peer2) , res); } + + void allocate_resources( + int resources + , std::vector& _sessions + , resource_request session::* res) + { + typedef std::vector::iterator orig_iter; + typedef session* in_param; + typedef boost::transform_iterator new_iter; + + aux::allocate_resources_impl( + resources + , new_iter(_sessions.begin(), &aux::deref) + , new_iter(_sessions.end(), &aux::deref) + , res); + } + #endif } // namespace libtorrent diff --git a/libtorrent/src/bandwidth_manager.cpp b/libtorrent/src/bandwidth_manager.cpp new file mode 100644 index 000000000..a5868d439 --- /dev/null +++ b/libtorrent/src/bandwidth_manager.cpp @@ -0,0 +1,242 @@ +/* + +Copyright (c) 2007, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "libtorrent/invariant_check.hpp" +#include "libtorrent/bandwidth_manager.hpp" +#include "libtorrent/peer_connection.hpp" +#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING +#include "libtorrent/aux_/session_impl.hpp" +#endif + +namespace libtorrent +{ + namespace + { + const pt::time_duration window_size = pt::seconds(1); + } + + history_entry::history_entry(intrusive_ptr p + , weak_ptr t, int a, pt::ptime exp) + : expires_at(exp), amount(a), peer(p), tor(t) + {} + + bw_queue_entry::bw_queue_entry(intrusive_ptr const& pe + , bool no_prio) + : peer(pe), non_prioritized(no_prio) + {} + + bandwidth_manager::bandwidth_manager(io_service& ios, int channel) + : m_ios(ios) + , m_history_timer(m_ios) + , m_limit(bandwidth_limit::inf) + , m_current_quota(0) + , m_channel(channel) + {} + + void bandwidth_manager::request_bandwidth(intrusive_ptr peer + , bool non_prioritized) + { + INVARIANT_CHECK; + + // make sure this peer isn't already in line + // waiting for bandwidth +#ifndef NDEBUG + for (std::deque::iterator i = m_queue.begin() + , end(m_queue.end()); i != end; ++i) + { + assert(i->peer < peer || peer < i->peer); + } +#endif + + assert(peer->max_assignable_bandwidth(m_channel) > 0); + + // if the queue is empty, we have to push the new + // peer at the back of it. If the peer is non-prioritized + // it is not supposed to cut in fron of anybody, so then + // we also just add it at the end + if (m_queue.empty() || non_prioritized) + { + m_queue.push_back(bw_queue_entry(peer, non_prioritized)); + } + else + { + // skip forward in the queue until we find a prioritized peer + // or hit the front of it. + std::deque::reverse_iterator i = m_queue.rbegin(); + while (i != m_queue.rend() && i->non_prioritized) ++i; + m_queue.insert(i.base(), bw_queue_entry(peer, non_prioritized)); + } + if (m_queue.size() == 1) hand_out_bandwidth(); + } + + +#ifndef NDEBUG + void bandwidth_manager::check_invariant() const + { + int current_quota = 0; + for (std::deque::const_iterator i + = m_history.begin(), end(m_history.end()); i != end; ++i) + { + current_quota += i->amount; + } + + assert(current_quota == m_current_quota); + } +#endif + + void bandwidth_manager::add_history_entry(history_entry const& e) try + { + INVARIANT_CHECK; +#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING +// (*m_ses->m_logger) << "bw history [" << m_channel << "]\n"; +#endif + + m_history.push_front(e); + m_current_quota += e.amount; + // in case the size > 1 there is already a timer + // active that will be invoked, no need to set one up + if (m_history.size() > 1) return; + + m_history_timer.expires_at(e.expires_at); + m_history_timer.async_wait(bind(&bandwidth_manager::on_history_expire, this, _1)); + } + catch (std::exception&) { assert(false); } + + void bandwidth_manager::on_history_expire(asio::error_code const& e) try + { + INVARIANT_CHECK; + + if (e) return; + +#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING +// (*m_ses->m_logger) << "bw expire [" << m_channel << "]\n"; +#endif + + assert(!m_history.empty()); + + pt::ptime now(pt::microsec_clock::universal_time()); + while (!m_history.empty() && m_history.back().expires_at <= now) + { + history_entry e = m_history.back(); + m_history.pop_back(); + m_current_quota -= e.amount; + assert(m_current_quota >= 0); + intrusive_ptr c = e.peer; + shared_ptr t = e.tor.lock(); + if (!c->is_disconnecting()) c->expire_bandwidth(m_channel, e.amount); + if (t) t->expire_bandwidth(m_channel, e.amount); + } + + // now, wait for the next chunk to expire + if (!m_history.empty()) + { + m_history_timer.expires_at(m_history.back().expires_at); + m_history_timer.async_wait(bind(&bandwidth_manager::on_history_expire, this, _1)); + } + + // since some bandwidth just expired, it + // means we can hand out more (in case there + // are still consumers in line) + if (!m_queue.empty()) hand_out_bandwidth(); + } + catch (std::exception&) + { + assert(false); + }; + + void bandwidth_manager::hand_out_bandwidth() try + { + INVARIANT_CHECK; +#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING +// (*m_ses->m_logger) << "hand out bw [" << m_channel << "]\n"; +#endif + + pt::ptime now(pt::microsec_clock::universal_time()); + + mutex_t::scoped_lock l(m_mutex); + int limit = m_limit; + l.unlock(); + + // available bandwidth to hand out + int amount = limit - m_current_quota; + + int bandwidth_block_size_limit = max_bandwidth_block_size; + if (m_queue.size() > 3 && bandwidth_block_size_limit > limit / int(m_queue.size())) + bandwidth_block_size_limit = std::max(max_bandwidth_block_size / int(m_queue.size() - 3) + , min_bandwidth_block_size); + + while (!m_queue.empty() && amount > 0) + { + assert(amount == limit - m_current_quota); + bw_queue_entry qe = m_queue.front(); + m_queue.pop_front(); + + shared_ptr t = qe.peer->associated_torrent().lock(); + if (!t) continue; + if (qe.peer->is_disconnecting()) + { + t->expire_bandwidth(m_channel, -1); + continue; + } + + // at this point, max_assignable may actually be zero. Since + // the bandwidth quota is subtracted once the data has been + // send. If the peer was added to the queue while the data was + // still being sent, max_assignable may have been > 0 at that time. + int max_assignable = qe.peer->max_assignable_bandwidth(m_channel); + if (max_assignable == 0) + { + t->expire_bandwidth(m_channel, -1); + continue; + } + // don't hand out chunks larger than the throttle + // per second on the torrent + if (max_assignable > t->bandwidth_throttle(m_channel)) + max_assignable = t->bandwidth_throttle(m_channel); + + // so, hand out max_assignable, but no more than + // the available bandwidth (amount) and no more + // than the max_bandwidth_block_size + int single_amount = std::min(amount + , std::min(bandwidth_block_size_limit + , max_assignable)); + assert(single_amount > 0); + amount -= single_amount; + qe.peer->assign_bandwidth(m_channel, single_amount); + t->assign_bandwidth(m_channel, single_amount); + add_history_entry(history_entry(qe.peer, t, single_amount, now + window_size)); + } + } + catch (std::exception& e) + { assert(false); }; + +} diff --git a/libtorrent/src/bt_peer_connection.cpp b/libtorrent/src/bt_peer_connection.cpp index 0cff4b253..d96eea92a 100644 --- a/libtorrent/src/bt_peer_connection.cpp +++ b/libtorrent/src/bt_peer_connection.cpp @@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/invariant_check.hpp" #include "libtorrent/io.hpp" #include "libtorrent/version.hpp" +#include "libtorrent/extensions.hpp" #include "libtorrent/aux_/session_impl.hpp" using namespace boost::posix_time; @@ -55,11 +56,6 @@ using libtorrent::aux::session_impl; namespace libtorrent { - // the names of the extensions to look for in - // the extensions-message - const char* bt_peer_connection::extension_names[] = - { "", "LT_chat", "LT_metadata", "LT_peer_exchange" }; - const bt_peer_connection::message_handler bt_peer_connection::m_message_handler[] = { @@ -83,19 +79,14 @@ namespace libtorrent , boost::weak_ptr tor , shared_ptr s , tcp::endpoint const& remote) - : peer_connection(ses, tor, s, remote) + : peer_connection(ses, tor, s, remote, tcp::endpoint()) , m_state(read_protocol_length) +#ifndef TORRENT_DISABLE_EXTENSIONS , m_supports_extensions(false) +#endif , m_supports_dht_port(false) - , m_no_metadata( - boost::gregorian::date(1970, boost::date_time::Jan, 1) - , boost::posix_time::seconds(0)) - , m_metadata_request( - boost::gregorian::date(1970, boost::date_time::Jan, 1) - , boost::posix_time::seconds(0)) - , m_waiting_metadata_request(false) - , m_metadata_progress(0) #ifndef NDEBUG + , m_sent_bitfield(false) , m_in_constructor(true) #endif { @@ -103,11 +94,6 @@ namespace libtorrent (*m_logger) << "*** bt_peer_connection\n"; #endif - // initialize the extension list to zero, since - // we don't know which extensions the other - // end supports yet - std::fill(m_extension_messages, m_extension_messages + num_supported_extensions, 0); - write_handshake(); // start in the state where we are trying to read the @@ -133,29 +119,27 @@ namespace libtorrent , boost::shared_ptr s) : peer_connection(ses, s) , m_state(read_protocol_length) +#ifndef TORRENT_DISABLE_EXTENSIONS , m_supports_extensions(false) +#endif , m_supports_dht_port(false) - , m_no_metadata( - boost::gregorian::date(1970, boost::date_time::Jan, 1) - , boost::posix_time::seconds(0)) - , m_metadata_request( - boost::gregorian::date(1970, boost::date_time::Jan, 1) - , boost::posix_time::seconds(0)) - , m_waiting_metadata_request(false) - , m_metadata_progress(0) #ifndef NDEBUG + , m_sent_bitfield(false) , m_in_constructor(true) #endif { - // initialize the extension list to zero, since - // we don't know which extensions the other - // end supports yet - std::fill(m_extension_messages, m_extension_messages + num_supported_extensions, 0); - // we are not attached to any torrent yet. // we have to wait for the handshake to see // which torrent the connector want's to connect to + + // upload bandwidth will only be given to connections + // that are part of a torrent. Since this is an incoming + // connection, we have to give it some initial bandwidth + // to send the handshake. + m_bandwidth_limit[download_channel].assign(80); + m_bandwidth_limit[upload_channel].assign(80); + // start in the state where we are trying to read the // handshake from the other side reset_recv_buffer(1); @@ -169,6 +153,13 @@ namespace libtorrent { } + void bt_peer_connection::on_metadata() + { + boost::shared_ptr t = associated_torrent().lock(); + assert(t); + write_bitfield(t->pieces()); + } + void bt_peer_connection::write_dht_port(int listen_port) { INVARIANT_CHECK; @@ -191,19 +182,22 @@ namespace libtorrent p.payload_up_speed = statistics().upload_payload_rate(); p.pid = pid(); p.ip = remote(); + + p.country[0] = m_country[0]; + p.country[1] = m_country[1]; p.total_download = statistics().total_payload_download(); p.total_upload = statistics().total_payload_upload(); - if (m_ul_bandwidth_quota.given == std::numeric_limits::max()) + if (m_bandwidth_limit[upload_channel].throttle() == bandwidth_limit::inf) p.upload_limit = -1; else - p.upload_limit = m_ul_bandwidth_quota.given; + p.upload_limit = m_bandwidth_limit[upload_channel].throttle(); - if (m_dl_bandwidth_quota.given == std::numeric_limits::max()) + if (m_bandwidth_limit[download_channel].throttle() == bandwidth_limit::inf) p.download_limit = -1; else - p.download_limit = m_dl_bandwidth_quota.given; + p.download_limit = m_bandwidth_limit[download_channel].throttle(); p.load_balancing = total_free_upload(); @@ -243,6 +237,11 @@ namespace libtorrent p.client = m_client_version; p.connection_type = peer_info::standard_bittorrent; } + + bool bt_peer_connection::in_handshake() const + { + return m_state < read_packet_size; + } void bt_peer_connection::write_handshake() { @@ -268,18 +267,17 @@ namespace libtorrent i.begin += string_len; // 8 zeroes - std::fill( - i.begin - , i.begin + 8 - , 0); + std::fill(i.begin, i.begin + 8, 0); #ifndef TORRENT_DISABLE_DHT // indicate that we support the DHT messages *(i.begin + 7) = 0x01; #endif - + +#ifndef TORRENT_DISABLE_EXTENSIONS // we support extensions *(i.begin + 5) = 0x10; +#endif i.begin += 8; @@ -312,7 +310,7 @@ namespace libtorrent buffer::const_interval recv_buffer = receive_buffer(); // are we currently receiving a 'piece' message? if (m_state != read_packet - || (recv_buffer.end - recv_buffer.begin) < 9 + || recv_buffer.left() < 9 || recv_buffer[0] != msg_piece) return boost::optional(); @@ -330,7 +328,7 @@ namespace libtorrent p.piece_index = r.piece; p.block_index = r.start / t->block_size(); - p.bytes_downloaded = recv_buffer.end - recv_buffer.begin - 9; + p.bytes_downloaded = recv_buffer.left() - 9; p.full_block_bytes = r.length; return boost::optional(p); @@ -369,6 +367,14 @@ namespace libtorrent m_statistics.received_bytes(0, received); if (!packet_finished()) return; +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + if ((*i)->on_choke()) return; + } +#endif + incoming_choke(); } @@ -386,6 +392,14 @@ namespace libtorrent m_statistics.received_bytes(0, received); if (!packet_finished()) return; +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + if ((*i)->on_unchoke()) return; + } +#endif + incoming_unchoke(); } @@ -403,6 +417,14 @@ namespace libtorrent m_statistics.received_bytes(0, received); if (!packet_finished()) return; +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + if ((*i)->on_interested()) return; + } +#endif + incoming_interested(); } @@ -420,6 +442,14 @@ namespace libtorrent m_statistics.received_bytes(0, received); if (!packet_finished()) return; +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + if ((*i)->on_not_interested()) return; + } +#endif + incoming_not_interested(); } @@ -442,6 +472,14 @@ namespace libtorrent const char* ptr = recv_buffer.begin + 1; int index = detail::read_int32(ptr); +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + if ((*i)->on_have(index)) return; + } +#endif + incoming_have(index); } @@ -482,6 +520,15 @@ namespace libtorrent // (since it doesn't exist yet) for (int i = 0; i < (int)bitfield.size(); ++i) bitfield[i] = (recv_buffer[1 + (i>>3)] & (1 << (7 - (i&7)))) != 0; + +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + if ((*i)->on_bitfield(bitfield)) return; + } +#endif + incoming_bitfield(bitfield); } @@ -507,6 +554,14 @@ namespace libtorrent r.start = detail::read_int32(ptr); r.length = detail::read_int32(ptr); +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + if ((*i)->on_request(r)) return; + } +#endif + incoming_request(r); } @@ -551,6 +606,14 @@ namespace libtorrent p.start = detail::read_int32(ptr); p.length = packet_size() - 9; +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + if ((*i)->on_piece(p, recv_buffer.begin + 9)) return; + } +#endif + incoming_piece(p, recv_buffer.begin + 9); } @@ -576,6 +639,14 @@ namespace libtorrent r.start = detail::read_int32(ptr); r.length = detail::read_int32(ptr); +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + if ((*i)->on_cancel(r)) return; + } +#endif + incoming_cancel(r); } @@ -618,60 +689,34 @@ namespace libtorrent throw protocol_error("'extended' message sent before proper handshake"); buffer::const_interval recv_buffer = receive_buffer(); - if (recv_buffer.end - recv_buffer.begin < 2) return; + if (recv_buffer.left() < 2) return; assert(*recv_buffer.begin == msg_extended); ++recv_buffer.begin; int extended_id = detail::read_uint8(recv_buffer.begin); - if (extended_id > 0 && extended_id < num_supported_extensions - && !m_ses.extension_enabled(extended_id)) - throw protocol_error("'extended' message using disabled extension"); - - switch (extended_id) + if (extended_id == 0) { - case extended_handshake: - on_extended_handshake(); break; - case extended_chat_message: - on_chat(); break; - case extended_metadata_message: - on_metadata(); break; - case extended_peer_exchange_message: - on_peer_exchange(); break; - default: - throw protocol_error("unknown extended message id: " - + boost::lexical_cast(extended_id)); - }; + on_extended_handshake(); + return; + } + +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + if ((*i)->on_extended(packet_size() - 2, extended_id + , recv_buffer)) + return; + } +#endif + + throw protocol_error("unknown extended message id: " + + boost::lexical_cast(extended_id)); } - void bt_peer_connection::write_chat_message(const std::string& msg) - { - INVARIANT_CHECK; - - assert(msg.length() <= 1 * 1024); - if (!supports_extension(extended_chat_message)) return; - - entry e(entry::dictionary_t); - e["msg"] = msg; - - std::vector message; - bencode(std::back_inserter(message), e); - - buffer::interval i = allocate_send_buffer(message.size() + 6); - - detail::write_uint32(1 + 1 + (int)message.size(), i.begin); - detail::write_uint8(msg_extended, i.begin); - detail::write_uint8(m_extension_messages[extended_chat_message], i.begin); - - std::copy(message.begin(), message.end(), i.begin); - i.begin += message.size(); - assert(i.begin == i.end); - setup_send(); - } - - - void bt_peer_connection::on_extended_handshake() try + void bt_peer_connection::on_extended_handshake() { if (!packet_finished()) return; @@ -679,8 +724,19 @@ namespace libtorrent assert(t); buffer::const_interval recv_buffer = receive_buffer(); - - entry root = bdecode(recv_buffer.begin + 2, recv_buffer.end); + + entry root; + try + { + root = bdecode(recv_buffer.begin + 2, recv_buffer.end); + } + catch (std::exception& exc) + { +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << "invalid extended handshake: " << exc.what() << "\n"; +#endif + return; + } #ifdef TORRENT_VERBOSE_LOGGING std::stringstream ext; @@ -688,26 +744,18 @@ namespace libtorrent (*m_logger) << "<== EXTENDED HANDSHAKE: \n" << ext.str(); #endif - if (entry* msgs = root.find_key("m")) +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end;) { - if (msgs->type() == entry::dictionary_t) - { - // this must be the initial handshake message - // lets see if any of our extensions are supported - // if not, we will signal no extensions support to the upper layer - for (int i = 1; i < num_supported_extensions; ++i) - { - if (entry* f = msgs->find_key(extension_names[i])) - { - m_extension_messages[i] = (int)f->integer(); - } - else - { - m_extension_messages[i] = 0; - } - } - } + // a false return value means that the extension + // isn't supported by the other end. So, it is removed. + if (!(*i)->on_extension_handshake(root)) + i = m_extensions.erase(i); + else + ++i; } +#endif // there is supposed to be a remote listen port if (entry* listen_port = root.find_key("p")) @@ -736,154 +784,6 @@ namespace libtorrent m_max_out_request_queue = 1; } } - catch (std::exception& exc) - { -#ifdef TORRENT_VERBOSE_LOGGIGN - (*m_logger) << "invalid extended handshake: " << exc.what() << "\n"; -#endif - } - - // ----------------------------- - // ----------- CHAT ------------ - // ----------------------------- - - void bt_peer_connection::on_chat() - { - if (packet_size() > 2 * 1024) - throw protocol_error("CHAT message larger than 2 kB"); - - if (!packet_finished()) return; - - try - { - boost::shared_ptr t = associated_torrent().lock(); - assert(t); - - buffer::const_interval recv_buffer = receive_buffer(); - entry d = bdecode(recv_buffer.begin + 2, recv_buffer.end); - const std::string& str = d["msg"].string(); - - if (t->alerts().should_post(alert::critical)) - { - t->alerts().post_alert( - chat_message_alert( - t->get_handle() - , remote(), str)); - } - - } - catch (invalid_encoding&) - { - // TODO: post an alert about the invalid chat message - return; -// throw protocol_error("invalid bencoding in CHAT message"); - } - catch (type_error&) - { - // TODO: post an alert about the invalid chat message - return; -// throw protocol_error("invalid types in bencoded CHAT message"); - } - return; - } - - // ----------------------------- - // --------- METADATA ---------- - // ----------------------------- - - void bt_peer_connection::on_metadata() - { - boost::shared_ptr t = associated_torrent().lock(); - assert(t); - - if (packet_size() > 500 * 1024) - throw protocol_error("metadata message larger than 500 kB"); - - if (!packet_finished()) return; - - buffer::const_interval recv_buffer = receive_buffer(); - recv_buffer.begin += 2; - int type = detail::read_uint8(recv_buffer.begin); - - switch (type) - { - case 0: // request - { - int start = detail::read_uint8(recv_buffer.begin); - int size = detail::read_uint8(recv_buffer.begin) + 1; - - if (packet_size() != 5) - { - // invalid metadata request - throw protocol_error("invalid metadata request"); - } - - write_metadata(std::make_pair(start, size)); - } - break; - case 1: // data - { - if (recv_buffer.end - recv_buffer.begin < 8) return; - int total_size = detail::read_int32(recv_buffer.begin); - int offset = detail::read_int32(recv_buffer.begin); - int data_size = packet_size() - 2 - 9; - - if (total_size > 500 * 1024) - throw protocol_error("metadata size larger than 500 kB"); - if (total_size <= 0) - throw protocol_error("invalid metadata size"); - if (offset > total_size || offset < 0) - throw protocol_error("invalid metadata offset"); - if (offset + data_size > total_size) - throw protocol_error("invalid metadata message"); - - t->metadata_progress(total_size - , recv_buffer.left() - m_metadata_progress); - m_metadata_progress = recv_buffer.left(); - if (!packet_finished()) return; - -#ifdef TORRENT_VERBOSE_LOGGING - using namespace boost::posix_time; - (*m_logger) << to_simple_string(second_clock::universal_time()) - << " <== METADATA [ tot: " << total_size << " offset: " - << offset << " size: " << data_size << " ]\n"; -#endif - - m_waiting_metadata_request = false; - t->received_metadata(recv_buffer.begin, data_size - , offset, total_size); - m_metadata_progress = 0; - } - break; - case 2: // have no data - if (!packet_finished()) return; - - m_no_metadata = second_clock::universal_time(); - if (m_waiting_metadata_request) - t->cancel_metadata_request(m_last_metadata_request); - m_waiting_metadata_request = false; - break; - default: - throw protocol_error("unknown metadata extension message: " - + boost::lexical_cast(type)); - } - - } - - // ----------------------------- - // ------ PEER EXCHANGE -------- - // ----------------------------- - - void bt_peer_connection::on_peer_exchange() - { - - } - - bool bt_peer_connection::has_metadata() const - { - using namespace boost::posix_time; - return second_clock::universal_time() - m_no_metadata > minutes(5); - } bool bt_peer_connection::dispatch_message(int received) { @@ -901,6 +801,17 @@ namespace libtorrent || packet_type >= num_supported_messages || m_message_handler[packet_type] == 0) { +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + if ((*i)->on_unknown_message(packet_size(), packet_type + , buffer::const_interval(recv_buffer.begin+1 + , recv_buffer.end))) + return packet_finished(); + } +#endif + throw protocol_error("unknown message id: " + boost::lexical_cast(packet_type) + " size: " + boost::lexical_cast(packet_size())); @@ -911,9 +822,7 @@ namespace libtorrent // call the correct handler for this packet type (this->*m_message_handler[packet_type])(received); - if (!packet_finished()) return false; - - return true; + return packet_finished(); } void bt_peer_connection::write_keepalive() @@ -972,103 +881,14 @@ namespace libtorrent setup_send(); } - void bt_peer_connection::write_metadata(std::pair req) - { - assert(req.first >= 0); - assert(req.second > 0); - assert(req.second <= 256); - assert(req.first + req.second <= 256); - assert(!associated_torrent().expired()); - INVARIANT_CHECK; - - // abort if the peer doesn't support the metadata extension - if (!supports_extension(extended_metadata_message)) return; - - boost::shared_ptr t = associated_torrent().lock(); - assert(t); - - if (t->valid_metadata()) - { - std::pair offset - = req_to_offset(req, (int)t->metadata().size()); - - buffer::interval i = allocate_send_buffer(15 + offset.second); - - // yes, we have metadata, send it - detail::write_uint32(11 + offset.second, i.begin); - detail::write_uint8(msg_extended, i.begin); - detail::write_uint8(m_extension_messages[extended_metadata_message] - , i.begin); - // means 'data packet' - detail::write_uint8(1, i.begin); - detail::write_uint32((int)t->metadata().size(), i.begin); - detail::write_uint32(offset.first, i.begin); - std::vector const& metadata = t->metadata(); - std::copy(metadata.begin() + offset.first - , metadata.begin() + offset.first + offset.second, i.begin); - i.begin += offset.second; - assert(i.begin == i.end); - } - else - { - buffer::interval i = allocate_send_buffer(4 + 3); - // we don't have the metadata, reply with - // don't have-message - detail::write_uint32(1 + 2, i.begin); - detail::write_uint8(msg_extended, i.begin); - detail::write_uint8(m_extension_messages[extended_metadata_message] - , i.begin); - // means 'have no data' - detail::write_uint8(2, i.begin); - assert(i.begin == i.end); - } - setup_send(); - } - - void bt_peer_connection::write_metadata_request(std::pair req) - { - assert(req.first >= 0); - assert(req.second > 0); - assert(req.first + req.second <= 256); - assert(!associated_torrent().expired()); - assert(!associated_torrent().lock()->valid_metadata()); - INVARIANT_CHECK; - - int start = req.first; - int size = req.second; - - // abort if the peer doesn't support the metadata extension - if (!supports_extension(extended_metadata_message)) return; - -#ifdef TORRENT_VERBOSE_LOGGING - using namespace boost::posix_time; - (*m_logger) << to_simple_string(second_clock::universal_time()) - << " ==> METADATA_REQUEST [ start: " << req.first - << " size: " << req.second << " ]\n"; -#endif - - buffer::interval i = allocate_send_buffer(9); - - detail::write_uint32(1 + 1 + 3, i.begin); - detail::write_uint8(msg_extended, i.begin); - detail::write_uint8(m_extension_messages[extended_metadata_message] - , i.begin); - // means 'request data' - detail::write_uint8(0, i.begin); - detail::write_uint8(start, i.begin); - detail::write_uint8(size - 1, i.begin); - assert(i.begin == i.end); - setup_send(); - } - void bt_peer_connection::write_bitfield(std::vector const& bitfield) { INVARIANT_CHECK; boost::shared_ptr t = associated_torrent().lock(); assert(t); - - if (t->num_pieces() == 0) return; + assert(m_sent_bitfield == false); + assert(t->valid_metadata()); #ifdef TORRENT_VERBOSE_LOGGING using namespace boost::posix_time; @@ -1096,9 +916,13 @@ namespace libtorrent i.begin[c >> 3] |= 1 << (7 - (c & 7)); } assert(i.end - i.begin == ((int)bitfield.size() + 7) / 8); +#ifndef NDEBUG + m_sent_bitfield = true; +#endif setup_send(); } +#ifndef TORRENT_DISABLE_EXTENSIONS void bt_peer_connection::write_extensions() { INVARIANT_CHECK; @@ -1113,16 +937,12 @@ namespace libtorrent entry handshake(entry::dictionary_t); entry extension_list(entry::dictionary_t); - for (int i = 1; i < num_supported_extensions; ++i) - { - // if this specific extension is disabled - // just don't add it to the supported set - if (!m_ses.extension_enabled(i)) continue; - extension_list[extension_names[i]] = i; - } - handshake["m"] = extension_list; - handshake["p"] = m_ses.listen_port(); + + // only send the port in case we bade the connection + // on incoming connections the other end already knows + // our listen port + if (is_local()) handshake["p"] = m_ses.listen_port(); handshake["v"] = m_ses.settings().user_agent; std::string remote_address; std::back_insert_iterator out(remote_address); @@ -1130,6 +950,14 @@ namespace libtorrent handshake["ip"] = remote_address; handshake["reqq"] = m_ses.settings().max_allowed_in_request_queue; + // loop backwards, to make the first extension be the last + // to fill in the handshake (i.e. give the first extensions priority) + for (extension_list_t::reverse_iterator i = m_extensions.rbegin() + , end(m_extensions.rend()); i != end; ++i) + { + (*i)->add_handshake(handshake); + } + std::vector msg; bencode(std::back_inserter(msg), handshake); @@ -1140,7 +968,7 @@ namespace libtorrent detail::write_int32((int)msg.size() + 2, i.begin); detail::write_uint8(msg_extended, i.begin); // signal handshake message - detail::write_uint8(extended_handshake, i.begin); + detail::write_uint8(0, i.begin); std::copy(msg.begin(), msg.end(), i.begin); i.begin += msg.size(); @@ -1154,6 +982,7 @@ namespace libtorrent setup_send(); } +#endif void bt_peer_connection::write_choke() { @@ -1227,12 +1056,33 @@ namespace libtorrent setup_send(); } + namespace + { + struct match_peer_id + { + match_peer_id(peer_id const& id, peer_connection const* pc) + : m_id(id), m_pc(pc) + { assert(pc); } + + bool operator()(policy::peer const& p) const + { + return p.connection != m_pc + && p.connection + && p.connection->pid() == m_id + && !p.connection->pid().is_all_zeros(); + } + + peer_id m_id; + peer_connection const* m_pc; + }; + } + // -------------------------- // RECEIVE DATA // -------------------------- // throws exception when the client should be disconnected - void bt_peer_connection::on_receive(const asio::error& error + void bt_peer_connection::on_receive(asio::error_code const& error , std::size_t bytes_transferred) { INVARIANT_CHECK; @@ -1278,8 +1128,9 @@ namespace libtorrent , recv_buffer.end) << "'\n"; #endif const char protocol_string[] = "BitTorrent protocol"; - if (!std::equal(recv_buffer.begin, recv_buffer.end - , protocol_string)) + if (recv_buffer.end - recv_buffer.begin != 19 + || !std::equal(recv_buffer.begin, recv_buffer.end + , protocol_string)) { const char cmd[] = "version"; if (recv_buffer.end - recv_buffer.begin == 7 && std::equal( @@ -1311,7 +1162,6 @@ namespace libtorrent m_statistics.received_bytes(0, bytes_transferred); if (!packet_finished()) break; -// MassaRoddel #ifdef TORRENT_VERBOSE_LOGGING for (int i=0; i < 8; ++i) { @@ -1325,13 +1175,15 @@ namespace libtorrent if (recv_buffer[7] & 0x01) (*m_logger) << "supports DHT port message\n"; if (recv_buffer[7] & 0x02) - (*m_logger) << "supports XBT peer exchange message\n"; + (*m_logger) << "supports FAST extensions\n"; if (recv_buffer[5] & 0x10) - (*m_logger) << "supports LT/uT extensions\n"; + (*m_logger) << "supports extensions protocol\n"; #endif - if ((recv_buffer[5] & 0x10) && m_ses.extensions_enabled()) +#ifndef DISABLE_EXTENSIONS + if ((recv_buffer[5] & 0x10)) m_supports_extensions = true; +#endif if (recv_buffer[7] & 0x01) m_supports_dht_port = true; @@ -1349,12 +1201,11 @@ namespace libtorrent t = associated_torrent().lock(); assert(t); - assert(t->get_policy().has_connection(this)); - // yes, we found the torrent // reply with our handshake write_handshake(); - write_bitfield(t->pieces()); + if (t->valid_metadata()) + write_bitfield(t->pieces()); } else { @@ -1365,14 +1216,11 @@ namespace libtorrent #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << " received invalid info_hash\n"; #endif - throw std::runtime_error("invalid info-hash in handshake"); + throw protocol_error("invalid info-hash in handshake"); } } -#ifndef TORRENT_DISABLE_DHT - if (m_supports_dht_port && m_ses.m_dht) - write_dht_port(m_ses.kad_settings().service_port); -#endif + assert(t->get_policy().has_connection(this)); m_state = read_peer_id; reset_recv_buffer(20); @@ -1408,7 +1256,40 @@ namespace libtorrent peer_id pid; std::copy(recv_buffer.begin, recv_buffer.begin + 20, (char*)pid.begin()); set_pid(pid); - + + if (t->settings().allow_multiple_connections_per_ip) + { + // now, let's see if this connection should be closed + policy& p = t->get_policy(); + policy::iterator i = std::find_if(p.begin_peer(), p.end_peer() + , match_peer_id(pid, this)); + if (i != p.end_peer()) + { + assert(i->connection->pid() == pid); + // we found another connection with the same peer-id + // which connection should be closed in order to be + // sure that the other end closes the same connection? + // the peer with greatest peer-id is the one allowed to + // initiate connections. So, if our peer-id is greater than + // the others, we should close the incoming connection, + // if not, we should close the outgoing one. + if (pid < m_ses.get_peer_id() && is_local()) + { + i->connection->disconnect(); + } + else + { + throw protocol_error("duplicate peer-id, connection closed"); + } + } + + } + +#ifndef TORRENT_DISABLE_DHT + if (m_supports_dht_port && m_ses.m_dht) + write_dht_port(m_ses.kad_settings().service_port); +#endif + m_client_version = identify_client(pid); boost::optional f = client_fingerprint(pid); if (f && std::equal(f->name, f->name + 2, "BC")) @@ -1422,14 +1303,23 @@ namespace libtorrent if (pid == m_ses.get_peer_id()) throw std::runtime_error("closing connection to ourself"); - if (m_supports_extensions) write_extensions(); -/* - if (!m_active) +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end;) { - m_attached_to_torrent = true; - assert(m_torrent->get_policy().has_connection(this)); + if (!(*i)->on_handshake()) + { + i = m_extensions.erase(i); + } + else + { + ++i; + } } -*/ + + if (m_supports_extensions) write_extensions(); +#endif + m_state = read_packet_size; reset_recv_buffer(4); } @@ -1487,7 +1377,7 @@ namespace libtorrent // -------------------------- // throws exception when the client should be disconnected - void bt_peer_connection::on_sent(asio::error const& error + void bt_peer_connection::on_sent(asio::error_code const& error , std::size_t bytes_transferred) { INVARIANT_CHECK; @@ -1528,28 +1418,6 @@ namespace libtorrent m_statistics.sent_bytes(amount_payload, bytes_transferred - amount_payload); } - - void bt_peer_connection::on_tick() - { - boost::shared_ptr t = associated_torrent().lock(); - if (!t) return; - - // if we don't have any metadata, and this peer - // supports the request metadata extension - // and we aren't currently waiting for a request - // reply. Then, send a request for some metadata. - if (!t->valid_metadata() - && supports_extension(extended_metadata_message) - && !m_waiting_metadata_request - && has_metadata()) - { - m_last_metadata_request = t->metadata_request(); - write_metadata_request(m_last_metadata_request); - m_waiting_metadata_request = true; - m_metadata_request = second_clock::universal_time(); - } - } - #ifndef NDEBUG void bt_peer_connection::check_invariant() const { diff --git a/libtorrent/src/entry.cpp b/libtorrent/src/entry.cpp index 02d86a80f..55cbc3649 100644 --- a/libtorrent/src/entry.cpp +++ b/libtorrent/src/entry.cpp @@ -34,8 +34,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include "libtorrent/entry.hpp" #include "libtorrent/config.hpp" -#include -#include #if defined(_MSC_VER) namespace std @@ -139,52 +137,52 @@ namespace libtorrent return (*this)[key.c_str()]; } - entry::entry(const dictionary_type& v) + entry::entry(dictionary_type const& v) { new(data) dictionary_type(v); m_type = dictionary_t; } - entry::entry(const string_type& v) + entry::entry(string_type const& v) { new(data) string_type(v); m_type = string_t; } - entry::entry(const list_type& v) + entry::entry(list_type const& v) { new(data) list_type(v); m_type = list_t; } - entry::entry(const integer_type& v) + entry::entry(integer_type const& v) { new(data) integer_type(v); m_type = int_t; } - void entry::operator=(const dictionary_type& v) + void entry::operator=(dictionary_type const& v) { destruct(); new(data) dictionary_type(v); m_type = dictionary_t; } - void entry::operator=(const string_type& v) + void entry::operator=(string_type const& v) { destruct(); new(data) string_type(v); m_type = string_t; } - void entry::operator=(const list_type& v) + void entry::operator=(list_type const& v) { destruct(); new(data) list_type(v); m_type = list_t; } - void entry::operator=(const integer_type& v) + void entry::operator=(integer_type const& v) { destruct(); new(data) integer_type(v); @@ -234,7 +232,7 @@ namespace libtorrent } } - void entry::copy(const entry& e) + void entry::copy(entry const& e) { m_type = e.m_type; switch(m_type) diff --git a/libtorrent/src/file.cpp b/libtorrent/src/file.cpp index af8404660..2542f31de 100644 --- a/libtorrent/src/file.cpp +++ b/libtorrent/src/file.cpp @@ -163,8 +163,12 @@ namespace libtorrent wpath.c_str() , map_open_mode(mode) , S_IREAD | S_IWRITE); +#else +#ifdef _WIN32 + m_fd = ::_open( #else m_fd = ::open( +#endif utf8_native(path.native_file_string()).c_str() , map_open_mode(mode) #ifdef _WIN32 @@ -187,7 +191,11 @@ namespace libtorrent { if (m_fd == -1) return; +#ifdef _WIN32 + ::_close(m_fd); +#else ::close(m_fd); +#endif m_fd = -1; m_open_mode = 0; } @@ -197,7 +205,11 @@ namespace libtorrent assert(m_open_mode & mode_in); assert(m_fd != -1); +#ifdef _WIN32 + size_type ret = ::_read(m_fd, buf, num_bytes); +#else size_type ret = ::read(m_fd, buf, num_bytes); +#endif if (ret == -1) { std::stringstream msg; @@ -217,7 +229,11 @@ namespace libtorrent // if ((rand() % 100) > 80) // throw file_error("debug"); +#ifdef _WIN32 + size_type ret = ::_write(m_fd, buf, num_bytes); +#else size_type ret = ::write(m_fd, buf, num_bytes); +#endif if (ret == -1) { std::stringstream msg; diff --git a/libtorrent/src/file_pool.cpp b/libtorrent/src/file_pool.cpp new file mode 100644 index 000000000..2a4ad4972 --- /dev/null +++ b/libtorrent/src/file_pool.cpp @@ -0,0 +1,127 @@ +/* + +Copyright (c) 2006, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "libtorrent/file_pool.hpp" + +#include + +namespace libtorrent +{ + using boost::multi_index::nth_index; + using boost::multi_index::get; + + boost::shared_ptr file_pool::open_file(void* st, fs::path const& p, file::open_mode m) + { + assert(st != 0); + assert(p.is_complete()); + boost::mutex::scoped_lock l(m_mutex); + typedef nth_index::type path_view; + path_view& pt = get<0>(m_files); + path_view::iterator i = pt.find(p); + if (i != pt.end()) + { + lru_file_entry e = *i; + e.last_use = pt::second_clock::universal_time(); + + // if you hit this assert, you probably have more than one + // storage/torrent using the same file at the same time! + assert(e.key == st); + + e.key = st; + if ((e.mode & m) != m) + { + // close the file before we open it with + // the new read/write privilages + i->file_ptr.reset(); + assert(e.file_ptr.unique()); + e.file_ptr.reset(); + e.file_ptr.reset(new file(p, m)); + e.mode = m; + } + pt.replace(i, e); + return e.file_ptr; + } + // the file is not in our cache + if ((int)m_files.size() >= m_size) + { + // the file cache is at its maximum size, close + // the least recently used (lru) file from it + typedef nth_index::type lru_view; + lru_view& lt = get<1>(m_files); + lru_view::iterator i = lt.begin(); + // the first entry in this view is the least recently used + assert(lt.size() == 1 || (i->last_use <= boost::next(i)->last_use)); + lt.erase(i); + } + lru_file_entry e(boost::shared_ptr(new file(p, m))); + e.mode = m; + e.key = st; + e.file_path = p; + pt.insert(e); + return e.file_ptr; + } + + void file_pool::release(void* st) + { + boost::mutex::scoped_lock l(m_mutex); + assert(st != 0); + using boost::tie; + + typedef nth_index::type key_view; + key_view& kt = get<2>(m_files); + + key_view::iterator start, end; + tie(start, end) = kt.equal_range(st); + kt.erase(start, end); + } + + void file_pool::resize(int size) + { + assert(size > 0); + if (size == m_size) return; + boost::mutex::scoped_lock l(m_mutex); + m_size = size; + if (int(m_files.size()) <= m_size) return; + + // close the least recently used files + typedef nth_index::type lru_view; + lru_view& lt = get<1>(m_files); + lru_view::iterator i = lt.begin(); + while (int(m_files.size()) > m_size) + { + // the first entry in this view is the least recently used + assert(lt.size() == 1 || (i->last_use <= boost::next(i)->last_use)); + lt.erase(i++); + } + } + +} diff --git a/libtorrent/src/file_win.cpp b/libtorrent/src/file_win.cpp new file mode 100644 index 000000000..833c2124a --- /dev/null +++ b/libtorrent/src/file_win.cpp @@ -0,0 +1,346 @@ +/* + +Copyright (c) 2003, Magnus Jonsson & Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "libtorrent/file.hpp" +#include "libtorrent/utf8.hpp" + +#ifdef UNICODE +#include "libtorrent/storage.hpp" +#endif + +#include +#include + +namespace +{ + // must be used to not leak memory in case something would throw + class auto_localfree + { + public: + auto_localfree(HLOCAL memory) + : m_memory(memory) + { + } + ~auto_localfree() + { + if (m_memory) + LocalFree(m_memory); + } + private: + HLOCAL m_memory; + }; + + std::string utf8_native(std::string const& s) + { + try + { + std::wstring ws; + libtorrent::utf8_wchar(s, ws); + std::size_t size = wcstombs(0, ws.c_str(), 0); + if (size == std::size_t(-1)) return s; + std::string ret; + ret.resize(size); + size = wcstombs(&ret[0], ws.c_str(), size + 1); + if (size == wchar_t(-1)) return s; + ret.resize(size); + return ret; + } + catch(std::exception) + { + return s; + } + } + + void throw_exception(const char* thrower) + { + DWORD err = GetLastError(); + +#ifdef UNICODE + wchar_t *wbuffer = 0; + FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM + |FORMAT_MESSAGE_ALLOCATE_BUFFER + , 0, err, 0, (LPWSTR)&wbuffer, 0, 0); + auto_localfree auto_free(wbuffer); + std::string tmp_utf8; + libtorrent::wchar_utf8(wbuffer, tmp_utf8); + char const* buffer = tmp_utf8.c_str(); +#else + char* buffer = 0; + FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM + |FORMAT_MESSAGE_ALLOCATE_BUFFER + , 0, err, 0, (LPSTR)&buffer, 0, 0); + auto_localfree auto_free(buffer); +#endif + + std::stringstream s; + s << (thrower ? thrower : "NULL") << ": " << (buffer ? buffer : "NULL"); + + throw libtorrent::file_error(s.str()); + } +} + +namespace libtorrent +{ + + struct file::impl : boost::noncopyable + { + enum open_flags + { + read_flag = 1, + write_flag = 2 + }; + + enum seek_mode + { + seek_begin = FILE_BEGIN, + seek_from_here = FILE_CURRENT, + seek_end = FILE_END + }; + + impl() + { + m_file_handle = INVALID_HANDLE_VALUE; + } + + void open(const char *file_name, open_flags flags) + { + assert(file_name); + assert(flags & (read_flag | write_flag)); + + DWORD access_mask = 0; + if (flags & read_flag) + access_mask |= GENERIC_READ; + if (flags & write_flag) + access_mask |= GENERIC_WRITE; + + assert(access_mask & (GENERIC_READ | GENERIC_WRITE)); + + #ifdef UNICODE + std::wstring wfile_name(safe_convert(file_name)); + HANDLE new_handle = CreateFile( + wfile_name.c_str() + , access_mask + , FILE_SHARE_READ + , 0 + , (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING + , FILE_ATTRIBUTE_NORMAL + , 0); + #else + HANDLE new_handle = CreateFile( + utf8_native(file_name).c_str() + , access_mask + , FILE_SHARE_READ + , 0 + , (flags & write_flag)?OPEN_ALWAYS:OPEN_EXISTING + , FILE_ATTRIBUTE_NORMAL + , 0); + #endif + + if (new_handle == INVALID_HANDLE_VALUE) + { + std::stringstream s; + throw_exception(file_name); + } + // will only close old file if the open succeeded + close(); + m_file_handle = new_handle; + } + + void close() + { + if (m_file_handle != INVALID_HANDLE_VALUE) + { + CloseHandle(m_file_handle); + m_file_handle = INVALID_HANDLE_VALUE; + } + } + + ~impl() + { + close(); + } + + size_type write(const char* buffer, size_type num_bytes) + { + assert(buffer); + assert((DWORD)num_bytes == num_bytes); + DWORD bytes_written = 0; + if (num_bytes != 0) + { + if (FALSE == WriteFile( + m_file_handle + , buffer + , (DWORD)num_bytes + , &bytes_written + , 0)) + { + throw_exception("file::write"); + } + } + return bytes_written; + } + + size_type read(char* buffer, size_type num_bytes) + { + assert(buffer); + assert(num_bytes >= 0); + assert((DWORD)num_bytes == num_bytes); + + DWORD bytes_read = 0; + if (num_bytes != 0) + { + if (FALSE == ReadFile( + m_file_handle + , buffer + , (DWORD)num_bytes + , &bytes_read + , 0)) + { + throw_exception("file::read"); + } + } + return bytes_read; + } + + size_type seek(size_type pos, seek_mode from_where) + { + assert(pos >= 0 || from_where != seek_begin); + assert(pos <= 0 || from_where != seek_end); + LARGE_INTEGER offs; + offs.QuadPart = pos; + if (FALSE == SetFilePointerEx( + m_file_handle + , offs + , &offs + , from_where)) + { + throw_exception("file::seek"); + } + return offs.QuadPart; + } + + size_type tell() + { + LARGE_INTEGER offs; + offs.QuadPart = 0; + + // is there any other way to get offset? + if (FALSE == SetFilePointerEx( + m_file_handle + , offs + , &offs + , FILE_CURRENT)) + { + throw_exception("file::tell"); + } + + size_type pos = offs.QuadPart; + assert(pos >= 0); + return pos; + } +/* + size_type size() + { + LARGE_INTEGER s; + if (FALSE == GetFileSizeEx(m_file_handle, &s)) + { + throw_exception("file::size"); + } + + size_type size = s.QuadPart; + assert(size >= 0); + return size; + } +*/ + private: + + HANDLE m_file_handle; + + }; +} + +namespace libtorrent +{ + + const file::seek_mode file::begin(file::impl::seek_begin); + const file::seek_mode file::end(file::impl::seek_end); + + const file::open_mode file::in(file::impl::read_flag); + const file::open_mode file::out(file::impl::write_flag); + + file::file() + : m_impl(new libtorrent::file::impl()) + { + } + file::file(boost::filesystem::path const& p, open_mode m) + : m_impl(new libtorrent::file::impl()) + { + open(p,m); + } + + file::~file() + { + } + + void file::open(boost::filesystem::path const& p, open_mode m) + { + assert(p.is_complete()); + m_impl->open(p.native_file_string().c_str(), impl::open_flags(m.m_mask)); + } + + void file::close() + { + m_impl->close(); + } + + size_type file::write(const char* buffer, size_type num_bytes) + { + return m_impl->write(buffer, num_bytes); + } + + size_type file::read(char* buffer, size_type num_bytes) + { + return m_impl->read(buffer, num_bytes); + } + + size_type file::seek(size_type pos, seek_mode m) + { + return m_impl->seek(pos,impl::seek_mode(m.m_val)); + } + + size_type file::tell() + { + return m_impl->tell(); + } +} diff --git a/libtorrent/src/http_tracker_connection.cpp b/libtorrent/src/http_tracker_connection.cpp index 3299cf5b8..43f93d4c7 100644 --- a/libtorrent/src/http_tracker_connection.cpp +++ b/libtorrent/src/http_tracker_connection.cpp @@ -35,7 +35,9 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include +#include "libtorrent/config.hpp" #include "zlib.h" #ifdef _MSC_VER @@ -84,13 +86,30 @@ namespace using namespace boost::posix_time; +namespace +{ + bool url_has_argument(std::string const& url, std::string argument) + { + size_t i = url.find('?'); + if (i == std::string::npos) return false; + + argument += '='; + + if (url.compare(i + 1, argument.size(), argument) == 0) return true; + argument.insert(0, "&"); + return url.find(argument, i) + != std::string::npos; + } + + char to_lower(char c) { return std::tolower(c); } +} + namespace libtorrent { http_parser::http_parser() : m_recv_pos(0) , m_status_code(-1) , m_content_length(-1) - , m_content_encoding(plain) , m_state(read_status) , m_recv_buffer(0, 0) , m_body_start_pos(0) @@ -99,9 +118,13 @@ namespace libtorrent boost::tuple http_parser::incoming(buffer::const_interval recv_buffer) { - m_recv_buffer = recv_buffer; + assert(recv_buffer.left() >= m_recv_buffer.left()); boost::tuple ret(0, 0); + // early exit if there's nothing new in the receive buffer + if (recv_buffer.left() == m_recv_buffer.left()) return ret; + m_recv_buffer = recv_buffer; + char const* pos = recv_buffer.begin + m_recv_pos; if (m_state == read_status) { @@ -113,7 +136,10 @@ namespace libtorrent if (newline == pos) throw std::runtime_error("unexpected newline in HTTP response"); - std::istringstream line(std::string(pos, newline - 1)); + char const* line_end = newline; + if (pos != line_end && *(line_end - 1) == '\r') --line_end; + + std::istringstream line(std::string(pos, line_end)); ++newline; int incoming = (int)std::distance(pos, newline); m_recv_pos += incoming; @@ -124,7 +150,7 @@ namespace libtorrent if (m_protocol.substr(0, 5) != "HTTP/") { throw std::runtime_error("unknown protocol in HTTP response: " - + m_protocol); + + m_protocol + " line: " + std::string(pos, newline)); } line >> m_status_code; std::getline(line, m_server_message); @@ -139,10 +165,11 @@ namespace libtorrent while (newline != recv_buffer.end && m_state == read_header) { - if (newline == pos) - throw std::runtime_error("unexpected newline in HTTP response"); - - line.assign(pos, newline - 1); + // if the LF character is preceeded by a CR + // charachter, don't copy it into the line string. + char const* line_end = newline; + if (pos != line_end && *(line_end - 1) == '\r') --line_end; + line.assign(pos, line_end); m_recv_pos += newline - pos; boost::get<1>(ret) += newline - pos; pos = newline; @@ -150,6 +177,9 @@ namespace libtorrent std::string::size_type separator = line.find(": "); if (separator == std::string::npos) { + // this means we got a blank line, + // the header is finished and the body + // starts. ++pos; ++m_recv_pos; boost::get<1>(ret) += 1; @@ -160,10 +190,11 @@ namespace libtorrent } std::string name = line.substr(0, separator); + std::transform(name.begin(), name.end(), name.begin(), &to_lower); std::string value = line.substr(separator + 2, std::string::npos); m_header.insert(std::make_pair(name, value)); - if (name == "Content-Length") + if (name == "content-length") { try { @@ -171,20 +202,21 @@ namespace libtorrent } catch(boost::bad_lexical_cast&) {} } - else if (name == "Content-Encoding") + else if (name == "content-range") { - if (value == "gzip" || value == "x-gzip") + std::stringstream range_str(value); + char dummy; + std::string bytes; + size_type range_start, range_end; + range_str >> bytes >> range_start >> dummy >> range_end; + if (!range_str || range_end < range_start) { - m_content_encoding = gzip; - } - else - { - std::string error_str = "unknown content encoding in response: \""; - error_str += value; - error_str += "\""; - throw std::runtime_error(error_str); + throw std::runtime_error("invalid content-range in HTTP response: " + range_str.str()); } + // the http range is inclusive + m_content_length = range_end - range_start + 1; } + // TODO: make sure we don't step outside of the buffer ++pos; ++m_recv_pos; @@ -213,44 +245,51 @@ namespace libtorrent return ret; } - buffer::const_interval http_parser::get_body() + buffer::const_interval http_parser::get_body() const + { + assert(m_state == read_body); + if (m_content_length >= 0) + return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos + , m_recv_buffer.begin + std::min(m_recv_pos + , m_body_start_pos + m_content_length)); + else + return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos + , m_recv_buffer.begin + m_recv_pos); + } + + void http_parser::reset() { - char const* body_begin = m_recv_buffer.begin + m_body_start_pos; - char const* body_end = m_recv_buffer.begin + m_recv_pos; - m_recv_pos = 0; m_body_start_pos = 0; m_status_code = -1; m_content_length = -1; m_finished = false; m_state = read_status; + m_recv_buffer.begin = 0; + m_recv_buffer.end = 0; m_header.clear(); - - return buffer::const_interval(body_begin, body_end); } - + http_tracker_connection::http_tracker_connection( - demuxer& d + asio::strand& str , tracker_manager& man , tracker_request const& req , std::string const& hostname , unsigned short port , std::string request + , address bind_infc , boost::weak_ptr c , session_settings const& stn , std::string const& auth) - : tracker_connection(man, req, d, c) + : tracker_connection(man, req, str, bind_infc, c) , m_man(man) - , m_state(read_status) - , m_content_encoding(plain) - , m_content_length(0) - , m_name_lookup(d) + , m_strand(str) + , m_name_lookup(m_strand.io_service()) , m_port(port) , m_recv_pos(0) , m_buffer(http_buffer_size) , m_settings(stn) , m_password(auth) - , m_code(0) , m_timed_out(false) { const std::string* connect_to_host; @@ -295,51 +334,100 @@ namespace libtorrent // if request-string already contains // some parameters, append an ampersand instead // of a question mark - if (request.find('?') != std::string::npos) + size_t arguments_start = request.find('?'); + if (arguments_start != std::string::npos) m_send_buffer += "&"; else m_send_buffer += "?"; - m_send_buffer += "info_hash="; - m_send_buffer += escape_string( - reinterpret_cast(req.info_hash.begin()), 20); + if (!url_has_argument(request, "info_hash")) + { + m_send_buffer += "info_hash="; + m_send_buffer += escape_string( + reinterpret_cast(req.info_hash.begin()), 20); + m_send_buffer += '&'; + } if (tracker_req().kind == tracker_request::announce_request) { - m_send_buffer += "&peer_id="; - m_send_buffer += escape_string( - reinterpret_cast(req.pid.begin()), 20); + if (!url_has_argument(request, "peer_id")) + { + m_send_buffer += "peer_id="; + m_send_buffer += escape_string( + reinterpret_cast(req.pid.begin()), 20); + m_send_buffer += '&'; + } - m_send_buffer += "&port="; - m_send_buffer += boost::lexical_cast(req.listen_port); + if (!url_has_argument(request, "port")) + { + m_send_buffer += "port="; + m_send_buffer += boost::lexical_cast(req.listen_port); + m_send_buffer += '&'; + } - m_send_buffer += "&uploaded="; - m_send_buffer += boost::lexical_cast(req.uploaded); + if (!url_has_argument(request, "uploaded")) + { + m_send_buffer += "uploaded="; + m_send_buffer += boost::lexical_cast(req.uploaded); + m_send_buffer += '&'; + } - m_send_buffer += "&downloaded="; - m_send_buffer += boost::lexical_cast(req.downloaded); + if (!url_has_argument(request, "downloaded")) + { + m_send_buffer += "downloaded="; + m_send_buffer += boost::lexical_cast(req.downloaded); + m_send_buffer += '&'; + } - m_send_buffer += "&left="; - m_send_buffer += boost::lexical_cast(req.left); + if (!url_has_argument(request, "left")) + { + m_send_buffer += "left="; + m_send_buffer += boost::lexical_cast(req.left); + m_send_buffer += '&'; + } if (req.event != tracker_request::none) { - const char* event_string[] = {"completed", "started", "stopped"}; - m_send_buffer += "&event="; - m_send_buffer += event_string[req.event - 1]; + if (!url_has_argument(request, "event")) + { + const char* event_string[] = {"completed", "started", "stopped"}; + m_send_buffer += "event="; + m_send_buffer += event_string[req.event - 1]; + m_send_buffer += '&'; + } + } + if (!url_has_argument(request, "key")) + { + m_send_buffer += "key="; + std::stringstream key_string; + key_string << std::hex << req.key; + m_send_buffer += key_string.str(); + m_send_buffer += '&'; + } + + if (!url_has_argument(request, "compact")) + { + m_send_buffer += "compact=1&"; + } + if (!url_has_argument(request, "numwant")) + { + m_send_buffer += "numwant="; + m_send_buffer += boost::lexical_cast( + std::min(req.num_want, 999)); + m_send_buffer += '&'; } - m_send_buffer += "&key="; - std::stringstream key_string; - key_string << std::hex << req.key; - m_send_buffer += key_string.str(); - m_send_buffer += "&compact=1"; - m_send_buffer += "&numwant="; - m_send_buffer += boost::lexical_cast( - std::min(req.num_want, 999)); // extension that tells the tracker that // we don't need any peer_id's in the response - m_send_buffer += "&no_peer_id=1"; + if (!url_has_argument(request, "no_peer_id")) + { + m_send_buffer += "no_peer_id=1"; + } + else + { + // remove the trailing '&' + m_send_buffer.resize(m_send_buffer.size() - 1); + } } m_send_buffer += " HTTP/1.0\r\nAccept-Encoding: gzip\r\n" @@ -364,19 +452,23 @@ namespace libtorrent m_send_buffer += base64encode(auth); } m_send_buffer += "\r\n\r\n"; + #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) if (has_requester()) { requester().debug_log("==> TRACKER_REQUEST [ str: " + m_send_buffer + " ]"); std::stringstream info_hash_str; info_hash_str << req.info_hash; - requester().debug_log("info_hash: " + info_hash_str.str() + "\n"); + requester().debug_log("info_hash: " + + boost::lexical_cast(req.info_hash)); + requester().debug_log("name lookup: " + *connect_to_host); } #endif - tcp::resolver::query q(*connect_to_host, "0"); - m_name_lookup.async_resolve(q - , boost::bind(&http_tracker_connection::name_lookup, self(), _1, _2)); + tcp::resolver::query q(*connect_to_host + , boost::lexical_cast(m_port)); + m_name_lookup.async_resolve(q, m_strand.wrap( + boost::bind(&http_tracker_connection::name_lookup, self(), _1, _2))); set_timeout(m_settings.tracker_completion_timeout , m_settings.tracker_receive_timeout); } @@ -389,15 +481,18 @@ namespace libtorrent fail_timeout(); } - void http_tracker_connection::name_lookup(asio::error const& error + void http_tracker_connection::name_lookup(asio::error_code const& error , tcp::resolver::iterator i) try { +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + if (has_requester()) requester().debug_log("tracker name lookup handler called"); +#endif if (error == asio::error::operation_aborted) return; if (m_timed_out) return; if (error || i == tcp::resolver::iterator()) { - fail(-1, error.what()); + fail(-1, error.message().c_str()); return; } @@ -405,10 +500,37 @@ namespace libtorrent if (has_requester()) requester().debug_log("tracker name lookup successful"); #endif restart_read_timeout(); + + // look for an address that has the same kind as the one + // we're listening on. To make sure the tracker get our + // correct listening address. + tcp::resolver::iterator target = i; + tcp::resolver::iterator end; + tcp::endpoint target_address = *i; + for (; target != end && target->endpoint().address().is_v4() + != bind_interface().is_v4(); ++target); + if (target == end) + { + assert(target_address.address().is_v4() != bind_interface().is_v4()); + if (has_requester()) + { + std::string tracker_address_type = target_address.address().is_v4() ? "IPv4" : "IPv6"; + std::string bind_address_type = bind_interface().is_v4() ? "IPv4" : "IPv6"; + requester().tracker_warning("the tracker only resolves to an " + + tracker_address_type + " address, and you're listening on an " + + bind_address_type + " socket. This may prevent you from receiving incoming connections."); + } + } + else + { + target_address = *target; + } + + if (has_requester()) requester().m_tracker_address = target_address; m_socket.reset(new stream_socket(m_name_lookup.io_service())); - tcp::endpoint a(i->endpoint().address(), m_port); - if (has_requester()) requester().m_tracker_address = a; - m_socket->async_connect(a, bind(&http_tracker_connection::connected, self(), _1)); + m_socket->open(target_address.protocol()); + m_socket->bind(tcp::endpoint(bind_interface(), 0)); + m_socket->async_connect(target_address, bind(&http_tracker_connection::connected, self(), _1)); } catch (std::exception& e) { @@ -416,13 +538,13 @@ namespace libtorrent fail(-1, e.what()); }; - void http_tracker_connection::connected(asio::error const& error) try + void http_tracker_connection::connected(asio::error_code const& error) try { if (error == asio::error::operation_aborted) return; if (m_timed_out) return; if (error) { - fail(-1, error.what()); + fail(-1, error.message().c_str()); return; } @@ -441,13 +563,13 @@ namespace libtorrent fail(-1, e.what()); } - void http_tracker_connection::sent(asio::error const& error) try + void http_tracker_connection::sent(asio::error_code const& error) try { if (error == asio::error::operation_aborted) return; if (m_timed_out) return; if (error) { - fail(-1, error.what()); + fail(-1, error.message().c_str()); return; } @@ -467,7 +589,7 @@ namespace libtorrent }; // msvc 7.1 seems to require this semi-colon - void http_tracker_connection::receive(asio::error const& error + void http_tracker_connection::receive(asio::error_code const& error , std::size_t bytes_transferred) try { if (error == asio::error::operation_aborted) return; @@ -482,7 +604,7 @@ namespace libtorrent return; } - fail(-1, error.what()); + fail(-1, error.message().c_str()); return; } @@ -494,6 +616,8 @@ namespace libtorrent #endif m_recv_pos += bytes_transferred; + m_parser.incoming(buffer::const_interval(&m_buffer[0] + , &m_buffer[0] + m_recv_pos)); // if the receive buffer is full, expand it with http_buffer_size if ((int)m_buffer.size() == m_recv_pos) @@ -511,156 +635,26 @@ namespace libtorrent m_buffer.resize(m_buffer.size() + http_buffer_size); } - if (m_state == read_status) + if (m_parser.header_finished()) { - std::vector::iterator end = m_buffer.begin()+m_recv_pos; - std::vector::iterator newline = std::find(m_buffer.begin(), end, '\n'); - // if we don't have a full line yet, wait. - if (newline != end) + int cl = m_parser.header("content-length"); + if (cl > m_settings.tracker_maximum_response_length) { - -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (has_requester()) requester().debug_log(std::string(m_buffer.begin(), newline)); -#endif - - std::istringstream line(std::string(m_buffer.begin(), newline)); - ++newline; - m_recv_pos -= (int)std::distance(m_buffer.begin(), newline); - m_buffer.erase(m_buffer.begin(), newline); - - std::string protocol; - line >> m_server_protocol; - if (m_server_protocol.substr(0, 5) != "HTTP/") - { - std::string error_msg = "unknown protocol in response: " + m_server_protocol; - fail(-1, error_msg.c_str()); - return; - } - line >> m_code; - std::getline(line, m_server_message); - m_state = read_header; - } - } - - if (m_state == read_header) - { - std::vector::iterator end = m_buffer.begin() + m_recv_pos; - std::vector::iterator newline - = std::find(m_buffer.begin(), end, '\n'); - std::string line; - - while (newline != end && m_state == read_header) - { - line.assign(m_buffer.begin(), newline); - -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (has_requester()) requester().debug_log(line); -#endif - - if (line.substr(0, 16) == "Content-Length: ") - { - try - { - m_content_length = boost::lexical_cast( - line.substr(16, line.length() - 17)); - } - catch(boost::bad_lexical_cast&) - { - fail(-1, "invalid content-length in tracker response"); - return; - } - if (m_content_length > m_settings.tracker_maximum_response_length) - { - fail(-1, "content-length is greater than maximum response length"); - return; - } - - if (m_content_length < minimum_tracker_response_length && m_code == 200) - { - fail(-1, "content-length is smaller than minimum response length"); - return; - } - } - else if (line.substr(0, 18) == "Content-Encoding: ") - { - if (line.substr(18, 4) == "gzip" || line.substr(18, 6) == "x-gzip") - { - m_content_encoding = gzip; - } - else - { - std::string error_str = "unknown content encoding in response: \""; - error_str += line.substr(18, line.length() - 18 - 2); - error_str += "\""; - fail(-1, error_str.c_str()); - return; - } - } - else if (line.substr(0, 10) == "Location: ") - { - m_location.assign(line.begin() + 10, line.end()); - } - else if (line.substr(0, 7) == "Server: ") - { - m_server.assign(line.begin() + 7, line.end()); - } - else if (line.size() < 3) - { - m_state = read_body; -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (has_requester()) requester().debug_log("end of http header"); -#endif - if (m_code >= 300 && m_code < 400) - { - if (m_location.empty()) - { - std::string error_str = "got redirection response ("; - error_str += boost::lexical_cast(m_code); - error_str += ") without 'Location' header"; - fail(-1, error_str.c_str()); - return; - } - -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (has_requester()) requester().debug_log("Redirecting to \"" + m_location + "\""); -#endif - tracker_request req = tracker_req(); - std::string::size_type i = m_location.find('?'); - if (i == std::string::npos) - req.url = m_location; - else - req.url.assign(m_location.begin(), m_location.begin() + i); - - m_man.queue_request(m_socket->io_service(), req - , m_password, m_requester); - close(); - return; - } - } - - ++newline; - assert(m_recv_pos <= (int)m_buffer.size()); - m_recv_pos -= (int)std::distance(m_buffer.begin(), newline); - m_buffer.erase(m_buffer.begin(), newline); - assert(m_recv_pos <= (int)m_buffer.size()); - end = m_buffer.begin() + m_recv_pos; - newline = std::find(m_buffer.begin(), end, '\n'); + fail(-1, "content-length is greater than maximum response length"); + return; } - } - - if (m_state == read_body) - { - if (m_recv_pos == m_content_length) + if (cl > 0 && cl < minimum_tracker_response_length && m_parser.status_code() == 200) { - on_response(); - close(); + fail(-1, "content-length is smaller than minimum response length"); return; } } - else if (m_recv_pos > m_content_length && m_content_length > 0) + + if (m_parser.finished()) { - fail(-1, "invalid tracker response (body > content_length)"); + on_response(); + close(); return; } @@ -671,14 +665,60 @@ namespace libtorrent } catch (std::exception& e) { - assert(false); fail(-1, e.what()); }; void http_tracker_connection::on_response() { - // GZIP - if (m_content_encoding == gzip) + if (!m_parser.header_finished()) + { + fail(-1, "premature end of file"); + return; + } + + std::string location = m_parser.header("location"); + + if (m_parser.status_code() >= 300 && m_parser.status_code() < 400) + { + if (location.empty()) + { + std::string error_str = "got redirection response ("; + error_str += boost::lexical_cast(m_parser.status_code()); + error_str += ") without 'Location' header"; + fail(-1, error_str.c_str()); + return; + } + + // if the protocol isn't specified, assume http + if (location.compare(0, 7, "http://") != 0 + && location.compare(0, 6, "udp://") != 0) + { + location.insert(0, "http://"); + } + +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + if (has_requester()) requester().debug_log("Redirecting to \"" + location + "\""); +#endif + if (has_requester()) requester().tracker_warning("Redirecting to \"" + location + "\""); + tracker_request req = tracker_req(); + + req.url = location; + + m_man.queue_request(m_strand, req + , m_password, bind_interface(), m_requester); + close(); + return; + } + + buffer::const_interval buf(&m_buffer[0] + m_parser.body_start(), &m_buffer[0] + m_recv_pos); + + std::string content_encoding = m_parser.header("content-encoding"); + +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + if (has_requester()) requester().debug_log("content-encoding: \"" + content_encoding + "\""); +#endif + + if (content_encoding == "gzip" || content_encoding == "x-gzip") { boost::shared_ptr r = m_requester.lock(); @@ -687,26 +727,42 @@ namespace libtorrent close(); return; } + m_buffer.erase(m_buffer.begin(), m_buffer.begin() + m_parser.body_start()); if (inflate_gzip(m_buffer, tracker_request(), r.get(), m_settings.tracker_maximum_response_length)) { close(); return; } + buf.begin = &m_buffer[0]; + buf.end = &m_buffer[0] + m_buffer.size(); + } + else if (!content_encoding.empty()) + { + std::string error_str = "unknown content encoding in response: \""; + error_str += content_encoding; + error_str += "\""; + fail(-1, error_str.c_str()); + return; } // handle tracker response try { - entry e = bdecode(m_buffer.begin(), m_buffer.end()); + entry e = bdecode(buf.begin, buf.end); parse(e); } catch (std::exception& e) { std::string error_str(e.what()); - error_str += ": "; - error_str.append(m_buffer.begin(), m_buffer.end()); - fail(m_code, error_str.c_str()); + error_str += ": \""; + for (char const* i = buf.begin, *end(buf.end); i != end; ++i) + { + if (std::isprint(*i)) error_str += *i; + else error_str += "0x" + boost::lexical_cast((unsigned int)*i) + " "; + } + error_str += "\""; + fail(m_parser.status_code(), error_str.c_str()); } #ifndef NDEBUG catch (...) @@ -758,7 +814,7 @@ namespace libtorrent { entry const& failure = e["failure reason"]; - fail(m_code, failure.string().c_str()); + fail(m_parser.status_code(), failure.string().c_str()); return; } catch (type_error const&) {} @@ -833,11 +889,11 @@ namespace libtorrent } catch(type_error& e) { - requester().tracker_request_error(tracker_request(), m_code, e.what()); + requester().tracker_request_error(tracker_request(), m_parser.status_code(), e.what()); } catch(std::runtime_error& e) { - requester().tracker_request_error(tracker_request(), m_code, e.what()); + requester().tracker_request_error(tracker_request(), m_parser.status_code(), e.what()); } } diff --git a/libtorrent/src/identify_client.cpp b/libtorrent/src/identify_client.cpp index 96039f2b0..bfc06363c 100644 --- a/libtorrent/src/identify_client.cpp +++ b/libtorrent/src/identify_client.cpp @@ -145,19 +145,26 @@ namespace , map_entry("AZ", "Azureus") , map_entry("BB", "BitBuddy") , map_entry("BC", "BitComet") + , map_entry("BF", "Bitflu") + , map_entry("BG", "btgdaemon") , map_entry("BS", "BTSlave") , map_entry("BX", "BittorrentX") , map_entry("CD", "Enhanced CTorrent") , map_entry("CT", "CTorrent") , map_entry("DE", "Deluge") , map_entry("ES", "electric sheep") + , map_entry("HL", "Halite") , map_entry("KT", "KTorrent") + , map_entry("LK", "Linkage") , map_entry("LP", "lphant") , map_entry("LT", "libtorrent") , map_entry("M", "Mainline") + , map_entry("ML", "MLDonkey") + , map_entry("MO", "Mono Torrent") , map_entry("MP", "MooPolice") , map_entry("MT", "Moonlight Torrent") , map_entry("O", "Osprey Permaseed") + , map_entry("QT", "Qt 4") , map_entry("R", "Tribler") , map_entry("S", "Shadow") , map_entry("SB", "Swiftbit") @@ -172,6 +179,7 @@ namespace , map_entry("UL", "uLeecher") , map_entry("UT", "MicroTorrent") , map_entry("XT", "XanTorrent") + , map_entry("XX", "Xtorrent") , map_entry("ZT", "ZipTorrent") , map_entry("lt", "libTorrent (libtorrent.rakshasa.no/)") , map_entry("pX", "pHoeniX") diff --git a/libtorrent/src/kademlia/closest_nodes.cpp b/libtorrent/src/kademlia/closest_nodes.cpp index 8d0ccea87..e8bb9781c 100644 --- a/libtorrent/src/kademlia/closest_nodes.cpp +++ b/libtorrent/src/kademlia/closest_nodes.cpp @@ -47,12 +47,12 @@ public: closest_nodes_observer( boost::intrusive_ptr const& algorithm , node_id self - , node_id target - ) + , node_id target) : m_algorithm(algorithm) , m_target(target) , m_self(self) {} + ~closest_nodes_observer(); void send(msg& p) { @@ -61,6 +61,7 @@ public: void timeout(); void reply(msg const&); + void abort() { m_algorithm = 0; } private: boost::intrusive_ptr m_algorithm; @@ -68,8 +69,19 @@ private: node_id const m_self; }; +closest_nodes_observer::~closest_nodes_observer() +{ + if (m_algorithm) m_algorithm->failed(m_self, true); +} + void closest_nodes_observer::reply(msg const& in) { + if (!m_algorithm) + { + assert(false); + return; + } + if (!in.nodes.empty()) { for (msg::nodes_t::const_iterator i = in.nodes.begin() @@ -79,11 +91,14 @@ void closest_nodes_observer::reply(msg const& in) } } m_algorithm->finished(m_self); + m_algorithm = 0; } void closest_nodes_observer::timeout() { + if (!m_algorithm) return; m_algorithm->failed(m_self); + m_algorithm = 0; } diff --git a/libtorrent/src/kademlia/dht_tracker.cpp b/libtorrent/src/kademlia/dht_tracker.cpp index ca003e2b1..3b2e9a50b 100644 --- a/libtorrent/src/kademlia/dht_tracker.cpp +++ b/libtorrent/src/kademlia/dht_tracker.cpp @@ -126,26 +126,43 @@ namespace namespace libtorrent { namespace dht { + + void intrusive_ptr_add_ref(dht_tracker const* c) + { + assert(c != 0); + assert(c->m_refs >= 0); + ++c->m_refs; + } + + void intrusive_ptr_release(dht_tracker const* c) + { + assert(c != 0); + assert(c->m_refs > 0); + if (--c->m_refs == 0) + delete c; + } + #ifdef TORRENT_DHT_VERBOSE_LOGGING TORRENT_DEFINE_LOG(dht_tracker) #endif // class that puts the networking and the kademlia node in a single // unit and connecting them together. - dht_tracker::dht_tracker(asio::io_service& d, dht_settings const& settings + dht_tracker::dht_tracker(asio::io_service& ios, dht_settings const& settings , asio::ip::address listen_interface, entry const& bootstrap) - : m_demuxer(d) - , m_socket(m_demuxer, udp::endpoint(listen_interface, settings.service_port)) + : m_strand(ios) + , m_socket(ios, udp::endpoint(listen_interface, settings.service_port)) , m_dht(bind(&dht_tracker::send_packet, this, _1), settings , read_id(bootstrap)) , m_buffer(0) , m_last_refresh(second_clock::universal_time() - hours(1)) - , m_timer(m_demuxer) - , m_connection_timer(m_demuxer) - , m_refresh_timer(m_demuxer) + , m_timer(ios) + , m_connection_timer(ios) + , m_refresh_timer(ios) , m_settings(settings) , m_refresh_bucket(160) - , m_host_resolver(d) + , m_host_resolver(ios) + , m_refs(0) { using boost::bind; @@ -164,6 +181,7 @@ namespace libtorrent { namespace dht m_lt_message_input = 0; m_mp_message_input = 0; m_gr_message_input = 0; + m_mo_message_input = 0; m_total_in_bytes = 0; m_total_out_bytes = 0; m_queries_out_bytes = 0; @@ -187,47 +205,61 @@ namespace libtorrent { namespace dht } catch (std::exception&) {} } - m_dht.bootstrap(initial_nodes, bind(&dht_tracker::on_bootstrap, this)); - m_socket.async_receive_from(asio::buffer(&m_in_buf[m_buffer][0] , m_in_buf[m_buffer].size()), m_remote_endpoint[m_buffer] - , bind(&dht_tracker::on_receive, this, _1, _2)); + , m_strand.wrap(bind(&dht_tracker::on_receive, self(), _1, _2))); m_timer.expires_from_now(seconds(1)); - m_timer.async_wait(bind(&dht_tracker::tick, this, _1)); + m_timer.async_wait(m_strand.wrap(bind(&dht_tracker::tick, self(), _1))); m_connection_timer.expires_from_now(seconds(10)); - m_connection_timer.async_wait(bind(&dht_tracker::connection_timeout, this, _1)); + m_connection_timer.async_wait(m_strand.wrap( + bind(&dht_tracker::connection_timeout, self(), _1))); m_refresh_timer.expires_from_now(minutes(15)); - m_refresh_timer.async_wait(bind(&dht_tracker::refresh_timeout, this, _1)); + m_refresh_timer.async_wait(m_strand.wrap(bind(&dht_tracker::refresh_timeout, self(), _1))); + + m_dht.bootstrap(initial_nodes, bind(&dht_tracker::on_bootstrap, self())); + } + + void dht_tracker::stop() + { + m_timer.cancel(); + m_connection_timer.cancel(); + m_refresh_timer.cancel(); + m_socket.close(); } void dht_tracker::dht_status(session_status& s) { - boost::tie(s.m_dht_nodes, s.m_dht_node_cache) = m_dht.size(); - s.m_dht_torrents = m_dht.data_size(); + boost::tie(s.dht_nodes, s.dht_node_cache) = m_dht.size(); + s.dht_torrents = m_dht.data_size(); } - void dht_tracker::connection_timeout(asio::error const& e) + void dht_tracker::connection_timeout(asio::error_code const& e) try { if (e) return; time_duration d = m_dht.connection_timeout(); m_connection_timer.expires_from_now(d); - m_connection_timer.async_wait(bind(&dht_tracker::connection_timeout, this, _1)); + m_connection_timer.async_wait(m_strand.wrap(bind(&dht_tracker::connection_timeout, self(), _1))); } - catch (std::exception&) + catch (std::exception& exc) { +#ifndef NDEBUG + std::cerr << "exception-type: " << typeid(exc).name() << std::endl; + std::cerr << "what: " << exc.what() << std::endl; assert(false); +#endif }; - void dht_tracker::refresh_timeout(asio::error const& e) + void dht_tracker::refresh_timeout(asio::error_code const& e) try { if (e) return; time_duration d = m_dht.refresh_timeout(); m_refresh_timer.expires_from_now(d); - m_refresh_timer.async_wait(bind(&dht_tracker::refresh_timeout, this, _1)); + m_refresh_timer.async_wait(m_strand.wrap( + bind(&dht_tracker::refresh_timeout, self(), _1))); } catch (std::exception&) { @@ -237,16 +269,17 @@ namespace libtorrent { namespace dht void dht_tracker::rebind(asio::ip::address listen_interface, int listen_port) { m_socket.close(); - m_socket.open(asio::ip::udp::v4()); - m_socket.bind(udp::endpoint(listen_interface, listen_port)); + udp::endpoint ep(listen_interface, listen_port); + m_socket.open(ep.protocol()); + m_socket.bind(ep); } - void dht_tracker::tick(asio::error const& e) + void dht_tracker::tick(asio::error_code const& e) try { if (e) return; m_timer.expires_from_now(minutes(tick_period)); - m_timer.async_wait(bind(&dht_tracker::tick, this, _1)); + m_timer.async_wait(m_strand.wrap(bind(&dht_tracker::tick, this, _1))); m_dht.new_write_key(); @@ -313,6 +346,7 @@ namespace libtorrent { namespace dht << "\t" << (m_lt_message_input / float(tick_period)) << "\t" << (m_mp_message_input / float(tick_period)) << "\t" << (m_gr_message_input / float(tick_period)) + << "\t" << (m_mo_message_input / float(tick_period)) << "\t" << (m_total_in_bytes / float(tick_period*60)) << "\t" << (m_total_out_bytes / float(tick_period*60)) << "\t" << (m_queries_out_bytes / float(tick_period*60)) @@ -346,7 +380,7 @@ namespace libtorrent { namespace dht // translate bittorrent kademlia message into the generice kademlia message // used by the library - void dht_tracker::on_receive(asio::error const& error, size_t bytes_transferred) + void dht_tracker::on_receive(asio::error_code const& error, size_t bytes_transferred) try { if (error == asio::error::operation_aborted) return; @@ -355,7 +389,7 @@ namespace libtorrent { namespace dht m_buffer = (m_buffer + 1) & 1; m_socket.async_receive_from(asio::buffer(&m_in_buf[m_buffer][0] , m_in_buf[m_buffer].size()), m_remote_endpoint[m_buffer] - , bind(&dht_tracker::on_receive, this, _1, _2)); + , m_strand.wrap(bind(&dht_tracker::on_receive, self(), _1, _2))); if (error) return; @@ -412,6 +446,11 @@ namespace libtorrent { namespace dht ++m_gr_message_input; TORRENT_LOG(dht_tracker) << " client: GetRight"; } + else if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "MO")) + { + ++m_mo_message_input; + TORRENT_LOG(dht_tracker) << " client: Mono Torrent"; + } else { TORRENT_LOG(dht_tracker) << " client: generic"; @@ -438,10 +477,24 @@ namespace libtorrent { namespace dht if (id.size() != 20) throw std::runtime_error("invalid size of id"); std::copy(id.begin(), id.end(), m.id.begin()); - if (entry const* n = r.find_key("values")) + if (entry const* n = r.find_key("values")) { m.peers.clear(); - read_endpoint_list(n, m.peers); + if (n->list().size() == 1) + { + // assume it's mainline format + std::string const& peers = n->list().front().string(); + std::string::const_iterator i = peers.begin(); + std::string::const_iterator end = peers.end(); + + while (std::distance(i, end) >= 6) + m.peers.push_back(read_v4_endpoint(i)); + } + else + { + // assume it's uTorrent/libtorrent format + read_endpoint_list(n, m.peers); + } #ifdef TORRENT_DHT_VERBOSE_LOGGING TORRENT_LOG(dht_tracker) << " peers: " << m.peers.size(); #endif @@ -648,11 +701,11 @@ namespace libtorrent { namespace dht void dht_tracker::add_node(std::pair const& node) { udp::resolver::query q(node.first, lexical_cast(node.second)); - m_host_resolver.async_resolve(q, bind(&dht_tracker::on_name_lookup - , this, _1, _2)); + m_host_resolver.async_resolve(q, m_strand.wrap( + bind(&dht_tracker::on_name_lookup, self(), _1, _2))); } - void dht_tracker::on_name_lookup(asio::error const& e + void dht_tracker::on_name_lookup(asio::error_code const& e , udp::resolver::iterator host) try { if (e || host == udp::resolver::iterator()) return; @@ -666,11 +719,11 @@ namespace libtorrent { namespace dht void dht_tracker::add_router_node(std::pair const& node) { udp::resolver::query q(node.first, lexical_cast(node.second)); - m_host_resolver.async_resolve(q, bind(&dht_tracker::on_router_name_lookup - , this, _1, _2)); + m_host_resolver.async_resolve(q, m_strand.wrap( + bind(&dht_tracker::on_router_name_lookup, self(), _1, _2))); } - void dht_tracker::on_router_name_lookup(asio::error const& e + void dht_tracker::on_router_name_lookup(asio::error_code const& e , udp::resolver::iterator host) try { if (e || host == udp::resolver::iterator()) return; @@ -855,7 +908,7 @@ namespace libtorrent { namespace dht } case messages::announce_peer: a["port"] = m_settings.service_port; - a["info_hash"] = boost::lexical_cast(m.info_hash); + a["info_hash"] = std::string(m.info_hash.begin(), m.info_hash.end()); a["token"] = m.write_token; #ifdef TORRENT_DHT_VERBOSE_LOGGING TORRENT_LOG(dht_tracker) << " port: " diff --git a/libtorrent/src/kademlia/find_data.cpp b/libtorrent/src/kademlia/find_data.cpp index e1e09925b..9fe787807 100644 --- a/libtorrent/src/kademlia/find_data.cpp +++ b/libtorrent/src/kademlia/find_data.cpp @@ -51,6 +51,7 @@ public: , m_target(target) , m_self(self) {} + ~find_data_observer(); void send(msg& m) { @@ -61,6 +62,7 @@ public: void timeout(); void reply(msg const&); + void abort() { m_algorithm = 0; } private: boost::intrusive_ptr m_algorithm; @@ -68,8 +70,19 @@ private: node_id const m_self; }; +find_data_observer::~find_data_observer() +{ + if (m_algorithm) m_algorithm->failed(m_self); +} + void find_data_observer::reply(msg const& m) { + if (!m_algorithm) + { + assert(false); + return; + } + if (!m.peers.empty()) { m_algorithm->got_data(&m); @@ -83,11 +96,14 @@ void find_data_observer::reply(msg const& m) } } m_algorithm->finished(m_self); + m_algorithm = 0; } void find_data_observer::timeout() { + if (!m_algorithm) return; m_algorithm->failed(m_self); + m_algorithm = 0; } diff --git a/libtorrent/src/kademlia/node.cpp b/libtorrent/src/kademlia/node.cpp index 8a9d17818..07da958bb 100644 --- a/libtorrent/src/kademlia/node.cpp +++ b/libtorrent/src/kademlia/node.cpp @@ -210,7 +210,7 @@ void node_impl::new_write_key() m_secret[0] = std::rand(); } -void node_impl::refresh_bucket(int bucket) +void node_impl::refresh_bucket(int bucket) try { assert(bucket >= 0 && bucket < 160); @@ -246,7 +246,7 @@ void node_impl::refresh_bucket(int bucket) , m_table, start.begin(), start.end(), m_rpc, bind(&nop)); m_table.touch_bucket(bucket); } - +catch (std::exception&) {} void node_impl::incoming(msg const& m) { @@ -278,6 +278,7 @@ namespace void timeout() {} void reply(msg const&) {} + void abort() {} private: sha1_hash m_info_hash; @@ -311,6 +312,7 @@ namespace new announce_observer(m_info_hash, m_listen_port, r.write_token))); m_fun(r.peers, m_info_hash); } + void abort() {} private: sha1_hash m_info_hash; @@ -344,6 +346,7 @@ namespace virtual void reply(msg const&) {} virtual void timeout() {} virtual void send(msg&) {} + virtual void abort() {} }; } @@ -376,25 +379,30 @@ time_duration node_impl::refresh_timeout() int refresh = -1; ptime now = second_clock::universal_time(); ptime next = now + minutes(15); - for (int i = 0; i < 160; ++i) + try { - ptime r = m_table.next_refresh(i); - if (r <= now) + for (int i = 0; i < 160; ++i) { - if (refresh == -1) refresh = i; + ptime r = m_table.next_refresh(i); + if (r <= now) + { + if (refresh == -1) refresh = i; + } + else if (r < next) + { + next = r; + } } - else if (r < next) + if (refresh != -1) { - next = r; + #ifdef TORRENT_DHT_VERBOSE_LOGGING + TORRENT_LOG(node) << "refreshing bucket: " << refresh; + #endif + refresh_bucket(refresh); } } - if (refresh != -1) - { -#ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(node) << "refreshing bucket: " << refresh; -#endif - refresh_bucket(refresh); - } + catch (std::exception&) {} + if (next < now + seconds(5)) return seconds(5); return next - now; } @@ -402,26 +410,30 @@ time_duration node_impl::refresh_timeout() time_duration node_impl::connection_timeout() { time_duration d = m_rpc.tick(); - - ptime now(second_clock::universal_time()); - if (now - m_last_tracker_tick < minutes(10)) return d; - m_last_tracker_tick = now; - - // look through all peers and see if any have timed out - for (data_iterator i = begin_data(), end(end_data()); i != end;) + try { - torrent_entry& t = i->second; - node_id const& key = i->first; - ++i; - purge_peers(t.peers); - - // if there are no more peers, remove the entry altogether - if (t.peers.empty()) + ptime now(second_clock::universal_time()); + if (now - m_last_tracker_tick < minutes(10)) return d; + m_last_tracker_tick = now; + + // look through all peers and see if any have timed out + for (data_iterator i = begin_data(), end(end_data()); i != end;) { - table_t::iterator i = m_map.find(key); - if (i != m_map.end()) m_map.erase(i); + torrent_entry& t = i->second; + node_id const& key = i->first; + ++i; + purge_peers(t.peers); + + // if there are no more peers, remove the entry altogether + if (t.peers.empty()) + { + table_t::iterator i = m_map.find(key); + if (i != m_map.end()) m_map.erase(i); + } } } + catch (std::exception&) {} + return d; } diff --git a/libtorrent/src/kademlia/refresh.cpp b/libtorrent/src/kademlia/refresh.cpp index 37300d16e..ccd753de9 100644 --- a/libtorrent/src/kademlia/refresh.cpp +++ b/libtorrent/src/kademlia/refresh.cpp @@ -64,6 +64,7 @@ public: , m_self(self) , m_algorithm(algorithm) {} + ~refresh_observer(); void send(msg& m) { @@ -72,6 +73,8 @@ public: void timeout(); void reply(msg const& m); + void abort() { m_algorithm = 0; } + private: node_id const m_target; @@ -79,8 +82,15 @@ private: boost::intrusive_ptr m_algorithm; }; +refresh_observer::~refresh_observer() +{ + if (m_algorithm) m_algorithm->failed(m_self, true); +} + void refresh_observer::reply(msg const& in) { + if (!m_algorithm) return; + if (!in.nodes.empty()) { for (msg::nodes_t::const_iterator i = in.nodes.begin() @@ -90,11 +100,14 @@ void refresh_observer::reply(msg const& in) } } m_algorithm->finished(m_self); + m_algorithm = 0; } void refresh_observer::timeout() { + if (!m_algorithm) return; m_algorithm->failed(m_self); + m_algorithm = 0; } class ping_observer : public observer @@ -107,24 +120,37 @@ public: : m_self(self) , m_algorithm(algorithm) {} + ~ping_observer(); void send(msg& p) {} void timeout(); void reply(msg const& m); + void abort() { m_algorithm = 0; } + private: node_id const m_self; boost::intrusive_ptr m_algorithm; }; +ping_observer::~ping_observer() +{ + if (m_algorithm) m_algorithm->ping_timeout(m_self, true); +} + void ping_observer::reply(msg const& m) { + if (!m_algorithm) return; + m_algorithm->ping_reply(m_self); + m_algorithm = 0; } void ping_observer::timeout() { + if (!m_algorithm) return; m_algorithm->ping_timeout(m_self); + m_algorithm = 0; } void refresh::invoke(node_id const& nid, udp::endpoint addr) @@ -152,32 +178,44 @@ void refresh::ping_reply(node_id nid) invoke_pings_or_finish(); } -void refresh::ping_timeout(node_id nid) +void refresh::ping_timeout(node_id nid, bool prevent_request) { m_active_pings--; - invoke_pings_or_finish(); + invoke_pings_or_finish(prevent_request); } -void refresh::invoke_pings_or_finish() +void refresh::invoke_pings_or_finish(bool prevent_request) { - while (m_active_pings < m_max_active_pings) + if (prevent_request) { - if (m_leftover_nodes_iterator == m_results.end()) break; - - result const& node = *m_leftover_nodes_iterator; - - // Skip initial nodes - if (node.flags & result::initial) + --m_max_active_pings; + if (m_max_active_pings <= 0) + m_max_active_pings = 1; + } + else + { + while (m_active_pings < m_max_active_pings) { - ++m_leftover_nodes_iterator; - continue; + if (m_leftover_nodes_iterator == m_results.end()) break; + + result const& node = *m_leftover_nodes_iterator; + + // Skip initial nodes + if (node.flags & result::initial) + { + ++m_leftover_nodes_iterator; + continue; + } + + try + { + observer_ptr p(new ping_observer(this, node.id)); + m_rpc.invoke(messages::ping, node.addr, p); + ++m_active_pings; + ++m_leftover_nodes_iterator; + } + catch (std::exception& e) {} } - - observer_ptr p(new ping_observer(this, node.id)); - - m_rpc.invoke(messages::ping, node.addr, p); - ++m_active_pings; - ++m_leftover_nodes_iterator; } if (m_active_pings == 0) diff --git a/libtorrent/src/kademlia/rpc_manager.cpp b/libtorrent/src/kademlia/rpc_manager.cpp index 770b11bf5..7295938d0 100644 --- a/libtorrent/src/kademlia/rpc_manager.cpp +++ b/libtorrent/src/kademlia/rpc_manager.cpp @@ -72,15 +72,25 @@ rpc_manager::rpc_manager(fun const& f, node_id const& our_id , m_table(table) , m_timer(boost::posix_time::microsec_clock::universal_time()) , m_random_number(generate_id()) + , m_destructing(false) { std::srand(time(0)); } rpc_manager::~rpc_manager() { + m_destructing = true; #ifdef TORRENT_DHT_VERBOSE_LOGGING TORRENT_LOG(rpc) << "Destructing"; #endif + std::for_each(m_aborted_transactions.begin(), m_aborted_transactions.end() + , bind(&observer::abort, _1)); + + for (transactions_t::iterator i = m_transactions.begin() + , end(m_transactions.end()); i != end; ++i) + { + if (*i) (*i)->abort(); + } } #ifndef NDEBUG @@ -104,6 +114,8 @@ bool rpc_manager::incoming(msg const& m) { INVARIANT_CHECK; + if (m_destructing) return false; + if (m.reply) { // if we don't have the transaction id in our @@ -189,12 +201,14 @@ time_duration rpc_manager::tick() using boost::posix_time::microsec_clock; - const int timeout_ms = 20 * 1000; + const int timeout_ms = 10 * 1000; // look for observers that has timed out if (m_next_transaction_id == m_oldest_transaction_id) return milliseconds(timeout_ms); + std::vector > timeouts; + for (;m_next_transaction_id != m_oldest_transaction_id; m_oldest_transaction_id = (m_oldest_transaction_id + 1) % max_transactions) { @@ -212,24 +226,40 @@ time_duration rpc_manager::tick() return diff; } - m_transactions[m_oldest_transaction_id].reset(); - o->timeout(); + try + { + m_transactions[m_oldest_transaction_id].reset(); + timeouts.push_back(o); + } catch (std::exception) {} } + + std::for_each(timeouts.begin(), timeouts.end(), bind(&observer::timeout, _1)); + timeouts.clear(); + + // clear the aborted transactions, will likely + // generate new requests. We need to swap, since the + // destrutors may add more observers to the m_aborted_transactions + std::vector >().swap(m_aborted_transactions); return milliseconds(timeout_ms); } -unsigned int rpc_manager::new_transaction_id() +unsigned int rpc_manager::new_transaction_id(shared_ptr o) { INVARIANT_CHECK; unsigned int tid = m_next_transaction_id; m_next_transaction_id = (m_next_transaction_id + 1) % max_transactions; -// boost::shared_ptr o = m_transactions[m_next_transaction_id]; if (m_transactions[m_next_transaction_id]) { + // moving the observer into the set of aborted transactions + // it will prevent it from spawning new requests right now, + // since that would break the invariant + m_aborted_transactions.push_back(m_transactions[m_next_transaction_id]); m_transactions[m_next_transaction_id].reset(); assert(m_oldest_transaction_id == m_next_transaction_id); } + assert(!m_transactions[tid]); + m_transactions[tid] = o; if (m_oldest_transaction_id == m_next_transaction_id) { m_oldest_transaction_id = (m_oldest_transaction_id + 1) % max_transactions; @@ -240,21 +270,6 @@ unsigned int rpc_manager::new_transaction_id() update_oldest_transaction_id(); } -#ifndef NDEBUG - assert(!m_transactions[m_next_transaction_id]); - for (int i = (m_next_transaction_id + 1) % max_transactions; - i != m_oldest_transaction_id; i = (i + 1) % max_transactions) - { - assert(!m_transactions[i]); - } -#endif - -// hopefully this wouldn't happen, but unfortunately, the -// traversal algorithm will simply fail in case its connections -// are overwritten. If timeout() is called, it will likely spawn -// another connection, which in turn will close the next one -// and so on. -// if (o) o->timeout(); return tid; } @@ -277,33 +292,53 @@ void rpc_manager::invoke(int message_id, udp::endpoint target_addr { INVARIANT_CHECK; + if (m_destructing) + { + o->abort(); + return; + } + msg m; m.message_id = message_id; m.reply = false; m.id = m_our_id; m.addr = target_addr; - int tid = new_transaction_id(); - m.transaction_id.clear(); - std::back_insert_iterator out(m.transaction_id); - io::write_uint16(tid, out); - - o->send(m); + assert(!m_transactions[m_next_transaction_id]); +#ifndef NDEBUG + int potential_new_id = m_next_transaction_id; +#endif + try + { + m.transaction_id.clear(); + std::back_insert_iterator out(m.transaction_id); + io::write_uint16(m_next_transaction_id, out); + + o->send(m); - m_transactions[tid] = o; - o->sent = boost::posix_time::microsec_clock::universal_time(); - o->target_addr = target_addr; + o->sent = boost::posix_time::microsec_clock::universal_time(); + o->target_addr = target_addr; -#ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(rpc) << "Invoking " << messages::ids[message_id] - << " -> " << target_addr; -#endif - m_send(m); + #ifdef TORRENT_DHT_VERBOSE_LOGGING + TORRENT_LOG(rpc) << "Invoking " << messages::ids[message_id] + << " -> " << target_addr; + #endif + m_send(m); + new_transaction_id(o); + } + catch (std::exception& e) + { + // m_send may fail with "no route to host" + assert(potential_new_id == m_next_transaction_id); + o->abort(); + } } void rpc_manager::reply(msg& m, msg const& reply_to) { INVARIANT_CHECK; + if (m_destructing) return; + if (m.message_id != messages::error) m.message_id = reply_to.message_id; m.addr = reply_to.addr; @@ -322,6 +357,7 @@ namespace virtual void reply(msg const&) {} virtual void timeout() {} virtual void send(msg&) {} + void abort() {} }; } @@ -329,6 +365,8 @@ void rpc_manager::reply_with_ping(msg& m, msg const& reply_to) { INVARIANT_CHECK; + if (m_destructing) return; + if (m.message_id != messages::error) m.message_id = reply_to.message_id; m.addr = reply_to.addr; @@ -337,17 +375,24 @@ void rpc_manager::reply_with_ping(msg& m, msg const& reply_to) m.id = m_our_id; m.transaction_id = reply_to.transaction_id; - int ptid = new_transaction_id(); - m.ping_transaction_id.clear(); - std::back_insert_iterator out(m.ping_transaction_id); - io::write_uint16(ptid, out); + try + { + m.ping_transaction_id.clear(); + std::back_insert_iterator out(m.ping_transaction_id); + io::write_uint16(m_next_transaction_id, out); - boost::shared_ptr o(new dummy_observer); - m_transactions[ptid] = o; - o->sent = boost::posix_time::microsec_clock::universal_time(); - o->target_addr = m.addr; - - m_send(m); + boost::shared_ptr o(new dummy_observer); + assert(!m_transactions[m_next_transaction_id]); + o->sent = boost::posix_time::microsec_clock::universal_time(); + o->target_addr = m.addr; + + m_send(m); + new_transaction_id(o); + } + catch (std::exception& e) + { + // m_send may fail with "no route to host" + } } diff --git a/libtorrent/src/kademlia/traversal_algorithm.cpp b/libtorrent/src/kademlia/traversal_algorithm.cpp index 88c62f836..1efe76e77 100644 --- a/libtorrent/src/kademlia/traversal_algorithm.cpp +++ b/libtorrent/src/kademlia/traversal_algorithm.cpp @@ -65,6 +65,9 @@ void traversal_algorithm::add_entry(node_id const& id, udp::endpoint addr, unsig if (i == m_results.end() || i->id != id) { + assert(std::find_if(m_results.begin(), m_results.end() + , bind(std::equal_to() + , bind(&result::id, _1), id)) == m_results.end()); #ifdef TORRENT_DHT_VERBOSE_LOGGING TORRENT_LOG(traversal) << "adding result: " << id << " " << addr; #endif @@ -84,7 +87,10 @@ void traversal_algorithm::finished(node_id const& id) if (m_invoke_count == 0) done(); } -void traversal_algorithm::failed(node_id const& id) +// prevent request means that the total number of requests has +// overflown. This query failed because it was the oldest one. +// So, if this is true, don't make another request +void traversal_algorithm::failed(node_id const& id, bool prevent_request) { m_invoke_count--; @@ -100,23 +106,28 @@ void traversal_algorithm::failed(node_id const& id) assert(i != m_results.end()); - assert(i->flags & result::queried); - m_failed.insert(i->addr); + if (i != m_results.end()) + { + assert(i->flags & result::queried); + m_failed.insert(i->addr); #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(traversal) << "failed: " << i->id << " " << i->addr; + TORRENT_LOG(traversal) << "failed: " << i->id << " " << i->addr; #endif - m_results.erase(i); - m_table.node_failed(id); + m_results.erase(i); + } + if (prevent_request) + { + --m_branch_factor; + if (m_branch_factor <= 0) m_branch_factor = 1; + } + else + { + m_table.node_failed(id); + } add_requests(); if (m_invoke_count == 0) done(); } -void traversal_algorithm::add_request(node_id const& id, udp::endpoint addr) -{ - invoke(id, addr); - ++m_invoke_count; -} - namespace { bool bitwise_nand(unsigned char lhs, unsigned char rhs) @@ -128,7 +139,7 @@ namespace void traversal_algorithm::add_requests() { while (m_invoke_count < m_branch_factor) - { + { // Find the first node that hasn't already been queried. // TODO: Better heuristic std::vector::iterator i = std::find_if( @@ -146,8 +157,13 @@ void traversal_algorithm::add_requests() if (i == last_iterator()) break; - add_request(i->id, i->addr); - i->flags |= result::queried; + try + { + invoke(i->id, i->addr); + ++m_invoke_count; + i->flags |= result::queried; + } + catch (std::exception& e) {} } } diff --git a/libtorrent/src/logger.cpp b/libtorrent/src/logger.cpp new file mode 100644 index 000000000..be101d02c --- /dev/null +++ b/libtorrent/src/logger.cpp @@ -0,0 +1,231 @@ +/* + +Copyright (c) 2006, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include + +#include "libtorrent/extensions/logger.hpp" +#include "libtorrent/extensions.hpp" +#include "libtorrent/entry.hpp" +#include "libtorrent/peer_request.hpp" +#include "libtorrent/peer_connection.hpp" + +namespace libtorrent { namespace +{ + + struct logger_peer_plugin : peer_plugin + { + logger_peer_plugin(std::string const& filename) + { + using namespace boost::filesystem; + path dir(complete("libtorrent_ext_logs")); + if (!exists(dir)) create_directories(dir); + m_file.open(dir / filename, std::ios_base::out | std::ios_base::out); + m_file << "\n\n\n"; + log_timestamp(); + m_file << "*** starting log ***\n"; + } + + void log_timestamp() + { + using namespace boost::posix_time; + std::string now(to_simple_string(second_clock::universal_time())); + m_file << now << ": "; + } + + // can add entries to the extension handshake + virtual void add_handshake(entry&) {} + + // called when the extension handshake from the other end is received + virtual bool on_extension_handshake(entry const& h) + { + log_timestamp(); + m_file << "<== EXTENSION_HANDSHAKE\n"; + h.print(m_file); + return true; + } + + // returning true from any of the message handlers + // indicates that the plugin has handeled the message. + // it will break the plugin chain traversing and not let + // anyone else handle the message, including the default + // handler. + + virtual bool on_choke() + { + log_timestamp(); + m_file << "<== CHOKE\n"; + m_file.flush(); + return false; + } + + virtual bool on_unchoke() + { + log_timestamp(); + m_file << "<== UNCHOKE\n"; + m_file.flush(); + return false; + } + + virtual bool on_interested() + { + log_timestamp(); + m_file << "<== INTERESTED\n"; + m_file.flush(); + return false; + } + + virtual bool on_not_interested() + { + log_timestamp(); + m_file << "<== NOT_INTERESTED\n"; + m_file.flush(); + return false; + } + + virtual bool on_have(int index) + { + log_timestamp(); + m_file << "<== HAVE [" << index << "]\n"; + m_file.flush(); + return false; + } + + virtual bool on_bitfield(std::vector const& bitfield) + { + log_timestamp(); + m_file << "<== BITFIELD\n"; + m_file.flush(); + return false; + } + + virtual bool on_request(peer_request const& r) + { + log_timestamp(); + m_file << "<== REQUEST [ piece: " << r.piece << " | s: " << r.start + << " | l: " << r.length << " ]\n"; + m_file.flush(); + return false; + } + + virtual bool on_piece(peer_request const& r, char const*) + { + log_timestamp(); + m_file << "<== PIECE [ piece: " << r.piece << " | s: " << r.start + << " | l: " << r.length << " ]\n"; + m_file.flush(); + return false; + } + + virtual bool on_cancel(peer_request const& r) + { + log_timestamp(); + m_file << "<== CANCEL [ piece: " << r.piece << " | s: " << r.start + << " | l: " << r.length << " ]\n"; + m_file.flush(); + return false; + } + + // called when an extended message is received. If returning true, + // the message is not processed by any other plugin and if false + // is returned the next plugin in the chain will receive it to + // be able to handle it + virtual bool on_extended(int length + , int msg, buffer::const_interval body) + { return false; } + + virtual bool on_unknown_message(int length, int msg + , buffer::const_interval body) + { + if (body.left() < length) return false; + log_timestamp(); + m_file << "<== UNKNOWN [ msg: " << msg + << " | l: " << length << " ]\n"; + m_file.flush(); + return false; + } + + virtual void on_piece_pass(int index) + { + log_timestamp(); + m_file << "*** HASH PASSED *** [ piece: " << index << " ]\n"; + m_file.flush(); + } + + virtual void on_piece_failed(int index) + { + log_timestamp(); + m_file << "*** HASH FAILED *** [ piece: " << index << " ]\n"; + m_file.flush(); + } + + private: + boost::filesystem::ofstream m_file; + }; + + struct logger_plugin : torrent_plugin + { + virtual boost::shared_ptr new_connection( + peer_connection* pc) + { + return boost::shared_ptr(new logger_peer_plugin( + pc->remote().address().to_string() + "_" + + boost::lexical_cast(pc->remote().port()) + ".log")); + } + }; + +} } + +namespace libtorrent +{ + + boost::shared_ptr create_logger_plugin(torrent*) + { + return boost::shared_ptr(new logger_plugin()); + } + +} + + diff --git a/libtorrent/src/metadata_transfer.cpp b/libtorrent/src/metadata_transfer.cpp new file mode 100644 index 000000000..3777cd71e --- /dev/null +++ b/libtorrent/src/metadata_transfer.cpp @@ -0,0 +1,556 @@ +/* + +Copyright (c) 2006, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include +#include +#include + +#include "libtorrent/peer_connection.hpp" +#include "libtorrent/bt_peer_connection.hpp" +#include "libtorrent/hasher.hpp" +#include "libtorrent/bencode.hpp" +#include "libtorrent/torrent.hpp" +#include "libtorrent/extensions.hpp" +#include "libtorrent/extensions/metadata_transfer.hpp" + +using boost::posix_time::second_clock; + +namespace libtorrent { namespace +{ + int div_round_up(int numerator, int denominator) + { + return (numerator + denominator - 1) / denominator; + } + + std::pair req_to_offset(std::pair req, int total_size) + { + assert(req.first >= 0); + assert(req.second > 0); + assert(req.second <= 256); + assert(req.first + req.second <= 256); + + int start = div_round_up(req.first * total_size, 256); + int size = div_round_up((req.first + req.second) * total_size, 256) - start; + return std::make_pair(start, size); + } + + std::pair offset_to_req(std::pair offset, int total_size) + { + int start = offset.first * 256 / total_size; + int size = (offset.first + offset.second) * 256 / total_size - start; + + std::pair ret(start, size); + + assert(start >= 0); + assert(size > 0); + assert(start <= 256); + assert(start + size <= 256); + + // assert the identity of this function +#ifndef NDEBUG + std::pair identity = req_to_offset(ret, total_size); + assert(offset == identity); +#endif + return ret; + } + + + struct metadata_plugin : torrent_plugin + { + metadata_plugin(torrent& t) + : m_torrent(t) + , m_metadata_progress(0) + , m_metadata_size(0) + { + m_requested_metadata.resize(256, 0); + } + + virtual boost::shared_ptr new_connection( + peer_connection* pc); + + std::vector const& metadata() const + { + if (m_metadata.empty()) + { + bencode(std::back_inserter(m_metadata) + , m_torrent.torrent_file().create_info_metadata()); + + assert(hasher(&m_metadata[0], m_metadata.size()).final() + == m_torrent.torrent_file().info_hash()); + } + assert(!m_metadata.empty()); + return m_metadata; + } + + bool received_metadata(char const* buf, int size, int offset, int total_size) + { + if (m_torrent.valid_metadata()) return false; + + if ((int)m_metadata.size() < total_size) + m_metadata.resize(total_size); + + std::copy( + buf + , buf + size + , &m_metadata[offset]); + + if (m_have_metadata.empty()) + m_have_metadata.resize(256, false); + + std::pair req = offset_to_req(std::make_pair(offset, size) + , total_size); + + assert(req.first + req.second <= (int)m_have_metadata.size()); + + std::fill( + m_have_metadata.begin() + req.first + , m_have_metadata.begin() + req.first + req.second + , true); + + bool have_all = std::count( + m_have_metadata.begin() + , m_have_metadata.end() + , true) == 256; + + if (!have_all) return false; + + hasher h; + h.update(&m_metadata[0], (int)m_metadata.size()); + sha1_hash info_hash = h.final(); + + if (info_hash != m_torrent.torrent_file().info_hash()) + { + std::fill( + m_have_metadata.begin() + , m_have_metadata.begin() + req.first + req.second + , false); + m_metadata_progress = 0; + m_metadata_size = 0; + // TODO: allow plugins to post alerts +/* + if (m_ses.m_alerts.should_post(alert::info)) + { + m_ses.m_alerts.post_alert(metadata_failed_alert( + get_handle(), "invalid metadata received from swarm")); + } +*/ + return false; + } + + entry metadata = bdecode(m_metadata.begin(), m_metadata.end()); + m_torrent.set_metadata(metadata); + + // clear the storage for the bitfield + std::vector().swap(m_have_metadata); + std::vector().swap(m_requested_metadata); + + return true; + } + + // returns a range of the metadata that + // we should request. + std::pair metadata_request(); + + void cancel_metadata_request(std::pair req) + { + for (int i = req.first; i < req.first + req.second; ++i) + { + assert(m_requested_metadata[i] > 0); + if (m_requested_metadata[i] > 0) + --m_requested_metadata[i]; + } + } + + // this is called from the peer_connection for + // each piece of metadata it receives + void metadata_progress(int total_size, int received) + { + m_metadata_progress += received; + m_metadata_size = total_size; + } + + private: + torrent& m_torrent; + + // this buffer is filled with the info-section of + // the metadata file while downloading it from + // peers, and while sending it. + // it is mutable because it's generated lazily + mutable std::vector m_metadata; + + int m_metadata_progress; + int m_metadata_size; + + // this is a bitfield of size 256, each bit represents + // a piece of the metadata. It is set to one if we + // have that piece. This vector may be empty + // (size 0) if we haven't received any metadata + // or if we already have all metadata + std::vector m_have_metadata; + // this vector keeps track of how many times each meatdata + // block has been requested + std::vector m_requested_metadata; + }; + + + struct metadata_peer_plugin : peer_plugin + { + metadata_peer_plugin(torrent& t, peer_connection& pc + , metadata_plugin& tp) + : m_waiting_metadata_request(false) + , m_message_index(0) + , m_metadata_progress(0) + , m_no_metadata( + boost::gregorian::date(1970, boost::date_time::Jan, 1) + , boost::posix_time::seconds(0)) + , m_metadata_request( + boost::gregorian::date(1970, boost::date_time::Jan, 1) + , boost::posix_time::seconds(0)) + , m_torrent(t) + , m_pc(pc) + , m_tp(tp) + {} + + // can add entries to the extension handshake + virtual void add_handshake(entry& h) + { + entry& messages = h["m"]; + messages["LT_metadata"] = 14; + } + + // called when the extension handshake from the other end is received + virtual bool on_extension_handshake(entry const& h) + { + entry const& messages = h["m"]; + if (entry const* index = messages.find_key("LT_metadata")) + { + m_message_index = index->integer(); + return true; + } + else + { + m_message_index = 0; + return false; + } + } + + void write_metadata_request(std::pair req) + { + assert(req.first >= 0); + assert(req.second > 0); + assert(req.first + req.second <= 256); + assert(!m_pc.associated_torrent().expired()); + assert(!m_pc.associated_torrent().lock()->valid_metadata()); + + int start = req.first; + int size = req.second; + + // abort if the peer doesn't support the metadata extension + if (m_message_index == 0) return; + + buffer::interval i = m_pc.allocate_send_buffer(9); + + detail::write_uint32(1 + 1 + 3, i.begin); + detail::write_uint8(bt_peer_connection::msg_extended, i.begin); + detail::write_uint8(m_message_index, i.begin); + // means 'request data' + detail::write_uint8(0, i.begin); + detail::write_uint8(start, i.begin); + detail::write_uint8(size - 1, i.begin); + assert(i.begin == i.end); + m_pc.setup_send(); + } + + void write_metadata(std::pair req) + { + assert(req.first >= 0); + assert(req.second > 0); + assert(req.second <= 256); + assert(req.first + req.second <= 256); + assert(!m_pc.associated_torrent().expired()); + + // abort if the peer doesn't support the metadata extension + if (m_message_index == 0) return; + + // only send metadata if the torrent is non-private + if (m_torrent.valid_metadata() && !m_torrent.torrent_file().priv()) + { + std::pair offset + = req_to_offset(req, (int)m_tp.metadata().size()); + + buffer::interval i = m_pc.allocate_send_buffer(15 + offset.second); + + // yes, we have metadata, send it + detail::write_uint32(11 + offset.second, i.begin); + detail::write_uint8(bt_peer_connection::msg_extended, i.begin); + detail::write_uint8(m_message_index, i.begin); + // means 'data packet' + detail::write_uint8(1, i.begin); + detail::write_uint32((int)m_tp.metadata().size(), i.begin); + detail::write_uint32(offset.first, i.begin); + std::vector const& metadata = m_tp.metadata(); + std::copy(metadata.begin() + offset.first + , metadata.begin() + offset.first + offset.second, i.begin); + i.begin += offset.second; + assert(i.begin == i.end); + } + else + { + buffer::interval i = m_pc.allocate_send_buffer(4 + 3); + // we don't have the metadata, reply with + // don't have-message + detail::write_uint32(1 + 2, i.begin); + detail::write_uint8(bt_peer_connection::msg_extended, i.begin); + detail::write_uint8(m_message_index, i.begin); + // means 'have no data' + detail::write_uint8(2, i.begin); + assert(i.begin == i.end); + } + m_pc.setup_send(); + } + + virtual bool on_extended(int length + , int msg, buffer::const_interval body) + { + if (msg != 14) return false; + if (m_message_index == 0) return false; + + if (length > 500 * 1024) + throw protocol_error("LT_metadata message larger than 500 kB"); + + if (body.left() < 1) return true; + int type = detail::read_uint8(body.begin); + + switch (type) + { + case 0: // request + { + if (body.left() < 2) return true; + int start = detail::read_uint8(body.begin); + int size = detail::read_uint8(body.begin) + 1; + + if (length != 3) + { + // invalid metadata request + throw protocol_error("invalid metadata request"); + } + + write_metadata(std::make_pair(start, size)); + } + break; + case 1: // data + { + if (body.left() < 8) return true; + + int total_size = detail::read_int32(body.begin); + int offset = detail::read_int32(body.begin); + int data_size = length - 9; + + if (total_size > 500 * 1024) + throw protocol_error("metadata size larger than 500 kB"); + if (total_size <= 0) + throw protocol_error("invalid metadata size"); + if (offset > total_size || offset < 0) + throw protocol_error("invalid metadata offset"); + if (offset + data_size > total_size) + throw protocol_error("invalid metadata message"); + + m_tp.metadata_progress(total_size + , body.left() - m_metadata_progress); + m_metadata_progress = body.left(); + + if (body.left() < data_size) return true; + + m_waiting_metadata_request = false; + m_tp.received_metadata(body.begin, data_size + , offset, total_size); + m_metadata_progress = 0; + } + break; + case 2: // have no data + m_no_metadata = second_clock::universal_time(); + if (m_waiting_metadata_request) + m_tp.cancel_metadata_request(m_last_metadata_request); + m_waiting_metadata_request = false; + break; + default: + throw protocol_error("unknown metadata extension message: " + + boost::lexical_cast(type)); + } + return true; + } + + virtual void tick() + { + // if we don't have any metadata, and this peer + // supports the request metadata extension + // and we aren't currently waiting for a request + // reply. Then, send a request for some metadata. + if (!m_torrent.valid_metadata() + && m_message_index != 0 + && !m_waiting_metadata_request + && has_metadata()) + { + m_last_metadata_request = m_tp.metadata_request(); + write_metadata_request(m_last_metadata_request); + m_waiting_metadata_request = true; + m_metadata_request = second_clock::universal_time(); + } + } + + bool has_metadata() const + { + using namespace boost::posix_time; + return second_clock::universal_time() - m_no_metadata > minutes(5); + } + + private: + + // this is set to true when we send a metadata + // request to this peer, and reset to false when + // we receive a reply to our request. + bool m_waiting_metadata_request; + + // this is the message index the remote peer uses + // for metadata extension messages. + int m_message_index; + + // the number of bytes of metadata we have received + // so far from this per, only counting the current + // request. Any previously finished requests + // that have been forwarded to the torrent object + // do not count. + int m_metadata_progress; + + // this is set to the current time each time we get a + // "I don't have metadata" message. + boost::posix_time::ptime m_no_metadata; + + // this is set to the time when we last sent + // a request for metadata to this peer + boost::posix_time::ptime m_metadata_request; + + // if we're waiting for a metadata request + // this was the request we sent + std::pair m_last_metadata_request; + + torrent& m_torrent; + peer_connection& m_pc; + metadata_plugin& m_tp; + }; + + boost::shared_ptr metadata_plugin::new_connection( + peer_connection* pc) + { + return boost::shared_ptr(new metadata_peer_plugin(m_torrent, *pc, *this)); + } + + std::pair metadata_plugin::metadata_request() + { + // count the number of peers that supports the + // extension and that has metadata + int peers = 0; +#ifndef TORRENT_DISABLE_EXTENSIONS + typedef std::map conn_map; + for (conn_map::iterator i = m_torrent.begin() + , end(m_torrent.end()); i != end; ++i) + { + bt_peer_connection* c = dynamic_cast(i->second); + if (c == 0) continue; + metadata_peer_plugin* p + = c->supports_extension(); + if (p == 0) continue; + if (!p->has_metadata()) continue; + ++peers; + } +#endif + + // the number of blocks to request + int num_blocks = 256 / (peers + 1); + if (num_blocks < 1) num_blocks = 1; + assert(num_blocks <= 128); + + int min_element = std::numeric_limits::max(); + int best_index = 0; + for (int i = 0; i < 256 - num_blocks + 1; ++i) + { + int min = *std::min_element(m_requested_metadata.begin() + i + , m_requested_metadata.begin() + i + num_blocks); + min += std::accumulate(m_requested_metadata.begin() + i + , m_requested_metadata.begin() + i + num_blocks, (int)0); + + if (min_element > min) + { + best_index = i; + min_element = min; + } + } + + std::pair ret(best_index, num_blocks); + for (int i = ret.first; i < ret.first + ret.second; ++i) + m_requested_metadata[i]++; + + assert(ret.first >= 0); + assert(ret.second > 0); + assert(ret.second <= 256); + assert(ret.first + ret.second <= 256); + + return ret; + } + +} } + +namespace libtorrent +{ + + boost::shared_ptr create_metadata_plugin(torrent* t) + { + return boost::shared_ptr(new metadata_plugin(*t)); + } + +} + + diff --git a/libtorrent/src/peer_connection.cpp b/libtorrent/src/peer_connection.cpp index 3be09de21..def1aeb22 100644 --- a/libtorrent/src/peer_connection.cpp +++ b/libtorrent/src/peer_connection.cpp @@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/io.hpp" #include "libtorrent/file.hpp" #include "libtorrent/version.hpp" +#include "libtorrent/extensions.hpp" #include "libtorrent/aux_/session_impl.hpp" using namespace boost::posix_time; @@ -74,7 +75,8 @@ namespace libtorrent session_impl& ses , boost::weak_ptr tor , shared_ptr s - , tcp::endpoint const& remote) + , tcp::endpoint const& remote + , tcp::endpoint const& proxy) : #ifndef NDEBUG m_last_choke(boost::posix_time::second_clock::universal_time() @@ -93,6 +95,7 @@ namespace libtorrent , m_last_sent(second_clock::universal_time()) , m_socket(s) , m_remote(remote) + , m_remote_proxy(proxy) , m_torrent(tor) , m_active(true) , m_peer_interested(false) @@ -112,51 +115,26 @@ namespace libtorrent , m_connecting(true) , m_queued(true) , m_writing(false) - , m_last_write_size(0) , m_reading(false) - , m_last_read_size(0) + , m_prefer_whole_pieces(false) + , m_request_large_blocks(false) + , m_non_prioritized(false) , m_refs(0) + , m_upload_limit(resource_request::inf) + , m_download_limit(resource_request::inf) #ifndef NDEBUG , m_in_constructor(true) #endif { + std::fill(m_country, m_country + 2, 0); #ifdef TORRENT_VERBOSE_LOGGING m_logger = m_ses.create_log(m_remote.address().to_string() + "_" - + boost::lexical_cast(m_remote.port())); + + boost::lexical_cast(m_remote.port()), m_ses.listen_port()); (*m_logger) << "*** OUTGOING CONNECTION\n"; #endif boost::shared_ptr t = m_torrent.lock(); assert(t); - // these numbers are used the first second of connection. - // then the given upload limits will be applied by running - // allocate_resources(). - m_ul_bandwidth_quota.min = 10; - m_ul_bandwidth_quota.max = resource_request::inf; - - if (t->m_ul_bandwidth_quota.given == resource_request::inf) - { - m_ul_bandwidth_quota.given = resource_request::inf; - } - else - { - // just enough to get started with the handshake and bitmask - m_ul_bandwidth_quota.given = 400; - } - - m_dl_bandwidth_quota.min = 10; - m_dl_bandwidth_quota.max = resource_request::inf; - - if (t->m_dl_bandwidth_quota.given == resource_request::inf) - { - m_dl_bandwidth_quota.given = resource_request::inf; - } - else - { - // just enough to get started with the handshake and bitmask - m_dl_bandwidth_quota.given = 400; - } - std::fill(m_peer_id.begin(), m_peer_id.end(), 0); if (t->ready_for_connections()) @@ -201,61 +179,37 @@ namespace libtorrent , m_connecting(false) , m_queued(false) , m_writing(false) - , m_last_write_size(0) , m_reading(false) - , m_last_read_size(0) + , m_prefer_whole_pieces(false) + , m_request_large_blocks(false) + , m_non_prioritized(false) , m_refs(0) + , m_upload_limit(resource_request::inf) + , m_download_limit(resource_request::inf) #ifndef NDEBUG , m_in_constructor(true) #endif { + std::fill(m_country, m_country + 2, 0); m_remote = m_socket->remote_endpoint(); #ifdef TORRENT_VERBOSE_LOGGING assert(m_socket->remote_endpoint() == remote()); m_logger = m_ses.create_log(remote().address().to_string() + "_" - + boost::lexical_cast(remote().port())); + + boost::lexical_cast(remote().port()), m_ses.listen_port()); (*m_logger) << "*** INCOMING CONNECTION\n"; #endif - - - // upload bandwidth will only be given to connections - // that are part of a torrent. Since this is an incoming - // connection, we have to give it some initial bandwidth - // to send the handshake. - // after one second, allocate_resources() will be called - // and the correct bandwidth limits will be set on all - // connections. - - m_ul_bandwidth_quota.min = 10; - m_ul_bandwidth_quota.max = resource_request::inf; - - if (m_ses.m_upload_rate == -1) - { - m_ul_bandwidth_quota.given = resource_request::inf; - } - else - { - // just enough to get started with the handshake and bitmask - m_ul_bandwidth_quota.given = 400; - } - - m_dl_bandwidth_quota.min = 10; - m_dl_bandwidth_quota.max = resource_request::inf; - - if (m_ses.m_download_rate == -1) - { - m_dl_bandwidth_quota.given = resource_request::inf; - } - else - { - // just enough to get started with the handshake and bitmask - m_dl_bandwidth_quota.given = 400; - } - + std::fill(m_peer_id.begin(), m_peer_id.end(), 0); } +#ifndef TORRENT_DISABLE_EXTENSIONS + void peer_connection::add_extension(boost::shared_ptr ext) + { + m_extensions.push_back(ext); + } +#endif + void peer_connection::init() { INVARIANT_CHECK; @@ -338,7 +292,18 @@ namespace libtorrent // optimization, don't send have messages // to peers that already have the piece if (has_piece(index)) return; + +#ifdef TORRENT_VERBOSE_LOGGING + using namespace boost::posix_time; + (*m_logger) << to_simple_string(second_clock::universal_time()) + << " ==> HAVE [ piece: " << index << "]\n"; +#endif write_have(index); +#ifndef NDEBUG + boost::shared_ptr t = m_torrent.lock(); + assert(t); + assert(t->have_piece(index)); +#endif } bool peer_connection::has_piece(int i) const @@ -380,19 +345,35 @@ namespace libtorrent return m_have_piece; } - void peer_connection::received_valid_data() + void peer_connection::received_valid_data(int index) { INVARIANT_CHECK; +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + try { (*i)->on_piece_pass(index); } catch (std::exception&) {} + } +#endif + m_trust_points++; // TODO: make this limit user settable if (m_trust_points > 20) m_trust_points = 20; } - void peer_connection::received_invalid_data() + void peer_connection::received_invalid_data(int index) { INVARIANT_CHECK; +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + try { (*i)->on_piece_failed(index); } catch (std::exception&) {} + } +#endif + // we decrease more than we increase, to keep the // allowed failed/passed ratio low. // TODO: make this limit user settable @@ -417,16 +398,6 @@ namespace libtorrent m_free_upload += free_upload; } - void peer_connection::reset_upload_quota() - { - m_ul_bandwidth_quota.used = 0; - m_dl_bandwidth_quota.used = 0; - assert(m_ul_bandwidth_quota.left() >= 0); - assert(m_dl_bandwidth_quota.left() >= 0); - setup_send(); - setup_receive(); - } - // verifies a piece to see if it is valid (is within a valid range) // and if it can correspond to a request generated by libtorrent. bool peer_connection::verify_piece(const peer_request& p) const @@ -444,10 +415,12 @@ namespace libtorrent && p.start >= 0 && (p.length == t->block_size() || (p.length < t->block_size() - && p.piece == t->torrent_file().num_pieces()-1 - && p.start + p.length == t->torrent_file().piece_size(p.piece))) + && p.piece == t->torrent_file().num_pieces()-1 + && p.start + p.length == t->torrent_file().piece_size(p.piece)) + || (m_request_large_blocks + && p.length <= t->torrent_file().piece_size(p.piece))) && p.start + p.length <= t->torrent_file().piece_size(p.piece) - && p.start % t->block_size() == 0; + && (p.start % t->block_size() == 0); } struct disconnect_torrent @@ -546,27 +519,28 @@ namespace libtorrent #endif m_peer_choked = true; t->get_policy().choked(*this); - - // remove all pieces from this peers download queue and - // remove the 'downloading' flag from piece_picker. - for (std::deque::iterator i = m_download_queue.begin(); - i != m_download_queue.end(); ++i) + + if (!t->is_seed()) { - t->picker().abort_download(*i); - } - for (std::deque::const_iterator i = m_request_queue.begin() - , end(m_request_queue.end()); i != end; ++i) - { - // since this piece was skipped, clear it and allow it to - // be requested from other peers - t->picker().abort_download(*i); + piece_picker& p = t->picker(); + // remove all pieces from this peers download queue and + // remove the 'downloading' flag from piece_picker. + for (std::deque::iterator i = m_download_queue.begin(); + i != m_download_queue.end(); ++i) + { + p.abort_download(*i); + } + for (std::deque::const_iterator i = m_request_queue.begin() + , end(m_request_queue.end()); i != end; ++i) + { + // since this piece was skipped, clear it and allow it to + // be requested from other peers + p.abort_download(*i); + } } + m_download_queue.clear(); m_request_queue.clear(); - -#ifndef NDEBUG -// t->picker().integrity_check(m_torrent); -#endif } // ----------------------------- @@ -621,7 +595,7 @@ namespace libtorrent // clear the request queue if the client isn't interested m_requests.clear(); - setup_send(); +// setup_send(); #ifdef TORRENT_VERBOSE_LOGGING using namespace boost::posix_time; @@ -669,13 +643,16 @@ namespace libtorrent m_have_piece[index] = true; // only update the piece_picker if - // we have the metadata + // we have the metadata and if + // we're not a seed (in which case + // we won't have a piece picker) if (t->valid_metadata()) { ++m_num_pieces; t->peer_has(index); if (!t->have_piece(index) + && !t->is_seed() && !is_interesting() && !t->picker().is_filtered(index)) t->get_policy().peer_is_interesting(*this); @@ -709,21 +686,26 @@ namespace libtorrent // verify the bitfield size if (t->valid_metadata() && (bitfield.size() / 8) != (m_have_piece.size() / 8)) - throw protocol_error("got bitfield with invalid size"); + throw protocol_error("got bitfield with invalid size: " + + boost::lexical_cast(bitfield.size() / 8) + + "bytes. expected: " + + boost::lexical_cast(m_have_piece.size() / 8) + + "bytes"); // if we don't have metadata yet // just remember the bitmask // don't update the piecepicker // (since it doesn't exist yet) - if (!t->valid_metadata()) + if (!t->ready_for_connections()) { m_have_piece = bitfield; m_num_pieces = std::count(bitfield.begin(), bitfield.end(), true); return; } - // build a vector of all pieces - std::vector piece_list; + // let the torrent know which pieces the + // peer has + bool interesting = false; for (int i = 0; i < (int)m_have_piece.size(); ++i) { bool have = bitfield[i]; @@ -731,7 +713,10 @@ namespace libtorrent { m_have_piece[i] = true; ++m_num_pieces; - piece_list.push_back(i); + t->peer_has(i); + if (!t->have_piece(i) + && !t->picker().is_filtered(i)) + interesting = true; } else if (!have && m_have_piece[i]) { @@ -742,20 +727,7 @@ namespace libtorrent } } - // let the torrent know which pieces the - // peer has, in a shuffled order - bool interesting = false; - for (std::vector::reverse_iterator i = piece_list.rbegin(); - i != piece_list.rend(); ++i) - { - int index = *i; - t->peer_has(index); - if (!t->have_piece(index) - && !t->picker().is_filtered(index)) - interesting = true; - } - - if (piece_list.size() == m_have_piece.size()) + if (m_num_pieces == int(m_have_piece.size())) { #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << " *** THIS IS A SEED ***\n"; @@ -831,6 +803,11 @@ namespace libtorrent && r.length + r.start <= t->torrent_file().piece_size(r.piece) && m_peer_interested) { +#ifdef TORRENT_VERBOSE_LOGGING + using namespace boost::posix_time; + (*m_logger) << to_simple_string(second_clock::universal_time()) + << " <== REQUEST [ piece: " << r.piece << " | s: " << r.start << " | l: " << r.length << " ]\n"; +#endif // if we have choked the client // ignore the request if (m_choked) @@ -838,11 +815,6 @@ namespace libtorrent m_requests.push_back(r); fill_send_buffer(); -#ifdef TORRENT_VERBOSE_LOGGING - using namespace boost::posix_time; - (*m_logger) << to_simple_string(second_clock::universal_time()) - << " <== REQUEST [ piece: " << r.piece << " | s: " << r.start << " | l: " << r.length << " ]\n"; -#endif } else { @@ -855,7 +827,8 @@ namespace libtorrent "l: " << r.length << " | " "i: " << m_peer_interested << " | " "t: " << (int)t->torrent_file().piece_size(r.piece) << " | " - "n: " << t->torrent_file().num_pieces() << " ]\n"; + "n: " << t->torrent_file().num_pieces() << " | " + "h: " << t->have_piece(r.piece) << " ]\n"; #endif ++m_num_invalid_requests; @@ -876,7 +849,38 @@ namespace libtorrent { m_last_piece = second_clock::universal_time(); } + +#ifndef NDEBUG + struct check_postcondition + { + check_postcondition(boost::shared_ptr const& t_ + , bool init_check = true): t(t_) { if (init_check) check(); } + ~check_postcondition() { check(); } + + void check() + { + if (!t->is_seed()) + { + const int blocks_per_piece = static_cast( + t->torrent_file().piece_length() / t->block_size()); + + std::vector const& dl_queue + = t->picker().get_download_queue(); + + for (std::vector::const_iterator i = + dl_queue.begin(); i != dl_queue.end(); ++i) + { + assert(int(i->finished_blocks.count()) < blocks_per_piece); + } + } + } + + shared_ptr t; + }; +#endif + + // ----------------------------- // ----------- PIECE ----------- // ----------------------------- @@ -887,11 +891,14 @@ namespace libtorrent boost::shared_ptr t = m_torrent.lock(); assert(t); +#ifndef NDEBUG + check_postcondition post_checker_(t); + t->check_invariant(); +#endif #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << to_simple_string(second_clock::universal_time()) << " <== PIECE [ piece: " << p.piece << " | " - "b: " << p.start / t->block_size() << " | " "s: " << p.start << " | " "l: " << p.length << " | " "ds: " << statistics().download_rate() << " | " @@ -912,22 +919,39 @@ namespace libtorrent using namespace boost::posix_time; - piece_picker& picker = t->picker(); + // if we're already seeding, don't bother, + // just ignore it + if (t->is_seed()) + { + t->received_redundant_data(p.length); + return; + } + piece_picker& picker = t->picker(); + piece_manager& fs = t->filesystem(); + policy& pol = t->get_policy(); + + std::vector finished_blocks; piece_block block_finished(p.piece, p.start / t->block_size()); + assert(p.start % t->block_size() == 0); + assert(p.length == t->block_size() + || p.length == t->torrent_file().total_size() % t->block_size()); + std::deque::iterator b = std::find( m_download_queue.begin() , m_download_queue.end() , block_finished); - std::deque::iterator i; + // if there's another peer that needs to do another + // piece request, this will point to it + peer_connection* request_peer = 0; if (b != m_download_queue.end()) { if (m_assume_fifo) { - for (i = m_download_queue.begin(); + for (std::deque::iterator i = m_download_queue.begin(); i != b; ++i) { #ifdef TORRENT_VERBOSE_LOGGING @@ -951,7 +975,6 @@ namespace libtorrent { m_download_queue.erase(b); } - send_block_requests(); } else { @@ -961,10 +984,12 @@ namespace libtorrent = t->picker().get_downloader(block_finished); if (peer) { + assert(!t->picker().is_finished(block_finished)); peer_connection* pc = t->connection_for(*peer); if (pc && pc != this) { pc->cancel_request(block_finished); + request_peer = pc; } } else @@ -987,48 +1012,81 @@ namespace libtorrent // if the block we got is already finished, then ignore it if (picker.is_finished(block_finished)) { - t->received_redundant_data(p.length); + t->received_redundant_data(t->block_size()); + pol.block_finished(*this, block_finished); + send_block_requests(); + + if (request_peer && !request_peer->has_peer_choked() && !t->is_seed()) + { + request_a_block(*t, *request_peer); + request_peer->send_block_requests(); + } return; } + + fs.write(data, p.piece, p.start, p.length); - t->filesystem().write(data, p.piece, p.start, p.length); + picker.mark_as_finished(block_finished, m_remote); + + try + { + pol.block_finished(*this, block_finished); + send_block_requests(); + } + catch (std::exception const&) {} + + if (request_peer && !request_peer->has_peer_choked() && !t->is_seed()) + { + request_a_block(*t, *request_peer); + request_peer->send_block_requests(); + } + +#ifndef NDEBUG + try + { +#endif bool was_seed = t->is_seed(); bool was_finished = picker.num_filtered() + t->num_pieces() == t->torrent_file().num_pieces(); - - picker.mark_as_finished(block_finished, m_remote); - - t->get_policy().block_finished(*this, block_finished); - - // if the piece failed, this connection may be closed, and - // detached from the torrent. In that case m_torrent will - // be set to 0. So, we need to temporarily save it in this function // did we just finish the piece? if (picker.is_piece_finished(p.piece)) { +#ifndef NDEBUG + check_postcondition post_checker2_(t, false); +#endif bool verified = t->verify_piece(p.piece); if (verified) { + // the following call may cause picker to become invalid + // in case we just became a seed t->announce_piece(p.piece); assert(t->valid_metadata()); + // if we jsut became a seed, picker is now invalid, since it + // is deallocated by the torrent once it starts seeding if (!was_finished - && picker.num_filtered() + t->num_pieces() - == t->torrent_file().num_pieces()) + && (t->is_seed() + || picker.num_filtered() + t->num_pieces() + == t->torrent_file().num_pieces())) { // torrent finished // i.e. all the pieces we're interested in have // been downloaded. Release the files (they will open // in read only mode if needed) - t->finished(); + try { t->finished(); } + catch (std::exception&) + { + assert(false); + } } } else { t->piece_failed(p.piece); } - t->get_policy().piece_finished(p.piece, verified); + + pol.piece_finished(p.piece, verified); if (!was_seed && t->is_seed()) { @@ -1036,6 +1094,15 @@ namespace libtorrent t->completed(); } } + +#ifndef NDEBUG + } + catch (std::exception const& e) + { + std::string err = e.what(); + assert(false); + } +#endif } // ----------------------------- @@ -1140,8 +1207,6 @@ namespace libtorrent m_download_queue.erase(it); } - send_block_requests(); - int block_offset = block.block_index * t->block_size(); int block_size = std::min((int)t->torrent_file().piece_size(block.piece_index)-block_offset, @@ -1244,10 +1309,12 @@ namespace libtorrent void peer_connection::send_block_requests() { INVARIANT_CHECK; + + if (has_peer_choked()) return; boost::shared_ptr t = m_torrent.lock(); assert(t); - + assert(!has_peer_choked()); if ((int)m_download_queue.size() >= m_desired_queue_size) return; @@ -1256,11 +1323,9 @@ namespace libtorrent && (int)m_download_queue.size() < m_desired_queue_size) { piece_block block = m_request_queue.front(); - m_request_queue.pop_front(); - m_download_queue.push_back(block); int block_offset = block.block_index * t->block_size(); - int block_size = std::min((int)t->torrent_file().piece_size( + int block_size = std::min((int)t->torrent_file().piece_size( block.piece_index) - block_offset, t->block_size()); assert(block_size > 0); assert(block_size <= t->block_size()); @@ -1270,19 +1335,68 @@ namespace libtorrent r.start = block_offset; r.length = block_size; + m_request_queue.pop_front(); + m_download_queue.push_back(block); +/* +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << to_simple_string(second_clock::universal_time()) + << " *** REQUEST-QUEUE** [ " + "piece: " << block.piece_index << " | " + "block: " << block.block_index << " ]\n"; +#endif +*/ + // if we are requesting large blocks, merge the smaller + // blocks that are in the same piece into larger requests + if (m_request_large_blocks) + { + while (!m_request_queue.empty() + && m_request_queue.front().piece_index == r.piece + && m_request_queue.front().block_index == block.block_index + 1) + { + block = m_request_queue.front(); + m_request_queue.pop_front(); + m_download_queue.push_back(block); +/* +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << to_simple_string(second_clock::universal_time()) + << " *** REQUEST-QUEUE** [ " + "piece: " << block.piece_index << " | " + "block: " << block.block_index << " ]\n"; +#endif +*/ + block_offset = block.block_index * t->block_size(); + block_size = std::min((int)t->torrent_file().piece_size( + block.piece_index) - block_offset, t->block_size()); + assert(block_size > 0); + assert(block_size <= t->block_size()); + + r.length += block_size; + } + } + assert(verify_piece(r)); - write_request(r); +#ifndef TORRENT_DISABLE_EXTENSIONS + bool handled = false; + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + if (handled = (*i)->write_request(r)) break; + } + if (!handled) write_request(r); +#else + write_request(r); +#endif + using namespace boost::posix_time; #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << to_simple_string(second_clock::universal_time()) << " ==> REQUEST [ " - "piece: " << block.piece_index << " | " - "b: " << block.block_index << " | " - "s: " << block_offset << " | " - "l: " << block_size << " | " - "ds: " << statistics().download_rate() << " | " + "piece: " << r.piece << " | " + "s: " << r.start << " | " + "l: " << r.length << " | " + "ds: " << statistics().download_rate() << " B/s | " "qs: " << m_desired_queue_size << " ]\n"; #endif } @@ -1292,7 +1406,8 @@ namespace libtorrent void close_socket_ignore_error(boost::shared_ptr s) { - s->close(asio::ignore_error()); + asio::error_code e; + s->close(e); } void peer_connection::disconnect() @@ -1303,13 +1418,13 @@ namespace libtorrent if (m_disconnecting) return; m_disconnecting = true; - m_ses.m_selector.post(boost::bind(&close_socket_ignore_error, m_socket)); + m_ses.m_io_service.post(boost::bind(&close_socket_ignore_error, m_socket)); boost::shared_ptr t = m_torrent.lock(); if (t) { - if (t->valid_metadata()) + if (t->valid_metadata() && !t->is_seed()) { piece_picker& picker = t->picker(); @@ -1324,14 +1439,9 @@ namespace libtorrent m_request_queue.pop_back(); } } -#ifndef NDEBUG - else - { - assert(m_download_queue.empty()); - assert(m_request_queue.empty()); - } -#endif + t->remove_peer(this); + m_torrent.reset(); } @@ -1341,19 +1451,19 @@ namespace libtorrent void peer_connection::set_upload_limit(int limit) { assert(limit >= -1); - if (limit == -1) limit = std::numeric_limits::max(); + if (limit == -1) limit = resource_request::inf; if (limit < 10) limit = 10; - m_ul_bandwidth_quota.max = limit; - assert(m_ul_bandwidth_quota.max >= m_ul_bandwidth_quota.min); + m_upload_limit = limit; + m_bandwidth_limit[upload_channel].throttle(m_upload_limit); } void peer_connection::set_download_limit(int limit) { assert(limit >= -1); - if (limit == -1) limit = std::numeric_limits::max(); + if (limit == -1) limit = resource_request::inf; if (limit < 10) limit = 10; - m_dl_bandwidth_quota.max = limit; - assert(m_dl_bandwidth_quota.max >= m_dl_bandwidth_quota.min); + m_download_limit = limit; + m_bandwidth_limit[download_channel].throttle(m_download_limit); } size_type peer_connection::share_diff() const @@ -1379,8 +1489,9 @@ namespace libtorrent { INVARIANT_CHECK; + assert(packet_size > 0); assert((int)m_recv_buffer.size() >= size); - + // TODO: replace with memmov std::copy(m_recv_buffer.begin() + size, m_recv_buffer.begin() + m_recv_pos, m_recv_buffer.begin()); assert(m_recv_pos >= size); @@ -1391,7 +1502,7 @@ namespace libtorrent #endif m_packet_size = packet_size; - m_recv_buffer.resize(m_packet_size); + if (m_packet_size >= m_recv_pos) m_recv_buffer.resize(m_packet_size); } void peer_connection::second_tick(float tick_interval) @@ -1405,6 +1516,16 @@ namespace libtorrent on_tick(); +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + (*i)->tick(); + } +#endif + + m_statistics.second_tick(tick_interval); + if (!t->valid_metadata()) return; // calculate the desired download queue size @@ -1415,7 +1536,8 @@ namespace libtorrent // the minimum number of requests is 2 and the maximum is 48 // the block size doesn't have to be 16. So we first query the // torrent for it - const int block_size = t->block_size(); + const int block_size = m_request_large_blocks + ? t->torrent_file().piece_length() : t->block_size(); assert(block_size > 0); m_desired_queue_size = static_cast(queue_time @@ -1438,39 +1560,35 @@ namespace libtorrent << " " << to_simple_string(now - m_last_piece) << "] ***\n"; #endif - piece_picker& picker = t->picker(); - for (std::deque::const_iterator i = m_download_queue.begin() - , end(m_download_queue.end()); i != end; ++i) + if (t->is_seed()) { - // since this piece was skipped, clear it and allow it to - // be requested from other peers - picker.abort_download(*i); + m_download_queue.clear(); + m_request_queue.clear(); } - for (std::deque::const_iterator i = m_request_queue.begin() - , end(m_request_queue.end()); i != end; ++i) + else { - // since this piece was skipped, clear it and allow it to - // be requested from other peers - picker.abort_download(*i); + piece_picker& picker = t->picker(); + while (!m_download_queue.empty()) + { + picker.abort_download(m_download_queue.back()); + m_download_queue.pop_back(); + } + while (!m_request_queue.empty()) + { + picker.abort_download(m_request_queue.back()); + m_request_queue.pop_back(); + } + + // TODO: If we have a limited number of upload + // slots, choke this peer + + m_assume_fifo = true; + + request_a_block(*t, *this); + send_block_requests(); } - - m_download_queue.clear(); - m_request_queue.clear(); - - // TODO: If we have a limited number of upload - // slots, choke this peer - - m_assume_fifo = true; - - // this will trigger new picking of pieces - t->get_policy().unchoked(*this); } - m_statistics.second_tick(tick_interval); - m_ul_bandwidth_quota.used = std::min( - (int)ceil(statistics().upload_rate()) - , m_ul_bandwidth_quota.given); - // If the client sends more data // we send it data faster, otherwise, slower. // It will also depend on how much data the @@ -1483,15 +1601,11 @@ namespace libtorrent // if we have downloaded more than one piece more // than we have uploaded OR if we are a seed // have an unlimited upload rate - if(send_buffer_size() > 0 - || (!m_requests.empty() && !is_choked())) - m_ul_bandwidth_quota.max = resource_request::inf; - else - m_ul_bandwidth_quota.max = m_ul_bandwidth_quota.min; + m_bandwidth_limit[upload_channel].throttle(m_upload_limit); } else { - size_type bias = 0x10000+2*t->block_size() + m_free_upload; + size_type bias = 0x10000 + 2 * t->block_size() + m_free_upload; double break_even_time = 15; // seconds. size_type have_uploaded = m_statistics.total_payload_upload(); @@ -1501,23 +1615,19 @@ namespace libtorrent size_type soon_downloaded = have_downloaded + (size_type)(download_speed * break_even_time*1.5); - if(t->ratio() != 1.f) + if (t->ratio() != 1.f) soon_downloaded = (size_type)(soon_downloaded*(double)t->ratio()); - double upload_speed_limit = (soon_downloaded - have_uploaded - + bias) / break_even_time; + double upload_speed_limit = std::min((soon_downloaded - have_uploaded + + bias) / break_even_time, double(m_upload_limit)); upload_speed_limit = std::min(upload_speed_limit, (double)std::numeric_limits::max()); - m_ul_bandwidth_quota.max - = std::max((int)upload_speed_limit, m_ul_bandwidth_quota.min); + m_bandwidth_limit[upload_channel].throttle( + std::min(std::max((int)upload_speed_limit, 20) + , m_upload_limit)); } - if (m_ul_bandwidth_quota.given > m_ul_bandwidth_quota.max) - m_ul_bandwidth_quota.given = m_ul_bandwidth_quota.max; - - if (m_ul_bandwidth_quota.used > m_ul_bandwidth_quota.given) - m_ul_bandwidth_quota.used = m_ul_bandwidth_quota.given; fill_send_buffer(); /* @@ -1608,6 +1718,42 @@ namespace libtorrent } } + void peer_connection::assign_bandwidth(int channel, int amount) + { + session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << "bandwidth [ " << channel << " ] + " << amount << "\n"; +#endif + + m_bandwidth_limit[channel].assign(amount); + if (channel == upload_channel) + { + m_writing = false; + setup_send(); + } + else if (channel == download_channel) + { + m_reading = false; + setup_receive(); + } + } + + void peer_connection::expire_bandwidth(int channel, int amount) + { + session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + + m_bandwidth_limit[channel].expire(amount); + if (channel == upload_channel) + { + setup_send(); + } + else if (channel == download_channel) + { + setup_receive(); + } + } + void peer_connection::setup_send() { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); @@ -1615,6 +1761,32 @@ namespace libtorrent INVARIANT_CHECK; if (m_writing) return; + + shared_ptr t = m_torrent.lock(); + + if (m_bandwidth_limit[upload_channel].quota_left() == 0 + && (!m_send_buffer[m_current_send_buffer].empty() + || !m_send_buffer[(m_current_send_buffer + 1) & 1].empty()) + && !m_connecting + && t) + { + // in this case, we have data to send, but no + // bandwidth. So, we simply request bandwidth + // from the torrent + assert(t); + if (m_bandwidth_limit[upload_channel].max_assignable() > 0) + { +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << "req bandwidth [ " << upload_channel << " ]\n"; +#endif + + // the upload queue should not have non-prioritized peers + t->request_bandwidth(upload_channel, self(), false); + m_writing = true; + } + return; + } + if (!can_write()) return; assert(!m_writing); @@ -1622,7 +1794,7 @@ namespace libtorrent int sending_buffer = (m_current_send_buffer + 1) & 1; if (m_send_buffer[sending_buffer].empty()) { - // thise means we have to swap buffer, because there's no + // this means we have to swap buffer, because there's no // previous buffer we're still waiting for. std::swap(m_current_send_buffer, sending_buffer); m_write_pos = 0; @@ -1632,7 +1804,7 @@ namespace libtorrent if (!m_send_buffer[sending_buffer].empty()) { int amount_to_send - = std::min(m_ul_bandwidth_quota.left() + = std::min(m_bandwidth_limit[upload_channel].quota_left() , (int)m_send_buffer[sending_buffer].size() - m_write_pos); assert(amount_to_send > 0); @@ -1643,8 +1815,6 @@ namespace libtorrent , bind(&peer_connection::on_send_data, self(), _1, _2)); m_writing = true; - m_last_write_size = amount_to_send; - m_ul_bandwidth_quota.used += m_last_write_size; } } @@ -1655,30 +1825,51 @@ namespace libtorrent INVARIANT_CHECK; if (m_reading) return; + + shared_ptr t = m_torrent.lock(); + + if (m_bandwidth_limit[download_channel].quota_left() == 0 + && !m_connecting + && t) + { + assert(t); + if (m_bandwidth_limit[download_channel].max_assignable() > 0) + { +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << "req bandwidth [ " << download_channel << " ]\n"; +#endif + t->request_bandwidth(download_channel, self(), m_non_prioritized); + m_reading = true; + } + return; + } + if (!can_read()) return; assert(m_packet_size > 0); int max_receive = std::min( - m_dl_bandwidth_quota.left() + m_bandwidth_limit[download_channel].quota_left() , m_packet_size - m_recv_pos); + assert(max_receive > 0); assert(m_recv_pos >= 0); assert(m_packet_size > 0); - assert(m_dl_bandwidth_quota.left() > 0); assert(max_receive > 0); assert(can_read()); m_socket->async_read_some(asio::buffer(&m_recv_buffer[m_recv_pos] , max_receive), bind(&peer_connection::on_receive_data, self(), _1, _2)); m_reading = true; - m_last_read_size = max_receive; - m_dl_bandwidth_quota.used += max_receive; - assert(m_dl_bandwidth_quota.used <= m_dl_bandwidth_quota.given); } void peer_connection::reset_recv_buffer(int packet_size) { assert(packet_size > 0); + if (m_recv_pos > m_packet_size) + { + cut_receive_buffer(m_packet_size, packet_size); + return; + } m_recv_pos = 0; m_packet_size = packet_size; if (int(m_recv_buffer.size()) < m_packet_size) @@ -1719,7 +1910,7 @@ namespace libtorrent // -------------------------- // throws exception when the client should be disconnected - void peer_connection::on_receive_data(const asio::error& error + void peer_connection::on_receive_data(const asio::error_code& error , std::size_t bytes_transferred) try { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); @@ -1727,20 +1918,17 @@ namespace libtorrent INVARIANT_CHECK; assert(m_reading); - assert(m_last_read_size > 0); - assert(m_last_read_size >= int(bytes_transferred)); m_reading = false; // correct the dl quota usage, if not all of the buffer was actually read - m_dl_bandwidth_quota.used -= m_last_read_size - bytes_transferred; - m_last_read_size = 0; + m_bandwidth_limit[download_channel].use_quota(bytes_transferred); if (error) { #ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << "**ERROR**: " << error.what() << "\n"; + (*m_logger) << "**ERROR**: " << error.message() << "\n"; #endif on_receive(error, bytes_transferred); - throw std::runtime_error(error.what()); + throw std::runtime_error(error.message()); } if (m_disconnecting) return; @@ -1750,14 +1938,7 @@ namespace libtorrent m_last_receive = second_clock::universal_time(); m_recv_pos += bytes_transferred; - - // this will reset the m_recv_pos to 0 if the - // entire packet was received - // it is important that this is done before - // setup_receive() is called. Therefore, fire() is - // called before setup_receive(). - assert(m_recv_pos <= m_packet_size); - set_to_zero reset(m_recv_pos, m_recv_pos == m_packet_size); + assert(m_recv_pos <= int(m_recv_buffer.size())); { INVARIANT_CHECK; @@ -1766,9 +1947,6 @@ namespace libtorrent assert(m_packet_size > 0); - // do the reset immediately - reset.fire(); - setup_receive(); } catch (file_error& e) @@ -1811,7 +1989,7 @@ namespace libtorrent // we want to send data return (!m_send_buffer[m_current_send_buffer].empty() || !m_send_buffer[(m_current_send_buffer + 1) & 1].empty()) - && m_ul_bandwidth_quota.left() > 0 + && m_bandwidth_limit[upload_channel].quota_left() > 0 && !m_connecting; } @@ -1819,7 +1997,8 @@ namespace libtorrent { INVARIANT_CHECK; - return m_dl_bandwidth_quota.left() > 0 && !m_connecting; + return m_bandwidth_limit[download_channel].quota_left() > 0 + && !m_connecting; } void peer_connection::connect() @@ -1835,10 +2014,18 @@ namespace libtorrent m_queued = false; assert(m_connecting); - m_socket->open(asio::ip::tcp::v4()); + m_socket->open(t->get_interface().protocol()); m_socket->bind(t->get_interface()); - m_socket->async_connect(m_remote - , bind(&peer_connection::on_connection_complete, self(), _1)); + if (m_remote_proxy != tcp::endpoint()) + { + m_socket->async_connect(m_remote_proxy + , bind(&peer_connection::on_connection_complete, self(), _1)); + } + else + { + m_socket->async_connect(m_remote + , bind(&peer_connection::on_connection_complete, self(), _1)); + } if (t->alerts().should_post(alert::debug)) { @@ -1847,7 +2034,7 @@ namespace libtorrent } } - void peer_connection::on_connection_complete(asio::error const& e) try + void peer_connection::on_connection_complete(asio::error_code const& e) try { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); @@ -1856,9 +2043,10 @@ namespace libtorrent if (e) { #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - (*m_ses.m_logger) << "CONNECTION FAILED: " << m_remote.address().to_string() << "\n"; + (*m_ses.m_logger) << "CONNECTION FAILED: " << m_remote.address().to_string() + << ": " << e.message() << "\n"; #endif - m_ses.connection_failed(m_socket, m_remote, e.what()); + m_ses.connection_failed(m_socket, m_remote, e.message().c_str()); return; } @@ -1871,10 +2059,11 @@ namespace libtorrent (*m_ses.m_logger) << "COMPLETED: " << m_remote.address().to_string() << "\n"; #endif - m_connecting = false; m_ses.connection_completed(self()); + m_connecting = false; on_connected(); setup_send(); + setup_receive(); } catch (std::exception& ex) { @@ -1894,7 +2083,7 @@ namespace libtorrent // -------------------------- // throws exception when the client should be disconnected - void peer_connection::on_send_data(asio::error const& error + void peer_connection::on_send_data(asio::error_code const& error , std::size_t bytes_transferred) try { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); @@ -1902,19 +2091,17 @@ namespace libtorrent INVARIANT_CHECK; assert(m_writing); - assert(m_last_write_size > 0); m_writing = false; - // correct the ul quota usage, if not all of the buffer was sent - m_ul_bandwidth_quota.used -= m_last_write_size - bytes_transferred; - m_last_write_size = 0; + + m_bandwidth_limit[upload_channel].use_quota(bytes_transferred); m_write_pos += bytes_transferred; if (error) { #ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << "**ERROR**: " << error.what() << "\n"; + (*m_logger) << "**ERROR**: " << error.message() << "\n"; #endif - throw std::runtime_error(error.what()); + throw std::runtime_error(error.message()); } if (m_disconnecting) return; @@ -1971,6 +2158,8 @@ namespace libtorrent assert(false); } +// expensive when using checked iterators +/* if (t->valid_metadata()) { int piece_count = std::count(m_have_piece.begin() @@ -1980,9 +2169,40 @@ namespace libtorrent assert(false); } } - +*/ assert(m_write_pos <= int(m_send_buffer[ (m_current_send_buffer + 1) & 1].size())); + +// extremely expensive invariant check +/* + if (!t->is_seed()) + { + piece_picker& p = t->picker(); + const std::vector& dlq = p.get_download_queue(); + const int blocks_per_piece = static_cast( + t->torrent_file().piece_length() / t->block_size()); + + for (std::vector::const_iterator i = + dlq.begin(); i != dlq.end(); ++i) + { + for (int j = 0; j < blocks_per_piece; ++j) + { + if (std::find(m_request_queue.begin(), m_request_queue.end() + , piece_block(i->index, j)) != m_request_queue.end() + || + std::find(m_download_queue.begin(), m_download_queue.end() + , piece_block(i->index, j)) != m_download_queue.end()) + { + assert(i->info[j].peer == m_remote); + } + else + { + assert(i->info[j].peer != m_remote || i->finished_blocks[j]); + } + } + } + } +*/ } #endif @@ -1991,6 +2211,11 @@ namespace libtorrent // TODO: the timeout should be called by an event INVARIANT_CHECK; +#ifndef NDEBUG + // allow step debugging without timing out + return false; +#endif + using namespace boost::posix_time; ptime now(second_clock::universal_time()); diff --git a/libtorrent/src/piece_picker.cpp b/libtorrent/src/piece_picker.cpp index 61e7df66f..593b72d47 100644 --- a/libtorrent/src/piece_picker.cpp +++ b/libtorrent/src/piece_picker.cpp @@ -62,6 +62,9 @@ namespace libtorrent { assert(blocks_per_piece > 0); assert(total_num_blocks >= 0); +#ifndef NDEBUG + m_files_checked_called = false; +#endif // the piece index is stored in 20 bits, which limits the allowed // number of pieces somewhat @@ -87,6 +90,9 @@ namespace libtorrent const std::vector& pieces , const std::vector& unfinished) { +#ifndef NDEBUG + m_files_checked_called = true; +#endif // build a vector of all the pieces we don't have std::vector piece_list; piece_list.reserve(std::count(pieces.begin(), pieces.end(), false)); @@ -136,6 +142,12 @@ namespace libtorrent if (i->finished_blocks[j]) mark_as_finished(piece_block(i->index, j), peer); } + if (is_piece_finished(i->index)) + { + // TODO: handle this case by verifying the + // piece and either accept it or discard it + assert(false); + } } } } @@ -417,6 +429,7 @@ namespace libtorrent assert(elem_index != piece_pos::we_have_index); std::vector >& src_vec(pick_piece_info_vector( downloading, filtered)); + assert(m_files_checked_called); assert((int)src_vec.size() > priority); assert((int)src_vec[priority].size() > elem_index); @@ -531,6 +544,7 @@ namespace libtorrent assert(!filtered); assert(priority >= 0); assert(elem_index >= 0); + assert(m_files_checked_called); std::vector >& src_vec(pick_piece_info_vector(downloading, filtered)); @@ -582,6 +596,7 @@ namespace libtorrent assert(index >= 0); assert(index < (int)m_piece_map.size()); + assert(m_files_checked_called); assert(m_piece_map[index].downloading == 1); @@ -603,6 +618,7 @@ namespace libtorrent TORRENT_PIECE_PICKER_INVARIANT_CHECK; assert(i >= 0); assert(i < (int)m_piece_map.size()); + assert(m_files_checked_called); int index = m_piece_map[i].index; int prev_priority = m_piece_map[i].priority(m_sequenced_download_threshold); @@ -630,6 +646,7 @@ namespace libtorrent { TORRENT_PIECE_PICKER_INVARIANT_CHECK; + assert(m_files_checked_called); assert(i >= 0); assert(i < (int)m_piece_map.size()); @@ -669,7 +686,6 @@ namespace libtorrent { --m_num_filtered; ++m_num_have_filtered; - return; } if (info_index == piece_pos::we_have_index) return; remove(p.downloading, p.filtered, priority, info_index); @@ -752,6 +768,7 @@ namespace libtorrent TORRENT_PIECE_PICKER_INVARIANT_CHECK; assert(num_blocks > 0); assert(pieces.size() == m_piece_map.size()); + assert(m_files_checked_called); // free refers to pieces that are free to download, no one else // is downloading them. @@ -965,13 +982,18 @@ namespace libtorrent assert(index < (int)m_piece_map.size()); assert(index >= 0); - if (m_piece_map[index].downloading == 0) return false; + if (m_piece_map[index].downloading == 0) + { + assert(std::find_if(m_downloads.begin(), m_downloads.end(), has_index(index)) + == m_downloads.end()); + return false; + } std::vector::const_iterator i = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(index)); assert(i != m_downloads.end()); assert((int)i->finished_blocks.count() <= m_blocks_per_piece); int max_blocks = blocks_in_piece(index); - if ((int)i->finished_blocks.count() != max_blocks) return false; + if ((int)i->finished_blocks.count() < max_blocks) return false; assert((int)i->requested_blocks.count() == max_blocks); return true; @@ -1163,16 +1185,19 @@ namespace libtorrent assert(block.block_index < blocks_in_piece(block.piece_index)); #ifndef NDEBUG - if (i->requested_blocks[block.block_index] != 1) + if (i->requested_blocks[block.block_index] == false) { assert(false); } #endif // clear this block as being downloaded - i->requested_blocks[block.block_index] = 0; + i->requested_blocks[block.block_index] = false; + + // clear the downloader of this block + i->info[block.block_index].peer = tcp::endpoint(); - // if there are no other blocks in this pieces + // if there are no other blocks in this piece // that's being downloaded, remove it from the list if (i->requested_blocks.count() == 0) { diff --git a/libtorrent/src/policy.cpp b/libtorrent/src/policy.cpp index bdd90ac77..785e21fad 100644 --- a/libtorrent/src/policy.cpp +++ b/libtorrent/src/policy.cpp @@ -65,6 +65,102 @@ namespace { using namespace libtorrent; + size_type collect_free_download( + torrent::peer_iterator start + , torrent::peer_iterator end) + { + size_type accumulator = 0; + for (torrent::peer_iterator i = start; i != end; ++i) + { + // if the peer is interested in us, it means it may + // want to trade it's surplus uploads for downloads itself + // (and we should not consider it free). If the share diff is + // negative, there's no free download to get from this peer. + size_type diff = i->second->share_diff(); + assert(diff < std::numeric_limits::max()); + if (i->second->is_peer_interested() || diff <= 0) + continue; + + assert(diff > 0); + i->second->add_free_upload(-diff); + accumulator += diff; + assert(accumulator > 0); + } + assert(accumulator >= 0); + return accumulator; + } + + + // returns the amount of free upload left after + // it has been distributed to the peers + size_type distribute_free_upload( + torrent::peer_iterator start + , torrent::peer_iterator end + , size_type free_upload) + { + if (free_upload <= 0) return free_upload; + int num_peers = 0; + size_type total_diff = 0; + for (torrent::peer_iterator i = start; i != end; ++i) + { + size_type d = i->second->share_diff(); + assert(d < std::numeric_limits::max()); + total_diff += d; + if (!i->second->is_peer_interested() || i->second->share_diff() >= 0) continue; + ++num_peers; + } + + if (num_peers == 0) return free_upload; + size_type upload_share; + if (total_diff >= 0) + { + upload_share = std::min(free_upload, total_diff) / num_peers; + } + else + { + upload_share = (free_upload + total_diff) / num_peers; + } + if (upload_share < 0) return free_upload; + + for (torrent::peer_iterator i = start; i != end; ++i) + { + peer_connection* p = i->second; + if (!p->is_peer_interested() || p->share_diff() >= 0) continue; + p->add_free_upload(upload_share); + free_upload -= upload_share; + } + return free_upload; + } + + struct match_peer_ip + { + match_peer_ip(tcp::endpoint const& ip) + : m_ip(ip) + {} + + bool operator()(policy::peer const& p) const + { return p.ip.address() == m_ip.address(); } + + tcp::endpoint m_ip; + }; + + struct match_peer_connection + { + match_peer_connection(peer_connection const& c) + : m_conn(c) + {} + + bool operator()(policy::peer const& p) const + { return p.connection == &m_conn; } + + const peer_connection& m_conn; + }; + + +} + +namespace libtorrent +{ // the case where ignore_peer is motivated is if two peers // have only one piece that we don't have, and it's the // same piece for both peers. Then they might get into an @@ -72,12 +168,15 @@ namespace void request_a_block( torrent& t , peer_connection& c - , std::vector ignore = std::vector()) + , std::vector ignore) { + assert(!t.is_seed()); + assert(!c.has_peer_choked()); int num_requests = c.desired_queue_size() - (int)c.download_queue().size() - (int)c.request_queue().size(); + assert(c.desired_queue_size() > 0); // if our request queue is already full, we // don't have to make any new requests yet if (num_requests <= 0) return; @@ -86,6 +185,21 @@ namespace std::vector interesting_pieces; interesting_pieces.reserve(100); + bool prefer_whole_pieces = c.prefer_whole_pieces(); + if (!prefer_whole_pieces) + { + prefer_whole_pieces = c.statistics().download_payload_rate() + * t.settings().whole_pieces_threshold + > t.torrent_file().piece_length(); + } + + // if we prefer whole pieces, the piece picker will pick at least + // the number of blocks we want, but it will try to make the picked + // blocks be from whole pieces, possibly by returning more blocks + // than we requested. + assert((c.proxy() == tcp::endpoint() && c.remote() == c.get_socket()->remote_endpoint()) + || c.proxy() == c.get_socket()->remote_endpoint()); + // picks the interesting pieces from this peer // the integer is the number of pieces that // should be guaranteed to be available for download @@ -94,17 +208,6 @@ namespace // the last argument is if we should prefer whole pieces // for this peer. If we're downloading one piece in 20 seconds // then use this mode. - bool prefer_whole_pieces = c.statistics().download_payload_rate() - * t.settings().whole_pieces_threshold - > t.torrent_file().piece_length(); - - // if we prefer whole pieces, the piece picker will pick at least - // the number of blocks we want, but it will try to make the picked - // blocks be from whole pieces, possibly by returning more blocks - // than we requested. -#ifndef NDEBUG - assert(c.remote() == c.get_socket()->remote_endpoint()); -#endif p.pick_pieces(c.get_bitfield(), interesting_pieces , num_requests, prefer_whole_pieces, c.remote()); @@ -177,25 +280,35 @@ namespace const std::deque& request_queue = i->second->request_queue(); const int queue_size = (int)i->second->download_queue().size() + (int)i->second->request_queue().size(); - const float weight = queue_size == 0 + + bool in_request_queue = std::find_first_of( + busy_pieces.begin() + , busy_pieces.end() + , request_queue.begin() + , request_queue.end()) != busy_pieces.end(); + + bool in_download_queue = std::find_first_of( + busy_pieces.begin() + , busy_pieces.end() + , download_queue.begin() + , download_queue.end()) != busy_pieces.end(); + + // if the block is in the request queue rather than the download queue + // (i.e. the request message hasn't been sent yet) lower the weight in + // order to prioritize it. Taking over a block in the request queue is + // free in terms of redundant download. A block that already has been + // requested is likely to be in transit already, and would in that case + // mean redundant data to receive. + const float weight = (queue_size == 0) ? std::numeric_limits::max() - : i->second->statistics().download_payload_rate() / queue_size; + : i->second->statistics().download_payload_rate() / queue_size + * in_request_queue ? .1f : 1.f; // if the peer's (i) weight is less than the lowest we've found so // far (weight == priority) and it has blocks in its request- // or download queue that we could request from this peer (c), // replace the currently lowest ranking peer. - if (weight < min_weight - && (std::find_first_of( - busy_pieces.begin() - , busy_pieces.end() - , request_queue.begin() - , request_queue.end()) != busy_pieces.end() - || std::find_first_of( - busy_pieces.begin() - , busy_pieces.end() - , download_queue.begin() - , download_queue.end()) != busy_pieces.end())) + if (weight < min_weight && (in_request_queue || in_download_queue)) { peer = i->second; min_weight = weight; @@ -229,14 +342,20 @@ namespace } piece_block block = *common_block; - peer->cancel_request(block); - c.add_request(block); // the one we interrupted may need to request a new piece. // make sure it doesn't take over a block from the peer - // that just took over its block + // that just took over its block (that would cause an + // infinite recursion) + peer->cancel_request(block); + c.add_request(block); ignore.push_back(&c); - request_a_block(t, *peer, ignore); + if (!peer->has_peer_choked() && !t.is_seed()) + { + request_a_block(t, *peer, ignore); + peer->send_block_requests(); + } + num_requests--; const int queue_size = (int)c.download_queue().size() @@ -252,107 +371,8 @@ namespace c.send_block_requests(); } - - size_type collect_free_download( - torrent::peer_iterator start - , torrent::peer_iterator end) - { - size_type accumulator = 0; - for (torrent::peer_iterator i = start; i != end; ++i) - { - // if the peer is interested in us, it means it may - // want to trade it's surplus uploads for downloads itself - // (and we should not consider it free). If the share diff is - // negative, there's no free download to get from this peer. - size_type diff = i->second->share_diff(); - assert(diff < std::numeric_limits::max()); - if (i->second->is_peer_interested() || diff <= 0) - continue; - - assert(diff > 0); - i->second->add_free_upload(-diff); - accumulator += diff; - assert(accumulator > 0); - } - assert(accumulator >= 0); - return accumulator; - } - - - // returns the amount of free upload left after - // it has been distributed to the peers - size_type distribute_free_upload( - torrent::peer_iterator start - , torrent::peer_iterator end - , size_type free_upload) - { - if (free_upload <= 0) return free_upload; - int num_peers = 0; - size_type total_diff = 0; - for (torrent::peer_iterator i = start; i != end; ++i) - { - size_type d = i->second->share_diff(); - assert(d < std::numeric_limits::max()); - total_diff += d; - if (!i->second->is_peer_interested() || i->second->share_diff() >= 0) continue; - ++num_peers; - } - - if (num_peers == 0) return free_upload; - size_type upload_share; - if (total_diff >= 0) - { - upload_share = std::min(free_upload, total_diff) / num_peers; - } - else - { - upload_share = (free_upload + total_diff) / num_peers; - } - if (upload_share < 0) return free_upload; - - for (torrent::peer_iterator i = start; i != end; ++i) - { - peer_connection* p = i->second; - if (!p->is_peer_interested() || p->share_diff() >= 0) continue; - p->add_free_upload(upload_share); - free_upload -= upload_share; - } - return free_upload; - } - - struct match_peer_ip - { - match_peer_ip(const tcp::endpoint& ip) - : m_ip(ip) - {} - - bool operator()(const policy::peer& p) const - { return p.ip.address() == m_ip.address(); } - - tcp::endpoint m_ip; - }; - - struct match_peer_connection - { - match_peer_connection(const peer_connection& c) - : m_conn(c) - {} - - bool operator()(const policy::peer& p) const - { return p.connection == &m_conn; } - - const peer_connection& m_conn; - }; - - -} - -namespace libtorrent -{ policy::policy(torrent* t) : m_torrent(t) -// , m_max_uploads(std::numeric_limits::max()) -// , m_max_connections(std::numeric_limits::max()) , m_num_unchoked(0) , m_available_free_upload(0) , m_last_optimistic_disconnect(boost::gregorian::date(1970,boost::gregorian::Jan,1)) @@ -434,7 +454,6 @@ namespace libtorrent if (c->share_diff() < -free_upload_amount && m_torrent->ratio() != 0) continue; if (c->statistics().download_rate() < max_down_speed) continue; -// if (i->last_optimistically_unchoked > min_time) continue; min_time = i->last_optimistically_unchoked; max_down_speed = c->statistics().download_rate(); @@ -630,10 +649,6 @@ namespace libtorrent using namespace boost::posix_time; - // TODO: we must also remove peers that - // we failed to connect to from this list - // to avoid being part of a DDOS-attack - // remove old disconnected peers from the list m_peers.erase( std::remove_if(m_peers.begin() @@ -868,30 +883,18 @@ namespace libtorrent void policy::new_connection(peer_connection& c) { assert(!c.is_local()); -/* -#ifndef NDEBUG - // avoid the invariant check to fail - peer p(tcp::endpoint("0.0.0.0", 0), peer::not_connectable); - p.connection = &c; - m_peers.push_back(p); -#endif -*/ + INVARIANT_CHECK; -/* -#ifndef NDEBUG - // avoid the invariant check to fail - m_peers.erase(m_peers.end() - 1); -#endif -*/ + // if the connection comes from the tracker, // it's probably just a NAT-check. Ignore the // num connections constraint then. // TODO: only allow _one_ connection to use this // override at a time -#ifndef NDEBUG - assert(c.remote() == c.get_socket()->remote_endpoint()); -#endif + assert((c.proxy() == tcp::endpoint() && c.remote() == c.get_socket()->remote_endpoint()) + || c.proxy() == c.get_socket()->remote_endpoint()); + if (m_torrent->num_peers() >= m_torrent->m_connections_quota.given && c.remote().address() != m_torrent->current_tracker().address()) { @@ -905,11 +908,19 @@ namespace libtorrent } #endif - std::vector::iterator i = std::find_if( - m_peers.begin() - , m_peers.end() - , match_peer_ip(c.remote())); + std::vector::iterator i; + if (m_torrent->settings().allow_multiple_connections_per_ip) + { + i = m_peers.end(); + } + else + { + i = std::find_if( + m_peers.begin() + , m_peers.end() + , match_peer_ip(c.remote())); + } if (i != m_peers.end()) { @@ -918,6 +929,7 @@ namespace libtorrent if (i->connection != 0) { + assert(i->connection != &c); // the new connection is a local (outgoing) connection // or the current one is already connected if (!i->connection->is_connecting() || c.is_local()) @@ -943,9 +955,9 @@ namespace libtorrent // we don't have ny info about this peer. // add a new entry -#ifndef NDEBUG - assert(c.remote() == c.get_socket()->remote_endpoint()); -#endif + assert((c.proxy() == tcp::endpoint() && c.remote() == c.get_socket()->remote_endpoint()) + || c.proxy() == c.get_socket()->remote_endpoint()); + peer p(c.remote(), peer::not_connectable); m_peers.push_back(p); i = m_peers.end()-1; @@ -971,10 +983,19 @@ namespace libtorrent try { - std::vector::iterator i = std::find_if( - m_peers.begin() - , m_peers.end() - , match_peer_ip(remote)); + std::vector::iterator i; + + if (m_torrent->settings().allow_multiple_connections_per_ip) + { + i = m_peers.end(); + } + else + { + i = std::find_if( + m_peers.begin() + , m_peers.end() + , match_peer_ip(remote)); + } bool just_added = false; @@ -1009,7 +1030,8 @@ namespace libtorrent #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) m_torrent->debug_log("already connected to peer: " + remote.address().to_string() + ":" - + boost::lexical_cast(remote.port())); + + boost::lexical_cast(remote.port()) + " " + + boost::lexical_cast(i->connection->pid())); #endif assert(i->connection->associated_torrent().lock().get() == m_torrent); @@ -1094,7 +1116,7 @@ namespace libtorrent INVARIANT_CHECK; // if the peer hasn't choked us, ask for another piece - if (!c.has_peer_choked()) + if (!c.has_peer_choked() && !m_torrent->is_seed()) request_a_block(*m_torrent, c); } @@ -1313,13 +1335,13 @@ namespace libtorrent bool policy::has_connection(const peer_connection* c) { assert(c); -#ifndef NDEBUG - assert(c->remote() == c->get_socket()->remote_endpoint()); -#endif + assert((c->proxy() == tcp::endpoint() && c->remote() == c->get_socket()->remote_endpoint()) + || c->proxy() == c->get_socket()->remote_endpoint()); + return std::find_if( m_peers.begin() , m_peers.end() - , match_peer_ip(c->remote())) != m_peers.end(); + , match_peer_connection(*c)) != m_peers.end(); } void policy::check_invariant() const diff --git a/libtorrent/src/session.cpp b/libtorrent/src/session.cpp index 611267427..4d906a419 100644 --- a/libtorrent/src/session.cpp +++ b/libtorrent/src/session.cpp @@ -83,6 +83,16 @@ using libtorrent::aux::session_impl; namespace libtorrent { + namespace aux + { + filesystem_init::filesystem_init() + { + using namespace boost::filesystem; + if (path::default_name_check_writable()) + path::default_name_check(no_check); + } + } + session::session( fingerprint const& id , std::pair listen_port_range @@ -90,9 +100,6 @@ namespace libtorrent : m_impl(new session_impl(listen_port_range, id, listen_interface)) { // turn off the filename checking in boost.filesystem - using namespace boost::filesystem; - if (path::default_name_check_writable()) - path::default_name_check(no_check); assert(listen_port_range.first > 0); assert(listen_port_range.first < listen_port_range.second); #ifndef NDEBUG @@ -123,9 +130,9 @@ namespace libtorrent m_impl->abort(); } - void session::disable_extensions() + void session::add_extension(boost::function(torrent*)> ext) { - m_impl->disable_extensions(); + m_impl->add_extension(ext); } void session::set_ip_filter(ip_filter const& f) @@ -143,15 +150,16 @@ namespace libtorrent m_impl->set_key(key); } - void session::enable_extension(extension_index i) - { - m_impl->enable_extension(i); - } - std::vector session::get_torrents() const { return m_impl->get_torrents(); } + + torrent_handle session::find_torrent(sha1_hash const& info_hash) const + { + return m_impl->find_torrent_handle(info_hash); + } + // if the torrent already exists, this will throw duplicate_torrent torrent_handle session::add_torrent( @@ -168,12 +176,13 @@ namespace libtorrent torrent_handle session::add_torrent( char const* tracker_url , sha1_hash const& info_hash + , char const* name , boost::filesystem::path const& save_path , entry const& e , bool compact_mode , int block_size) { - return m_impl->add_torrent(tracker_url, info_hash, save_path, e + return m_impl->add_torrent(tracker_url, info_hash, name, save_path, e , compact_mode, block_size); } @@ -263,6 +272,16 @@ namespace libtorrent m_impl->set_max_half_open_connections(limit); } + int session::upload_rate_limit() const + { + return m_impl->upload_rate_limit(); + } + + int session::download_rate_limit() const + { + return m_impl->download_rate_limit(); + } + void session::set_upload_rate_limit(int bytes_per_second) { m_impl->set_upload_rate_limit(bytes_per_second); @@ -273,6 +292,16 @@ namespace libtorrent m_impl->set_download_rate_limit(bytes_per_second); } + int session::num_uploads() const + { + return m_impl->num_uploads(); + } + + int session::num_connections() const + { + return m_impl->num_connections(); + } + std::auto_ptr session::pop_alert() { return m_impl->pop_alert(); diff --git a/libtorrent/src/session_impl.cpp b/libtorrent/src/session_impl.cpp index c8005879a..f4a5d8904 100644 --- a/libtorrent/src/session_impl.cpp +++ b/libtorrent/src/session_impl.cpp @@ -120,7 +120,7 @@ namespace libtorrent { namespace detail // if the job queue is empty and // we shouldn't abort // wait for a signal - if (m_torrents.empty() && !m_abort && !processing) + while (m_torrents.empty() && !m_abort && !processing) m_cond.wait(l); if (m_abort) @@ -181,6 +181,9 @@ namespace libtorrent { namespace detail #endif } + // lock the session to add the new torrent + session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + mutex::scoped_lock l2(m_mutex); // clear the resume data now that it has been used // (the fast resume data is now parsed and stored in t) t->resume_data = entry(); @@ -188,9 +191,6 @@ namespace libtorrent { namespace detail if (up_to_date) { - // lock the session to add the new torrent - session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); - mutex::scoped_lock l2(m_mutex); INVARIANT_CHECK; assert(m_torrents.front() == t); @@ -225,26 +225,26 @@ namespace libtorrent { namespace detail continue; } - // lock the checker while we move the torrent from - // m_torrents to m_processing - { - mutex::scoped_lock l(m_mutex); - assert(m_torrents.front() == t); + l.unlock(); - m_torrents.pop_front(); - m_processing.push_back(t); - if (!processing) - { - processing = t; - processing->processing = true; - t.reset(); - } + // move the torrent from + // m_torrents to m_processing + assert(m_torrents.front() == t); + + m_torrents.pop_front(); + m_processing.push_back(t); + if (!processing) + { + processing = t; + processing->processing = true; + t.reset(); } } } catch (const std::exception& e) { // This will happen if the storage fails to initialize + // for example if one of the files has an invalid filename. session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); mutex::scoped_lock l2(m_mutex); @@ -461,36 +461,55 @@ namespace libtorrent { namespace detail } #endif + struct seed_random_generator + { + seed_random_generator() + { + std::srand((unsigned int)(boost::posix_time::microsec_clock:: + universal_time().time_of_day().total_microseconds())); + } + }; + session_impl::session_impl( std::pair listen_port_range , fingerprint const& cl_fprint , char const* listen_interface) - : m_tracker_manager(m_settings) + : m_strand(m_io_service) + , m_dl_bandwidth_manager(m_io_service, peer_connection::download_channel) + , m_ul_bandwidth_manager(m_io_service, peer_connection::upload_channel) + , m_tracker_manager(m_settings) , m_listen_port_range(listen_port_range) , m_listen_interface(address::from_string(listen_interface), listen_port_range.first) , m_abort(false) - , m_upload_rate(-1) - , m_download_rate(-1) , m_max_uploads(-1) , m_max_connections(-1) , m_half_open_limit(-1) , m_incoming_connection(false) + , m_files(40) , m_last_tick(microsec_clock::universal_time()) - , m_timer(m_selector) + , m_timer(m_io_service) , m_checker_impl(*this) { #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - m_logger = create_log("main_session", false); + m_logger = create_log("main_session", listen_port(), false); using boost::posix_time::second_clock; using boost::posix_time::to_simple_string; (*m_logger) << to_simple_string(second_clock::universal_time()) << "\n"; + + m_stats_logger = create_log("session_stats", listen_port(), false); + (*m_stats_logger) << + "1. second\n" + "2. hard upload quota\n" + "3. hard download quota\n" + "\n"; + m_second_counter = 0; + m_dl_bandwidth_manager.m_ses = this; + m_ul_bandwidth_manager.m_ses = this; #endif - std::fill(m_extension_enabled, m_extension_enabled - + num_supported_extensions, true); - // ---- generate a peer id ---- - std::srand((unsigned int)std::time(0)); + // ---- generate a peer id ---- + static seed_random_generator seeder; m_key = rand() + (rand() << 15) + (rand() << 30); std::string print = cl_fprint.to_string(); @@ -514,12 +533,21 @@ namespace libtorrent { namespace detail } m_timer.expires_from_now(seconds(1)); - m_timer.async_wait(bind(&session_impl::second_tick, this, _1)); + m_timer.async_wait(m_strand.wrap( + bind(&session_impl::second_tick, this, _1))); m_thread.reset(new boost::thread(boost::ref(*this))); m_checker_thread.reset(new boost::thread(boost::ref(m_checker_impl))); } +#ifndef TORRENT_DISABLE_EXTENSIONS + void session_impl::add_extension( + boost::function(torrent*)> ext) + { + m_extensions.push_back(ext); + } +#endif + #ifndef TORRENT_DISABLE_DHT void session_impl::add_dht_node(udp::endpoint n) { @@ -533,7 +561,7 @@ namespace libtorrent { namespace detail assert(!m_abort); // abort the main thread m_abort = true; - m_selector.interrupt(); + m_io_service.stop(); l.unlock(); mutex::scoped_lock l2(m_checker_impl.m_mutex); @@ -565,17 +593,11 @@ namespace libtorrent { namespace detail } } - bool session_impl::extensions_enabled() const - { - const int n = num_supported_extensions; - return std::find(m_extension_enabled - , m_extension_enabled + n, true) != m_extension_enabled + n; - } - void session_impl::set_settings(session_settings const& s) { mutex_t::scoped_lock l(m_mutex); m_settings = s; + m_files.resize(m_settings.file_pool_size); // replace all occurances of '\n' with ' '. std::string::iterator i = m_settings.user_agent.begin(); while ((i = std::find(i, m_settings.user_agent.end(), '\n')) @@ -588,18 +610,18 @@ namespace libtorrent { namespace detail try { // create listener socket - m_listen_socket = boost::shared_ptr(new socket_acceptor(m_selector)); + m_listen_socket = boost::shared_ptr(new socket_acceptor(m_io_service)); for(;;) { try { - m_listen_socket->open(asio::ip::tcp::v4()); + m_listen_socket->open(m_listen_interface.protocol()); m_listen_socket->bind(m_listen_interface); m_listen_socket->listen(); break; } - catch (asio::error& e) + catch (asio::system_error& e) { // TODO: make sure this is correct if (e.code() == asio::error::host_not_found) @@ -619,6 +641,7 @@ namespace libtorrent { namespace detail m_listen_socket.reset(); break; } + m_listen_socket->close(); m_listen_interface.port(m_listen_interface.port() + 1); if (m_listen_interface.port() > m_listen_port_range.second) { @@ -637,12 +660,12 @@ namespace libtorrent { namespace detail } } } - catch (asio::error& e) + catch (asio::system_error& e) { if (m_alerts.should_post(alert::fatal)) { m_alerts.post_alert(listen_failed_alert( - std::string("failed to open listen port") + e.what())); + std::string("failed to open listen port: ") + e.what())); } } @@ -686,14 +709,14 @@ namespace libtorrent { namespace detail void session_impl::async_accept() { - shared_ptr c(new stream_socket(m_selector)); + shared_ptr c(new stream_socket(m_io_service)); m_listen_socket->async_accept(*c , bind(&session_impl::on_incoming_connection, this, c , weak_ptr(m_listen_socket), _1)); } void session_impl::on_incoming_connection(shared_ptr const& s - , weak_ptr const& listen_socket, asio::error const& e) try + , weak_ptr const& listen_socket, asio::error_code const& e) try { if (listen_socket.expired()) return; @@ -725,7 +748,7 @@ namespace libtorrent { namespace detail #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) (*m_logger) << endp << " <== INCOMING CONNECTION\n"; #endif - if (m_ip_filter.access(endp.address().to_v4()) & ip_filter::blocked) + if (m_ip_filter.access(endp.address()) & ip_filter::blocked) { #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) (*m_logger) << "filtered blocked ip\n"; @@ -864,17 +887,17 @@ namespace libtorrent { namespace detail m_key = key; } - void session_impl::second_tick(asio::error const& e) try + void session_impl::second_tick(asio::error_code const& e) try { session_impl::mutex_t::scoped_lock l(m_mutex); if (e) { #if defined(TORRENT_LOGGING) - (*m_logger) << "*** SECOND TIMER FAILED " << e.what() << "\n"; + (*m_logger) << "*** SECOND TIMER FAILED " << e.message() << "\n"; #endif m_abort = true; - m_selector.interrupt(); + m_io_service.stop(); return; } @@ -884,7 +907,8 @@ namespace libtorrent { namespace detail m_last_tick = microsec_clock::universal_time(); m_timer.expires_from_now(seconds(1)); - m_timer.async_wait(bind(&session_impl::second_tick, this, _1)); + m_timer.async_wait(m_strand.wrap( + bind(&session_impl::second_tick, this, _1))); // do the second_tick() on each connection // this will update their statistics (download and upload speeds) @@ -934,8 +958,8 @@ namespace libtorrent { namespace detail tracker_request req = t.generate_tracker_request(); req.listen_port = m_listen_interface.port(); req.key = m_key; - m_tracker_manager.queue_request(m_selector, req, t.tracker_login() - , i->second); + m_tracker_manager.queue_request(m_strand, req, t.tracker_login() + , m_listen_interface.address(), i->second); if (m_alerts.should_post(alert::info)) { @@ -954,23 +978,9 @@ namespace libtorrent { namespace detail // distribute the maximum upload rate among the torrents - assert(m_upload_rate >= -1); - assert(m_download_rate >= -1); assert(m_max_uploads >= -1); assert(m_max_connections >= -1); - allocate_resources(m_upload_rate == -1 - ? std::numeric_limits::max() - : int(m_upload_rate * tick_interval) - , m_torrents - , &torrent::m_ul_bandwidth_quota); - - allocate_resources(m_download_rate == -1 - ? std::numeric_limits::max() - : int(m_download_rate * tick_interval) - , m_torrents - , &torrent::m_dl_bandwidth_quota); - allocate_resources(m_max_uploads == -1 ? std::numeric_limits::max() : m_max_uploads @@ -989,7 +999,7 @@ namespace libtorrent { namespace detail #ifndef NDEBUG i->second->check_invariant(); #endif - i->second->distribute_resources(); + i->second->distribute_resources(tick_interval); } } catch (std::exception& exc) @@ -1002,17 +1012,18 @@ namespace libtorrent { namespace detail void session_impl::connection_completed( boost::intrusive_ptr const& p) #ifndef NDEBUG - try + try #endif { mutex_t::scoped_lock l(m_mutex); - - if (m_abort) return; connection_map::iterator i = m_half_open.find(p->get_socket()); - m_connections.insert(std::make_pair(p->get_socket(), p)); + assert(i != m_half_open.end()); if (i != m_half_open.end()) m_half_open.erase(i); + + if (m_abort) return; + process_connection_queue(); } #ifndef NDEBUG @@ -1038,21 +1049,21 @@ namespace libtorrent { namespace detail { try { - m_selector.run(); + m_io_service.run(); assert(m_abort == true); } catch (std::exception& e) { - #ifndef NDEBUG +#ifndef NDEBUG std::cerr << e.what() << "\n"; std::string err = e.what(); - #endif +#endif assert(false); } } while (!m_abort); - deadline_timer tracker_timer(m_selector); + deadline_timer tracker_timer(m_io_service); session_impl::mutex_t::scoped_lock l(m_mutex); @@ -1061,13 +1072,24 @@ namespace libtorrent { namespace detail m_torrents.begin(); i != m_torrents.end(); ++i) { i->second->abort(); - if (!i->second->is_paused() || i->second->should_request()) + // generate a tracker request in case the torrent is not paused + // (in which case it's not currently announced with the tracker) + // or if the torrent itself thinks we should request. Do not build + // a request in case the torrent doesn't have any trackers + if ((!i->second->is_paused() || i->second->should_request()) + && !i->second->trackers().empty()) { tracker_request req = i->second->generate_tracker_request(); req.listen_port = m_listen_interface.port(); req.key = m_key; std::string login = i->second->tracker_login(); - m_tracker_manager.queue_request(m_selector, req, login); +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + boost::shared_ptr tl(new tracker_logger(*this)); + m_tracker_loggers.push_back(tl); + m_tracker_manager.queue_request(m_strand, req, login, m_listen_interface.address(), tl); +#else + m_tracker_manager.queue_request(m_strand, req, login, m_listen_interface.address()); +#endif } } @@ -1079,23 +1101,24 @@ namespace libtorrent { namespace detail && !m_tracker_manager.empty()) { tracker_timer.expires_from_now(boost::posix_time::milliseconds(100)); - tracker_timer.async_wait(bind(&demuxer::interrupt, &m_selector)); + tracker_timer.async_wait(m_strand.wrap( + bind(&io_service::stop, &m_io_service))); - m_selector.reset(); - m_selector.run(); + m_io_service.reset(); + m_io_service.run(); } l.lock(); assert(m_abort); m_abort = true; - while (!m_connections.empty()) - m_connections.begin()->second->disconnect(); + m_connection_queue.clear(); while (!m_half_open.empty()) m_half_open.begin()->second->disconnect(); - m_connection_queue.clear(); + while (!m_connections.empty()) + m_connections.begin()->second->disconnect(); #ifndef NDEBUG for (torrent_map::iterator i = m_torrents.begin(); @@ -1131,28 +1154,14 @@ namespace libtorrent { namespace detail } #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - boost::shared_ptr session_impl::create_log(std::string const& name, bool append) + boost::shared_ptr session_impl::create_log(std::string const& name + , int instance, bool append) { // current options are file_logger, cout_logger and null_logger - return boost::shared_ptr(new logger(name + ".log", append)); + return boost::shared_ptr(new logger(name + ".log", instance, append)); } #endif - void session_impl::disable_extensions() - { - mutex_t::scoped_lock l(m_mutex); - std::fill(m_extension_enabled, m_extension_enabled - + num_supported_extensions, false); - } - - void session_impl::enable_extension(extension_index i) - { - assert(i >= 0); - assert(i < num_supported_extensions); - mutex_t::scoped_lock l(m_mutex); - m_extension_enabled[i] = true; - } - std::vector session_impl::get_torrents() { mutex_t::scoped_lock l(m_mutex); @@ -1167,6 +1176,15 @@ namespace libtorrent { namespace detail , (*i)->info_hash)); } + for (std::deque >::iterator i + = m_checker_impl.m_processing.begin() + , end(m_checker_impl.m_processing.end()); i != end; ++i) + { + if ((*i)->abort) continue; + ret.push_back(torrent_handle(this, &m_checker_impl + , (*i)->info_hash)); + } + for (session_impl::torrent_map::iterator i = m_torrents.begin(), end(m_torrents.end()); i != end; ++i) @@ -1178,6 +1196,11 @@ namespace libtorrent { namespace detail return ret; } + torrent_handle session_impl::find_torrent_handle(sha1_hash const& info_hash) + { + return torrent_handle(this, &m_checker_impl, info_hash); + } + torrent_handle session_impl::add_torrent( torrent_info const& ti , boost::filesystem::path const& save_path @@ -1225,6 +1248,15 @@ namespace libtorrent { namespace detail , m_listen_interface, compact_mode, block_size , settings())); +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + boost::shared_ptr tp((*i)(torrent_ptr.get())); + if (tp) torrent_ptr->add_extension(tp); + } +#endif + boost::shared_ptr d( new aux::piece_checker_data); d->torrent_ptr = torrent_ptr; @@ -1255,6 +1287,7 @@ namespace libtorrent { namespace detail torrent_handle session_impl::add_torrent( char const* tracker_url , sha1_hash const& info_hash + , char const* name , boost::filesystem::path const& save_path , entry const& , bool compact_mode @@ -1286,10 +1319,6 @@ namespace libtorrent { namespace detail // lock the session session_impl::mutex_t::scoped_lock l(m_mutex); - // the metadata extension has to be enabled for this to work - assert(m_extension_enabled - [extended_metadata_message]); - // is the torrent already active? if (!find_torrent(info_hash).expired()) throw duplicate_torrent(); @@ -1301,10 +1330,19 @@ namespace libtorrent { namespace detail // the checker thread and store it before starting // the thread boost::shared_ptr torrent_ptr( - new torrent(*this, m_checker_impl, tracker_url, info_hash, save_path - , m_listen_interface, compact_mode, block_size + new torrent(*this, m_checker_impl, tracker_url, info_hash, name + , save_path, m_listen_interface, compact_mode, block_size , settings())); +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + boost::shared_ptr tp((*i)(torrent_ptr.get())); + if (tp) torrent_ptr->add_extension(tp); + } +#endif + m_torrents.insert( std::make_pair(info_hash, torrent_ptr)).first; @@ -1325,14 +1363,23 @@ namespace libtorrent { namespace detail torrent& t = *i->second; t.abort(); - if (!t.is_paused() || t.should_request()) + if ((!t.is_paused() || t.should_request()) + && !t.torrent_file().trackers().empty()) { tracker_request req = t.generate_tracker_request(); assert(req.event == tracker_request::stopped); req.listen_port = m_listen_interface.port(); req.key = m_key; - m_tracker_manager.queue_request(m_selector, req - , t.tracker_login()); + +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + boost::shared_ptr tl(new tracker_logger(*this)); + m_tracker_loggers.push_back(tl); + m_tracker_manager.queue_request(m_strand, req + , t.tracker_login(), m_listen_interface.address(), tl); +#else + m_tracker_manager.queue_request(m_strand, req + , t.tracker_login(), m_listen_interface.address()); +#endif if (m_alerts.should_post(alert::info)) { @@ -1400,6 +1447,14 @@ namespace libtorrent { namespace detail m_listen_interface = new_interface; open_listen_port(); + +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + m_logger = create_log("main_session", listen_port(), false); + using boost::posix_time::second_clock; + using boost::posix_time::to_simple_string; + (*m_logger) << to_simple_string(second_clock::universal_time()) << "\n"; +#endif + return m_listen_socket; } @@ -1438,9 +1493,9 @@ namespace libtorrent { namespace detail } else { - s.m_dht_nodes = 0; - s.m_dht_node_cache = 0; - s.m_dht_torrents = 0; + s.dht_nodes = 0; + s.dht_node_cache = 0; + s.dht_torrents = 0; } #endif @@ -1452,15 +1507,22 @@ namespace libtorrent { namespace detail void session_impl::start_dht(entry const& startup_state) { mutex_t::scoped_lock l(m_mutex); - m_dht.reset(new dht::dht_tracker(m_selector + if (m_dht) + { + m_dht->stop(); + m_dht = 0; + } + m_dht = new dht::dht_tracker(m_io_service , m_dht_settings, m_listen_interface.address() - , startup_state)); + , startup_state); } void session_impl::stop_dht() { mutex_t::scoped_lock l(m_mutex); - m_dht.reset(); + if (!m_dht) return; + m_dht->stop(); + m_dht = 0; } void session_impl::set_dht_settings(dht_settings const& settings) @@ -1498,13 +1560,14 @@ namespace libtorrent { namespace detail #endif - void session_impl::set_download_rate_limit(int bytes_per_second) { assert(bytes_per_second > 0 || bytes_per_second == -1); mutex_t::scoped_lock l(m_mutex); - m_download_rate = bytes_per_second; + if (bytes_per_second == -1) bytes_per_second = bandwidth_limit::inf; + m_dl_bandwidth_manager.throttle(bytes_per_second); } + bool session_impl::is_listening() const { mutex_t::scoped_lock l(m_mutex); @@ -1513,12 +1576,15 @@ namespace libtorrent { namespace detail session_impl::~session_impl() { - { - // lock the main thread and abort it - mutex_t::scoped_lock l(m_mutex); - m_abort = true; - m_selector.interrupt(); - } +#ifndef TORRENT_DISABLE_DHT + stop_dht(); +#endif + // lock the main thread and abort it + mutex_t::scoped_lock l(m_mutex); + m_abort = true; + m_io_service.stop(); + l.unlock(); + m_thread->join(); // it's important that the main thread is closed completely before @@ -1565,6 +1631,7 @@ namespace libtorrent { namespace detail { assert(limit > 0 || limit == -1); mutex_t::scoped_lock l(m_mutex); + m_half_open_limit = limit; } @@ -1572,9 +1639,29 @@ namespace libtorrent { namespace detail { assert(bytes_per_second > 0 || bytes_per_second == -1); mutex_t::scoped_lock l(m_mutex); - m_upload_rate = bytes_per_second; + if (bytes_per_second == -1) bytes_per_second = bandwidth_limit::inf; + m_ul_bandwidth_manager.throttle(bytes_per_second); } + int session_impl::num_uploads() const + { + int uploads = 0; + mutex_t::scoped_lock l(m_mutex); + for (torrent_map::const_iterator i = m_torrents.begin() + , end(m_torrents.end()); i != end; i++) + { + uploads += i->second->get_policy().num_uploads(); + } + return uploads; + } + + int session_impl::num_connections() const + { + mutex_t::scoped_lock l(m_mutex); + return m_connections.size() + m_half_open.size(); + } + + std::auto_ptr session_impl::pop_alert() { mutex_t::scoped_lock l(m_mutex); @@ -1589,6 +1676,18 @@ namespace libtorrent { namespace detail m_alerts.set_severity(s); } + int session_impl::upload_rate_limit() const + { + mutex_t::scoped_lock l(m_mutex); + return m_ul_bandwidth_manager.throttle(); + } + + int session_impl::download_rate_limit() const + { + mutex_t::scoped_lock l(m_mutex); + return m_dl_bandwidth_manager.throttle(); + } + #ifndef NDEBUG void session_impl::check_invariant(const char *place) { @@ -1612,9 +1711,6 @@ namespace libtorrent { namespace detail error_log << "peer_connection::is_connecting() " << p->is_connecting() << "\n"; error_log << "peer_connection::can_write() " << p->can_write() << "\n"; error_log << "peer_connection::can_read() " << p->can_read() << "\n"; - error_log << "peer_connection::ul_quota_left " << p->m_ul_bandwidth_quota.left() << "\n"; - error_log << "peer_connection::dl_quota_left " << p->m_dl_bandwidth_quota.left() << "\n"; - error_log << "peer_connection::m_ul_bandwidth_quota.given " << p->m_ul_bandwidth_quota.given << "\n"; error_log << "peer_connection::get_peer_id " << p->pid() << "\n"; error_log << "place: " << place << "\n"; error_log.flush(); @@ -1657,11 +1753,10 @@ namespace libtorrent { namespace detail } // verify info_hash - const std::string &hash = rd["info-hash"].string(); - std::string real_hash((char*)info.info_hash().begin(), (char*)info.info_hash().end()); - if (hash != real_hash) + sha1_hash hash = rd["info-hash"].string(); + if (hash != info.info_hash()) { - error = "mismatching info-hash: " + hash; + error = "mismatching info-hash: " + boost::lexical_cast(hash); return; } @@ -1780,7 +1875,7 @@ namespace libtorrent { namespace detail const entry& ad = (*i)["adler32"]; // crc's didn't match, don't use the resume data - if (ad.integer() != adler) + if (ad.integer() != entry::integer_type(adler)) { error = "checksum mismatch on piece " + boost::lexical_cast(p.index); return; diff --git a/libtorrent/src/storage.cpp b/libtorrent/src/storage.cpp index 33b32bad3..69c192275 100644 --- a/libtorrent/src/storage.cpp +++ b/libtorrent/src/storage.cpp @@ -64,6 +64,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/peer_id.hpp" #include "libtorrent/file.hpp" #include "libtorrent/invariant_check.hpp" +#include "libtorrent/file_pool.hpp" #include "libtorrent/aux_/session_impl.hpp" #ifndef NDEBUG @@ -90,11 +91,13 @@ namespace libtorrent catch (std::exception) { std::wstring ret; - for (const char* i = &*s.begin(); i < &*s.end(); ++i) + const char* end = &s[0] + s.size(); + for (const char* i = &s[0]; i < end;) { - wchar_t c; - c = '.'; - std::mbtowc(&c, i, 1); + wchar_t c = '.'; + int result = std::mbtowc(&c, i, end - i); + if (result > 0) i += result; + else ++i; ret += c; } return ret; @@ -218,135 +221,7 @@ namespace log << s; log.flush(); } -/* - struct file_key - { - file_key(sha1_hash ih, path f): info_hash(ih), file_path(f) {} - file_key() {} - sha1_hash info_hash; - path file_path; - bool operator<(file_key const& fk) const - { - if (info_hash < fk.info_hash) return true; - if (fk.info_hash < info_hash) return false; - return file_path < fk.file_path; - } - }; -*/ - struct lru_file_entry - { - lru_file_entry(boost::shared_ptr const& f) - : file_ptr(f) - , last_use(pt::second_clock::universal_time()) {} - mutable boost::shared_ptr file_ptr; - path file_path; - void* key; - pt::ptime last_use; - file::open_mode mode; - }; - struct file_pool - { - file_pool(int size): m_size(size) {} - - boost::shared_ptr open_file(void* st, path const& p, file::open_mode m) - { - assert(st != 0); - assert(p.is_complete()); - typedef nth_index::type path_view; - path_view& pt = get<0>(m_files); - path_view::iterator i = pt.find(p); - if (i != pt.end()) - { - lru_file_entry e = *i; - e.last_use = pt::second_clock::universal_time(); - - // if you hit this assert, you probably have more than one - // storage/torrent using the same file at the same time! - assert(e.key == st); - - e.key = st; - if ((e.mode & m) != m) - { - // close the file before we open it with - // the new read/write privilages - i->file_ptr.reset(); - assert(e.file_ptr.unique()); - e.file_ptr.reset(); - e.file_ptr.reset(new file(p, m)); - e.mode = m; - } - pt.replace(i, e); - return e.file_ptr; - } - // the file is not in our cache - if ((int)m_files.size() >= m_size) - { - // the file cache is at its maximum size, close - // the least recently used (lru) file from it - typedef nth_index::type lru_view; - lru_view& lt = get<1>(m_files); - lru_view::iterator i = lt.begin(); - // the first entry in this view is the least recently used -/* for (lru_view::iterator i = lt.begin(); i != lt.end(); ++i) - { - std::cerr << i->last_use << "\n"; - } -*/ assert(lt.size() == 1 || (i->last_use <= boost::next(i)->last_use)); - lt.erase(i); - } - lru_file_entry e(boost::shared_ptr(new file(p, m))); - e.mode = m; - e.key = st; - e.file_path = p; - pt.insert(e); - return e.file_ptr; - } - - void release(void* st) - { - assert(st != 0); - using boost::tie; - - typedef nth_index::type key_view; - key_view& kt = get<2>(m_files); - - key_view::iterator start, end; - tie(start, end) = kt.equal_range(st); - -/* - std::cerr << "releasing files!\n"; - for (path_view::iterator i = r.first; i != r.second; ++i) - { - std::cerr << i->key.file_path.native_file_string() << "\n"; - } -*/ - kt.erase(start, end); -/* - std::cerr << "files left: " << pt.size() << "\n"; - for (path_view::iterator i = pt.begin(); i != pt.end(); ++i) - { - std::cerr << i->key.file_path.native_file_string() << "\n"; - } -*/ - } - - private: - int m_size; - - typedef multi_index_container< - lru_file_entry, indexed_by< - ordered_unique > - , ordered_non_unique > - , ordered_non_unique > - > - > file_set; - - file_set m_files; - }; } namespace libtorrent @@ -469,9 +344,10 @@ namespace libtorrent class storage::impl : public thread_safe_storage, boost::noncopyable { public: - impl(torrent_info const& info, path const& path) + impl(torrent_info const& info, path const& path, file_pool& fp) : thread_safe_storage(info.num_pieces()) , info(info) + , files(fp) { save_path = complete(path); assert(save_path.is_complete()); @@ -481,6 +357,7 @@ namespace libtorrent : thread_safe_storage(x.info.num_pieces()) , info(x.info) , save_path(x.save_path) + , files(x.files) {} ~impl() @@ -490,13 +367,15 @@ namespace libtorrent torrent_info const& info; path save_path; - static file_pool files; + // the file pool is typically stored in + // the session, to make all storage + // instances use the same pool + file_pool& files; }; - file_pool storage::impl::files(40); - - storage::storage(torrent_info const& info, path const& path) - : m_pimpl(new impl(info, path)) + storage::storage(torrent_info const& info, path const& path + , file_pool& fp) + : m_pimpl(new impl(info, path, fp)) { assert(info.begin_files() != info.end_files()); } @@ -538,29 +417,8 @@ namespace libtorrent m_pimpl->files.release(m_pimpl.get()); - if (m_pimpl->info.num_files() == 1) - { - path single_file = m_pimpl->info.begin_files()->path; - if (single_file.has_branch_path()) - { -#if defined(_WIN32) && defined(UNICODE) - std::wstring wsave_path(safe_convert((save_path / single_file.branch_path()) - .native_directory_string())); - CreateDirectory(wsave_path.c_str(), 0); -#else - create_directory(save_path / single_file.branch_path()); -#endif - } - - old_path = m_pimpl->save_path / single_file; - new_path = save_path / m_pimpl->info.begin_files()->path; - } - else - { - assert(m_pimpl->info.num_files() > 1); - old_path = m_pimpl->save_path / m_pimpl->info.name(); - new_path = save_path / m_pimpl->info.name(); - } + old_path = m_pimpl->save_path / m_pimpl->info.name(); + new_path = save_path / m_pimpl->info.name(); try { @@ -862,7 +720,8 @@ namespace libtorrent impl( torrent_info const& info - , path const& path); + , path const& path + , file_pool& fp); bool check_fastresume( aux::piece_checker_data& d @@ -872,7 +731,7 @@ namespace libtorrent std::pair check_files( std::vector& pieces - , int& num_pieces); + , int& num_pieces, boost::recursive_mutex& mutex); void release_files(); @@ -920,7 +779,8 @@ namespace libtorrent , int current_slot , std::vector& have_pieces , int& num_pieces - , const std::multimap& hash_to_piece); + , const std::multimap& hash_to_piece + , boost::recursive_mutex& mutex); int allocate_slot_for_piece(int piece_index); #ifndef NDEBUG @@ -1011,8 +871,9 @@ namespace libtorrent piece_manager::impl::impl( torrent_info const& info - , path const& save_path) - : m_storage(info, save_path) + , path const& save_path + , file_pool& fp) + : m_storage(info, save_path, fp) , m_compact_mode(false) , m_fill_mode(true) , m_info(info) @@ -1024,8 +885,9 @@ namespace libtorrent piece_manager::piece_manager( torrent_info const& info - , path const& save_path) - : m_pimpl(new impl(info, save_path)) + , path const& save_path + , file_pool& fp) + : m_pimpl(new impl(info, save_path, fp)) { } @@ -1215,9 +1077,10 @@ namespace libtorrent , int current_slot , std::vector& have_pieces , int& num_pieces - , const std::multimap& hash_to_piece) + , const std::multimap& hash_to_piece + , boost::recursive_mutex& mutex) { - INVARIANT_CHECK; +// INVARIANT_CHECK; assert((int)have_pieces.size() == m_info.num_pieces()); @@ -1275,6 +1138,9 @@ namespace libtorrent { const int piece_index = current_slot; + // lock because we're writing to have_pieces + boost::recursive_mutex::scoped_lock l(mutex); + if (have_pieces[piece_index]) { // we have already found a piece with @@ -1344,6 +1210,9 @@ namespace libtorrent if (free_piece >= 0) { + // lock because we're writing to have_pieces + boost::recursive_mutex::scoped_lock l(mutex); + assert(have_pieces[free_piece] == false); assert(m_piece_to_slot[free_piece] == has_no_slot); have_pieces[free_piece] = true; @@ -1456,7 +1325,7 @@ namespace libtorrent // file check is at. 0 is nothing done, and 1 // is finished std::pair piece_manager::impl::check_files( - std::vector& pieces, int& num_pieces) + std::vector& pieces, int& num_pieces, boost::recursive_mutex& mutex) { assert(num_pieces == std::count(pieces.begin(), pieces.end(), true)); @@ -1547,7 +1416,8 @@ namespace libtorrent , m_current_slot , pieces , num_pieces - , m_hash_to_piece); + , m_hash_to_piece + , mutex); assert(num_pieces == std::count(pieces.begin(), pieces.end(), true)); assert(piece_index == unassigned || piece_index >= 0); @@ -1816,9 +1686,10 @@ namespace libtorrent std::pair piece_manager::check_files( std::vector& pieces - , int& num_pieces) + , int& num_pieces + , boost::recursive_mutex& mutex) { - return m_pimpl->check_files(pieces, num_pieces); + return m_pimpl->check_files(pieces, num_pieces, mutex); } int piece_manager::impl::allocate_slot_for_piece(int piece_index) @@ -1827,7 +1698,7 @@ namespace libtorrent boost::recursive_mutex::scoped_lock lock(m_mutex); // ---------------------------------------------------------------------- - // INVARIANT_CHECK; +// INVARIANT_CHECK; assert(piece_index >= 0); assert(piece_index < (int)m_piece_to_slot.size()); @@ -1986,7 +1857,7 @@ namespace libtorrent boost::recursive_mutex::scoped_lock lock(m_mutex); // ---------------------------------------------------------------------- - // INVARIANT_CHECK; +// INVARIANT_CHECK; assert(!m_unallocated_slots.empty()); diff --git a/libtorrent/src/torrent.cpp b/libtorrent/src/torrent.cpp index 39936ffca..8efbff573 100644 --- a/libtorrent/src/torrent.cpp +++ b/libtorrent/src/torrent.cpp @@ -66,6 +66,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert.hpp" #include "libtorrent/identify_client.hpp" #include "libtorrent/alert_types.hpp" +#include "libtorrent/extensions.hpp" #include "libtorrent/aux_/session_impl.hpp" using namespace libtorrent; @@ -186,6 +187,33 @@ namespace peer_id const& pid; }; + +#ifdef TORRENT_LOGGING + void print_legend(boost::shared_ptr l) + { + (*l) << "1. time, seconds\n" + << "2. hard send quota, bytes\n" + << "3. soft send quota, bytes\n" + << "4. excess bytes sent\n" + << "5. excess bytes sent last time slice\n" + << "6. hard receive quota, bytes\n" + << "7. soft receive quota, bytes\n" + << "8. excess bytes received\n" + << "9. excess bytes received last time slice\n" + << "10. num peers\n" + << "11. max ul quota limit\n" + << "12. max dl quota limit\n" + << "13. bytes sent\n" + << "14. bytes sent 10 seconds mean\n" + << "15. bytes received\n" + << "16. bytes received 10 seconds mean\n" + << "17. total payload download\n" + << "18. total web seed payload download\n" + << "19. total redundant bytes downloaded\n" + << "\n"; + } +#endif + } namespace libtorrent @@ -210,9 +238,11 @@ namespace libtorrent , m_duration(1800) , m_complete(-1) , m_incomplete(-1) - , m_host_resolver(ses.m_selector) + , m_host_resolver(ses.m_io_service) + , m_resolving_country(false) + , m_resolve_countries(false) #ifndef TORRENT_DISABLE_DHT - , m_dht_announce_timer(ses.m_selector) + , m_dht_announce_timer(ses.m_io_service) #endif , m_policy() , m_ses(ses) @@ -223,25 +253,34 @@ namespace libtorrent , m_currently_trying_tracker(0) , m_failed_trackers(0) , m_time_scaler(0) - , m_priority(.5) , m_num_pieces(0) , m_got_tracker_response(false) , m_ratio(0.f) , m_total_failed_bytes(0) , m_total_redundant_bytes(0) , m_net_interface(net_interface.address(), 0) - , m_upload_bandwidth_limit(std::numeric_limits::max()) - , m_download_bandwidth_limit(std::numeric_limits::max()) , m_save_path(complete(save_path)) , m_compact_mode(compact_mode) - , m_metadata_progress(0) - , m_metadata_size(0) , m_default_block_size(block_size) , m_connections_initialized(true) , m_settings(s) { #ifndef NDEBUG m_initial_done = 0; +#endif +#ifdef TORRENT_LOGGING + m_log = ses.create_log("torrent_" + + boost::lexical_cast(tf.info_hash()) + , m_ses.listen_port(), false); + print_legend(m_log); + m_second_count = 0; + std::fill_n(m_ul_history, 10, 0); + std::fill_n(m_dl_history, 10, 0); + + m_peer_log = ses.create_log("torrent_peers_" + + boost::lexical_cast(tf.info_hash()) + , m_ses.listen_port(), false); + #endif INVARIANT_CHECK; @@ -252,39 +291,15 @@ namespace libtorrent m_connections_quota.given = 100; m_uploads_quota.max = std::numeric_limits::max(); m_connections_quota.max = std::numeric_limits::max(); - - m_dl_bandwidth_quota.min = 100; - m_dl_bandwidth_quota.max = resource_request::inf; - - if (m_ses.m_download_rate == -1) - { - m_dl_bandwidth_quota.given = resource_request::inf; - } - else - { - m_dl_bandwidth_quota.given = 400; - } - - m_ul_bandwidth_quota.min = 100; - m_ul_bandwidth_quota.max = resource_request::inf; - - if (m_ses.m_upload_rate == -1) - { - m_ul_bandwidth_quota.given = resource_request::inf; - } - else - { - m_ul_bandwidth_quota.given = 400; - } - m_policy.reset(new policy(this)); init(); #ifndef TORRENT_DISABLE_DHT - if (!tf.priv()) + if (should_announce_dht()) { m_dht_announce_timer.expires_from_now(seconds(10)); - m_dht_announce_timer.async_wait(bind(&torrent::on_dht_announce, this, _1)); + m_dht_announce_timer.async_wait(m_ses.m_strand.wrap( + bind(&torrent::on_dht_announce, this, _1))); } #endif } @@ -294,6 +309,7 @@ namespace libtorrent , aux::checker_impl& checker , char const* tracker_url , sha1_hash const& info_hash + , char const* name , boost::filesystem::path const& save_path , tcp::endpoint const& net_interface , bool compact_mode @@ -310,9 +326,11 @@ namespace libtorrent , m_duration(1800) , m_complete(-1) , m_incomplete(-1) - , m_host_resolver(ses.m_selector) + , m_host_resolver(ses.m_io_service) + , m_resolving_country(false) + , m_resolve_countries(false) #ifndef TORRENT_DISABLE_DHT - , m_dht_announce_timer(ses.m_selector) + , m_dht_announce_timer(ses.m_io_service) #endif , m_policy() , m_ses(ses) @@ -322,19 +340,14 @@ namespace libtorrent , m_currently_trying_tracker(0) , m_failed_trackers(0) , m_time_scaler(0) - , m_priority(.5) , m_num_pieces(0) , m_got_tracker_response(false) , m_ratio(0.f) , m_total_failed_bytes(0) , m_total_redundant_bytes(0) , m_net_interface(net_interface.address(), 0) - , m_upload_bandwidth_limit(std::numeric_limits::max()) - , m_download_bandwidth_limit(std::numeric_limits::max()) , m_save_path(complete(save_path)) , m_compact_mode(compact_mode) - , m_metadata_progress(0) - , m_metadata_size(0) , m_default_block_size(block_size) , m_connections_initialized(false) , m_settings(s) @@ -342,8 +355,21 @@ namespace libtorrent #ifndef NDEBUG m_initial_done = 0; #endif + +#ifdef TORRENT_LOGGING + m_log = ses.create_log("torrent_" + + boost::lexical_cast(info_hash) + , m_ses.listen_port(), true); + print_legend(m_log); + m_second_count = 0; + std::fill_n(m_ul_history, 10, 0); + std::fill_n(m_dl_history, 10, 0); +#endif + INVARIANT_CHECK; + if (name) m_name.reset(new std::string(name)); + m_uploads_quota.min = 2; m_connections_quota.min = 2; // this will be corrected the next time the main session @@ -351,43 +377,35 @@ namespace libtorrent m_connections_quota.given = 100; m_uploads_quota.max = std::numeric_limits::max(); m_connections_quota.max = std::numeric_limits::max(); - - m_dl_bandwidth_quota.min = 100; - m_dl_bandwidth_quota.max = resource_request::inf; - - if (m_ses.m_download_rate == -1) + if (tracker_url) { - m_dl_bandwidth_quota.given = resource_request::inf; + m_trackers.push_back(announce_entry(tracker_url)); + m_torrent_file.add_tracker(tracker_url); } - else - { - m_dl_bandwidth_quota.given = 400; - } - - m_ul_bandwidth_quota.min = 100; - m_ul_bandwidth_quota.max = resource_request::inf; - - - if (m_ses.m_upload_rate == -1) - { - m_ul_bandwidth_quota.given = resource_request::inf; - } - else - { - m_ul_bandwidth_quota.given = 400; - } - - m_trackers.push_back(announce_entry(tracker_url)); - m_requested_metadata.resize(256, 0); m_policy.reset(new policy(this)); - m_torrent_file.add_tracker(tracker_url); #ifndef TORRENT_DISABLE_DHT - m_dht_announce_timer.expires_from_now(seconds(10)); - m_dht_announce_timer.async_wait(bind(&torrent::on_dht_announce, this, _1)); + if (should_announce_dht()) + { + m_dht_announce_timer.expires_from_now(seconds(10)); + m_dht_announce_timer.async_wait(m_ses.m_strand.wrap( + bind(&torrent::on_dht_announce, this, _1))); + } #endif } +#ifndef TORRENT_DISABLE_DHT + bool torrent::should_announce_dht() const + { + // don't announce private torrents + if (m_torrent_file.is_valid() && m_torrent_file.priv()) return false; + + if (m_trackers.empty()) return true; + + return m_failed_trackers > 0 || !m_ses.settings().use_dht_as_fallback; + } +#endif + torrent::~torrent() { // The invariant can't be maintained here, since the torrent @@ -409,6 +427,20 @@ namespace libtorrent disconnect_all(); } + std::string torrent::name() const + { + if (valid_metadata()) return m_torrent_file.name(); + if (m_name) return *m_name; + return ""; + } + +#ifndef TORRENT_DISABLE_EXTENSIONS + void torrent::add_extension(boost::shared_ptr ext) + { + m_extensions.push_back(ext); + } +#endif + void torrent::init() { INVARIANT_CHECK; @@ -418,7 +450,7 @@ namespace libtorrent assert(m_torrent_file.total_size() >= 0); m_have_pieces.resize(m_torrent_file.num_pieces(), false); - m_storage.reset(new piece_manager(m_torrent_file, m_save_path)); + m_storage.reset(new piece_manager(m_torrent_file, m_save_path, m_ses.m_files)); m_block_size = calculate_block_size(m_torrent_file, m_default_block_size); m_picker.reset(new piece_picker( static_cast(m_torrent_file.piece_length() / m_block_size) @@ -446,22 +478,33 @@ namespace libtorrent tor->on_dht_announce_response(peers); } - void torrent::on_dht_announce(asio::error const& e) + void torrent::on_dht_announce(asio::error_code const& e) { if (e) return; - m_dht_announce_timer.expires_from_now(boost::posix_time::minutes(30)); - m_dht_announce_timer.async_wait(bind(&torrent::on_dht_announce, this, _1)); + if (should_announce_dht()) + { + m_dht_announce_timer.expires_from_now(boost::posix_time::minutes(30)); + m_dht_announce_timer.async_wait(m_ses.m_strand.wrap( + bind(&torrent::on_dht_announce, this, _1))); + } if (!m_ses.m_dht) return; // TODO: There should be a way to abort an announce operation on the dht. // when the torrent is destructed boost::weak_ptr self(shared_from_this()); m_ses.m_dht->announce(m_torrent_file.info_hash() , m_ses.m_listen_interface.port() - , bind(&torrent::on_dht_announce_response_disp, self, _1)); + , m_ses.m_strand.wrap(bind(&torrent::on_dht_announce_response_disp, self, _1))); } void torrent::on_dht_announce_response(std::vector const& peers) { + if (peers.empty()) return; + + if (m_ses.m_alerts.should_post(alert::info)) + { + m_ses.m_alerts.post_alert(tracker_reply_alert( + get_handle(), peers.size(), "Got peers from DHT")); + } std::for_each(peers.begin(), peers.end(), bind( &policy::peer_from_tracker, boost::ref(m_policy), _1, peer_id(0))); } @@ -487,6 +530,8 @@ namespace libtorrent void torrent::tracker_warning(std::string const& msg) { + session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + INVARIANT_CHECK; if (m_ses.m_alerts.should_post(alert::warning)) @@ -502,12 +547,12 @@ namespace libtorrent , int complete , int incomplete) { - INVARIANT_CHECK; - session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + INVARIANT_CHECK; + m_failed_trackers = 0; - // less than 5 minutes announce intervals + // announce intervals less than 5 minutes // are insane. if (interval < 60 * 5) interval = 60 * 5; @@ -547,17 +592,29 @@ namespace libtorrent if (i->pid == m_ses.get_peer_id()) continue; - tcp::endpoint a(address::from_string(i->ip), i->port); - - if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked) + try { + tcp::endpoint a(address::from_string(i->ip), i->port); + + if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked) + { #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - debug_log("blocked ip from tracker: " + i->ip); + debug_log("blocked ip from tracker: " + i->ip); #endif - continue; - } + continue; + } - m_policy->peer_from_tracker(a, i->pid); + m_policy->peer_from_tracker(a, i->pid); + } + catch (std::exception&) + { + // assume this is because we got a hostname instead of + // an ip address from the tracker + + tcp::resolver::query q(i->ip, boost::lexical_cast(i->port)); + m_host_resolver.async_resolve(q, m_ses.m_strand.wrap( + bind(&torrent::on_peer_name_lookup, shared_from_this(), _1, _2, i->pid))); + } } if (m_ses.m_alerts.should_post(alert::info)) @@ -566,11 +623,34 @@ namespace libtorrent s << "Got response from tracker: " << m_trackers[m_last_working_tracker].url; m_ses.m_alerts.post_alert(tracker_reply_alert( - get_handle(), s.str())); + get_handle(), peer_list.size(), s.str())); } m_got_tracker_response = true; } + void torrent::on_peer_name_lookup(asio::error_code const& e, tcp::resolver::iterator host + , peer_id pid) try + { + session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + + INVARIANT_CHECK; + + if (e || host == tcp::resolver::iterator() || + m_ses.is_aborted()) return; + + if (m_ses.m_ip_filter.access(host->endpoint().address()) & ip_filter::blocked) + { +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + debug_log("blocked ip from tracker: " + host->endpoint().address().to_string()); +#endif + return; + } + + m_policy->peer_from_tracker(*host, pid); + } + catch (std::exception&) + {}; + size_type torrent::bytes_left() const { // if we don't have the metadata yet, we @@ -582,14 +662,15 @@ namespace libtorrent size_type torrent::quantized_bytes_done() const { - INVARIANT_CHECK; +// INVARIANT_CHECK; if (!valid_metadata()) return 0; - assert(m_picker.get()); - if (m_torrent_file.num_pieces() == 0) return 0; + + if (is_seed()) return m_torrent_file.total_size(); + const int last_piece = m_torrent_file.num_pieces() - 1; size_type total_done @@ -616,17 +697,20 @@ namespace libtorrent if (!valid_metadata()) return tuple(0,0); - assert(m_picker.get()); - if (m_torrent_file.num_pieces() == 0) return tuple(0,0); const int last_piece = m_torrent_file.num_pieces() - 1; + if (is_seed()) + return make_tuple(m_torrent_file.total_size() + , m_torrent_file.total_size()); + size_type wanted_done = (m_num_pieces - m_picker->num_have_filtered()) * m_torrent_file.piece_length(); size_type total_done = m_num_pieces * m_torrent_file.piece_length(); + assert(m_num_pieces < m_torrent_file.num_pieces()); // if we have the last piece, we have to correct // the amount we have, since the first calculation @@ -640,6 +724,9 @@ namespace libtorrent wanted_done += corr; } + assert(total_done <= m_torrent_file.total_size()); + assert(wanted_done <= m_torrent_file.total_size()); + const std::vector& dl_queue = m_picker->get_download_queue(); @@ -650,11 +737,26 @@ namespace libtorrent dl_queue.begin(); i != dl_queue.end(); ++i) { int corr = 0; - assert(!m_have_pieces[i->index]); + int index = i->index; + assert(!m_have_pieces[index]); + assert(int(i->finished_blocks.count()) + < m_picker->blocks_in_piece(index)); + +#ifndef NDEBUG + for (std::vector::const_iterator j = boost::next(i); + j != dl_queue.end(); ++j) + { + assert(j->index != index); + } +#endif for (int j = 0; j < blocks_per_piece; ++j) { - corr += (i->finished_blocks[j]) * m_block_size; + assert(i->finished_blocks[j] == 0 || i->finished_blocks[j] == 1); + assert(m_picker->is_finished(piece_block(index, j)) == i->finished_blocks[j]); + corr += i->finished_blocks[j] * m_block_size; + assert(index != last_piece || j < m_picker->blocks_in_last_piece() + || i->finished_blocks[j] == 0); } // correction if this was the last piece @@ -666,10 +768,13 @@ namespace libtorrent corr += m_torrent_file.piece_size(last_piece) % m_block_size; } total_done += corr; - if (!m_picker->is_filtered(i->index)) + if (!m_picker->is_filtered(index)) wanted_done += corr; } + assert(total_done < m_torrent_file.total_size()); + assert(wanted_done < m_torrent_file.total_size()); + std::map downloading_piece; for (const_peer_iterator i = begin(); i != end(); ++i) { @@ -696,7 +801,15 @@ namespace libtorrent { downloading_piece[block] = p->bytes_downloaded; } +#ifndef NDEBUG assert(p->bytes_downloaded <= p->full_block_bytes); + int last_piece = m_torrent_file.num_pieces() - 1; + if (p->piece_index == last_piece + && p->block_index == m_torrent_file.piece_size(last_piece) / block_size()) + assert(p->full_block_bytes == m_torrent_file.piece_size(last_piece) % block_size()); + else + assert(p->full_block_bytes == block_size()); +#endif } } for (std::map::iterator i = downloading_piece.begin(); @@ -706,12 +819,57 @@ namespace libtorrent if (!m_picker->is_filtered(i->first.piece_index)) wanted_done += i->second; } + +#ifndef NDEBUG + + if (total_done >= m_torrent_file.total_size()) + { + std::copy(m_have_pieces.begin(), m_have_pieces.end() + , std::ostream_iterator(std::cerr, " ")); + std::cerr << std::endl; + std::cerr << "num_pieces: " << m_num_pieces << std::endl; + + std::cerr << "unfinished:" << std::endl; + + for (std::vector::const_iterator i = + dl_queue.begin(); i != dl_queue.end(); ++i) + { + std::cerr << " " << i->index << " "; + for (int j = 0; j < blocks_per_piece; ++j) + { + std::cerr << i->finished_blocks[j]; + } + std::cerr << std::endl; + } + + std::cerr << "downloading pieces:" << std::endl; + + for (std::map::iterator i = downloading_piece.begin(); + i != downloading_piece.end(); ++i) + { + std::cerr << " " << i->first.piece_index << ":" << i->first.block_index + << " " << i->second << std::endl; + } + + } + + assert(total_done < m_torrent_file.total_size()); + assert(wanted_done < m_torrent_file.total_size()); + +#endif + + assert(total_done >= wanted_done); return make_tuple(total_done, wanted_done); } void torrent::piece_failed(int index) { - INVARIANT_CHECK; + // if the last piece fails the peer connection will still + // think that it has received all of it until this function + // resets the download queue. So, we cannot do the + // invariant check here since it assumes: + // (total_done == m_torrent_file.total_size()) => is_seed() +// INVARIANT_CHECK; assert(m_storage.get()); assert(m_picker.get()); @@ -736,12 +894,20 @@ namespace libtorrent std::set peers; std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin())); +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + try { (*i)->on_piece_failed(index); } catch (std::exception&) {} + } +#endif + for (std::set::iterator i = peers.begin() , end(peers.end()); i != end; ++i) { peer_iterator p = m_connections.find(*i); if (p == m_connections.end()) continue; - p->second->received_invalid_data(); + p->second->received_invalid_data(index); // either, we have received too many failed hashes // or this was the only peer that sent us this piece. @@ -798,9 +964,8 @@ namespace libtorrent void torrent::announce_piece(int index) { - INVARIANT_CHECK; +// INVARIANT_CHECK; - assert(m_picker.get()); assert(index >= 0); assert(index < m_torrent_file.num_pieces()); @@ -812,17 +977,33 @@ namespace libtorrent std::set peers; std::copy(downloaders.begin(), downloaders.end(), std::inserter(peers, peers.begin())); + if (!m_have_pieces[index]) + m_num_pieces++; + m_have_pieces[index] = true; + + assert(std::accumulate(m_have_pieces.begin(), m_have_pieces.end(), 0) + == m_num_pieces); + + m_picker->we_have(index); + for (peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i) + try { i->second->announce_piece(index); } catch (std::exception&) {} + for (std::set::iterator i = peers.begin() , end(peers.end()); i != end; ++i) { peer_iterator p = m_connections.find(*i); if (p == m_connections.end()) continue; - p->second->received_valid_data(); + p->second->received_valid_data(index); } - m_picker->we_have(index); - for (peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i) - i->second->announce_piece(index); +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + try { (*i)->on_piece_pass(index); } catch (std::exception&) {} + } +#endif + if (is_seed()) m_picker.reset(); } std::string torrent::tracker_login() const @@ -835,6 +1016,9 @@ namespace libtorrent { INVARIANT_CHECK; + assert(valid_metadata()); + if (is_seed()) return; + // this call is only valid on torrents with metadata assert(m_picker.get()); assert(index >= 0); @@ -851,6 +1035,9 @@ namespace libtorrent INVARIANT_CHECK; // this call is only valid on torrents with metadata + assert(valid_metadata()); + if (is_seed()) return; + assert(m_picker.get()); // TODO: update peer's interesting-bit @@ -878,6 +1065,9 @@ namespace libtorrent bool torrent::is_piece_filtered(int index) const { // this call is only valid on torrents with metadata + assert(valid_metadata()); + if (is_seed()) return false; + assert(m_picker.get()); assert(index >= 0); assert(index < m_torrent_file.num_pieces()); @@ -890,6 +1080,14 @@ namespace libtorrent INVARIANT_CHECK; // this call is only valid on torrents with metadata + assert(valid_metadata()); + if (is_seed()) + { + bitmask.clear(); + bitmask.resize(m_torrent_file.num_pieces(), false); + return; + } + assert(m_picker.get()); m_picker->filtered_pieces(bitmask); } @@ -899,7 +1097,7 @@ namespace libtorrent INVARIANT_CHECK; // this call is only valid on torrents with metadata - if (!valid_metadata()) return; + if (!valid_metadata() || is_seed()) return; // the bitmask need to have exactly one bit for every file // in the torrent @@ -946,6 +1144,8 @@ namespace libtorrent { INVARIANT_CHECK; + assert(!m_trackers.empty()); + m_next_request = second_clock::universal_time() + boost::posix_time::seconds(tracker_retry_delay_max); @@ -954,6 +1154,7 @@ namespace libtorrent req.info_hash = m_torrent_file.info_hash(); req.pid = m_ses.get_peer_id(); req.downloaded = m_stat.total_payload_download(); + req.web_downloaded = m_web_stat.total_payload_download(); req.uploaded = m_stat.total_payload_upload(); req.left = bytes_left(); if (req.left == -1) req.left = 16*1024; @@ -962,10 +1163,7 @@ namespace libtorrent if (m_event != tracker_request::stopped) m_event = tracker_request::none; req.url = m_trackers[m_currently_trying_tracker].url; - assert(m_connections_quota.given > 0); - req.num_want = std::max( - (m_connections_quota.given - - m_policy->num_peers()), 10); + req.num_want = 50; // if we are aborting. we don't want any new peers if (req.event == tracker_request::stopped) req.num_want = 0; @@ -1030,6 +1228,70 @@ namespace libtorrent (*m_ses.m_logger) << now << " resolving: " << url << "\n"; #endif + m_resolving_web_seeds.insert(url); + if (m_ses.settings().proxy_ip.empty()) + { + std::string protocol; + std::string hostname; + int port; + std::string path; + boost::tie(protocol, hostname, port, path) + = parse_url_components(url); + + tcp::resolver::query q(hostname, boost::lexical_cast(port)); + m_host_resolver.async_resolve(q, m_ses.m_strand.wrap( + bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url + , tcp::endpoint()))); + } + else + { + // use proxy + tcp::resolver::query q(m_ses.settings().proxy_ip + , boost::lexical_cast(m_ses.settings().proxy_port)); + m_host_resolver.async_resolve(q, m_ses.m_strand.wrap( + bind(&torrent::on_proxy_name_lookup, shared_from_this(), _1, _2, url))); + } + + } + + void torrent::on_proxy_name_lookup(asio::error_code const& e, tcp::resolver::iterator host + , std::string url) try + { + session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + + INVARIANT_CHECK; + +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + std::string now(to_simple_string(second_clock::universal_time())); + (*m_ses.m_logger) << now << " completed resolve proxy hostname for: " << url << "\n"; +#endif + + if (e || host == tcp::resolver::iterator()) + { + if (m_ses.m_alerts.should_post(alert::warning)) + { + std::stringstream msg; + msg << "HTTP seed proxy hostname lookup failed: " << e.message(); + m_ses.m_alerts.post_alert( + url_seed_alert(get_handle(), url, msg.str())); + } + + // the name lookup failed for the http host. Don't try + // this host again + remove_url_seed(url); + return; + } + + if (m_ses.is_aborted()) return; + + tcp::endpoint a(host->endpoint()); + + if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked) + { + // TODO: post alert: "proxy at " + a.address().to_string() + " (" + hostname + ") blocked by ip filter"); + return; + } + std::string protocol; std::string hostname; int port; @@ -1037,26 +1299,17 @@ namespace libtorrent boost::tie(protocol, hostname, port, path) = parse_url_components(url); - m_resolving_web_seeds.insert(url); - if (m_ses.settings().proxy_ip.empty()) - { - tcp::resolver::query q(hostname, boost::lexical_cast(port)); - m_host_resolver.async_resolve(q, bind(&torrent::on_name_lookup - , shared_from_this(), _1, _2, url)); - } - else - { - // use proxy - tcp::resolver::query q(m_ses.settings().proxy_ip - , boost::lexical_cast(m_ses.settings().proxy_port)); - m_host_resolver.async_resolve(q, bind(&torrent::on_name_lookup - , shared_from_this(), _1, _2, url)); - } - + tcp::resolver::query q(hostname, boost::lexical_cast(port)); + m_host_resolver.async_resolve(q, m_ses.m_strand.wrap( + bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url, a))); } + catch (std::exception& exc) + { + assert(false); + }; - void torrent::on_name_lookup(asio::error const& e, tcp::resolver::iterator host - , std::string url) try + void torrent::on_name_lookup(asio::error_code const& e, tcp::resolver::iterator host + , std::string url, tcp::endpoint proxy) try { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); @@ -1066,7 +1319,7 @@ namespace libtorrent std::string now(to_simple_string(second_clock::universal_time())); (*m_ses.m_logger) << now << " completed resolve: " << url << "\n"; #endif - + std::set::iterator i = m_resolving_web_seeds.find(url); if (i != m_resolving_web_seeds.end()) m_resolving_web_seeds.erase(i); @@ -1075,9 +1328,9 @@ namespace libtorrent if (m_ses.m_alerts.should_post(alert::warning)) { std::stringstream msg; - msg << "HTTP seed hostname lookup failed: " << e.what(); + msg << "HTTP seed hostname lookup failed: " << e.message(); m_ses.m_alerts.post_alert( - url_seed_alert(url, msg.str())); + url_seed_alert(get_handle(), url, msg.str())); } #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) (*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << url << "\n"; @@ -1093,9 +1346,24 @@ namespace libtorrent tcp::endpoint a(host->endpoint()); - boost::shared_ptr s(new stream_socket(m_ses.m_selector)); + if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked) + { + // TODO: post alert: "web seed at " + a.address().to_string() + " blocked by ip filter"); + return; + } + + peer_iterator conn = m_connections.find(a); + if (conn != m_connections.end()) + { + if (dynamic_cast(conn->second) == 0 + || conn->second->is_disconnecting()) conn->second->disconnect(); + else return; + } + + boost::shared_ptr s(new stream_socket(m_ses.m_io_service)); boost::intrusive_ptr c(new web_peer_connection( - m_ses, shared_from_this(), s, a, url)); + m_ses, shared_from_this(), s, a, proxy, url)); + #ifndef NDEBUG c->m_in_constructor = false; #endif @@ -1137,20 +1405,347 @@ namespace libtorrent assert(false); }; + void torrent::resolve_peer_country(boost::intrusive_ptr const& p) const + { + if (m_resolving_country + || p->has_country() + || p->is_connecting() + || p->is_queued() + || p->in_handshake()) return; + + m_resolving_country = true; + tcp::resolver::query q(boost::lexical_cast(p->remote().address()) + + ".zz.countries.nerd.dk", "0"); + m_host_resolver.async_resolve(q, m_ses.m_strand.wrap( + bind(&torrent::on_country_lookup, shared_from_this(), _1, _2, p))); + } + + namespace + { + typedef std::pair country_entry; + + bool compare_first(country_entry const& lhs, country_entry const& rhs) + { + return lhs.first < rhs.first; + } + } + + void torrent::on_country_lookup(asio::error_code const& error, tcp::resolver::iterator i + , intrusive_ptr p) const + { + session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + + INVARIANT_CHECK; + + m_resolving_country = false; + + // must be ordered in increasing order + country_entry country_map[] = + { + country_entry( 4, "AF") + , country_entry( 8, "AL") + , country_entry( 10, "AQ") + , country_entry( 12, "DZ") + , country_entry( 16, "AS") + , country_entry( 20, "AD") + , country_entry( 24, "AO") + , country_entry( 28, "AG") + , country_entry( 31, "AZ") + , country_entry( 32, "AR") + , country_entry( 36, "AU") + , country_entry( 40, "AT") + , country_entry( 44, "BS") + , country_entry( 48, "BH") + , country_entry( 50, "BD") + , country_entry( 51, "AM") + , country_entry( 52, "BB") + , country_entry( 56, "BE") + , country_entry( 60, "BM") + , country_entry( 64, "BT") + , country_entry( 68, "BO") + , country_entry( 70, "BA") + , country_entry( 72, "BW") + , country_entry( 74, "BV") + , country_entry( 76, "BR") + , country_entry( 84, "BZ") + , country_entry( 86, "IO") + , country_entry( 90, "SB") + , country_entry( 92, "VG") + , country_entry( 96, "BN") + , country_entry(100, "BG") + , country_entry(104, "MM") + , country_entry(108, "BI") + , country_entry(112, "BY") + , country_entry(116, "KH") + , country_entry(120, "CM") + , country_entry(124, "CA") + , country_entry(132, "CV") + , country_entry(136, "KY") + , country_entry(140, "CF") + , country_entry(144, "LK") + , country_entry(148, "TD") + , country_entry(152, "CL") + , country_entry(156, "CN") + , country_entry(158, "TW") + , country_entry(162, "CX") + , country_entry(166, "CC") + , country_entry(170, "CO") + , country_entry(174, "KM") + , country_entry(175, "YT") + , country_entry(178, "CG") + , country_entry(180, "CD") + , country_entry(184, "CK") + , country_entry(188, "CR") + , country_entry(191, "HR") + , country_entry(192, "CU") + , country_entry(203, "CZ") + , country_entry(204, "BJ") + , country_entry(208, "DK") + , country_entry(212, "DM") + , country_entry(214, "DO") + , country_entry(218, "EC") + , country_entry(222, "SV") + , country_entry(226, "GQ") + , country_entry(231, "ET") + , country_entry(232, "ER") + , country_entry(233, "EE") + , country_entry(234, "FO") + , country_entry(238, "FK") + , country_entry(239, "GS") + , country_entry(242, "FJ") + , country_entry(246, "FI") + , country_entry(248, "AX") + , country_entry(250, "FR") + , country_entry(254, "GF") + , country_entry(258, "PF") + , country_entry(260, "TF") + , country_entry(262, "DJ") + , country_entry(266, "GA") + , country_entry(268, "GE") + , country_entry(270, "GM") + , country_entry(275, "PS") + , country_entry(276, "DE") + , country_entry(288, "GH") + , country_entry(292, "GI") + , country_entry(296, "KI") + , country_entry(300, "GR") + , country_entry(304, "GL") + , country_entry(308, "GD") + , country_entry(312, "GP") + , country_entry(316, "GU") + , country_entry(320, "GT") + , country_entry(324, "GN") + , country_entry(328, "GY") + , country_entry(332, "HT") + , country_entry(334, "HM") + , country_entry(336, "VA") + , country_entry(340, "HN") + , country_entry(344, "HK") + , country_entry(348, "HU") + , country_entry(352, "IS") + , country_entry(356, "IN") + , country_entry(360, "ID") + , country_entry(364, "IR") + , country_entry(368, "IQ") + , country_entry(372, "IE") + , country_entry(376, "IL") + , country_entry(380, "IT") + , country_entry(384, "CI") + , country_entry(388, "JM") + , country_entry(392, "JP") + , country_entry(398, "KZ") + , country_entry(400, "JO") + , country_entry(404, "KE") + , country_entry(408, "KP") + , country_entry(410, "KR") + , country_entry(414, "KW") + , country_entry(417, "KG") + , country_entry(418, "LA") + , country_entry(422, "LB") + , country_entry(426, "LS") + , country_entry(428, "LV") + , country_entry(430, "LR") + , country_entry(434, "LY") + , country_entry(438, "LI") + , country_entry(440, "LT") + , country_entry(442, "LU") + , country_entry(446, "MO") + , country_entry(450, "MG") + , country_entry(454, "MW") + , country_entry(458, "MY") + , country_entry(462, "MV") + , country_entry(466, "ML") + , country_entry(470, "MT") + , country_entry(474, "MQ") + , country_entry(478, "MR") + , country_entry(480, "MU") + , country_entry(484, "MX") + , country_entry(492, "MC") + , country_entry(496, "MN") + , country_entry(498, "MD") + , country_entry(500, "MS") + , country_entry(504, "MA") + , country_entry(508, "MZ") + , country_entry(512, "OM") + , country_entry(516, "NA") + , country_entry(520, "NR") + , country_entry(524, "NP") + , country_entry(528, "NL") + , country_entry(530, "AN") + , country_entry(533, "AW") + , country_entry(540, "NC") + , country_entry(548, "VU") + , country_entry(554, "NZ") + , country_entry(558, "NI") + , country_entry(562, "NE") + , country_entry(566, "NG") + , country_entry(570, "NU") + , country_entry(574, "NF") + , country_entry(578, "NO") + , country_entry(580, "MP") + , country_entry(581, "UM") + , country_entry(583, "FM") + , country_entry(584, "MH") + , country_entry(585, "PW") + , country_entry(586, "PK") + , country_entry(591, "PA") + , country_entry(598, "PG") + , country_entry(600, "PY") + , country_entry(604, "PE") + , country_entry(608, "PH") + , country_entry(612, "PN") + , country_entry(616, "PL") + , country_entry(620, "PT") + , country_entry(624, "GW") + , country_entry(626, "TL") + , country_entry(630, "PR") + , country_entry(634, "QA") + , country_entry(634, "QA") + , country_entry(638, "RE") + , country_entry(642, "RO") + , country_entry(643, "RU") + , country_entry(646, "RW") + , country_entry(654, "SH") + , country_entry(659, "KN") + , country_entry(660, "AI") + , country_entry(662, "LC") + , country_entry(666, "PM") + , country_entry(670, "VC") + , country_entry(674, "SM") + , country_entry(678, "ST") + , country_entry(682, "SA") + , country_entry(686, "SN") + , country_entry(690, "SC") + , country_entry(694, "SL") + , country_entry(702, "SG") + , country_entry(703, "SK") + , country_entry(704, "VN") + , country_entry(705, "SI") + , country_entry(706, "SO") + , country_entry(710, "ZA") + , country_entry(716, "ZW") + , country_entry(724, "ES") + , country_entry(732, "EH") + , country_entry(736, "SD") + , country_entry(740, "SR") + , country_entry(744, "SJ") + , country_entry(748, "SZ") + , country_entry(752, "SE") + , country_entry(756, "CH") + , country_entry(760, "SY") + , country_entry(762, "TJ") + , country_entry(764, "TH") + , country_entry(768, "TG") + , country_entry(772, "TK") + , country_entry(776, "TO") + , country_entry(780, "TT") + , country_entry(784, "AE") + , country_entry(788, "TN") + , country_entry(792, "TR") + , country_entry(795, "TM") + , country_entry(796, "TC") + , country_entry(798, "TV") + , country_entry(800, "UG") + , country_entry(804, "UA") + , country_entry(807, "MK") + , country_entry(818, "EG") + , country_entry(826, "GB") + , country_entry(834, "TZ") + , country_entry(840, "US") + , country_entry(850, "VI") + , country_entry(854, "BF") + , country_entry(858, "UY") + , country_entry(860, "UZ") + , country_entry(862, "VE") + , country_entry(876, "WF") + , country_entry(882, "WS") + , country_entry(887, "YE") + , country_entry(891, "CS") + , country_entry(894, "ZM") + }; + + if (error || i == tcp::resolver::iterator()) + { + // this is used to indicate that we shouldn't + // try to resolve it again + p->set_country("--"); + return; + } + + while (i != tcp::resolver::iterator() + && !i->endpoint().address().is_v4()) ++i; + if (i != tcp::resolver::iterator()) + { + // country is an ISO 3166 country code + int country = i->endpoint().address().to_v4().to_ulong() & 0xffff; + + // look up the country code in the map + const int size = sizeof(country_map)/sizeof(country_map[0]); + country_entry* i = + std::lower_bound(country_map, country_map + size + , country_entry(country, ""), &compare_first); + if (i == country_map + size + || i->first != country) + { + // unknown country! + p->set_country("!!"); +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + (*m_ses.m_logger) << "IP " << p->remote().address() << " was mapped to unknown country: " << country << "\n"; +#endif + return; + } + + p->set_country(i->second); + } + } + peer_connection& torrent::connect_to_peer(const tcp::endpoint& a) { INVARIANT_CHECK; + if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked) + throw protocol_error(a.address().to_string() + " blocked by ip filter"); + if (m_connections.find(a) != m_connections.end()) throw protocol_error("already connected to peer"); - boost::shared_ptr s(new stream_socket(m_ses.m_selector)); + boost::shared_ptr s(new stream_socket(m_ses.m_io_service)); boost::intrusive_ptr c(new bt_peer_connection( m_ses, shared_from_this(), s, a)); + #ifndef NDEBUG c->m_in_constructor = false; #endif +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + boost::shared_ptr pp((*i)->new_connection(c.get())); + if (pp) c->add_extension(pp); + } +#endif + try { m_ses.m_connection_queue.push_back(c); @@ -1183,6 +1778,35 @@ namespace libtorrent return *c; } + void torrent::set_metadata(entry const& metadata) + { + m_torrent_file.parse_info_section(metadata); + + boost::mutex::scoped_lock(m_checker.m_mutex); + + boost::shared_ptr d( + new aux::piece_checker_data); + d->torrent_ptr = shared_from_this(); + d->save_path = m_save_path; + d->info_hash = m_torrent_file.info_hash(); + // add the torrent to the queue to be checked + m_checker.m_torrents.push_back(d); + typedef session_impl::torrent_map torrent_map; + torrent_map::iterator i = m_ses.m_torrents.find( + m_torrent_file.info_hash()); + assert(i != m_ses.m_torrents.end()); + m_ses.m_torrents.erase(i); + // and notify the thread that it got another + // job in its queue + m_checker.m_cond.notify_one(); + + if (m_ses.m_alerts.should_post(alert::info)) + { + m_ses.m_alerts.post_alert(metadata_received_alert( + get_handle(), "metadata successfully received from swarm")); + } + } + void torrent::attach_peer(peer_connection* p) { INVARIANT_CHECK; @@ -1217,24 +1841,30 @@ namespace libtorrent throw protocol_error("session is closing"); } - peer_iterator i = m_connections.insert( + peer_iterator ci = m_connections.insert( std::make_pair(p->remote(), p)).first; - try { // if new_connection throws, we have to remove the // it from the list. - m_policy->new_connection(*i->second); +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + boost::shared_ptr pp((*i)->new_connection(p)); + if (pp) p->add_extension(pp); + } +#endif + m_policy->new_connection(*ci->second); } catch (std::exception& e) { - m_connections.erase(i); + m_connections.erase(ci); throw; } -#ifndef NDEBUG - assert(p->remote() == p->get_socket()->remote_endpoint()); -#endif + assert((p->proxy() == tcp::endpoint() && p->remote() == p->get_socket()->remote_endpoint()) + || p->proxy() == p->get_socket()->remote_endpoint()); #ifndef NDEBUG m_policy->check_invariant(); @@ -1266,6 +1896,68 @@ namespace libtorrent } } + bool torrent::request_bandwidth_from_session(int channel) const + { + int max_assignable = m_bandwidth_limit[channel].max_assignable(); + return max_assignable > max_bandwidth_block_size + || (m_bandwidth_limit[channel].throttle() < max_bandwidth_block_size + && max_assignable == m_bandwidth_limit[channel].throttle()); + } + + int torrent::bandwidth_throttle(int channel) const + { + return m_bandwidth_limit[channel].throttle(); + } + + void torrent::request_bandwidth(int channel + , boost::intrusive_ptr p + , bool non_prioritized) + { + if (request_bandwidth_from_session(channel)) + { + if (channel == peer_connection::upload_channel) + m_ses.m_ul_bandwidth_manager.request_bandwidth(p, non_prioritized); + else if (channel == peer_connection::download_channel) + m_ses.m_dl_bandwidth_manager.request_bandwidth(p, non_prioritized); + + m_bandwidth_limit[channel].assign(max_bandwidth_block_size); + } + else + { + m_bandwidth_queue[channel].push_back(bw_queue_entry(p, non_prioritized)); + } + } + + void torrent::expire_bandwidth(int channel, int amount) + { + session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + + assert(amount >= -1); + if (amount == -1) amount = max_bandwidth_block_size; + m_bandwidth_limit[channel].expire(amount); + + while (!m_bandwidth_queue[channel].empty() + && request_bandwidth_from_session(channel)) + { + bw_queue_entry qe = m_bandwidth_queue[channel].front(); + m_bandwidth_queue[channel].pop_front(); + if (channel == peer_connection::upload_channel) + m_ses.m_ul_bandwidth_manager.request_bandwidth(qe.peer, qe.non_prioritized); + else if (channel == peer_connection::download_channel) + m_ses.m_dl_bandwidth_manager.request_bandwidth(qe.peer, qe.non_prioritized); + m_bandwidth_limit[channel].assign(max_bandwidth_block_size); + } + } + + void torrent::assign_bandwidth(int channel, int amount) + { + session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + + assert(amount >= 0); + if (amount < max_bandwidth_block_size) + expire_bandwidth(channel, max_bandwidth_block_size - amount); + } + // called when torrent is finished (all interested pieces downloaded) void torrent::finished() { @@ -1279,6 +1971,8 @@ namespace libtorrent } // disconnect all seeds + // TODO: should disconnect all peers that have the pieces we have + // not just seeds std::vector seeds; for (peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i) @@ -1303,14 +1997,6 @@ namespace libtorrent { INVARIANT_CHECK; -/* - if (alerts().should_post(alert::info)) - { - alerts().post_alert(torrent_complete_alert( - get_handle() - , "torrent is complete")); - } -*/ // make the next tracker request // be a completed-event m_event = tracker_request::completed; @@ -1353,6 +2039,19 @@ namespace libtorrent // if we've looped the tracker list, wait a bit before retrying m_currently_trying_tracker = 0; m_next_request = second_clock::universal_time() + seconds(delay); + +#ifndef TORRENT_DISABLE_DHT + // only start the dht announce unless we already are already running + // the announce timer (a positive expiration time indicates + // that it's running) + if (m_dht_announce_timer.expires_from_now().is_negative() && should_announce_dht()) + { + m_dht_announce_timer.expires_from_now(boost::posix_time::seconds(1)); + m_dht_announce_timer.async_wait(m_ses.m_strand.wrap( + bind(&torrent::on_dht_announce, this, _1))); + } +#endif + } else { @@ -1374,8 +2073,27 @@ namespace libtorrent } assert(m_storage.get()); - bool done = m_storage->check_fastresume(data, m_have_pieces, m_num_pieces - , m_compact_mode); + bool done = true; + try + { + done = m_storage->check_fastresume(data, m_have_pieces, m_num_pieces + , m_compact_mode); + } + catch (std::exception& e) + { + // probably means file permission failure or invalid filename + std::fill(m_have_pieces.begin(), m_have_pieces.end(), false); + m_num_pieces = 0; + + if (m_ses.m_alerts.should_post(alert::fatal)) + { + m_ses.m_alerts.post_alert( + file_error_alert( + get_handle() + , e.what())); + } + pause(); + } #ifndef NDEBUG m_initial_done = boost::get<0>(bytes_done()); #endif @@ -1387,7 +2105,28 @@ namespace libtorrent INVARIANT_CHECK; assert(m_storage.get()); - std::pair progress = m_storage->check_files(m_have_pieces, m_num_pieces); + + std::pair progress(true, 1.f); + try + { + progress = m_storage->check_files(m_have_pieces, m_num_pieces + , m_ses.m_mutex); + } + catch (std::exception& e) + { + // probably means file permission failure or invalid filename + std::fill(m_have_pieces.begin(), m_have_pieces.end(), false); + m_num_pieces = 0; + + if (m_ses.m_alerts.should_post(alert::fatal)) + { + m_ses.m_alerts.post_alert( + file_error_alert( + get_handle() + , e.what())); + } + pause(); + } #ifndef NDEBUG m_initial_done = boost::get<0>(bytes_done()); @@ -1402,7 +2141,14 @@ namespace libtorrent INVARIANT_CHECK; - m_picker->files_checked(m_have_pieces, unfinished_pieces); + if (!is_seed()) + { + m_picker->files_checked(m_have_pieces, unfinished_pieces); + } + else + { + m_picker.reset(); + } if (!m_connections_initialized) { m_connections_initialized = true; @@ -1412,7 +2158,12 @@ namespace libtorrent for (conn_map::iterator i = m_connections.begin() , end(m_connections.end()); i != end;) { - try { i->second->init(); ++i;} + try + { + i->second->init(); + i->second->on_metadata(); + ++i; + } catch (std::exception& e) { // the connection failed, close it @@ -1469,12 +2220,12 @@ namespace libtorrent { INVARIANT_CHECK; - return torrent_handle(&m_ses, 0, m_torrent_file.info_hash()); + return torrent_handle(&m_ses, &m_checker, m_torrent_file.info_hash()); } session_settings const& torrent::settings() const { - INVARIANT_CHECK; +// INVARIANT_CHECK; return m_ses.settings(); } @@ -1493,18 +2244,42 @@ namespace libtorrent assert(false); } + if (valid_metadata()) + { + assert(int(m_have_pieces.size()) == m_torrent_file.num_pieces()); + } + else + { + assert(m_have_pieces.empty()); + } + + size_type total_done = quantized_bytes_done(); + if (m_torrent_file.is_valid()) + { + if (is_seed()) + assert(total_done == m_torrent_file.total_size()); + else + assert(total_done != m_torrent_file.total_size()); + } + else + { + assert(total_done == 0); + } + // This check is very expensive. -// assert(m_num_pieces -// == std::count(m_have_pieces.begin(), m_have_pieces.end(), true)); - assert(m_priority >= 0.f && m_priority < 1.f); + assert(m_num_pieces + == std::count(m_have_pieces.begin(), m_have_pieces.end(), true)); assert(!valid_metadata() || m_block_size > 0); assert(!valid_metadata() || (m_torrent_file.piece_length() % m_block_size) == 0); +// if (is_seed()) assert(m_picker.get() == 0); } #endif void torrent::set_sequenced_download_threshold(int threshold) { - if (valid_metadata()) + // TODO: if there is not valid metadata, save this setting and + // set it once the piece picker is created. + if (valid_metadata() && !is_seed()) picker().set_sequenced_download_threshold(threshold); } @@ -1544,7 +2319,7 @@ namespace libtorrent assert(limit >= -1); if (limit == -1) limit = std::numeric_limits::max(); if (limit < num_peers() * 10) limit = num_peers() * 10; - m_upload_bandwidth_limit = limit; + m_bandwidth_limit[peer_connection::upload_channel].throttle(limit); } void torrent::set_download_limit(int limit) @@ -1552,7 +2327,7 @@ namespace libtorrent assert(limit >= -1); if (limit == -1) limit = std::numeric_limits::max(); if (limit < num_peers() * 10) limit = num_peers() * 10; - m_download_bandwidth_limit = limit; + m_bandwidth_limit[peer_connection::download_channel].throttle(limit); } void torrent::pause() @@ -1560,6 +2335,15 @@ namespace libtorrent INVARIANT_CHECK; if (m_paused) return; + +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + try { if ((*i)->on_pause()) return; } catch (std::exception&) {} + } +#endif + disconnect_all(); m_paused = true; // tell the tracker that we stopped @@ -1575,7 +2359,20 @@ namespace libtorrent INVARIANT_CHECK; if (!m_paused) return; + +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + try { if ((*i)->on_resume()) return; } catch (std::exception&) {} + } +#endif + m_paused = false; + m_uploads_quota.min = 2; + m_connections_quota.min = 2; + m_uploads_quota.max = std::numeric_limits::max(); + m_connections_quota.max = std::numeric_limits::max(); // tell the tracker that we're back m_event = tracker_request::started; @@ -1592,18 +2389,23 @@ namespace libtorrent m_connections_quota.used = (int)m_connections.size(); m_uploads_quota.used = m_policy->num_uploads(); - m_ul_bandwidth_quota.used = 0; - m_ul_bandwidth_quota.max = 0; - m_ul_bandwidth_quota.min = 0; - - m_dl_bandwidth_quota.used = 0; - m_dl_bandwidth_quota.min = 0; - m_dl_bandwidth_quota.max = 0; +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + try { (*i)->tick(); } catch (std::exception&) {} + } +#endif if (m_paused) { // let the stats fade out to 0 m_stat.second_tick(tick_interval); + m_web_stat.second_tick(tick_interval); + m_connections_quota.min = 0; + m_connections_quota.max = 0; + m_uploads_quota.min = 0; + m_uploads_quota.max = 0; return; } @@ -1644,41 +2446,20 @@ namespace libtorrent { peer_connection* p = i->second; m_stat += p->statistics(); + if (dynamic_cast(p)) + { + m_web_stat += p->statistics(); + } // updates the peer connection's ul/dl bandwidth // resource requests p->second_tick(tick_interval); - - m_ul_bandwidth_quota.used += p->m_ul_bandwidth_quota.used; - m_ul_bandwidth_quota.min += p->m_ul_bandwidth_quota.min; - m_dl_bandwidth_quota.used += p->m_dl_bandwidth_quota.used; - m_dl_bandwidth_quota.min += p->m_dl_bandwidth_quota.min; - - m_ul_bandwidth_quota.max = saturated_add( - m_ul_bandwidth_quota.max - , p->m_ul_bandwidth_quota.max); - - m_dl_bandwidth_quota.max = saturated_add( - m_dl_bandwidth_quota.max - , p->m_dl_bandwidth_quota.max); } - - m_ul_bandwidth_quota.max - = std::min(m_ul_bandwidth_quota.max, m_upload_bandwidth_limit); - - if (m_upload_bandwidth_limit == resource_request::inf) - m_ul_bandwidth_quota.max = resource_request::inf; - - m_dl_bandwidth_quota.max - = std::min(m_dl_bandwidth_quota.max, m_download_bandwidth_limit); - - if (m_download_bandwidth_limit == resource_request::inf) - m_dl_bandwidth_quota.max = resource_request::inf; - accumulator += m_stat; m_stat.second_tick(tick_interval); + m_web_stat.second_tick(tick_interval); } - void torrent::distribute_resources() + void torrent::distribute_resources(float tick_interval) { INVARIANT_CHECK; @@ -1688,37 +2469,11 @@ namespace libtorrent m_time_scaler = 10; m_policy->pulse(); } - - assert(m_ul_bandwidth_quota.given >= 0); - assert(m_dl_bandwidth_quota.given >= 0); - - // distribute allowed upload among the peers - allocate_resources(m_ul_bandwidth_quota.given - , m_connections - , &peer_connection::m_ul_bandwidth_quota); - - // distribute allowed download among the peers - allocate_resources(m_dl_bandwidth_quota.given - , m_connections - , &peer_connection::m_dl_bandwidth_quota); - - using boost::bind; - - // tell all peers to reset their used quota. This is - // a new second and they can again use up their quota - - for (std::map::iterator i - = m_connections.begin(); i != m_connections.end(); ++i) - { - i->second->reset_upload_quota(); - assert(i->second->m_dl_bandwidth_quota.used - <= i->second->m_dl_bandwidth_quota.given); - } } bool torrent::verify_piece(int piece_index) { - INVARIANT_CHECK; +// INVARIANT_CHECK; assert(m_storage.get()); assert(piece_index >= 0); @@ -1737,12 +2492,6 @@ namespace libtorrent if (m_torrent_file.hash_for_piece(piece_index) != digest) return false; - if (!m_have_pieces[piece_index]) - m_num_pieces++; - m_have_pieces[piece_index] = true; - - assert(std::accumulate(m_have_pieces.begin(), m_have_pieces.end(), 0) - == m_num_pieces); return true; } @@ -1754,22 +2503,6 @@ namespace libtorrent bool torrent::is_allocating() const { return m_storage.get() && m_storage->is_allocating(); } - std::vector const& torrent::metadata() const - { - INVARIANT_CHECK; - - if (m_metadata.empty()) - { - bencode(std::back_inserter(m_metadata) - , m_torrent_file.create_info_metadata()); - - assert(hasher(&m_metadata[0], m_metadata.size()).final() - == m_torrent_file.info_hash()); - } - assert(!m_metadata.empty()); - return m_metadata; - } - void torrent::file_progress(std::vector& fp) const { assert(valid_metadata()); @@ -1817,7 +2550,7 @@ namespace libtorrent torrent_status st; - st.num_peers = (int)std::count_if(m_connections.begin(), m_connections.end(), + st.num_peers = (int)std::count_if(m_connections.begin(), m_connections.end(), boost::bind(std::logical_not(), boost::bind(&peer_connection::is_connecting, boost::bind(&std::map::value_type::second, _1)))); @@ -1867,8 +2600,11 @@ namespace libtorrent else st.state = torrent_status::downloading_metadata; - if (m_metadata_size == 0) st.progress = 0.f; - else st.progress = std::min(1.f, m_metadata_progress / (float)m_metadata_size); +// TODO: add a progress member to the torrent that will be used in this case +// and that may be set by a plugin +// if (m_metadata_size == 0) st.progress = 0.f; +// else st.progress = std::min(1.f, m_metadata_progress / (float)m_metadata_size); + st.progress = 0.f; st.block_size = 0; @@ -1906,16 +2642,29 @@ namespace libtorrent st.num_pieces = m_num_pieces; if (m_got_tracker_response == false) + { st.state = torrent_status::connecting_to_tracker; - else if (m_num_pieces == (int)m_have_pieces.size()) + } + else if (is_seed()) + { + assert(st.total_done == m_torrent_file.total_size()); st.state = torrent_status::seeding; + } else if (st.total_wanted_done == st.total_wanted) + { + assert(st.total_done != m_torrent_file.total_size()); st.state = torrent_status::finished; + } else + { st.state = torrent_status::downloading; + } st.num_seeds = num_seeds(); - st.distributed_copies = m_picker->distributed_copies(); + if (m_picker.get()) + st.distributed_copies = m_picker->distributed_copies(); + else + st.distributed_copies = -1; return st; } @@ -1925,206 +2674,15 @@ namespace libtorrent return (int)std::count_if(m_connections.begin(), m_connections.end(), boost::bind(&peer_connection::is_seed, - boost::bind(&std::map::value_type::second, _1))); - } - - int div_round_up(int numerator, int denominator) - { - return (numerator + denominator - 1) / denominator; - } - - std::pair req_to_offset(std::pair req, int total_size) - { - assert(req.first >= 0); - assert(req.second > 0); - assert(req.second <= 256); - assert(req.first + req.second <= 256); - - int start = div_round_up(req.first * total_size, 256); - int size = div_round_up((req.first + req.second) * total_size, 256) - start; - return std::make_pair(start, size); - } - - std::pair offset_to_req(std::pair offset, int total_size) - { - int start = offset.first * 256 / total_size; - int size = (offset.first + offset.second) * 256 / total_size - start; - - std::pair ret(start, size); - - assert(start >= 0); - assert(size > 0); - assert(start <= 256); - assert(start + size <= 256); - - // assert the identity of this function -#ifndef NDEBUG - std::pair identity = req_to_offset(ret, total_size); - assert(offset == identity); -#endif - return ret; - } - - bool torrent::received_metadata(char const* buf, int size, int offset, int total_size) - { - INVARIANT_CHECK; - - if (valid_metadata()) return false; - - if ((int)m_metadata.size() < total_size) - m_metadata.resize(total_size); - - std::copy( - buf - , buf + size - , &m_metadata[offset]); - - if (m_have_metadata.empty()) - m_have_metadata.resize(256, false); - - std::pair req = offset_to_req(std::make_pair(offset, size) - , total_size); - - assert(req.first + req.second <= (int)m_have_metadata.size()); - - std::fill( - m_have_metadata.begin() + req.first - , m_have_metadata.begin() + req.first + req.second - , true); - - bool have_all = std::count( - m_have_metadata.begin() - , m_have_metadata.end() - , true) == 256; - - if (!have_all) return false; - - hasher h; - h.update(&m_metadata[0], (int)m_metadata.size()); - sha1_hash info_hash = h.final(); - - if (info_hash != m_torrent_file.info_hash()) - { - std::fill( - m_have_metadata.begin() - , m_have_metadata.begin() + req.first + req.second - , false); - m_metadata_progress = 0; - m_metadata_size = 0; - if (m_ses.m_alerts.should_post(alert::info)) - { - m_ses.m_alerts.post_alert(metadata_failed_alert( - get_handle(), "invalid metadata received from swarm")); - } - - return false; - } - - entry metadata = bdecode(m_metadata.begin(), m_metadata.end()); - m_torrent_file.parse_info_section(metadata); - - { - boost::mutex::scoped_lock(m_checker.m_mutex); - - boost::shared_ptr d( - new aux::piece_checker_data); - d->torrent_ptr = shared_from_this(); - d->save_path = m_save_path; - d->info_hash = m_torrent_file.info_hash(); - // add the torrent to the queue to be checked - m_checker.m_torrents.push_back(d); - typedef session_impl::torrent_map torrent_map; - torrent_map::iterator i = m_ses.m_torrents.find( - m_torrent_file.info_hash()); - assert(i != m_ses.m_torrents.end()); - m_ses.m_torrents.erase(i); - // and notify the thread that it got another - // job in its queue - m_checker.m_cond.notify_one(); - } - if (m_ses.m_alerts.should_post(alert::info)) - { - m_ses.m_alerts.post_alert(metadata_received_alert( - get_handle(), "metadata successfully received from swarm")); - } - - // clear the storage for the bitfield - std::vector().swap(m_have_metadata); - std::vector().swap(m_requested_metadata); - - return true; - } - - std::pair torrent::metadata_request() - { - INVARIANT_CHECK; - - // count the number of peers that supports the - // extension and that has metadata - int peers = 0; - typedef std::map conn_map; - for (conn_map::iterator i = m_connections.begin() - , end(m_connections.end()); i != end; ++i) - { - bt_peer_connection* c = dynamic_cast(i->second); - if (c == 0) continue; - if (!c->supports_extension( - extended_metadata_message)) - continue; - if (!c->has_metadata()) - continue; - ++peers; - } - - // the number of blocks to request - int num_blocks = 256 / (peers + 1); - if (num_blocks < 1) num_blocks = 1; - assert(num_blocks <= 128); - - int min_element = std::numeric_limits::max(); - int best_index = 0; - for (int i = 0; i < 256 - num_blocks + 1; ++i) - { - int min = *std::min_element(m_requested_metadata.begin() + i - , m_requested_metadata.begin() + i + num_blocks); - min += std::accumulate(m_requested_metadata.begin() + i - , m_requested_metadata.begin() + i + num_blocks, (int)0); - - if (min_element > min) - { - best_index = i; - min_element = min; - } - } - - std::pair ret(best_index, num_blocks); - for (int i = ret.first; i < ret.first + ret.second; ++i) - m_requested_metadata[i]++; - - assert(ret.first >= 0); - assert(ret.second > 0); - assert(ret.second <= 256); - assert(ret.first + ret.second <= 256); - - return ret; - } - - void torrent::cancel_metadata_request(std::pair req) - { - INVARIANT_CHECK; - - for (int i = req.first; i < req.first + req.second; ++i) - { - assert(m_requested_metadata[i] > 0); - if (m_requested_metadata[i] > 0) - --m_requested_metadata[i]; - } + boost::bind(&std::map::value_type::second, _1))); } void torrent::tracker_request_timed_out( tracker_request const&) { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + INVARIANT_CHECK; #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) @@ -2149,9 +2707,10 @@ namespace libtorrent void torrent::tracker_request_error(tracker_request const& , int response_code, const std::string& str) { + session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + INVARIANT_CHECK; - session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) debug_log(std::string("*** tracker error: ") + str); #endif @@ -2176,11 +2735,5 @@ namespace libtorrent } #endif - void torrent::metadata_progress(int total_size, int received) - { - m_metadata_progress += received; - m_metadata_size = total_size; - } - } diff --git a/libtorrent/src/torrent_handle.cpp b/libtorrent/src/torrent_handle.cpp index b8fe6f415..dcc46fd47 100644 --- a/libtorrent/src/torrent_handle.cpp +++ b/libtorrent/src/torrent_handle.cpp @@ -107,6 +107,9 @@ namespace libtorrent if (t) return f(*t); } + // throwing directly instead of calling + // the throw_invalid_handle() function + // avoids a warning in gcc throw invalid_handle(); } } @@ -346,6 +349,13 @@ namespace libtorrent , bind(&torrent::is_piece_filtered, _1, index)); } + std::string torrent_handle::name() const + { + INVARIANT_CHECK; + return call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::name, _1)); + } + std::vector torrent_handle::filtered_pieces() const { INVARIANT_CHECK; @@ -387,7 +397,7 @@ namespace libtorrent , bind(&torrent::replace_trackers, _1, urls)); } - const torrent_info& torrent_handle::get_torrent_info() const + torrent_info const& torrent_handle::get_torrent_info() const { INVARIANT_CHECK; @@ -445,57 +455,61 @@ namespace libtorrent entry::list_type& slots = ret["slots"].list(); std::copy(piece_index.begin(), piece_index.end(), std::back_inserter(slots)); - const piece_picker& p = t->picker(); - - const std::vector& q - = p.get_download_queue(); - // blocks per piece int num_blocks_per_piece = static_cast(t->torrent_file().piece_length()) / t->block_size(); ret["blocks per piece"] = num_blocks_per_piece; - // unfinished pieces - ret["unfinished"] = entry::list_type(); - entry::list_type& up = ret["unfinished"].list(); - - // info for each unfinished piece - for (std::vector::const_iterator i - = q.begin(); i != q.end(); ++i) + // if this torrent is a seed, we won't have a piece picker + // and there will be no half-finished pieces. + if (!t->is_seed()) { - if (i->finished_blocks.count() == 0) continue; + const piece_picker& p = t->picker(); - entry piece_struct(entry::dictionary_t); + const std::vector& q + = p.get_download_queue(); - // the unfinished piece's index - piece_struct["piece"] = i->index; + // unfinished pieces + ret["unfinished"] = entry::list_type(); + entry::list_type& up = ret["unfinished"].list(); - std::string bitmask; - const int num_bitmask_bytes - = std::max(num_blocks_per_piece / 8, 1); - - for (int j = 0; j < num_bitmask_bytes; ++j) + // info for each unfinished piece + for (std::vector::const_iterator i + = q.begin(); i != q.end(); ++i) { - unsigned char v = 0; - for (int k = 0; k < 8; ++k) - v |= i->finished_blocks[j*8+k]?(1 << k):0; - bitmask.insert(bitmask.end(), v); + if (i->finished_blocks.count() == 0) continue; + + entry piece_struct(entry::dictionary_t); + + // the unfinished piece's index + piece_struct["piece"] = i->index; + + std::string bitmask; + const int num_bitmask_bytes + = std::max(num_blocks_per_piece / 8, 1); + + for (int j = 0; j < num_bitmask_bytes; ++j) + { + unsigned char v = 0; + for (int k = 0; k < 8; ++k) + v |= i->finished_blocks[j*8+k]?(1 << k):0; + bitmask.insert(bitmask.end(), v); + } + piece_struct["bitmask"] = bitmask; + + assert(t->filesystem().slot_for_piece(i->index) >= 0); + unsigned long adler + = t->filesystem().piece_crc( + t->filesystem().slot_for_piece(i->index) + , t->block_size() + , i->finished_blocks); + + piece_struct["adler32"] = adler; + + // push the struct onto the unfinished-piece list + up.push_back(piece_struct); } - piece_struct["bitmask"] = bitmask; - - assert(t->filesystem().slot_for_piece(i->index) >= 0); - unsigned long adler - = t->filesystem().piece_crc( - t->filesystem().slot_for_piece(i->index) - , t->block_size() - , i->finished_blocks); - - piece_struct["adler32"] = adler; - - // push the struct onto the unfinished-piece list - up.push_back(piece_struct); } - // write local peers ret["peers"] = entry::list_type(); @@ -549,14 +563,6 @@ namespace libtorrent , bind(&torrent::save_path, _1)); } - std::vector const& torrent_handle::metadata() const - { - INVARIANT_CHECK; - - return call_member const&>(m_ses, m_chk, m_info_hash - , bind(&torrent::metadata, _1)); - } - void torrent_handle::connect_peer(tcp::endpoint const& adr) const { INVARIANT_CHECK; @@ -626,6 +632,20 @@ namespace libtorrent , bind(&torrent::set_ratio, _1, ratio)); } + void torrent_handle::resolve_countries(bool r) + { + INVARIANT_CHECK; + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::resolve_countries, _1, r)); + } + + bool torrent_handle::resolve_countries() const + { + INVARIANT_CHECK; + return call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::resolving_countries, _1)); + } + void torrent_handle::get_peer_info(std::vector& v) const { INVARIANT_CHECK; @@ -651,44 +671,10 @@ namespace libtorrent peer_info& p = v.back(); peer->get_peer_info(p); + if (t->resolving_countries()) + t->resolve_peer_country(intrusive_ptr(peer)); } } - - bool torrent_handle::send_chat_message(tcp::endpoint ip, std::string message) const - { - if (m_ses == 0) throw_invalid_handle(); - - session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); - boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); - if (!t) return false; - - for (torrent::const_peer_iterator i = t->begin(); - i != t->end(); ++i) - { - peer_connection* peer = i->second; - - // peers that haven't finished the handshake should - // not be included in this list - if (peer->associated_torrent().expired()) continue; - - tcp::endpoint sender = peer->get_socket()->remote_endpoint(); - // loop until we find the required ip tcp::endpoint - if (ip != sender) continue; - - bt_peer_connection* p = dynamic_cast(peer); - if (!p) return false; - - // peers that don's support chat message extension - // should not be included either - if (!p->supports_extension(extended_chat_message)) - return false; - - // send the message - p->write_chat_message(message); - return true; - } - return false; - } void torrent_handle::get_download_queue(std::vector& queue) const { @@ -702,6 +688,8 @@ namespace libtorrent queue.clear(); if (!t) return; if (!t->valid_metadata()) return; + // if we're a seed, the piece picker has been removed + if (t->is_seed()) return; const piece_picker& p = t->picker(); diff --git a/libtorrent/src/torrent_info.cpp b/libtorrent/src/torrent_info.cpp index 6b008369b..238864283 100644 --- a/libtorrent/src/torrent_info.cpp +++ b/libtorrent/src/torrent_info.cpp @@ -238,23 +238,25 @@ namespace libtorrent // just the necessary to use it with piece manager // used for torrents with no metadata torrent_info::torrent_info(sha1_hash const& info_hash) - : m_piece_length(256 * 1024) + : m_piece_length(0) , m_total_size(0) , m_info_hash(info_hash) , m_name() , m_creation_date(second_clock::universal_time()) , m_multifile(false) + , m_private(false) , m_extra_info(entry::dictionary_t) { } torrent_info::torrent_info() - : m_piece_length(256 * 1024) + : m_piece_length(0) , m_total_size(0) , m_info_hash(0) , m_name() , m_creation_date(second_clock::universal_time()) , m_multifile(false) + , m_private(false) , m_extra_info(entry::dictionary_t) { } @@ -538,21 +540,23 @@ namespace libtorrent file_entry e; e.path = file; e.size = size; + e.offset = m_files.empty() ? 0 : m_files.back().offset + + m_files.back().size; m_files.push_back(e); m_total_size += size; + + if (m_piece_length == 0) + m_piece_length = 256 * 1024; int num_pieces = static_cast( (m_total_size + m_piece_length - 1) / m_piece_length); int old_num_pieces = static_cast(m_piece_hash.size()); m_piece_hash.resize(num_pieces); - for (std::vector::iterator i = m_piece_hash.begin() + old_num_pieces; - i != m_piece_hash.end(); ++i) - { - i->clear(); - } - + if (num_pieces > old_num_pieces) + std::for_each(m_piece_hash.begin() + old_num_pieces + , m_piece_hash.end(), boost::bind(&sha1_hash::clear, _1)); } void torrent_info::add_url_seed(std::string const& url) @@ -591,16 +595,14 @@ namespace libtorrent if (!info.find_key("files")) { entry& files = info["files"]; - files = entry(entry::list_t); for (std::vector::const_iterator i = m_files.begin(); i != m_files.end(); ++i) { - files.list().push_back(entry(entry::dictionary_t)); + files.list().push_back(entry()); entry& file_e = files.list().back(); file_e["length"] = i->size; entry& path_e = file_e["path"]; - path_e = entry(entry::list_t); fs::path const* file_path; if (i->orig_path) file_path = &(*i->orig_path); @@ -619,7 +621,6 @@ namespace libtorrent info["piece length"] = piece_length(); entry& pieces = info["pieces"]; - pieces = entry(entry::string_t); std::string& p = pieces.string(); @@ -641,8 +642,6 @@ namespace libtorrent namespace fs = boost::filesystem; - entry dict(entry::dictionary_t); - if ((m_urls.empty() && m_nodes.empty()) || m_files.empty()) { // TODO: throw something here @@ -650,6 +649,8 @@ namespace libtorrent return entry(); } + entry dict; + if (m_private) dict["private"] = 1; if (!m_urls.empty()) @@ -658,7 +659,6 @@ namespace libtorrent if (!m_nodes.empty()) { entry& nodes = dict["nodes"]; - nodes = entry(entry::list_t); entry::list_type& nodes_list = nodes.list(); for (nodes_t::const_iterator i = m_nodes.begin() , end(m_nodes.end()); i != end; ++i) @@ -708,7 +708,6 @@ namespace libtorrent else { entry& list = dict["url-list"]; - list = entry(entry::list_t); for (std::vector::const_iterator i = m_url_seeds.begin(); i != m_url_seeds.end(); ++i) { diff --git a/libtorrent/src/tracker_manager.cpp b/libtorrent/src/tracker_manager.cpp index 20e234c1f..f27620072 100644 --- a/libtorrent/src/tracker_manager.cpp +++ b/libtorrent/src/tracker_manager.cpp @@ -46,6 +46,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/entry.hpp" #include "libtorrent/bencode.hpp" #include "libtorrent/torrent.hpp" +#include "libtorrent/peer_connection.hpp" using namespace libtorrent; using boost::tuples::make_tuple; @@ -313,11 +314,11 @@ namespace libtorrent } - timeout_handler::timeout_handler(demuxer& d) - : m_demuxer(d) + timeout_handler::timeout_handler(asio::strand& str) + : m_strand(str) , m_start_time(second_clock::universal_time()) , m_read_time(second_clock::universal_time()) - , m_timeout(d) + , m_timeout(str.io_service()) , m_completion_timeout(0) , m_read_timeout(0) , m_refs(0) @@ -333,7 +334,8 @@ namespace libtorrent m_timeout.expires_at(std::min( m_read_time + seconds(m_read_timeout) , m_start_time + seconds(m_completion_timeout))); - m_timeout.async_wait(bind(&timeout_handler::timeout_callback, self(), _1)); + m_timeout.async_wait(m_strand.wrap(bind( + &timeout_handler::timeout_callback, self(), _1))); } void timeout_handler::restart_read_timeout() @@ -347,7 +349,7 @@ namespace libtorrent m_timeout.cancel(); } - void timeout_handler::timeout_callback(asio::error const& error) try + void timeout_handler::timeout_callback(asio::error_code const& error) try { if (error) return; if (m_completion_timeout == 0) return; @@ -368,7 +370,8 @@ namespace libtorrent m_timeout.expires_at(std::min( m_read_time + seconds(m_read_timeout) , m_start_time + seconds(m_completion_timeout))); - m_timeout.async_wait(bind(&timeout_handler::timeout_callback, self(), _1)); + m_timeout.async_wait(m_strand.wrap( + bind(&timeout_handler::timeout_callback, self(), _1))); } catch (std::exception& e) { @@ -378,10 +381,12 @@ namespace libtorrent tracker_connection::tracker_connection( tracker_manager& man , tracker_request req - , demuxer& d + , asio::strand& str + , address bind_interface_ , boost::weak_ptr r) - : timeout_handler(d) + : timeout_handler(str) , m_requester(r) + , m_bind_interface(bind_interface_) , m_man(man) , m_req(req) {} @@ -478,9 +483,10 @@ namespace libtorrent } void tracker_manager::queue_request( - demuxer& d + asio::strand& str , tracker_request req , std::string const& auth + , address bind_infc , boost::weak_ptr c) { mutex_t::scoped_lock l(m_mutex); @@ -503,12 +509,13 @@ namespace libtorrent if (protocol == "http") { con = new http_tracker_connection( - d + str , *this , req , hostname , port , request_string + , bind_infc , c , m_settings , auth); @@ -516,11 +523,12 @@ namespace libtorrent else if (protocol == "udp") { con = new udp_tracker_connection( - d + str , *this , req , hostname , port + , bind_infc , c , m_settings); } diff --git a/libtorrent/src/udp_tracker_connection.cpp b/libtorrent/src/udp_tracker_connection.cpp index 2a1e97d1a..16aec7691 100644 --- a/libtorrent/src/udp_tracker_connection.cpp +++ b/libtorrent/src/udp_tracker_connection.cpp @@ -73,38 +73,39 @@ namespace libtorrent { udp_tracker_connection::udp_tracker_connection( - demuxer& d + asio::strand& str , tracker_manager& man , tracker_request const& req , std::string const& hostname , unsigned short port + , address bind_infc , boost::weak_ptr c , session_settings const& stn) - : tracker_connection(man, req, d, c) + : tracker_connection(man, req, str, bind_infc, c) , m_man(man) - , m_name_lookup(d) - , m_port(port) + , m_strand(str) + , m_name_lookup(m_strand.io_service()) , m_transaction_id(0) , m_connection_id(0) , m_settings(stn) , m_attempts(0) { - m_socket.reset(new datagram_socket(d)); - tcp::resolver::query q(hostname, "0"); + udp::resolver::query q(hostname, boost::lexical_cast(port)); m_name_lookup.async_resolve(q - , boost::bind(&udp_tracker_connection::name_lookup, self(), _1, _2)); + , m_strand.wrap(boost::bind( + &udp_tracker_connection::name_lookup, self(), _1, _2))); set_timeout(m_settings.tracker_completion_timeout , m_settings.tracker_receive_timeout); } - void udp_tracker_connection::name_lookup(asio::error const& error - , tcp::resolver::iterator i) try + void udp_tracker_connection::name_lookup(asio::error_code const& error + , udp::resolver::iterator i) try { if (error == asio::error::operation_aborted) return; if (!m_socket) return; // the operation was aborted - if (error || i == tcp::resolver::iterator()) + if (error || i == udp::resolver::iterator()) { - fail(-1, error.what()); + fail(-1, error.message().c_str()); return; } @@ -112,10 +113,38 @@ namespace libtorrent if (has_requester()) requester().debug_log("udp tracker name lookup successful"); #endif restart_read_timeout(); - m_target = udp::endpoint(i->endpoint().address(), m_port); - if (has_requester()) requester().m_tracker_address - = tcp::endpoint(i->endpoint().address(), m_port); - m_socket->connect(m_target); + + // look for an address that has the same kind as the one + // we're listening on. To make sure the tracker get our + // correct listening address. + udp::resolver::iterator target = i; + udp::resolver::iterator end; + udp::endpoint target_address = *i; + for (; target != end && target->endpoint().address().is_v4() + != bind_interface().is_v4(); ++target); + if (target == end) + { + assert(target_address.address().is_v4() != bind_interface().is_v4()); + if (has_requester()) + { + std::string tracker_address_type = target_address.address().is_v4() ? "IPv4" : "IPv6"; + std::string bind_address_type = bind_interface().is_v4() ? "IPv4" : "IPv6"; + requester().tracker_warning("the tracker only resolves to an " + + tracker_address_type + " address, and you're listening on an " + + bind_address_type + " socket. This may prevent you from receiving incoming connections."); + } + } + else + { + target_address = *target; + } + + if (has_requester()) requester().m_tracker_address = tcp::endpoint(target_address.address(), target_address.port()); + m_target = target_address; + m_socket.reset(new datagram_socket(m_name_lookup.io_service())); + m_socket->open(target_address.protocol()); + m_socket->bind(udp::endpoint(bind_interface(), 0)); + m_socket->connect(target_address); send_udp_connect(); } catch (std::exception& e) @@ -162,14 +191,14 @@ namespace libtorrent , boost::bind(&udp_tracker_connection::connect_response, self(), _1, _2)); } - void udp_tracker_connection::connect_response(asio::error const& error + void udp_tracker_connection::connect_response(asio::error_code const& error , std::size_t bytes_transferred) try { if (error == asio::error::operation_aborted) return; if (!m_socket) return; // the operation was aborted if (error) { - fail(-1, error.what()); + fail(-1, error.message().c_str()); return; } @@ -328,14 +357,14 @@ namespace libtorrent , bind(&udp_tracker_connection::scrape_response, self(), _1, _2)); } - void udp_tracker_connection::announce_response(asio::error const& error + void udp_tracker_connection::announce_response(asio::error_code const& error , std::size_t bytes_transferred) try { if (error == asio::error::operation_aborted) return; if (!m_socket) return; // the operation was aborted if (error) { - fail(-1, error.what()); + fail(-1, error.message().c_str()); return; } @@ -437,14 +466,14 @@ namespace libtorrent fail(-1, e.what()); }; // msvc 7.1 seems to require this - void udp_tracker_connection::scrape_response(asio::error const& error + void udp_tracker_connection::scrape_response(asio::error_code const& error , std::size_t bytes_transferred) try { if (error == asio::error::operation_aborted) return; if (!m_socket) return; // the operation was aborted if (error) { - fail(-1, error.what()); + fail(-1, error.message().c_str()); return; } diff --git a/libtorrent/src/ut_pex.cpp b/libtorrent/src/ut_pex.cpp new file mode 100644 index 000000000..e1da13f76 --- /dev/null +++ b/libtorrent/src/ut_pex.cpp @@ -0,0 +1,273 @@ +/* + +Copyright (c) 2006, MassaRoddel, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/peer_connection.hpp" +#include "libtorrent/bt_peer_connection.hpp" +#include "libtorrent/bencode.hpp" +#include "libtorrent/torrent.hpp" +#include "libtorrent/extensions.hpp" + +#include "libtorrent/extensions/ut_pex.hpp" + +namespace libtorrent { namespace +{ + const char extension_name[] = "ut_pex"; + + enum + { + extension_index = 1, + max_peer_entries = 100 + }; + + struct ut_pex_plugin: torrent_plugin + { + ut_pex_plugin(torrent& t): m_torrent(t), m_1_minute(0) {} + + virtual boost::shared_ptr new_connection(peer_connection* pc); + + std::vector& get_ut_pex_msg() + { + return m_ut_pex_msg; + } + + // the second tick of the torrent + // each minute the new lists of "added" + "added.f" and "dropped" + // are calculated here and the pex message is created + // each peer connection will use this message + // max_peer_entries limits the packet size + virtual void tick() + { + if (++m_1_minute < 60) return; + + m_1_minute = 0; + std::list cs; + for (torrent::peer_iterator i = m_torrent.begin() + , end(m_torrent.end()); i != end; ++i) + { + // don't send out peers that we haven't connected to + // (that have connected to us) + if (!i->second->is_local()) continue; + // don't send out peers that we haven't successfully connected to + if (i->second->is_connecting()) continue; + cs.push_back(i->first); + } + std::list added_peers, dropped_peers; + + std::set_difference(cs.begin(), cs.end(), m_old_peers.begin() + , m_old_peers.end(), std::back_inserter(added_peers)); + std::set_difference(m_old_peers.begin(), m_old_peers.end() + , cs.begin(), cs.end(), std::back_inserter(dropped_peers)); + m_old_peers = cs; + + unsigned int num_peers = max_peer_entries; + + std::string pla, pld, plf; + std::back_insert_iterator pla_out(pla); + std::back_insert_iterator pld_out(pld); + std::back_insert_iterator plf_out(plf); + + // TODO: use random selection in case added_peers.size() > num_peers + for (std::list::const_iterator i = added_peers.begin() + , end(added_peers.end());i != end; ++i) + { + if (!i->address().is_v4()) continue; + detail::write_endpoint(*i, pla_out); + // no supported flags to set yet + // 0x01 - peer supports encryption + detail::write_uint8(0, plf_out); + + if (--num_peers == 0) break; + } + + num_peers = max_peer_entries; + // TODO: use random selection in case dropped_peers.size() > num_peers + for (std::list::const_iterator i = dropped_peers.begin() + , end(dropped_peers.end());i != end; ++i) + { + if (!i->address().is_v4()) continue; + detail::write_endpoint(*i, pld_out); + + if (--num_peers == 0) break; + } + + entry pex(entry::dictionary_t); + pex["added"] = pla; + pex["dropped"] = pld; + pex["added.f"] = plf; + + m_ut_pex_msg.clear(); + bencode(std::back_inserter(m_ut_pex_msg), pex); + } + + private: + torrent& m_torrent; + + std::list m_old_peers; + int m_1_minute; + std::vector m_ut_pex_msg; + }; + + + struct ut_pex_peer_plugin : peer_plugin + { + ut_pex_peer_plugin(torrent& t, peer_connection& pc, ut_pex_plugin& tp) + : m_torrent(t) + , m_pc(pc) + , m_tp(tp) + , m_1_minute(0) + , m_message_index(0) + {} + + virtual void add_handshake(entry& h) + { + entry& messages = h["m"]; + messages[extension_name] = extension_index; + } + + virtual bool on_extension_handshake(entry const& h) + { + entry const& messages = h["m"]; + + if (entry const* index = messages.find_key(extension_name)) + { + m_message_index = index->integer(); + return true; + } + else + { + m_message_index = 0; + return false; + } + } + + virtual bool on_extended(int length, int msg, buffer::const_interval body) + { + if (msg != extension_index) return false; + if (m_message_index == 0) return false; + + if (length > 500 * 1024) + throw protocol_error("ut peer exchange message larger than 500 kB"); + + if (body.left() < length) return true; + + // in case we are a seed we do not use the peers + // from the pex message to prevent us from + // overloading ourself + if (m_torrent.is_seed()) return true; + + entry Pex = bdecode(body.begin, body.end); + entry* PeerList = Pex.find_key("added"); + + if (!PeerList) return true; + std::string const& peers = PeerList->string(); + int num_peers = peers.length() / 6; + char const* in = peers.c_str(); + + peer_id pid; + pid.clear(); + policy& p = m_torrent.get_policy(); + for (int i = 0; i < num_peers; ++i) + { + tcp::endpoint adr = detail::read_v4_endpoint(in); + if (!m_torrent.connection_for(adr)) p.peer_from_tracker(adr, pid); + } + return true; + } + + // the peers second tick + // every minute we send a pex message + virtual void tick() + { + if (!m_message_index) return; // no handshake yet + if (++m_1_minute <= 60) return; + + send_ut_peer_list(); + m_1_minute = 0; + } + + private: + + void send_ut_peer_list() + { + std::vector& pex_msg = m_tp.get_ut_pex_msg(); + + buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size()); + + detail::write_uint32(1 + 1 + pex_msg.size(), i.begin); + detail::write_uint8(bt_peer_connection::msg_extended, i.begin); + detail::write_uint8(m_message_index, i.begin); + std::copy(pex_msg.begin(), pex_msg.end(), i.begin); + i.begin += pex_msg.size(); + + assert(i.begin == i.end); + m_pc.setup_send(); + } + + torrent& m_torrent; + peer_connection& m_pc; + ut_pex_plugin& m_tp; + int m_1_minute; + int m_message_index; + }; + + boost::shared_ptr ut_pex_plugin::new_connection(peer_connection* pc) + { + return boost::shared_ptr(new ut_pex_peer_plugin(m_torrent + , *pc, *this)); + } +}} + +namespace libtorrent +{ + + boost::shared_ptr create_ut_pex_plugin(torrent* t) + { + if (t->torrent_file().priv()) + { + return boost::shared_ptr(); + } + return boost::shared_ptr(new ut_pex_plugin(*t)); + } + +} + + diff --git a/libtorrent/src/web_peer_connection.cpp b/libtorrent/src/web_peer_connection.cpp index 5be9610f4..65652db2e 100644 --- a/libtorrent/src/web_peer_connection.cpp +++ b/libtorrent/src/web_peer_connection.cpp @@ -60,14 +60,30 @@ namespace libtorrent , boost::weak_ptr t , boost::shared_ptr s , tcp::endpoint const& remote + , tcp::endpoint const& proxy , std::string const& url) - : peer_connection(ses, t, s, remote) + : peer_connection(ses, t, s, remote, proxy) , m_url(url) , m_first_request(true) { INVARIANT_CHECK; - m_max_out_request_queue = ses.settings().urlseed_pipeline_size; + // we always prefer downloading entire + // pieces from web seeds + prefer_whole_pieces(true); + // we want large blocks as well, so + // we can request more bytes at once + request_large_blocks(true); + // we only want left-over bandwidth + set_non_prioritized(true); + shared_ptr tor = t.lock(); + assert(tor); + int blocks_per_piece = tor->torrent_file().piece_length() / tor->block_size(); + + // multiply with the blocks per piece since that many requests are + // merged into one http request + m_max_out_request_queue = ses.settings().urlseed_pipeline_size + * blocks_per_piece; // since this is a web seed, change the timeout // according to the settings. @@ -96,15 +112,17 @@ namespace libtorrent boost::shared_ptr t = associated_torrent().lock(); assert(t); - int body_start = m_parser.body_start(); - buffer::const_interval recv_buffer = receive_buffer(); - assert(body_start <= recv_buffer.left()); + buffer::const_interval http_body = m_parser.get_body(); piece_block_progress ret; ret.piece_index = m_requests.front().piece; - ret.block_index = m_requests.front().start / t->block_size(); - ret.bytes_downloaded = recv_buffer.left() - body_start; - ret.full_block_bytes = m_requests.front().length; + ret.bytes_downloaded = http_body.left() % t->block_size(); + ret.block_index = (m_requests.front().start + ret.bytes_downloaded) / t->block_size(); + ret.full_block_bytes = t->block_size(); + const int last_piece = t->torrent_file().num_pieces() - 1; + if (ret.piece_index == last_piece && ret.block_index + == t->torrent_file().piece_size(last_piece) / t->block_size()) + ret.full_block_bytes = t->torrent_file().piece_size(last_piece) % t->block_size(); return ret; } @@ -119,7 +137,7 @@ namespace libtorrent // it is always possible to request pieces incoming_unchoke(); - reset_recv_buffer(512*1024+1024); + reset_recv_buffer(t->torrent_file().piece_length() + 1024 * 2); } void web_peer_connection::write_request(peer_request const& r) @@ -139,7 +157,16 @@ namespace libtorrent std::string request; - m_requests.push_back(r); + int size = r.length; + const int block_size = t->block_size(); + while (size > 0) + { + int request_size = std::min(block_size, size); + peer_request pr = {r.piece, r.start + r.length - size + , request_size}; + m_requests.push_back(pr); + size -= request_size; + } bool using_proxy = false; if (!m_ses.settings().proxy_ip.empty()) @@ -148,8 +175,9 @@ namespace libtorrent if (single_file_request) { request += "GET "; - if (using_proxy) request += m_url; - else request += escape_path(m_path.c_str(), m_path.length()); + // do not encode single file paths, they are + // assumed to be encoded in the torrent file + request += using_proxy ? m_url : m_path; request += " HTTP/1.1\r\n"; request += "Host: "; request += m_host; @@ -233,6 +261,10 @@ namespace libtorrent } } +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << request << "\n"; +#endif + send_buffer(request.c_str(), request.c_str() + request.size()); } @@ -240,16 +272,22 @@ namespace libtorrent // RECEIVE DATA // -------------------------- + namespace + { + bool range_contains(peer_request const& range, peer_request const& req) + { + return range.start <= req.start + && range.start + range.length >= req.start + req.length; + } + } + // throws exception when the client should be disconnected - void web_peer_connection::on_receive(const asio::error& error + void web_peer_connection::on_receive(asio::error_code const& error , std::size_t bytes_transferred) { INVARIANT_CHECK; - if (error) - { - return; - } + if (error) return; boost::shared_ptr t = associated_torrent().lock(); assert(t); @@ -259,46 +297,126 @@ namespace libtorrent for (;;) { buffer::const_interval recv_buffer = receive_buffer(); + int payload; int protocol; + bool header_finished = m_parser.header_finished(); boost::tie(payload, protocol) = m_parser.incoming(recv_buffer); m_statistics.received_bytes(payload, protocol); + + assert(recv_buffer.left() <= packet_size()); + assert (recv_buffer.left() < packet_size() + || m_parser.finished()); + + // this means the entire status line hasn't been received yet + if (m_parser.status_code() == -1) break; - if (m_parser.status_code() != 206 && m_parser.status_code() != -1) + // if the status code is not one of the accepted ones, abort + if (m_parser.status_code() != 206 // partial content + && m_parser.status_code() != 200 // OK + && !(m_parser.status_code() >= 300 // redirect + && m_parser.status_code() < 400)) { // we should not try this server again. t->remove_url_seed(m_url); - if (m_parser.status_code() == 404) - throw std::runtime_error("File not found on server"); - throw std::runtime_error("HTTP server does not support byte range requests"); + std::string error_msg = boost::lexical_cast(m_parser.status_code()) + + " " + m_parser.message(); + if (m_ses.m_alerts.should_post(alert::warning)) + { + session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + m_ses.m_alerts.post_alert(url_seed_alert(t->get_handle(), url() + , error_msg)); + } + throw std::runtime_error(error_msg); } - if (!m_parser.finished()) break; + if (!m_parser.header_finished()) break; - std::string server_version = m_parser.header("Server"); - if (!server_version.empty()) + // we just completed reading the header + if (!header_finished) { - m_server_string = "URL seed @ "; - m_server_string += m_host; - m_server_string += " ("; - m_server_string += server_version; - m_server_string += ")"; + if (m_parser.status_code() >= 300 && m_parser.status_code() < 400) + { + // this means we got a redirection request + // look for the location header + std::string location = m_parser.header("location"); + + if (location.empty()) + { + // we should not try this server again. + t->remove_url_seed(m_url); + throw std::runtime_error("got HTTP redirection status without location header"); + } + + bool single_file_request = false; + if (!m_path.empty() && m_path[m_path.size() - 1] != '/') + single_file_request = true; + + // add the redirected url and remove the current one + if (!single_file_request) + { + assert(!m_file_requests.empty()); + int file_index = m_file_requests.front(); + + torrent_info const& info = t->torrent_file(); + std::string path = info.file_at(file_index).path.string(); + path = escape_path(path.c_str(), path.length()); + size_t i = location.rfind(path); + if (i == std::string::npos) + { + t->remove_url_seed(m_url); + throw std::runtime_error("got invalid HTTP redirection location (\"" + location + "\") " + "expected it to end with: " + path); + } + location.resize(i); + } + t->add_url_seed(location); + t->remove_url_seed(m_url); + throw std::runtime_error("redirecting to " + location); + } + + std::string server_version = m_parser.header("server"); + if (!server_version.empty()) + { + m_server_string = "URL seed @ "; + m_server_string += m_host; + m_server_string += " ("; + m_server_string += server_version; + m_server_string += ")"; + } + } - std::stringstream range_str(m_parser.header("Content-Range")); + buffer::const_interval http_body = m_parser.get_body(); + size_type range_start; size_type range_end; - char dummy; - std::string bytes; - range_str >> bytes >> range_start >> dummy >> range_end; - if (!range_str) + if (m_parser.status_code() == 206) { - // we should not try this server again. - t->remove_url_seed(m_url); - throw std::runtime_error("invalid range in HTTP response: " + range_str.str()); + std::stringstream range_str(m_parser.header("content-range")); + char dummy; + std::string bytes; + range_str >> bytes >> range_start >> dummy >> range_end; + if (!range_str) + { + // we should not try this server again. + t->remove_url_seed(m_url); + throw std::runtime_error("invalid range in HTTP response: " + range_str.str()); + } + // the http range is inclusive + range_end++; + } + else + { + range_start = 0; + range_end = m_parser.header("content-length"); + if (range_end == -1) + { + // we should not try this server again. + t->remove_url_seed(m_url); + throw std::runtime_error("no content-length in HTTP response"); + } } - // the http range is inclusive - range_end++; torrent_info const& info = t->torrent_file(); @@ -306,67 +424,112 @@ namespace libtorrent throw std::runtime_error("unexpected HTTP response"); int file_index = m_file_requests.front(); - m_file_requests.pop_front(); - - peer_request r = info.map_file(file_index, range_start + peer_request in_range = info.map_file(file_index, range_start , range_end - range_start); - buffer::const_interval http_body = m_parser.get_body(); - - if (r == m_requests.front()) + peer_request front_request = m_requests.front(); + if (in_range.piece != front_request.piece + || in_range.start > front_request.start + int(m_piece.size())) { - m_requests.pop_front(); - incoming_piece(r, http_body.begin); - cut_receive_buffer(http_body.end - recv_buffer.begin, 512*1024+1024); - return; + throw std::runtime_error("invalid range in HTTP response"); } - if (!m_piece.empty()) - { - // this is not the first partial request we get - if (m_intermediate_piece.start + m_intermediate_piece.length != r.start - || m_intermediate_piece.piece != r.piece) - { - throw std::runtime_error("invalid range in HTTP response"); - } - } - else - { - // this is the first part of a partial request - if (r.start != m_requests.front().start - || r.piece != m_requests.front().piece) - { - throw std::runtime_error("invalid range in HTTP response"); - } - m_intermediate_piece.piece = r.piece; - m_intermediate_piece.start = r.start; - m_intermediate_piece.length = 0; - } + front_request = m_requests.front(); - m_piece.reserve(info.piece_length()); - std::copy(http_body.begin, http_body.end, back_inserter(m_piece)); - m_intermediate_piece.length += r.length; - if (m_intermediate_piece.length == m_requests.front().length) + // skip the http header and the blocks we've already read. The + // http_body.begin is now in sync with the request at the front + // of the request queue + assert(in_range.start - int(m_piece.size()) <= front_request.start); + http_body.begin += front_request.start - in_range.start + int(m_piece.size()); + + // the http response body consists of 3 parts + // 1. the middle of a block or the ending of a block + // 2. a number of whole blocks + // 3. the start of a block + // in that order, these parts are parsed. + + bool range_overlaps_request = in_range.start + in_range.length + > front_request.start + int(m_piece.size()); + + // if the request is contained in the range (i.e. the entire request + // fits in the range) we should not start a partial piece, since we soon + // will receive enough to call incoming_piece() and pass the read buffer + // directly (in the next loop below). + if (range_overlaps_request && !range_contains(in_range, front_request)) { - assert(m_requests.front() == m_intermediate_piece); - assert(int(m_piece.size()) == m_intermediate_piece.length); + // the start of the next block to receive is stored + // in m_piece. We need to append the rest of that + // block from the http receive buffer and then + // (if it completed) call incoming_piece() with + // m_piece as buffer. + + m_piece.reserve(info.piece_length()); + int copy_size = std::min(front_request.length - int(m_piece.size()) + , http_body.left()); + std::copy(http_body.begin, http_body.begin + copy_size, std::back_inserter(m_piece)); + assert(int(m_piece.size()) <= front_request.length); + http_body.begin += copy_size; + int piece_size = int(m_piece.size()); + if (piece_size < front_request.length) + return; + + // each call to incoming_piece() may result in us becoming + // a seed. If we become a seed, all seeds we're connected to + // will be disconnected, including this web seed. We need to + // check for the disconnect condition after the call. + m_requests.pop_front(); - incoming_piece(m_intermediate_piece, &m_piece[0]); + incoming_piece(front_request, &m_piece[0]); + if (associated_torrent().expired()) return; m_piece.clear(); } - else if (m_intermediate_piece.length > m_requests.front().length) + + // report all received blocks to the bittorrent engine + while (!m_requests.empty() + && range_contains(in_range, m_requests.front()) + && http_body.left() >= m_requests.front().length) { - throw std::runtime_error("too large HTTP response body"); + peer_request r = m_requests.front(); + m_requests.pop_front(); + assert(http_body.begin == recv_buffer.begin + m_parser.body_start() + + r.start - in_range.start); + assert(http_body.left() >= r.length); + + incoming_piece(r, http_body.begin); + if (associated_torrent().expired()) return; + http_body.begin += r.length; } - cut_receive_buffer(http_body.end - recv_buffer.begin, 512*1024+1024); + if (!m_requests.empty()) + { + range_overlaps_request = in_range.start + in_range.length + > m_requests.front().start + int(m_piece.size()); + + if (in_range.start + in_range.length < m_requests.front().start + m_requests.front().length + && m_parser.finished()) + { + m_piece.reserve(info.piece_length()); + int copy_size = std::min(m_requests.front().length - int(m_piece.size()) + , http_body.left()); + std::copy(http_body.begin, http_body.begin + copy_size, std::back_inserter(m_piece)); + http_body.begin += copy_size; + } + } + + if (m_parser.finished()) + { + m_file_requests.pop_front(); + assert(http_body.left() == 0); + m_parser.reset(); + assert(recv_buffer.end == http_body.end || *http_body.end == 'H'); + cut_receive_buffer(http_body.end - recv_buffer.begin + , t->torrent_file().piece_length() + 1024 * 2); + continue; + } + break; } } - // -------------------------- - // SEND DATA - // -------------------------- - void web_peer_connection::get_peer_info(peer_info& p) const { assert(!associated_torrent().expired()); @@ -377,19 +540,22 @@ namespace libtorrent p.payload_up_speed = statistics().upload_payload_rate(); p.pid = pid(); p.ip = remote(); + + p.country[0] = m_country[0]; + p.country[1] = m_country[1]; p.total_download = statistics().total_payload_download(); p.total_upload = statistics().total_payload_upload(); - if (m_ul_bandwidth_quota.given == std::numeric_limits::max()) + if (m_bandwidth_limit[upload_channel].throttle() == bandwidth_limit::inf) p.upload_limit = -1; else - p.upload_limit = m_ul_bandwidth_quota.given; + p.upload_limit = m_bandwidth_limit[upload_channel].throttle(); - if (m_dl_bandwidth_quota.given == std::numeric_limits::max()) + if (m_bandwidth_limit[download_channel].throttle() == bandwidth_limit::inf) p.download_limit = -1; else - p.download_limit = m_dl_bandwidth_quota.given; + p.download_limit = m_bandwidth_limit[download_channel].throttle(); p.load_balancing = total_free_upload(); @@ -429,8 +595,13 @@ namespace libtorrent p.connection_type = peer_info::web_seed; } + bool web_peer_connection::in_handshake() const + { + return m_server_string.empty(); + } + // throws exception when the client should be disconnected - void web_peer_connection::on_sent(asio::error const& error + void web_peer_connection::on_sent(asio::error_code const& error , std::size_t bytes_transferred) { INVARIANT_CHECK; diff --git a/setup.py b/setup.py index d6f69fb88..d5fb5de75 100644 --- a/setup.py +++ b/setup.py @@ -127,13 +127,17 @@ deluge_core = Extension('deluge_core', sources = ['src/deluge_core.cpp', 'libtorrent/src/alert.cpp', 'libtorrent/src/allocate_resources.cpp', + 'libtorrent/src/bandwidth_manager.cpp', 'libtorrent/src/bt_peer_connection.cpp', 'libtorrent/src/entry.cpp', 'libtorrent/src/escape_string.cpp', 'libtorrent/src/file.cpp', + 'libtorrent/src/file_pool.cpp', 'libtorrent/src/http_tracker_connection.cpp', 'libtorrent/src/identify_client.cpp', 'libtorrent/src/ip_filter.cpp', + 'libtorrent/src/logger.cpp', + 'libtorrent/src/metadata_transfer.cpp', 'libtorrent/src/peer_connection.cpp', 'libtorrent/src/piece_picker.cpp', 'libtorrent/src/policy.cpp', @@ -147,6 +151,7 @@ deluge_core = Extension('deluge_core', 'libtorrent/src/torrent_info.cpp', 'libtorrent/src/tracker_manager.cpp', 'libtorrent/src/udp_tracker_connection.cpp', + 'libtorrent/src/ut_pex.cpp', 'libtorrent/src/web_peer_connection.cpp', 'libtorrent/src/kademlia/closest_nodes.cpp', 'libtorrent/src/kademlia/dht_tracker.cpp',