diff --git a/libtorrent/include/libtorrent/asio/detail/handler_queue.hpp b/libtorrent/include/libtorrent/asio/detail/handler_queue.hpp new file mode 100644 index 000000000..cd9870279 --- /dev/null +++ b/libtorrent/include/libtorrent/asio/detail/handler_queue.hpp @@ -0,0 +1,219 @@ +// +// handler_queue.hpp +// ~~~~~~~~~~~~~~~~~ +// +// Copyright (c) 2003-2007 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef ASIO_DETAIL_HANDLER_QUEUE_HPP +#define ASIO_DETAIL_HANDLER_QUEUE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include "asio/detail/push_options.hpp" + +#include "asio/detail/handler_alloc_helpers.hpp" +#include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/noncopyable.hpp" + +namespace asio { +namespace detail { + +class handler_queue + : private noncopyable +{ +public: + // Base class for handlers in the queue. + class handler + : private noncopyable + { + public: + void invoke() + { + invoke_func_(this); + } + + void destroy() + { + destroy_func_(this); + } + + protected: + typedef void (*invoke_func_type)(handler*); + typedef void (*destroy_func_type)(handler*); + + handler(invoke_func_type invoke_func, + destroy_func_type destroy_func) + : next_(0), + invoke_func_(invoke_func), + destroy_func_(destroy_func) + { + } + + ~handler() + { + } + + private: + friend class handler_queue; + handler* next_; + invoke_func_type invoke_func_; + destroy_func_type destroy_func_; + }; + + // Smart point to manager handler lifetimes. + class scoped_ptr + : private noncopyable + { + public: + explicit scoped_ptr(handler* h) + : handler_(h) + { + } + + ~scoped_ptr() + { + if (handler_) + handler_->destroy(); + } + + handler* get() const + { + return handler_; + } + + handler* release() + { + handler* tmp = handler_; + handler_ = 0; + return tmp; + } + + private: + handler* handler_; + }; + + // Constructor. + handler_queue() + : front_(0), + back_(0) + { + } + + // Wrap a handler to be pushed into the queue. + template + static handler* wrap(Handler h) + { + // Allocate and construct an object to wrap the handler. + typedef handler_wrapper value_type; + typedef handler_alloc_traits alloc_traits; + raw_handler_ptr raw_ptr(h); + handler_ptr ptr(raw_ptr, h); + return ptr.release(); + } + + // Get the handler at the front of the queue. + handler* front() + { + return front_; + } + + // Pop a handler from the front of the queue. + void pop() + { + if (front_) + { + handler* tmp = front_; + front_ = front_->next_; + if (front_ == 0) + back_ = 0; + tmp->next_= 0; + } + } + + // Push a handler on to the back of the queue. + void push(handler* h) + { + h->next_ = 0; + if (back_) + { + back_->next_ = h; + back_ = h; + } + else + { + front_ = back_ = h; + } + } + + // Whether the queue is empty. + bool empty() const + { + return front_ == 0; + } + +private: + // Template wrapper for handlers. + template + class handler_wrapper + : public handler + { + public: + handler_wrapper(Handler h) + : handler( + &handler_wrapper::do_call, + &handler_wrapper::do_destroy), + handler_(h) + { + } + + static void do_call(handler* base) + { + // Take ownership of the handler object. + typedef handler_wrapper this_type; + this_type* h(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(h->handler_, h); + + // Make a copy of the handler so that the memory can be deallocated before + // the upcall is made. + Handler handler(h->handler_); + + // Free the memory associated with the handler. + ptr.reset(); + + // Make the upcall. + asio_handler_invoke_helpers::invoke(handler, &handler); + } + + static void do_destroy(handler* base) + { + // Take ownership of the handler object. + typedef handler_wrapper this_type; + this_type* h(static_cast(base)); + typedef handler_alloc_traits alloc_traits; + handler_ptr ptr(h->handler_, h); + } + + private: + Handler handler_; + }; + + // The front of the queue. + handler* front_; + + // The back of the queue. + handler* back_; +}; + +} // namespace detail +} // namespace asio + +#include "asio/detail/pop_options.hpp" + +#endif // ASIO_DETAIL_HANDLER_QUEUE_HPP diff --git a/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp b/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp index 9c0075821..6b03c6bc5 100644 --- a/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp +++ b/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp @@ -450,7 +450,7 @@ public: } endpoint_type endpoint; - socket_addr_len_type addr_len = endpoint.capacity(); + std::size_t addr_len = endpoint.capacity(); if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) return endpoint_type(); endpoint.resize(addr_len); @@ -468,7 +468,7 @@ public: } endpoint_type endpoint; - socket_addr_len_type addr_len = endpoint.capacity(); + std::size_t addr_len = endpoint.capacity(); if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec)) return endpoint_type(); endpoint.resize(addr_len); @@ -1073,7 +1073,7 @@ public: for (;;) { // Try to complete the operation without blocking. - socket_addr_len_type addr_len = sender_endpoint.capacity(); + std::size_t addr_len = sender_endpoint.capacity(); int bytes_recvd = socket_ops::recvfrom(impl.socket_, bufs, i, flags, sender_endpoint.data(), &addr_len, ec); @@ -1144,7 +1144,7 @@ public: } // Receive some data. - socket_addr_len_type addr_len = sender_endpoint_.capacity(); + std::size_t addr_len = sender_endpoint_.capacity(); asio::error_code ec; int bytes = socket_ops::recvfrom(socket_, bufs, i, flags_, sender_endpoint_.data(), &addr_len, ec); @@ -1242,7 +1242,7 @@ public: // Try to complete the operation without blocking. asio::error_code ec; socket_holder new_socket; - socket_addr_len_type addr_len = 0; + std::size_t addr_len = 0; if (peer_endpoint) { addr_len = peer_endpoint->capacity(); @@ -1327,7 +1327,7 @@ public: // Accept the waiting connection. asio::error_code ec; socket_holder new_socket; - socket_addr_len_type addr_len = 0; + std::size_t addr_len = 0; if (peer_endpoint_) { addr_len = peer_endpoint_->capacity(); diff --git a/libtorrent/include/libtorrent/asio/detail/socket_ops.hpp b/libtorrent/include/libtorrent/asio/detail/socket_ops.hpp index 98f3b0f64..edea9ef6a 100644 --- a/libtorrent/include/libtorrent/asio/detail/socket_ops.hpp +++ b/libtorrent/include/libtorrent/asio/detail/socket_ops.hpp @@ -26,9 +26,6 @@ #include #include #include -#if defined(__MACH__) && defined(__APPLE__) -# include -#endif // defined(__MACH__) && defined(__APPLE__) #include "asio/detail/pop_options.hpp" #include "asio/error.hpp" @@ -38,6 +35,10 @@ namespace asio { namespace detail { namespace socket_ops { +#if defined(BOOST_WINDOWS) || defined(__CYGWIN__) +struct msghdr { int msg_namelen; }; +#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + inline void clear_error(asio::error_code& ec) { errno = 0; @@ -60,15 +61,28 @@ inline ReturnType error_wrapper(ReturnType return_value, return return_value; } +template +inline socket_type call_accept(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0; + socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0); + if (addrlen) + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + inline socket_type accept(socket_type s, socket_addr_type* addr, - socket_addr_len_type* addrlen, asio::error_code& ec) + std::size_t* addrlen, asio::error_code& ec) { clear_error(ec); -#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) - socket_type new_s = error_wrapper(::accept(s, addr, addrlen), ec); + + socket_type new_s = error_wrapper(call_accept( + &msghdr::msg_namelen, s, addr, addrlen), ec); if (new_s == invalid_socket) return new_s; +#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__) int optval = 1; int result = error_wrapper(::setsockopt(new_s, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)), ec); @@ -77,18 +91,23 @@ inline socket_type accept(socket_type s, socket_addr_type* addr, ::close(new_s); return invalid_socket; } +#endif return new_s; -#else - return error_wrapper(::accept(s, addr, addrlen), ec); -#endif +} + +template +inline int call_bind(SockLenType msghdr::*, + socket_type s, const socket_addr_type* addr, std::size_t addrlen) +{ + return ::bind(s, addr, (SockLenType)addrlen); } inline int bind(socket_type s, const socket_addr_type* addr, - socket_addr_len_type addrlen, asio::error_code& ec) + std::size_t addrlen, asio::error_code& ec) { clear_error(ec); - return error_wrapper(::bind(s, addr, addrlen), ec); + return error_wrapper(call_bind(&msghdr::msg_namelen, s, addr, addrlen), ec); } inline int close(socket_type s, asio::error_code& ec) @@ -107,11 +126,19 @@ inline int shutdown(socket_type s, int what, asio::error_code& ec) return error_wrapper(::shutdown(s, what), ec); } +template +inline int call_connect(SockLenType msghdr::*, + socket_type s, const socket_addr_type* addr, std::size_t addrlen) +{ + return ::connect(s, addr, (SockLenType)addrlen); +} + inline int connect(socket_type s, const socket_addr_type* addr, - socket_addr_len_type addrlen, asio::error_code& ec) + std::size_t addrlen, asio::error_code& ec) { clear_error(ec); - return error_wrapper(::connect(s, addr, addrlen), ec); + return error_wrapper(call_connect( + &msghdr::msg_namelen, s, addr, addrlen), ec); } inline int listen(socket_type s, int backlog, asio::error_code& ec) @@ -148,6 +175,28 @@ inline void init_buf(buf& b, const void* data, size_t size) #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } +inline void init_msghdr_msg_name(void*& name, socket_addr_type* addr) +{ + name = addr; +} + +inline void init_msghdr_msg_name(void*& name, const socket_addr_type* addr) +{ + name = const_cast(addr); +} + +template +inline void init_msghdr_msg_name(T& name, socket_addr_type* addr) +{ + name = reinterpret_cast(addr); +} + +template +inline void init_msghdr_msg_name(T& name, const socket_addr_type* addr) +{ + name = reinterpret_cast(const_cast(addr)); +} + inline int recv(socket_type s, buf* bufs, size_t count, int flags, asio::error_code& ec) { @@ -163,20 +212,15 @@ inline int recv(socket_type s, buf* bufs, size_t count, int flags, return -1; return bytes_transferred; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg; - msg.msg_name = 0; - msg.msg_namelen = 0; + msghdr msg = msghdr(); msg.msg_iov = bufs; msg.msg_iovlen = count; - msg.msg_control = 0; - msg.msg_controllen = 0; - msg.msg_flags = 0; return error_wrapper(::recvmsg(s, &msg, flags), ec); #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags, - socket_addr_type* addr, socket_addr_len_type* addrlen, + socket_addr_type* addr, std::size_t* addrlen, asio::error_code& ec) { clear_error(ec); @@ -185,25 +229,19 @@ inline int recvfrom(socket_type s, buf* bufs, size_t count, int flags, DWORD recv_buf_count = static_cast(count); DWORD bytes_transferred = 0; DWORD recv_flags = flags; + int tmp_addrlen = (int)*addrlen; int result = error_wrapper(::WSARecvFrom(s, bufs, recv_buf_count, - &bytes_transferred, &recv_flags, addr, addrlen, 0, 0), ec); + &bytes_transferred, &recv_flags, addr, &tmp_addrlen, 0, 0), ec); + *addrlen = (std::size_t)tmp_addrlen; if (result != 0) return -1; return bytes_transferred; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg; -#if defined(__MACH__) && defined(__APPLE__) \ - && (MAC_OS_X_VERSION_MAX_ALLOWED < 1040) - msg.msg_name = reinterpret_cast(addr); -#else - msg.msg_name = addr; -#endif + msghdr msg = msghdr(); + init_msghdr_msg_name(msg.msg_name, addr); msg.msg_namelen = *addrlen; msg.msg_iov = bufs; msg.msg_iovlen = count; - msg.msg_control = 0; - msg.msg_controllen = 0; - msg.msg_flags = 0; int result = error_wrapper(::recvmsg(s, &msg, flags), ec); *addrlen = msg.msg_namelen; return result; @@ -225,14 +263,9 @@ inline int send(socket_type s, const buf* bufs, size_t count, int flags, return -1; return bytes_transferred; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg; - msg.msg_name = 0; - msg.msg_namelen = 0; + msghdr msg = msghdr(); msg.msg_iov = const_cast(bufs); msg.msg_iovlen = count; - msg.msg_control = 0; - msg.msg_controllen = 0; - msg.msg_flags = 0; #if defined(__linux__) flags |= MSG_NOSIGNAL; #endif // defined(__linux__) @@ -241,7 +274,7 @@ inline int send(socket_type s, const buf* bufs, size_t count, int flags, } inline int sendto(socket_type s, const buf* bufs, size_t count, int flags, - const socket_addr_type* addr, socket_addr_len_type addrlen, + const socket_addr_type* addr, std::size_t addrlen, asio::error_code& ec) { clear_error(ec); @@ -255,19 +288,11 @@ inline int sendto(socket_type s, const buf* bufs, size_t count, int flags, return -1; return bytes_transferred; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - msghdr msg; -#if defined(__MACH__) && defined(__APPLE__) \ - && (MAC_OS_X_VERSION_MAX_ALLOWED < 1040) - msg.msg_name = reinterpret_cast(const_cast(addr)); -#else - msg.msg_name = const_cast(addr); -#endif + msghdr msg = msghdr(); + init_msghdr_msg_name(msg.msg_name, addr); msg.msg_namelen = addrlen; msg.msg_iov = const_cast(bufs); msg.msg_iovlen = count; - msg.msg_control = 0; - msg.msg_controllen = 0; - msg.msg_flags = 0; #if defined(__linux__) flags |= MSG_NOSIGNAL; #endif // defined(__linux__) @@ -316,8 +341,17 @@ inline socket_type socket(int af, int type, int protocol, #endif } +template +inline int call_setsockopt(SockLenType msghdr::*, + socket_type s, int level, int optname, + const void* optval, std::size_t optlen) +{ + return ::setsockopt(s, level, optname, + (const char*)optval, (SockLenType)optlen); +} + inline int setsockopt(socket_type s, int level, int optname, - const void* optval, size_t optlen, asio::error_code& ec) + const void* optval, std::size_t optlen, asio::error_code& ec) { if (level == custom_socket_option_level && optname == always_fail_option) { @@ -342,15 +376,22 @@ inline int setsockopt(socket_type s, int level, int optname, } ec = asio::error::fault; return -1; -#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) +#else // defined(__BORLANDC__) clear_error(ec); - return error_wrapper(::setsockopt(s, level, optname, - reinterpret_cast(optval), static_cast(optlen)), ec); -#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) - clear_error(ec); - return error_wrapper(::setsockopt(s, level, optname, optval, - static_cast(optlen)), ec); -#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) + return error_wrapper(call_setsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); +#endif // defined(__BORLANDC__) +} + +template +inline int call_getsockopt(SockLenType msghdr::*, + socket_type s, int level, int optname, + void* optval, std::size_t* optlen) +{ + SockLenType tmp_optlen = (SockLenType)*optlen; + int result = ::getsockopt(s, level, optname, (char*)optval, &tmp_optlen); + *optlen = (std::size_t)tmp_optlen; + return result; } inline int getsockopt(socket_type s, int level, int optname, void* optval, @@ -394,10 +435,8 @@ inline int getsockopt(socket_type s, int level, int optname, void* optval, return -1; #elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) clear_error(ec); - int tmp_optlen = static_cast(*optlen); - int result = error_wrapper(::getsockopt(s, level, optname, - reinterpret_cast(optval), &tmp_optlen), ec); - *optlen = static_cast(tmp_optlen); + int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD)) { @@ -412,10 +451,8 @@ inline int getsockopt(socket_type s, int level, int optname, void* optval, return result; #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) clear_error(ec); - socklen_t tmp_optlen = static_cast(*optlen); - int result = error_wrapper(::getsockopt(s, level, optname, - optval, &tmp_optlen), ec); - *optlen = static_cast(tmp_optlen); + int result = error_wrapper(call_getsockopt(&msghdr::msg_namelen, + s, level, optname, optval, optlen), ec); #if defined(__linux__) if (result == 0 && level == SOL_SOCKET && *optlen == sizeof(int) && (optname == SO_SNDBUF || optname == SO_RCVBUF)) @@ -432,18 +469,40 @@ inline int getsockopt(socket_type s, int level, int optname, void* optval, #endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) } +template +inline int call_getpeername(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = (SockLenType)*addrlen; + int result = ::getpeername(s, addr, &tmp_addrlen); + *addrlen = (std::size_t)tmp_addrlen; + return result; +} + inline int getpeername(socket_type s, socket_addr_type* addr, - socket_addr_len_type* addrlen, asio::error_code& ec) + std::size_t* addrlen, asio::error_code& ec) { clear_error(ec); - return error_wrapper(::getpeername(s, addr, addrlen), ec); + return error_wrapper(call_getpeername( + &msghdr::msg_namelen, s, addr, addrlen), ec); +} + +template +inline int call_getsockname(SockLenType msghdr::*, + socket_type s, socket_addr_type* addr, std::size_t* addrlen) +{ + SockLenType tmp_addrlen = (SockLenType)*addrlen; + int result = ::getsockname(s, addr, &tmp_addrlen); + *addrlen = (std::size_t)tmp_addrlen; + return result; } inline int getsockname(socket_type s, socket_addr_type* addr, - socket_addr_len_type* addrlen, asio::error_code& ec) + std::size_t* addrlen, asio::error_code& ec) { clear_error(ec); - return error_wrapper(::getsockname(s, addr, addrlen), ec); + return error_wrapper(call_getsockname( + &msghdr::msg_namelen, s, addr, addrlen), ec); } inline int ioctl(socket_type s, long cmd, ioctl_arg_type* arg, @@ -1373,7 +1432,7 @@ inline int getaddrinfo_emulation(const char* host, const char* service, } inline asio::error_code getnameinfo_emulation( - const socket_addr_type* sa, socket_addr_len_type salen, char* host, + const socket_addr_type* sa, std::size_t salen, char* host, std::size_t hostlen, char* serv, std::size_t servlen, int flags, asio::error_code& ec) { @@ -1595,7 +1654,7 @@ inline void freeaddrinfo(addrinfo_type* ai) } inline asio::error_code getnameinfo(const socket_addr_type* addr, - socket_addr_len_type addrlen, char* host, std::size_t hostlen, + std::size_t addrlen, char* host, std::size_t hostlen, char* serv, std::size_t servlen, int flags, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) @@ -1608,7 +1667,7 @@ inline asio::error_code getnameinfo(const socket_addr_type* addr, # else // Building for Windows 2000 or earlier. typedef int (WSAAPI *gni_t)(const socket_addr_type*, - socket_addr_len_type, char*, std::size_t, char*, std::size_t, int); + int, char*, std::size_t, char*, std::size_t, int); if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32")) { if (gni_t gni = (gni_t)::GetProcAddress(winsock_module, "getnameinfo")) @@ -1662,6 +1721,8 @@ inline u_short_type host_to_network_short(u_short_type value) } // namespace detail } // namespace asio +#undef ASIO_SOCKET_CALL + #include "asio/detail/pop_options.hpp" #endif // ASIO_DETAIL_SOCKET_OPS_HPP diff --git a/libtorrent/include/libtorrent/asio/detail/socket_select_interrupter.hpp b/libtorrent/include/libtorrent/asio/detail/socket_select_interrupter.hpp index ba62b12d6..988f92e8e 100644 --- a/libtorrent/include/libtorrent/asio/detail/socket_select_interrupter.hpp +++ b/libtorrent/include/libtorrent/asio/detail/socket_select_interrupter.hpp @@ -52,7 +52,7 @@ public: using namespace std; // For memset. sockaddr_in4_type addr; - socket_addr_len_type addr_len = sizeof(addr); + std::size_t addr_len = sizeof(addr); memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = inet_addr("127.0.0.1"); diff --git a/libtorrent/include/libtorrent/asio/detail/socket_types.hpp b/libtorrent/include/libtorrent/asio/detail/socket_types.hpp index 02c3a78d5..4e1c68792 100644 --- a/libtorrent/include/libtorrent/asio/detail/socket_types.hpp +++ b/libtorrent/include/libtorrent/asio/detail/socket_types.hpp @@ -116,7 +116,6 @@ const int socket_error_retval = SOCKET_ERROR; const int max_addr_v4_str_len = 256; const int max_addr_v6_str_len = 256; typedef sockaddr socket_addr_type; -typedef int socket_addr_len_type; typedef in_addr in4_addr_type; typedef ip_mreq in4_mreq_type; typedef sockaddr_in sockaddr_in4_type; @@ -154,7 +153,6 @@ const int socket_error_retval = -1; const int max_addr_v4_str_len = INET_ADDRSTRLEN; const int max_addr_v6_str_len = INET6_ADDRSTRLEN + 1 + IF_NAMESIZE; typedef sockaddr socket_addr_type; -typedef socklen_t socket_addr_len_type; typedef in_addr in4_addr_type; typedef ip_mreq in4_mreq_type; typedef sockaddr_in sockaddr_in4_type; diff --git a/libtorrent/include/libtorrent/asio/detail/strand_service.hpp b/libtorrent/include/libtorrent/asio/detail/strand_service.hpp index d987cb98d..8e3c183d0 100644 --- a/libtorrent/include/libtorrent/asio/detail/strand_service.hpp +++ b/libtorrent/include/libtorrent/asio/detail/strand_service.hpp @@ -135,9 +135,9 @@ public: handler_base* last_waiter_; // Storage for posted handlers. - typedef boost::aligned_storage<64> handler_storage_type; + typedef boost::aligned_storage<128> handler_storage_type; #if defined(__BORLANDC__) - boost::aligned_storage<64> handler_storage_; + boost::aligned_storage<128> handler_storage_; #else handler_storage_type handler_storage_; #endif @@ -235,7 +235,7 @@ public: void* do_handler_allocate(std::size_t size) { #if defined(__BORLANDC__) - BOOST_ASSERT(size <= boost::aligned_storage<64>::size); + BOOST_ASSERT(size <= boost::aligned_storage<128>::size); #else BOOST_ASSERT(size <= strand_impl::handler_storage_type::size); #endif diff --git a/libtorrent/include/libtorrent/asio/detail/task_io_service.hpp b/libtorrent/include/libtorrent/asio/detail/task_io_service.hpp index 802d7ea95..33934cf88 100644 --- a/libtorrent/include/libtorrent/asio/detail/task_io_service.hpp +++ b/libtorrent/include/libtorrent/asio/detail/task_io_service.hpp @@ -23,6 +23,7 @@ #include "asio/detail/event.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" +#include "asio/detail/handler_queue.hpp" #include "asio/detail/mutex.hpp" #include "asio/detail/service_base.hpp" #include "asio/detail/task_io_service_fwd.hpp" @@ -42,12 +43,11 @@ public: task_(use_service(io_service)), task_interrupted_(true), outstanding_work_(0), - handler_queue_(&task_handler_), - handler_queue_end_(&task_handler_), stopped_(false), shutdown_(false), first_idle_thread_(0) { + handler_queue_.push(&task_handler_); } void init(size_t /*concurrency_hint*/) @@ -62,17 +62,16 @@ public: lock.unlock(); // Destroy handler objects. - while (handler_queue_) + while (!handler_queue_.empty()) { - handler_base* h = handler_queue_; - handler_queue_ = h->next_; + handler_queue::handler* h = handler_queue_.front(); + handler_queue_.pop(); if (h != &task_handler_) h->destroy(); } // Reset handler queue to initial state. - handler_queue_ = &task_handler_; - handler_queue_end_ = &task_handler_; + handler_queue_.push(&task_handler_); } // Run the event loop until interrupted or no more work. @@ -173,10 +172,7 @@ public: void post(Handler handler) { // Allocate and construct an operation to wrap the handler. - typedef handler_wrapper value_type; - typedef handler_alloc_traits alloc_traits; - raw_handler_ptr raw_ptr(handler); - handler_ptr ptr(raw_ptr, handler); + handler_queue::scoped_ptr ptr(handler_queue::wrap(handler)); asio::detail::mutex::scoped_lock lock(mutex_); @@ -185,15 +181,7 @@ public: return; // Add the handler to the end of the queue. - if (handler_queue_end_) - { - handler_queue_end_->next_ = ptr.get(); - handler_queue_end_ = ptr.get(); - } - else - { - handler_queue_ = handler_queue_end_ = ptr.get(); - } + handler_queue_.push(ptr.get()); ptr.release(); // An undelivered handler is treated as unfinished work. @@ -227,18 +215,15 @@ private: bool task_has_run = false; while (!stopped_) { - if (handler_queue_) + if (!handler_queue_.empty()) { // Prepare to execute first handler from queue. - handler_base* h = handler_queue_; - handler_queue_ = h->next_; - if (handler_queue_ == 0) - handler_queue_end_ = 0; - h->next_ = 0; + handler_queue::handler* h = handler_queue_.front(); + handler_queue_.pop(); if (h == &task_handler_) { - bool more_handlers = (handler_queue_ != 0); + bool more_handlers = (!handler_queue_.empty()); task_interrupted_ = more_handlers || polling; lock.unlock(); @@ -263,7 +248,7 @@ private: handler_cleanup c(lock, *this); // Invoke the handler. May throw an exception. - h->call(); // call() deletes the handler object + h->invoke(); // invoke() deletes the handler object ec = asio::error_code(); return 1; @@ -330,93 +315,6 @@ 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. - class handler_base - { - public: - typedef void (*call_func_type)(handler_base*); - typedef void (*destroy_func_type)(handler_base*); - - handler_base(call_func_type call_func, destroy_func_type destroy_func) - : next_(0), - call_func_(call_func), - destroy_func_(destroy_func) - { - } - - void call() - { - call_func_(this); - } - - void destroy() - { - destroy_func_(this); - } - - protected: - // Prevent deletion through this type. - ~handler_base() - { - } - - private: - friend class task_io_service; - friend class task_cleanup; - handler_base* next_; - call_func_type call_func_; - destroy_func_type destroy_func_; - }; - - // Template wrapper for handlers. - template - class handler_wrapper - : public handler_base - { - public: - handler_wrapper(Handler handler) - : handler_base(&handler_wrapper::do_call, - &handler_wrapper::do_destroy), - handler_(handler) - { - } - - static void do_call(handler_base* base) - { - // Take ownership of the handler object. - typedef handler_wrapper this_type; - this_type* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(h->handler_, h); - - // Make a copy of the handler so that the memory can be deallocated before - // the upcall is made. - Handler handler(h->handler_); - - // Free the memory associated with the handler. - ptr.reset(); - - // Make the upcall. - asio_handler_invoke_helpers::invoke(handler, &handler); - } - - static void do_destroy(handler_base* base) - { - // Take ownership of the handler object. - typedef handler_wrapper this_type; - this_type* h(static_cast(base)); - typedef handler_alloc_traits alloc_traits; - handler_ptr ptr(h->handler_, h); - } - - private: - Handler handler_; - }; - // Helper class to perform task-related operations on block exit. class task_cleanup { @@ -433,20 +331,7 @@ private: // Reinsert the task at the end of the handler queue. lock_.lock(); task_io_service_.task_interrupted_ = true; - task_io_service_.task_handler_.next_ = 0; - if (task_io_service_.handler_queue_end_) - { - task_io_service_.handler_queue_end_->next_ - = &task_io_service_.task_handler_; - task_io_service_.handler_queue_end_ - = &task_io_service_.task_handler_; - } - else - { - task_io_service_.handler_queue_ - = task_io_service_.handler_queue_end_ - = &task_io_service_.task_handler_; - } + task_io_service_.handler_queue_.push(&task_io_service_.task_handler_); } private: @@ -487,11 +372,11 @@ private: // Handler object to represent the position of the task in the queue. class task_handler - : public handler_base + : public handler_queue::handler { public: task_handler() - : handler_base(0, 0) + : handler_queue::handler(0, 0) { } } task_handler_; @@ -502,11 +387,8 @@ private: // The count of unfinished work. int outstanding_work_; - // The start of a linked list of handlers that are ready to be delivered. - handler_base* handler_queue_; - - // The end of a linked list of handlers that are ready to be delivered. - handler_base* handler_queue_end_; + // The queue of handlers that are ready to be delivered. + handler_queue handler_queue_; // Flag to indicate that the dispatcher has been stopped. bool stopped_; diff --git a/libtorrent/include/libtorrent/asio/detail/win_iocp_socket_service.hpp b/libtorrent/include/libtorrent/asio/detail/win_iocp_socket_service.hpp index 17d1d5887..ece098f7b 100644 --- a/libtorrent/include/libtorrent/asio/detail/win_iocp_socket_service.hpp +++ b/libtorrent/include/libtorrent/asio/detail/win_iocp_socket_service.hpp @@ -561,7 +561,7 @@ public: } endpoint_type endpoint; - socket_addr_len_type addr_len = endpoint.capacity(); + std::size_t addr_len = endpoint.capacity(); if (socket_ops::getsockname(impl.socket_, endpoint.data(), &addr_len, ec)) return endpoint_type(); endpoint.resize(addr_len); @@ -600,7 +600,7 @@ public: else { endpoint_type endpoint; - socket_addr_len_type addr_len = endpoint.capacity(); + std::size_t addr_len = endpoint.capacity(); if (socket_ops::getpeername(impl.socket_, endpoint.data(), &addr_len, ec)) return endpoint_type(); endpoint.resize(addr_len); @@ -1261,7 +1261,7 @@ public: // Receive some data. DWORD bytes_transferred = 0; DWORD recv_flags = flags; - int endpoint_size = sender_endpoint.capacity(); + int endpoint_size = static_cast(sender_endpoint.capacity()); int result = ::WSARecvFrom(impl.socket_, bufs, i, &bytes_transferred, &recv_flags, sender_endpoint.data(), &endpoint_size, 0, 0); if (result != 0) @@ -1279,7 +1279,7 @@ public: return 0; } - sender_endpoint.resize(endpoint_size); + sender_endpoint.resize(static_cast(endpoint_size)); ec = asio::error_code(); return bytes_transferred; @@ -1299,7 +1299,7 @@ public: &receive_from_operation< MutableBufferSequence, Handler>::destroy_impl), endpoint_(endpoint), - endpoint_size_(endpoint.capacity()), + endpoint_size_(static_cast(endpoint.capacity())), work_(io_service), buffers_(buffers), handler_(handler) @@ -1463,7 +1463,7 @@ public: { asio::error_code ec; socket_holder new_socket; - socket_addr_len_type addr_len = 0; + std::size_t addr_len = 0; if (peer_endpoint) { addr_len = peer_endpoint->capacity(); @@ -1618,7 +1618,8 @@ public: GetAcceptExSockaddrs(handler_op->output_buffer(), 0, handler_op->address_length(), handler_op->address_length(), &local_addr, &local_addr_length, &remote_addr, &remote_addr_length); - if (remote_addr_length > peer_endpoint.capacity()) + if (static_cast(remote_addr_length) + > peer_endpoint.capacity()) { last_error = WSAEINVAL; } @@ -1626,7 +1627,7 @@ public: { using namespace std; // For memcpy. memcpy(peer_endpoint.data(), remote_addr, remote_addr_length); - peer_endpoint.resize(remote_addr_length); + peer_endpoint.resize(static_cast(remote_addr_length)); } } diff --git a/libtorrent/include/libtorrent/asio/error_code.hpp b/libtorrent/include/libtorrent/asio/error_code.hpp index 0941a8c00..db3f453e0 100644 --- a/libtorrent/include/libtorrent/asio/error_code.hpp +++ b/libtorrent/include/libtorrent/asio/error_code.hpp @@ -54,6 +54,9 @@ namespace error }; } // namespace error +/// Bring error category type into the asio namespace. +typedef asio::error::error_category error_category; + /// Class to represent an error code value. class error_code { @@ -69,7 +72,7 @@ public: } /// Construct with specific error code and category. - error_code(value_type v, error::error_category c) + error_code(value_type v, error_category c) : value_(v), category_(c) { @@ -89,7 +92,7 @@ public: } /// Get the error category. - error::error_category category() const + error_category category() const { return category_; } @@ -135,7 +138,7 @@ private: value_type value_; // The category associated with the error code. - error::error_category category_; + error_category category_; }; } // namespace asio diff --git a/libtorrent/include/libtorrent/asio/io_service.hpp b/libtorrent/include/libtorrent/asio/io_service.hpp index 2101e56c4..a6a6fbe0e 100644 --- a/libtorrent/include/libtorrent/asio/io_service.hpp +++ b/libtorrent/include/libtorrent/asio/io_service.hpp @@ -39,6 +39,11 @@ namespace asio { +class io_service; +template Service& use_service(io_service& ios); +template void add_service(io_service& ios, Service* svc); +template bool has_service(io_service& ios); + /// Provides core I/O functionality. /** * The io_service class provides the core I/O functionality for users of the diff --git a/libtorrent/include/libtorrent/asio/ip/address_v4.hpp b/libtorrent/include/libtorrent/asio/ip/address_v4.hpp index ae3891c95..c7de56b7e 100644 --- a/libtorrent/include/libtorrent/asio/ip/address_v4.hpp +++ b/libtorrent/include/libtorrent/asio/ip/address_v4.hpp @@ -268,7 +268,12 @@ std::basic_ostream& operator<<( asio::error_code ec; std::string s = addr.to_string(ec); if (ec) - os.setstate(std::ios_base::failbit); + { + if (os.exceptions() & std::ios::failbit) + asio::detail::throw_error(ec); + else + os.setstate(std::ios_base::failbit); + } else for (std::string::iterator i = s.begin(); i != s.end(); ++i) os << os.widen(*i); diff --git a/libtorrent/include/libtorrent/asio/ip/address_v6.hpp b/libtorrent/include/libtorrent/asio/ip/address_v6.hpp index f732955fa..87bb6d459 100644 --- a/libtorrent/include/libtorrent/asio/ip/address_v6.hpp +++ b/libtorrent/include/libtorrent/asio/ip/address_v6.hpp @@ -386,7 +386,12 @@ std::basic_ostream& operator<<( asio::error_code ec; std::string s = addr.to_string(ec); if (ec) - os.setstate(std::ios_base::failbit); + { + if (os.exceptions() & std::ios::failbit) + asio::detail::throw_error(ec); + else + os.setstate(std::ios_base::failbit); + } else for (std::string::iterator i = s.begin(); i != s.end(); ++i) os << os.widen(*i); diff --git a/libtorrent/include/libtorrent/asio/ip/basic_endpoint.hpp b/libtorrent/include/libtorrent/asio/ip/basic_endpoint.hpp index 3d1316e22..643df48a7 100644 --- a/libtorrent/include/libtorrent/asio/ip/basic_endpoint.hpp +++ b/libtorrent/include/libtorrent/asio/ip/basic_endpoint.hpp @@ -61,14 +61,6 @@ public: typedef asio::detail::socket_addr_type data_type; #endif - /// The type for the size of the endpoint structure. This type is dependent on - /// the underlying implementation of the socket layer. -#if defined(GENERATING_DOCUMENTATION) - typedef implementation_defined size_type; -#else - typedef asio::detail::socket_addr_len_type size_type; -#endif - /// Default constructor. basic_endpoint() : data_() @@ -190,7 +182,7 @@ public: } /// Get the underlying size of the endpoint in the native type. - size_type size() const + std::size_t size() const { if (is_v4(data_)) return sizeof(asio::detail::sockaddr_in4_type); @@ -199,9 +191,9 @@ public: } /// Set the underlying size of the endpoint in the native type. - void resize(size_type size) + void resize(std::size_t size) { - if (size > size_type(sizeof(data_))) + if (size > sizeof(data_)) { asio::system_error e(asio::error::invalid_argument); boost::throw_exception(e); @@ -209,7 +201,7 @@ public: } /// Get the capacity of the endpoint in the native type. - size_type capacity() const + std::size_t capacity() const { return sizeof(data_); } @@ -349,11 +341,23 @@ std::ostream& operator<<(std::ostream& os, const basic_endpoint& endpoint) { const address& addr = endpoint.address(); - if (addr.is_v4()) - os << addr.to_string(); + asio::error_code ec; + std::string a = addr.to_string(ec); + if (ec) + { + if (os.exceptions() & std::ios::failbit) + asio::detail::throw_error(ec); + else + os.setstate(std::ios_base::failbit); + } else - os << '[' << addr.to_string() << ']'; - os << ':' << endpoint.port(); + { + if (addr.is_v4()) + os << a; + else + os << '[' << a << ']'; + os << ':' << endpoint.port(); + } return os; } #else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) @@ -363,11 +367,23 @@ std::basic_ostream& operator<<( const basic_endpoint& endpoint) { const address& addr = endpoint.address(); - if (addr.is_v4()) - os << addr.to_string(); + asio::error_code ec; + std::string a = addr.to_string(ec); + if (ec) + { + if (os.exceptions() & std::ios::failbit) + asio::detail::throw_error(ec); + else + os.setstate(std::ios_base::failbit); + } else - os << '[' << addr.to_string() << ']'; - os << ':' << endpoint.port(); + { + if (addr.is_v4()) + os << a; + else + os << '[' << a << ']'; + os << ':' << endpoint.port(); + } return os; } #endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) diff --git a/libtorrent/include/libtorrent/asio/ip/basic_resolver_iterator.hpp b/libtorrent/include/libtorrent/asio/ip/basic_resolver_iterator.hpp index 686e4446e..81c652ce8 100644 --- a/libtorrent/include/libtorrent/asio/ip/basic_resolver_iterator.hpp +++ b/libtorrent/include/libtorrent/asio/ip/basic_resolver_iterator.hpp @@ -80,9 +80,7 @@ public: { using namespace std; // For memcpy. typename InternetProtocol::endpoint endpoint; - endpoint.resize( - static_cast( - address_info->ai_addrlen)); + endpoint.resize(static_cast(address_info->ai_addrlen)); memcpy(endpoint.data(), address_info->ai_addr, address_info->ai_addrlen); iter.values_->push_back( diff --git a/libtorrent/include/libtorrent/asio/ip/detail/socket_option.hpp b/libtorrent/include/libtorrent/asio/ip/detail/socket_option.hpp index a86307077..03c6940e9 100644 --- a/libtorrent/include/libtorrent/asio/ip/detail/socket_option.hpp +++ b/libtorrent/include/libtorrent/asio/ip/detail/socket_option.hpp @@ -37,7 +37,7 @@ template class boolean { public: -#if defined(__sun) +#if defined(__sun) || defined(_AIX) typedef unsigned char value_type; #else typedef int value_type; diff --git a/libtorrent/include/libtorrent/aux_/session_impl.hpp b/libtorrent/include/libtorrent/aux_/session_impl.hpp index afb358afe..e3dabcae0 100644 --- a/libtorrent/include/libtorrent/aux_/session_impl.hpp +++ b/libtorrent/include/libtorrent/aux_/session_impl.hpp @@ -168,6 +168,10 @@ namespace libtorrent // thread started to run the main downloader loop struct session_impl: boost::noncopyable { + + // the size of each allocation that is chained in the send buffer + enum { send_buffer_size = 200 }; + #ifndef NDEBUG friend class ::libtorrent::peer_connection; #endif @@ -329,6 +333,24 @@ namespace libtorrent { return m_dht_proxy; } #endif +#ifdef TORRENT_STATS + void log_buffer_usage() + { + int send_buffer_capacity = 0; + int used_send_buffer = 0; + for (connection_map::const_iterator i = m_connections.begin() + , end(m_connections.end()); i != end; ++i) + { + send_buffer_capacity += i->second->send_buffer_capacity(); + used_send_buffer += i->second->send_buffer_size(); + } + assert(send_buffer_capacity >= used_send_buffer); + m_buffer_usage_logger << log_time() << " send_buffer_size: " << send_buffer_capacity << std::endl; + m_buffer_usage_logger << log_time() << " used_send_buffer: " << used_send_buffer << std::endl; + m_buffer_usage_logger << log_time() << " send_buffer_utilization: " + << (used_send_buffer * 100.f / send_buffer_capacity) << std::endl; + } +#endif void start_lsd(); void start_natpmp(); void start_upnp(); @@ -339,11 +361,25 @@ namespace libtorrent // handles delayed alerts alert_manager m_alerts; + + std::pair allocate_buffer(int size); + void free_buffer(char* buf, int size); + void free_disk_buffer(char* buf); // private: void on_lsd_peer(tcp::endpoint peer, sha1_hash const& ih); + // handles disk io requests asynchronously + // peers have pointers into the disk buffer + // pool, and must be destructed before this + // object. + disk_io_thread m_disk_thread; + + // this pool is used to allocate and recycle send + // buffers from. + boost::pool<> m_send_buffers; + // this is where all active sockets are stored. // the selector can sleep while there's no activity on // them @@ -358,9 +394,6 @@ namespace libtorrent // when they are destructed. file_pool m_files; - // handles disk io requests asynchronously - disk_io_thread m_disk_thread; - // this is a list of half-open tcp connections // (only outgoing connections) // this has to be one of the last @@ -507,9 +540,9 @@ namespace libtorrent pe_settings m_pe_settings; #endif - boost::shared_ptr m_natpmp; - boost::shared_ptr m_upnp; - boost::shared_ptr m_lsd; + boost::intrusive_ptr m_natpmp; + boost::intrusive_ptr m_upnp; + boost::intrusive_ptr m_lsd; // the timer used to fire the second_tick deadline_timer m_timer; @@ -526,6 +559,10 @@ namespace libtorrent // logger used to write bandwidth usage statistics std::ofstream m_stats_logger; int m_second_counter; + // used to log send buffer usage statistics + std::ofstream m_buffer_usage_logger; + // the number of send buffers that are allocated + int m_buffer_allocations; #endif #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) boost::shared_ptr create_log(std::string const& name diff --git a/libtorrent/include/libtorrent/bt_peer_connection.hpp b/libtorrent/include/libtorrent/bt_peer_connection.hpp index 0fcba89a8..53e9667fc 100755 --- a/libtorrent/include/libtorrent/bt_peer_connection.hpp +++ b/libtorrent/include/libtorrent/bt_peer_connection.hpp @@ -208,7 +208,7 @@ namespace libtorrent void write_cancel(peer_request const& r); void write_bitfield(std::vector const& bitfield); void write_have(int index); - void write_piece(peer_request const& r, char const* buffer); + void write_piece(peer_request const& r, char* buffer); void write_handshake(); #ifndef TORRENT_DISABLE_EXTENSIONS void write_extensions(); @@ -270,8 +270,17 @@ namespace libtorrent // these functions encrypt the send buffer if m_rc4_encrypted // is true, otherwise it passes the call to the // peer_connection functions of the same names - void send_buffer(char* begin, char* end); + void send_buffer(char* buf, int size); buffer::interval allocate_send_buffer(int size); + template + void append_send_buffer(char* buffer, int size, Destructor const& destructor) + { +#ifndef TORRENT_DISABLE_ENCRYPTION + if (m_rc4_encrypted) + m_RC4_handler->encrypt(buffer, size); +#endif + peer_connection::append_send_buffer(buffer, size, destructor); + } void setup_send(); // Returns offset at which bytestream (src, src + src_size) diff --git a/libtorrent/include/libtorrent/chained_buffer.hpp b/libtorrent/include/libtorrent/chained_buffer.hpp new file mode 100644 index 000000000..dd98fd05f --- /dev/null +++ b/libtorrent/include/libtorrent/chained_buffer.hpp @@ -0,0 +1,192 @@ +/* + +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_CHAINED_BUFFER_HPP_INCLUDED +#define TORRENT_CHAINED_BUFFER_HPP_INCLUDED + +#include +#include +#include +#include + +namespace libtorrent +{ + struct chained_buffer + { + chained_buffer(): m_bytes(0), m_capacity(0) {} + + struct buffer_t + { + boost::function free; // destructs the buffer + char* buf; // the first byte of the buffer + int size; // the total size of the buffer + + char* start; // the first byte to send/receive in the buffer + int used_size; // this is the number of bytes to send/receive + }; + + bool empty() const { return m_bytes == 0; } + int size() const { return m_bytes; } + int capacity() const { return m_capacity; } + + void pop_front(int bytes_to_pop) + { + assert(bytes_to_pop <= m_bytes); + while (bytes_to_pop > 0 && !m_vec.empty()) + { + buffer_t& b = m_vec.front(); + if (b.used_size > bytes_to_pop) + { + b.start += bytes_to_pop; + b.used_size -= bytes_to_pop; + m_bytes -= bytes_to_pop; + assert(m_bytes <= m_capacity); + assert(m_bytes >= 0); + assert(m_capacity >= 0); + break; + } + + b.free(b.buf); + m_bytes -= b.used_size; + m_capacity -= b.size; + bytes_to_pop -= b.used_size; + assert(m_bytes >= 0); + assert(m_capacity >= 0); + assert(m_bytes <= m_capacity); + m_vec.pop_front(); + } + } + + template + void append_buffer(char* buffer, int size, int used_size, D const& destructor) + { + assert(size >= used_size); + buffer_t b; + b.buf = buffer; + b.size = size; + b.start = buffer; + b.used_size = used_size; + b.free = destructor; + m_vec.push_back(b); + + m_bytes += used_size; + m_capacity += size; + assert(m_bytes <= m_capacity); + } + + // returns the number of bytes available at the + // end of the last chained buffer. + int space_in_last_buffer() + { + if (m_vec.empty()) return 0; + buffer_t& b = m_vec.back(); + return b.size - b.used_size - (b.start - b.buf); + } + + // tries to copy the given buffer to the end of the + // last chained buffer. If there's not enough room + // it returns false + bool append(char const* buf, int size) + { + char* insert = allocate_appendix(size); + if (insert == 0) return false; + std::memcpy(insert, buf, size); + return true; + } + + // tries to allocate memory from the end + // of the last buffer. If there isn't + // enough room, returns 0 + char* allocate_appendix(int size) + { + if (m_vec.empty()) return 0; + buffer_t& b = m_vec.back(); + char* insert = b.start + b.used_size; + if (insert + size > b.buf + b.size) return 0; + b.used_size += size; + m_bytes += size; + assert(m_bytes <= m_capacity); + return insert; + } + + std::list const& build_iovec(int to_send) + { + m_tmp_vec.clear(); + + for (std::list::iterator i = m_vec.begin() + , end(m_vec.end()); to_send > 0 && i != end; ++i) + { + if (i->used_size > to_send) + { + assert(to_send > 0); + m_tmp_vec.push_back(asio::const_buffer(i->start, to_send)); + break; + } + assert(i->used_size > 0); + m_tmp_vec.push_back(asio::const_buffer(i->start, i->used_size)); + to_send -= i->used_size; + } + return m_tmp_vec; + } + + ~chained_buffer() + { + for (std::list::iterator i = m_vec.begin() + , end(m_vec.end()); i != end; ++i) + { + i->free(i->buf); + } + } + + private: + + // this is the list of all the buffers we want to + // send + std::list m_vec; + + // this is the number of bytes in the send buf. + // this will always be equal to the sum of the + // size of all buffers in vec + int m_bytes; + + // the total size of all buffers in the chain + // including unused space + int m_capacity; + + // this is the vector of buffers used when + // invoking the async write call + std::list m_tmp_vec; + }; +} + +#endif + diff --git a/libtorrent/include/libtorrent/disk_io_thread.hpp b/libtorrent/include/libtorrent/disk_io_thread.hpp index 61ca9bc53..b893aaf60 100644 --- a/libtorrent/include/libtorrent/disk_io_thread.hpp +++ b/libtorrent/include/libtorrent/disk_io_thread.hpp @@ -94,6 +94,11 @@ namespace libtorrent disk_io_thread(int block_size = 16 * 1024); ~disk_io_thread(); +#ifdef TORRENT_STATS + int disk_allocations() const + { return m_allocations; } +#endif + // aborts read operations void stop(boost::intrusive_ptr s); void add_job(disk_io_job const& j @@ -110,6 +115,7 @@ namespace libtorrent void operator()(); char* allocate_buffer(); + void free_buffer(char* buf); private: @@ -129,6 +135,9 @@ namespace libtorrent #ifdef TORRENT_DISK_STATS std::ofstream m_log; #endif +#ifdef TORRENT_STATS + int m_allocations; +#endif // thread for performing blocking disk io operations boost::thread m_disk_io_thread; diff --git a/libtorrent/include/libtorrent/http_tracker_connection.hpp b/libtorrent/include/libtorrent/http_tracker_connection.hpp index 76c3aac98..70be3054a 100755 --- a/libtorrent/include/libtorrent/http_tracker_connection.hpp +++ b/libtorrent/include/libtorrent/http_tracker_connection.hpp @@ -69,13 +69,20 @@ namespace libtorrent { public: http_parser(); - template - T header(char const* key) const; + std::string const& header(char const* key) const + { + static std::string empty; + std::map::const_iterator i + = m_header.find(key); + if (i == m_header.end()) return empty; + return i->second; + } + std::string const& protocol() const { return m_protocol; } int status_code() const { return m_status_code; } std::string const& method() const { return m_method; } std::string const& path() const { return m_path; } - std::string message() const { return m_server_message; } + std::string const& message() const { return m_server_message; } buffer::const_interval get_body() const; bool header_finished() const { return m_state == read_body; } bool finished() const { return m_finished; } @@ -103,15 +110,6 @@ namespace libtorrent bool m_finished; }; - template - T http_parser::header(char const* key) const - { - std::map::const_iterator i - = m_header.find(key); - if (i == m_header.end()) return T(); - return boost::lexical_cast(i->second); - } - class TORRENT_EXPORT http_tracker_connection : public tracker_connection { diff --git a/libtorrent/include/libtorrent/intrusive_ptr_base.hpp b/libtorrent/include/libtorrent/intrusive_ptr_base.hpp index d2c35ffe3..4d3c5b855 100644 --- a/libtorrent/include/libtorrent/intrusive_ptr_base.hpp +++ b/libtorrent/include/libtorrent/intrusive_ptr_base.hpp @@ -60,6 +60,12 @@ namespace libtorrent delete static_cast(s); } + boost::intrusive_ptr self() + { return boost::intrusive_ptr((T*)this); } + + boost::intrusive_ptr self() const + { return boost::intrusive_ptr((T const*)this); } + int refcount() const { return m_refs; } intrusive_ptr_base(): m_refs(0) {} diff --git a/libtorrent/include/libtorrent/lsd.hpp b/libtorrent/include/libtorrent/lsd.hpp index e8eaf0df1..6fb6b7c7b 100644 --- a/libtorrent/include/libtorrent/lsd.hpp +++ b/libtorrent/include/libtorrent/lsd.hpp @@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket.hpp" #include "libtorrent/peer_id.hpp" #include "libtorrent/broadcast_socket.hpp" +#include "libtorrent/intrusive_ptr_base.hpp" #include #include @@ -52,7 +53,7 @@ namespace libtorrent typedef boost::function peer_callback_t; -class lsd : boost::noncopyable +class lsd : public intrusive_ptr_base { public: lsd(io_service& ios, address const& listen_interface diff --git a/libtorrent/include/libtorrent/natpmp.hpp b/libtorrent/include/libtorrent/natpmp.hpp index 1c0ffd0be..3b9923972 100644 --- a/libtorrent/include/libtorrent/natpmp.hpp +++ b/libtorrent/include/libtorrent/natpmp.hpp @@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_NATPMP_HPP #include "libtorrent/socket.hpp" +#include "libtorrent/intrusive_ptr_base.hpp" #include @@ -49,7 +50,7 @@ namespace libtorrent // std::string: error message typedef boost::function portmap_callback_t; -class natpmp +class natpmp : public intrusive_ptr_base { public: natpmp(io_service& ios, address const& listen_interface, portmap_callback_t const& cb); diff --git a/libtorrent/include/libtorrent/peer_connection.hpp b/libtorrent/include/libtorrent/peer_connection.hpp index ac9aa0322..ce7e61ec5 100755 --- a/libtorrent/include/libtorrent/peer_connection.hpp +++ b/libtorrent/include/libtorrent/peer_connection.hpp @@ -51,6 +51,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #ifdef _MSC_VER #pragma warning(pop) @@ -73,6 +74,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket_type.hpp" #include "libtorrent/intrusive_ptr_base.hpp" #include "libtorrent/assert.hpp" +#include "libtorrent/chained_buffer.hpp" namespace libtorrent { @@ -356,14 +358,23 @@ namespace libtorrent virtual boost::optional downloading_piece_progress() const { - #ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << "downloading_piece_progress() dispatched to the base class!\n"; - #endif +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << "downloading_piece_progress() dispatched to the base class!\n"; +#endif return boost::optional(); } - void send_buffer(char const* begin, char const* end); + void send_buffer(char const* begin, int size); buffer::interval allocate_send_buffer(int size); + template + void append_send_buffer(char* buffer, int size, Destructor const& destructor) + { + m_send_buffer.append_buffer(buffer, size, size, destructor); +#ifdef TORRENT_STATS + m_ses.m_buffer_usage_logger << log_time() << " append_send_buffer: " << size << std::endl; + m_ses.log_buffer_usage(); +#endif + } void setup_send(); #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES @@ -376,6 +387,12 @@ namespace libtorrent bool has_country() const { return m_country[0] != 0; } #endif + int send_buffer_size() const + { return m_send_buffer.size(); } + + int send_buffer_capacity() const + { return m_send_buffer.capacity(); } + protected: virtual void get_specific_peer_info(peer_info& p) const = 0; @@ -388,7 +405,7 @@ namespace libtorrent virtual void write_cancel(peer_request const& r) = 0; virtual void write_have(int index) = 0; virtual void write_keepalive() = 0; - virtual void write_piece(peer_request const& r, char const* buffer) = 0; + virtual void write_piece(peer_request const& r, char* buffer) = 0; virtual void write_reject_request(peer_request const& r) = 0; virtual void write_allow_fast(int piece) = 0; @@ -401,13 +418,6 @@ namespace libtorrent virtual void on_sent(asio::error_code const& error , std::size_t bytes_transferred) = 0; - int send_buffer_size() const - { - return (int)m_send_buffer[0].size() - + (int)m_send_buffer[1].size() - - m_write_pos; - } - #ifndef TORRENT_DISABLE_ENCRYPTION buffer::interval wr_recv_buffer() { @@ -512,31 +522,13 @@ namespace libtorrent int m_recv_pos; buffer m_recv_buffer; - // this is the buffer where data that is - // to be sent is stored until it gets - // consumed by send(). Since asio requires - // the memory buffer that is given to async. - // operations to remain valid until the operation - // finishes, there has to be two buffers. While - // waiting for a async_write operation on one - // buffer, the other is used to write data to - // be queued up. - buffer m_send_buffer[2]; - // the current send buffer is the one to write to. - // (m_current_send_buffer + 1) % 2 is the - // buffer we're currently waiting for. - int m_current_send_buffer; + chained_buffer m_send_buffer; // the number of bytes we are currently reading // from disk, that will be added to the send // buffer as soon as they complete int m_reading_bytes; - // if the sending buffer doesn't finish in one send - // operation, this is the position within that buffer - // where the next operation should continue - int m_write_pos; - // timeouts ptime m_last_receive; ptime m_last_sent; diff --git a/libtorrent/include/libtorrent/storage.hpp b/libtorrent/include/libtorrent/storage.hpp index 9db79ea3d..67d74153d 100755 --- a/libtorrent/include/libtorrent/storage.hpp +++ b/libtorrent/include/libtorrent/storage.hpp @@ -184,6 +184,9 @@ namespace libtorrent std::pair check_files(std::vector& pieces , int& num_pieces, boost::recursive_mutex& mutex); + // frees a buffer that was returned from a read operation + void free_buffer(char* buf); + void write_resume_data(entry& rd) const; bool verify_resume_data(entry& rd, std::string& error); diff --git a/libtorrent/include/libtorrent/time.hpp b/libtorrent/include/libtorrent/time.hpp index 27d61af9d..0c4eab0e8 100644 --- a/libtorrent/include/libtorrent/time.hpp +++ b/libtorrent/include/libtorrent/time.hpp @@ -49,6 +49,8 @@ namespace libtorrent std::strftime(str, 200, "%b %d %X", timeinfo); return str; } + + inline std::string log_time(); } #if (!defined (__MACH__) && !defined (_WIN32) && (!defined(_POSIX_MONOTONIC_CLOCK) \ @@ -389,5 +391,6 @@ namespace libtorrent #endif #endif + #endif diff --git a/libtorrent/include/libtorrent/upnp.hpp b/libtorrent/include/libtorrent/upnp.hpp index fc0650631..2c819df5f 100644 --- a/libtorrent/include/libtorrent/upnp.hpp +++ b/libtorrent/include/libtorrent/upnp.hpp @@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/broadcast_socket.hpp" #include "libtorrent/http_connection.hpp" #include "libtorrent/connection_queue.hpp" +#include "libtorrent/intrusive_ptr_base.hpp" #include #include @@ -62,7 +63,7 @@ namespace libtorrent // std::string: error message typedef boost::function portmap_callback_t; -class upnp : boost::noncopyable +class upnp : public intrusive_ptr_base { public: upnp(io_service& ios, connection_queue& cc diff --git a/libtorrent/include/libtorrent/web_peer_connection.hpp b/libtorrent/include/libtorrent/web_peer_connection.hpp index 1290f14a1..8c9360e8f 100755 --- a/libtorrent/include/libtorrent/web_peer_connection.hpp +++ b/libtorrent/include/libtorrent/web_peer_connection.hpp @@ -122,7 +122,7 @@ namespace libtorrent void write_request(peer_request const& r); void write_cancel(peer_request const& r) {} void write_have(int index) {} - void write_piece(peer_request const& r, char const* buffer) { assert(false); } + void write_piece(peer_request const& r, char* buffer) { assert(false); } void write_keepalive() {} void on_connected(); void write_reject_request(peer_request const&) {} diff --git a/libtorrent/src/Makefile.am b/libtorrent/src/Makefile.am index 3ab9f73bd..bf652b2c5 100644 --- a/libtorrent/src/Makefile.am +++ b/libtorrent/src/Makefile.am @@ -58,6 +58,7 @@ $(top_srcdir)/include/libtorrent/intrusive_ptr_base.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/chained_buffer.hpp \ $(top_srcdir)/include/libtorrent/lsd.hpp \ $(top_srcdir)/include/libtorrent/peer.hpp \ $(top_srcdir)/include/libtorrent/peer_connection.hpp \ diff --git a/libtorrent/src/bt_peer_connection.cpp b/libtorrent/src/bt_peer_connection.cpp index e27a7f4c3..da7fd8937 100755 --- a/libtorrent/src/bt_peer_connection.cpp +++ b/libtorrent/src/bt_peer_connection.cpp @@ -251,12 +251,10 @@ namespace libtorrent (*m_logger) << time_now_string() << " ==> DHT_PORT [ " << listen_port << " ]\n"; #endif - buffer::interval packet = allocate_send_buffer(7); - detail::write_uint32(3, packet.begin); - detail::write_uint8(msg_dht_port, packet.begin); - detail::write_uint16(listen_port, packet.begin); - assert(packet.begin == packet.end); - setup_send(); + char msg[] = {0,0,0,3, msg_dht_port, 0, 0}; + char* ptr = msg + 5; + detail::write_uint16(listen_port, ptr); + send_buffer(msg, sizeof(msg)); } void bt_peer_connection::write_have_all() @@ -270,8 +268,8 @@ namespace libtorrent (*m_logger) << time_now_string() << " ==> HAVE_ALL\n"; #endif - char buf[] = {0,0,0,1, msg_have_all}; - send_buffer(buf, buf + sizeof(buf)); + char msg[] = {0,0,0,1, msg_have_all}; + send_buffer(msg, sizeof(msg)); } void bt_peer_connection::write_have_none() @@ -285,8 +283,8 @@ namespace libtorrent (*m_logger) << time_now_string() << " ==> HAVE_NONE\n"; #endif - char buf[] = {0,0,0,1, msg_have_none}; - send_buffer(buf, buf + sizeof(buf)); + char msg[] = {0,0,0,1, msg_have_none}; + send_buffer(msg, sizeof(msg)); } void bt_peer_connection::write_reject_request(peer_request const& r) @@ -296,22 +294,12 @@ namespace libtorrent assert(m_sent_handshake && m_sent_bitfield); assert(associated_torrent().lock()->valid_metadata()); - char buf[] = {0,0,0,13, msg_reject_request}; - - buffer::interval i = allocate_send_buffer(17); - - std::copy(buf, buf + 5, i.begin); - i.begin += 5; - - // index - detail::write_int32(r.piece, i.begin); - // begin - detail::write_int32(r.start, i.begin); - // length - detail::write_int32(r.length, i.begin); - assert(i.begin == i.end); - - setup_send(); + char msg[] = {0,0,0,13, msg_reject_request,0,0,0,0, 0,0,0,0, 0,0,0,0}; + char* ptr = msg + 5; + detail::write_int32(r.piece, ptr); // index + detail::write_int32(r.start, ptr); // begin + detail::write_int32(r.length, ptr); // length + send_buffer(msg, sizeof(msg)); } void bt_peer_connection::write_allow_fast(int piece) @@ -321,11 +309,10 @@ namespace libtorrent assert(m_sent_handshake && m_sent_bitfield); assert(associated_torrent().lock()->valid_metadata()); - char buf[] = {0,0,0,5, msg_allowed_fast, 0, 0, 0, 0}; - - char* ptr = buf + 5; + char msg[] = {0,0,0,5, msg_allowed_fast, 0, 0, 0, 0}; + char* ptr = msg + 5; detail::write_int32(piece, ptr); - send_buffer(buf, buf + sizeof(buf)); + send_buffer(msg, sizeof(msg)); } void bt_peer_connection::get_specific_peer_info(peer_info& p) const @@ -556,8 +543,8 @@ namespace libtorrent assert(secret); hasher h; - const char keyA[] = "keyA"; - const char keyB[] = "keyB"; + static const char keyA[] = "keyA"; + static const char keyB[] = "keyB"; // encryption rc4 longkeys // outgoing connection : hash ('keyA',S,SKEY) @@ -587,17 +574,16 @@ namespace libtorrent #endif } - void bt_peer_connection::send_buffer(char* begin, char* end) + void bt_peer_connection::send_buffer(char* buf, int size) { - assert (begin); - assert (end); - assert (end > begin); - assert (!m_rc4_encrypted || m_encrypted); + assert(buf); + assert(size > 0); + assert(!m_rc4_encrypted || m_encrypted); if (m_rc4_encrypted) - m_RC4_handler->encrypt(begin, end - begin); + m_RC4_handler->encrypt(buf, size); - peer_connection::send_buffer(begin, end); + peer_connection::send_buffer(buf, size); } buffer::interval bt_peer_connection::allocate_send_buffer(int size) @@ -606,6 +592,7 @@ namespace libtorrent if (m_rc4_encrypted) { + assert(m_enc_send_buffer.left() == 0); m_enc_send_buffer = peer_connection::allocate_send_buffer(size); return m_enc_send_buffer; } @@ -620,24 +607,24 @@ namespace libtorrent { assert(!m_rc4_encrypted || m_encrypted); - if (m_rc4_encrypted) + if (m_rc4_encrypted && m_enc_send_buffer.left()) { - assert (m_enc_send_buffer.begin); - assert (m_enc_send_buffer.end); - assert (m_enc_send_buffer.left() > 0); + assert(m_enc_send_buffer.begin); + assert(m_enc_send_buffer.end); - m_RC4_handler->encrypt (m_enc_send_buffer.begin, m_enc_send_buffer.left()); + m_RC4_handler->encrypt(m_enc_send_buffer.begin, m_enc_send_buffer.left()); + m_enc_send_buffer.end = m_enc_send_buffer.begin; } peer_connection::setup_send(); } int bt_peer_connection::get_syncoffset(char const* src, int src_size, - char const* target, int target_size) const + char const* target, int target_size) const { - assert (target_size >= src_size); - assert (src_size > 0); - assert (src); - assert (target); + assert(target_size >= src_size); + assert(src_size > 0); + assert(src); + assert(target); int traverse_limit = target_size - src_size; @@ -1288,8 +1275,8 @@ namespace libtorrent assert(m_sent_handshake && m_sent_bitfield); - char buf[] = {0,0,0,0}; - send_buffer(buf, buf + sizeof(buf)); + char msg[] = {0,0,0,0}; + send_buffer(msg, sizeof(msg)); } void bt_peer_connection::write_cancel(peer_request const& r) @@ -1299,22 +1286,12 @@ namespace libtorrent assert(m_sent_handshake && m_sent_bitfield); assert(associated_torrent().lock()->valid_metadata()); - char buf[] = {0,0,0,13, msg_cancel}; - - buffer::interval i = allocate_send_buffer(17); - - std::copy(buf, buf + 5, i.begin); - i.begin += 5; - - // index - detail::write_int32(r.piece, i.begin); - // begin - detail::write_int32(r.start, i.begin); - // length - detail::write_int32(r.length, i.begin); - assert(i.begin == i.end); - - setup_send(); + char msg[17] = {0,0,0,13, msg_cancel}; + char* ptr = msg + 5; + detail::write_int32(r.piece, ptr); // index + detail::write_int32(r.start, ptr); // begin + detail::write_int32(r.length, ptr); // length + send_buffer(msg, sizeof(msg)); } void bt_peer_connection::write_request(peer_request const& r) @@ -1324,22 +1301,13 @@ namespace libtorrent assert(m_sent_handshake && m_sent_bitfield); assert(associated_torrent().lock()->valid_metadata()); - char buf[] = {0,0,0,13, msg_request}; + char msg[17] = {0,0,0,13, msg_request}; + char* ptr = msg + 5; - buffer::interval i = allocate_send_buffer(17); - - std::copy(buf, buf + 5, i.begin); - i.begin += 5; - - // index - detail::write_int32(r.piece, i.begin); - // begin - detail::write_int32(r.start, i.begin); - // length - detail::write_int32(r.length, i.begin); - assert(i.begin == i.end); - - setup_send(); + detail::write_int32(r.piece, ptr); // index + detail::write_int32(r.start, ptr); // begin + detail::write_int32(r.length, ptr); // length + send_buffer(msg, sizeof(msg)); } void bt_peer_connection::write_bitfield(std::vector const& bitfield) @@ -1526,7 +1494,7 @@ namespace libtorrent if (is_choked()) return; char msg[] = {0,0,0,1,msg_choke}; - send_buffer(msg, msg + sizeof(msg)); + send_buffer(msg, sizeof(msg)); } void bt_peer_connection::write_unchoke() @@ -1536,7 +1504,7 @@ namespace libtorrent assert(m_sent_handshake && m_sent_bitfield); char msg[] = {0,0,0,1,msg_unchoke}; - send_buffer(msg, msg + sizeof(msg)); + send_buffer(msg, sizeof(msg)); } void bt_peer_connection::write_interested() @@ -1546,7 +1514,7 @@ namespace libtorrent assert(m_sent_handshake && m_sent_bitfield); char msg[] = {0,0,0,1,msg_interested}; - send_buffer(msg, msg + sizeof(msg)); + send_buffer(msg, sizeof(msg)); } void bt_peer_connection::write_not_interested() @@ -1556,7 +1524,7 @@ namespace libtorrent assert(m_sent_handshake && m_sent_bitfield); char msg[] = {0,0,0,1,msg_not_interested}; - send_buffer(msg, msg + sizeof(msg)); + send_buffer(msg, sizeof(msg)); } void bt_peer_connection::write_have(int index) @@ -1567,34 +1535,39 @@ namespace libtorrent assert(index < associated_torrent().lock()->torrent_file().num_pieces()); assert(m_sent_handshake && m_sent_bitfield); - const int packet_size = 9; - char msg[packet_size] = {0,0,0,5,msg_have}; + char msg[] = {0,0,0,5,msg_have,0,0,0,0}; char* ptr = msg + 5; detail::write_int32(index, ptr); - send_buffer(msg, msg + packet_size); + send_buffer(msg, sizeof(msg)); } - void bt_peer_connection::write_piece(peer_request const& r, char const* buffer) + void bt_peer_connection::write_piece(peer_request const& r, char* buffer) { INVARIANT_CHECK; assert(m_sent_handshake && m_sent_bitfield); - const int packet_size = 4 + 5 + 4 + r.length; - boost::shared_ptr t = associated_torrent().lock(); assert(t); - buffer::interval i = allocate_send_buffer(packet_size); - - detail::write_int32(packet_size-4, i.begin); - detail::write_uint8(msg_piece, i.begin); - detail::write_int32(r.piece, i.begin); - detail::write_int32(r.start, i.begin); + char msg[4 + 1 + 4 + 4]; + char* ptr = msg; + assert(r.length <= 16 * 1024); + detail::write_int32(r.length + 1 + 4 + 4, ptr); + detail::write_uint8(msg_piece, ptr); + detail::write_int32(r.piece, ptr); + detail::write_int32(r.start, ptr); + send_buffer(msg, sizeof(msg)); + + append_send_buffer(buffer, r.length + , boost::bind(&session_impl::free_disk_buffer + , boost::ref(m_ses), _1)); + +/* + buffer::interval i = allocate_send_buffer(r.length); std::memcpy(i.begin, buffer, r.length); - - assert(i.begin + r.length == i.end); - + t->filesystem().free_buffer(buffer); +*/ m_payloads.push_back(range(send_buffer_size() - r.length, r.length)); setup_send(); } diff --git a/libtorrent/src/disk_io_thread.cpp b/libtorrent/src/disk_io_thread.cpp index 4fb2cfb3a..c7f766ac4 100644 --- a/libtorrent/src/disk_io_thread.cpp +++ b/libtorrent/src/disk_io_thread.cpp @@ -37,18 +37,6 @@ POSSIBILITY OF SUCH DAMAGE. #ifdef TORRENT_DISK_STATS #include "libtorrent/time.hpp" -#include - -namespace -{ - std::string log_time() - { - using namespace libtorrent; - static ptime start = time_now(); - return boost::lexical_cast( - total_milliseconds(time_now() - start)); - } -} #endif @@ -64,7 +52,9 @@ namespace libtorrent #endif , m_disk_io_thread(boost::ref(*this)) { - +#ifdef TORRENT_STATS + m_allocations = 0; +#endif #ifdef TORRENT_DISK_STATS m_log.open("disk_io_thread.log", std::ios::trunc); #endif @@ -188,9 +178,21 @@ namespace libtorrent char* disk_io_thread::allocate_buffer() { boost::mutex::scoped_lock l(m_mutex); +#ifdef TORRENT_STATS + ++m_allocations; +#endif return (char*)m_pool.ordered_malloc(); } + void disk_io_thread::free_buffer(char* buf) + { + boost::mutex::scoped_lock l(m_mutex); +#ifdef TORRENT_STATS + --m_allocations; +#endif + m_pool.ordered_free(buf); + } + void disk_io_thread::operator()() { for (;;) @@ -225,10 +227,14 @@ namespace libtorrent #ifdef TORRENT_DISK_STATS m_log << log_time() << " read " << j.buffer_size << std::endl; #endif + free_buffer = false; if (j.buffer == 0) { l.lock(); j.buffer = (char*)m_pool.ordered_malloc(); +#ifdef TORRENT_STATS + ++m_allocations; +#endif l.unlock(); assert(j.buffer_size <= m_block_size); if (j.buffer == 0) @@ -238,10 +244,6 @@ namespace libtorrent break; } } - else - { - free_buffer = false; - } ret = j.storage->read_impl(j.buffer, j.piece, j.offset , j.buffer_size); @@ -301,6 +303,9 @@ namespace libtorrent { l.lock(); m_pool.ordered_free(j.buffer); +#ifdef TORRENT_STATS + --m_allocations; +#endif } } } diff --git a/libtorrent/src/http_connection.cpp b/libtorrent/src/http_connection.cpp index 2b306ca6d..5a0cfb741 100644 --- a/libtorrent/src/http_connection.cpp +++ b/libtorrent/src/http_connection.cpp @@ -263,7 +263,7 @@ void http_connection::on_read(asio::error_code const& e if (code >= 300 && code < 400) { // attempt a redirect - std::string url = m_parser.header("location"); + std::string const& url = m_parser.header("location"); if (url.empty()) { // missing location header diff --git a/libtorrent/src/http_tracker_connection.cpp b/libtorrent/src/http_tracker_connection.cpp index 64dea2e2e..8c54cf7ff 100755 --- a/libtorrent/src/http_tracker_connection.cpp +++ b/libtorrent/src/http_tracker_connection.cpp @@ -679,7 +679,7 @@ namespace libtorrent if (m_parser.header_finished()) { - int cl = m_parser.header("content-length"); + int cl = atoi(m_parser.header("content-length").c_str()); if (cl > m_settings.tracker_maximum_response_length) { fail(-1, "content-length is greater than maximum response length"); @@ -718,7 +718,7 @@ namespace libtorrent return; } - std::string location = m_parser.header("location"); + std::string location = m_parser.header("location"); boost::shared_ptr cb = requester(); @@ -763,7 +763,7 @@ namespace libtorrent 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"); + std::string content_encoding = m_parser.header("content-encoding"); #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) if (cb) cb->debug_log("content-encoding: \"" + content_encoding + "\""); diff --git a/libtorrent/src/lsd.cpp b/libtorrent/src/lsd.cpp index d7590ec47..cab115515 100644 --- a/libtorrent/src/lsd.cpp +++ b/libtorrent/src/lsd.cpp @@ -58,7 +58,7 @@ lsd::lsd(io_service& ios, address const& listen_interface : m_callback(cb) , m_retry_count(0) , m_socket(ios, udp::endpoint(address_v4::from_string("239.192.152.143"), 6771) - , bind(&lsd::on_announce, this, _1, _2, _3)) + , bind(&lsd::on_announce, self(), _1, _2, _3)) , m_broadcast_timer(ios) , m_disabled(false) { @@ -96,7 +96,7 @@ void lsd::announce(sha1_hash const& ih, int listen_port) #endif m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count)); - m_broadcast_timer.async_wait(bind(&lsd::resend_announce, this, _1, msg)); + m_broadcast_timer.async_wait(bind(&lsd::resend_announce, self(), _1, msg)); } void lsd::resend_announce(asio::error_code const& e, std::string msg) try @@ -111,7 +111,7 @@ void lsd::resend_announce(asio::error_code const& e, std::string msg) try return; m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count)); - m_broadcast_timer.async_wait(bind(&lsd::resend_announce, this, _1, msg)); + m_broadcast_timer.async_wait(bind(&lsd::resend_announce, self(), _1, msg)); } catch (std::exception&) {} @@ -121,48 +121,53 @@ void lsd::on_announce(udp::endpoint const& from, char* buffer { using namespace libtorrent::detail; - char* p = buffer; - char* end = buffer + bytes_transferred; - char* line = std::find(p, end, '\n'); - for (char* i = p; i < line; ++i) *i = std::tolower(*i); -#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) - m_log << time_now_string() - << " <== announce: " << std::string(p, line) << std::endl; -#endif - if (line == end || (line - p >= 9 && std::memcmp("bt-search", p, 9))) + http_parser p; + + p.incoming(buffer::const_interval(buffer, buffer + bytes_transferred)); + + if (!p.header_finished()) { #if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) - m_log << time_now_string() - << " *** assumed 'bt-search', ignoring" << std::endl; + m_log << time_now_string() + << " <== announce: incomplete HTTP message\n"; #endif return; } - p = line + 1; - int port = 0; - sha1_hash ih(0); - while (p != end) + + if (p.method() != "bt-search") { - line = std::find(p, end, '\n'); - if (line == end) break; - *line = 0; - for (char* i = p; i < line; ++i) *i = std::tolower(*i); - if (line - p >= 5 && memcmp(p, "port:", 5) == 0) - { - p += 5; - while (*p == ' ') ++p; - port = atoi(p); - } - else if (line - p >= 9 && memcmp(p, "infohash:", 9) == 0) - { - p += 9; - while (*p == ' ') ++p; - if (line - p > 40) p[40] = 0; - try { ih = boost::lexical_cast(p); } - catch (std::exception&) {} - } - p = line + 1; +#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) + m_log << time_now_string() + << " <== announce: invalid HTTP method: " << p.method() << std::endl; +#endif + return; } + std::string const& port_str = p.header("port"); + if (port_str.empty()) + { +#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) + m_log << time_now_string() + << " <== announce: invalid BT-SEARCH, missing port" << std::endl; +#endif + return; + } + + std::string const& ih_str = p.header("infohash"); + if (ih_str.empty()) + { +#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) + m_log << time_now_string() + << " <== announce: invalid BT-SEARCH, missing infohash" << std::endl; +#endif + return; + } + + sha1_hash ih(0); + std::istringstream ih_sstr(ih_str); + ih_sstr >> ih; + int port = atoi(port_str.c_str()); + if (!ih.is_all_zeros() && port != 0) { #if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) diff --git a/libtorrent/src/natpmp.cpp b/libtorrent/src/natpmp.cpp index bdcabce9a..5ddbb8dd8 100644 --- a/libtorrent/src/natpmp.cpp +++ b/libtorrent/src/natpmp.cpp @@ -161,7 +161,7 @@ void natpmp::update_mapping(int i, int port) m_retry_count = 0; send_map_request(i); m_socket.async_receive_from(asio::buffer(&m_response_buffer, 16) - , m_remote, bind(&natpmp::on_reply, this, _1, _2)); + , m_remote, bind(&natpmp::on_reply, self(), _1, _2)); } } @@ -194,7 +194,7 @@ void natpmp::send_map_request(int i) try // linear back-off instead of exponential ++m_retry_count; m_send_timer.expires_from_now(milliseconds(250 * m_retry_count)); - m_send_timer.async_wait(bind(&natpmp::resend_request, this, i, _1)); + m_send_timer.async_wait(bind(&natpmp::resend_request, self(), i, _1)); } catch (std::exception& e) { @@ -227,7 +227,7 @@ void natpmp::on_reply(asio::error_code const& e if (m_remote != m_nat_endpoint) { m_socket.async_receive_from(asio::buffer(&m_response_buffer, 16) - , m_remote, bind(&natpmp::on_reply, this, _1, _2)); + , m_remote, bind(&natpmp::on_reply, self(), _1, _2)); return; } @@ -346,7 +346,7 @@ void natpmp::update_expiration_timer() if (min_index >= 0) { m_refresh_timer.expires_from_now(min_expire - now); - m_refresh_timer.async_wait(bind(&natpmp::mapping_expired, this, _1, min_index)); + m_refresh_timer.async_wait(bind(&natpmp::mapping_expired, self(), _1, min_index)); } } @@ -369,7 +369,7 @@ void natpmp::refresh_mapping(int i) m_retry_count = 0; send_map_request(i); m_socket.async_receive_from(asio::buffer(&m_response_buffer, 16) - , m_remote, bind(&natpmp::on_reply, this, _1, _2)); + , m_remote, bind(&natpmp::on_reply, self(), _1, _2)); } } diff --git a/libtorrent/src/peer_connection.cpp b/libtorrent/src/peer_connection.cpp index ad5087325..535a90142 100755 --- a/libtorrent/src/peer_connection.cpp +++ b/libtorrent/src/peer_connection.cpp @@ -81,9 +81,7 @@ namespace libtorrent , m_last_unchoke(min_time()) , m_packet_size(0) , m_recv_pos(0) - , m_current_send_buffer(0) , m_reading_bytes(0) - , m_write_pos(0) , m_last_receive(time_now()) , m_last_sent(time_now()) , m_socket(s) @@ -161,9 +159,7 @@ namespace libtorrent , m_last_unchoke(min_time()) , m_packet_size(0) , m_recv_pos(0) - , m_current_send_buffer(0) , m_reading_bytes(0) - , m_write_pos(0) , m_last_receive(time_now()) , m_last_sent(time_now()) , m_socket(s) @@ -2082,8 +2078,7 @@ namespace libtorrent p.remote_dl_rate = 0; } - p.send_buffer_size = int(m_send_buffer[0].capacity() - + m_send_buffer[1].capacity()); + p.send_buffer_size = m_send_buffer.capacity(); } void peer_connection::cut_receive_buffer(int size, int packet_size) @@ -2386,8 +2381,7 @@ namespace libtorrent 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_send_buffer.empty() && !m_connecting && t && !m_ignore_bandwidth_limits) @@ -2415,32 +2409,21 @@ namespace libtorrent assert(!m_writing); - int sending_buffer = (m_current_send_buffer + 1) & 1; - if (m_send_buffer[sending_buffer].empty()) - { - // 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; - } - // send the actual buffer - if (!m_send_buffer[sending_buffer].empty()) + if (!m_send_buffer.empty()) { - int amount_to_send = (int)m_send_buffer[sending_buffer].size() - m_write_pos; + int amount_to_send = m_send_buffer.size(); int quota_left = m_bandwidth_limit[upload_channel].quota_left(); if (!m_ignore_bandwidth_limits && amount_to_send > quota_left) amount_to_send = quota_left; assert(amount_to_send > 0); - assert(m_write_pos < (int)m_send_buffer[sending_buffer].size()); #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << "async_write " << amount_to_send << " bytes\n"; #endif - m_socket->async_write_some(asio::buffer( - &m_send_buffer[sending_buffer][m_write_pos], amount_to_send) - , bind(&peer_connection::on_send_data, self(), _1, _2)); + std::list const& vec = m_send_buffer.build_iovec(amount_to_send); + m_socket->async_write_some(vec, bind(&peer_connection::on_send_data, self(), _1, _2)); m_writing = true; } @@ -2511,10 +2494,32 @@ namespace libtorrent m_recv_buffer.resize(m_packet_size); } - void peer_connection::send_buffer(char const* begin, char const* end) + void peer_connection::send_buffer(char const* buf, int size) { - buffer& buf = m_send_buffer[m_current_send_buffer]; - buf.insert(buf.end(), begin, end); + int free_space = m_send_buffer.space_in_last_buffer(); + if (free_space > size) free_space = size; + if (free_space > 0) + { + m_send_buffer.append(buf, free_space); + size -= free_space; + buf += free_space; +#ifdef TORRENT_STATS + m_ses.m_buffer_usage_logger << log_time() << " send_buffer: " + << free_space << std::endl; + m_ses.log_buffer_usage(); +#endif + } + if (size <= 0) return; + + std::pair buffer = m_ses.allocate_buffer(size); + assert(buffer.second >= size); + std::memcpy(buffer.first, buf, size); + m_send_buffer.append_buffer(buffer.first, buffer.second, size + , bind(&session_impl::free_buffer, boost::ref(m_ses), _1, buffer.second)); +#ifdef TORRENT_STATS + m_ses.m_buffer_usage_logger << log_time() << " send_buffer_alloc: " << size << std::endl; + m_ses.log_buffer_usage(); +#endif setup_send(); } @@ -2522,10 +2527,29 @@ namespace libtorrent // return value is destructed buffer::interval peer_connection::allocate_send_buffer(int size) { - buffer& buf = m_send_buffer[m_current_send_buffer]; - buf.resize(buf.size() + size); - buffer::interval ret(&buf[0] + buf.size() - size, &buf[0] + buf.size()); - return ret; + char* insert = m_send_buffer.allocate_appendix(size); + if (insert == 0) + { + std::pair buffer = m_ses.allocate_buffer(size); + assert(buffer.second >= size); + m_send_buffer.append_buffer(buffer.first, buffer.second, size + , bind(&session_impl::free_buffer, boost::ref(m_ses), _1, buffer.second)); + buffer::interval ret(buffer.first, buffer.first + size); +#ifdef TORRENT_STATS + m_ses.m_buffer_usage_logger << log_time() << " allocate_buffer_alloc: " << size << std::endl; + m_ses.log_buffer_usage(); +#endif + return ret; + } + else + { +#ifdef TORRENT_STATS + m_ses.m_buffer_usage_logger << log_time() << " allocate_buffer: " << size << std::endl; + m_ses.log_buffer_usage(); +#endif + buffer::interval ret(insert, insert + size); + return ret; + } } template @@ -2647,8 +2671,7 @@ namespace libtorrent // if we have requests or pending data to be sent or announcements to be made // we want to send data - return (!m_send_buffer[m_current_send_buffer].empty() - || !m_send_buffer[(m_current_send_buffer + 1) & 1].empty()) + return !m_send_buffer.empty() && (m_bandwidth_limit[upload_channel].quota_left() > 0 || m_ignore_bandwidth_limits) && !m_connecting; @@ -2763,6 +2786,9 @@ namespace libtorrent INVARIANT_CHECK; assert(m_writing); + + m_send_buffer.pop_front(bytes_transferred); + m_writing = false; if (!m_ignore_bandwidth_limits) @@ -2772,9 +2798,6 @@ namespace libtorrent (*m_logger) << "wrote " << bytes_transferred << " bytes\n"; #endif - m_write_pos += bytes_transferred; - - if (error) { #ifdef TORRENT_VERBOSE_LOGGING @@ -2787,34 +2810,11 @@ namespace libtorrent assert(!m_connecting); assert(bytes_transferred > 0); - int sending_buffer = (m_current_send_buffer + 1) & 1; - - assert(int(m_send_buffer[sending_buffer].size()) >= m_write_pos); - if (int(m_send_buffer[sending_buffer].size()) == m_write_pos) - { - m_send_buffer[sending_buffer].clear(); - m_write_pos = 0; - } - m_last_sent = time_now(); on_sent(error, bytes_transferred); fill_send_buffer(); - if (m_choked) - { - for (int i = 0; i < 2; ++i) - { - if (int(m_send_buffer[i].size()) < 64 - && int(m_send_buffer[i].capacity()) > 128) - { - buffer tmp(m_send_buffer[i]); - tmp.swap(m_send_buffer[i]); - assert(m_send_buffer[i].capacity() == m_send_buffer[i].size()); - } - } - } - setup_send(); } catch (std::exception& e) @@ -2876,8 +2876,6 @@ namespace libtorrent } } */ - assert(m_write_pos <= int(m_send_buffer[ - (m_current_send_buffer + 1) & 1].size())); // extremely expensive invariant check /* diff --git a/libtorrent/src/policy.cpp b/libtorrent/src/policy.cpp index 49671c5db..014d3ccaa 100755 --- a/libtorrent/src/policy.cpp +++ b/libtorrent/src/policy.cpp @@ -1426,16 +1426,16 @@ namespace libtorrent int nonempty_connections = 0; std::set
unique_test; - std::set unique_test2; +// std::set unique_test2; for (const_iterator i = m_peers.begin(); i != m_peers.end(); ++i) { peer const& p = *i; - if (!m_torrent->settings().allow_multiple_connections_per_ip) - assert(unique_test.find(p.ip.address()) == unique_test.end()); - assert(unique_test2.find(p.ip) == unique_test2.end()); - unique_test.insert(p.ip.address()); - unique_test2.insert(p.ip); +// if (!m_torrent->settings().allow_multiple_connections_per_ip) +// assert(unique_test.find(p.ip.address()) == unique_test.end()); +// assert(unique_test2.find(p.ip) == unique_test2.end()); +// unique_test.insert(p.ip.address()); +// unique_test2.insert(p.ip); ++total_connections; if (!p.connection) { diff --git a/libtorrent/src/session.cpp b/libtorrent/src/session.cpp index 6298b3c2c..478c6fe93 100755 --- a/libtorrent/src/session.cpp +++ b/libtorrent/src/session.cpp @@ -83,6 +83,14 @@ using libtorrent::aux::session_impl; namespace libtorrent { + std::string log_time() + { + static const ptime start = time_now(); + char ret[200]; + std::sprintf(ret, "%d", total_milliseconds(time_now() - start)); + return ret; + } + namespace aux { filesystem_init::filesystem_init() diff --git a/libtorrent/src/session_impl.cpp b/libtorrent/src/session_impl.cpp index a58906156..cca3e7059 100755 --- a/libtorrent/src/session_impl.cpp +++ b/libtorrent/src/session_impl.cpp @@ -507,7 +507,8 @@ namespace detail std::pair listen_port_range , fingerprint const& cl_fprint , char const* listen_interface) - : m_strand(m_io_service) + : m_send_buffers(send_buffer_size) + , m_strand(m_io_service) , m_files(40) , m_half_open(m_io_service) , m_download_channel(m_io_service, peer_connection::download_channel) @@ -546,7 +547,7 @@ namespace detail #endif #ifdef TORRENT_STATS - m_stats_logger.open("session_stats.log"); + m_stats_logger.open("session_stats.log", std::ios::trunc); m_stats_logger << "1. second\n" "2. upload rate\n" @@ -555,7 +556,9 @@ namespace detail "5. seeding torrents\n" "6. peers\n" "7. connecting peers\n" + "8. disk block buffers\n" "\n"; + m_buffer_usage_logger.open("buffer_stats.log", std::ios::trunc); m_second_counter = 0; #endif @@ -999,7 +1002,8 @@ namespace detail { session_impl::mutex_t::scoped_lock l(m_mutex); - INVARIANT_CHECK; +// too expensive +// INVARIANT_CHECK; if (e) { @@ -1031,7 +1035,7 @@ namespace detail else ++downloading_torrents; } - int num_connections = 0; + int num_complete_connections = 0; int num_half_open = 0; for (connection_map::iterator i = m_connections.begin() , end(m_connections.end()); i != end; ++i) @@ -1039,7 +1043,7 @@ namespace detail if (i->second->is_connecting()) ++num_half_open; else - ++num_connections; + ++num_complete_connections; } m_stats_logger @@ -1048,8 +1052,9 @@ namespace detail << m_stat.download_rate() << "\t" << downloading_torrents << "\t" << seeding_torrents << "\t" - << num_connections << "\t" + << num_complete_connections << "\t" << num_half_open << "\t" + << m_disk_thread.disk_allocations() << "\t" << std::endl; #endif @@ -2195,9 +2200,9 @@ namespace detail INVARIANT_CHECK; - m_lsd.reset(new lsd(m_io_service + m_lsd = new lsd(m_io_service , m_listen_interface.address() - , bind(&session_impl::on_lsd_peer, this, _1, _2))); + , bind(&session_impl::on_lsd_peer, this, _1, _2)); } void session_impl::start_natpmp() @@ -2206,10 +2211,10 @@ namespace detail INVARIANT_CHECK; - m_natpmp.reset(new natpmp(m_io_service + m_natpmp = new natpmp(m_io_service , m_listen_interface.address() , bind(&session_impl::on_port_mapping - , this, _1, _2, _3))); + , this, _1, _2, _3)); m_natpmp->set_mappings(m_listen_interface.port(), #ifndef TORRENT_DISABLE_DHT @@ -2224,11 +2229,11 @@ namespace detail INVARIANT_CHECK; - m_upnp.reset(new upnp(m_io_service, m_half_open + m_upnp = new upnp(m_io_service, m_half_open , m_listen_interface.address() , m_settings.user_agent , bind(&session_impl::on_port_mapping - , this, _1, _2, _3))); + , this, _1, _2, _3)); m_upnp->set_mappings(m_listen_interface.port(), #ifndef TORRENT_DISABLE_DHT @@ -2240,7 +2245,7 @@ namespace detail void session_impl::stop_lsd() { mutex_t::scoped_lock l(m_mutex); - m_lsd.reset(); + m_lsd = 0; } void session_impl::stop_natpmp() @@ -2248,7 +2253,7 @@ namespace detail mutex_t::scoped_lock l(m_mutex); if (m_natpmp.get()) m_natpmp->close(); - m_natpmp.reset(); + m_natpmp = 0; } void session_impl::stop_upnp() @@ -2256,9 +2261,38 @@ namespace detail mutex_t::scoped_lock l(m_mutex); if (m_upnp.get()) m_upnp->close(); - m_upnp.reset(); + m_upnp = 0; } + void session_impl::free_disk_buffer(char* buf) + { + m_disk_thread.free_buffer(buf); + } + + std::pair session_impl::allocate_buffer(int size) + { + int num_buffers = (size + send_buffer_size - 1) / send_buffer_size; +#ifdef TORRENT_STATS + m_buffer_allocations += num_buffers; + m_buffer_usage_logger << log_time() << " protocol_buffer: " + << (m_buffer_allocations * send_buffer_size) << std::endl; +#endif + return std::make_pair((char*)m_send_buffers.ordered_malloc(num_buffers) + , num_buffers * send_buffer_size); + } + + void session_impl::free_buffer(char* buf, int size) + { + assert(size % send_buffer_size == 0); + int num_buffers = size / send_buffer_size; +#ifdef TORRENT_STATS + m_buffer_allocations -= num_buffers; + assert(m_buffer_allocations >= 0); + m_buffer_usage_logger << log_time() << " protocol_buffer: " + << (m_buffer_allocations * send_buffer_size) << std::endl; +#endif + m_send_buffers.ordered_free(buf, num_buffers); + } #ifndef NDEBUG void session_impl::check_invariant() const diff --git a/libtorrent/src/storage.cpp b/libtorrent/src/storage.cpp index dbf6a9382..8c8d62a68 100755 --- a/libtorrent/src/storage.cpp +++ b/libtorrent/src/storage.cpp @@ -1065,6 +1065,11 @@ namespace libtorrent return m_storage->verify_resume_data(rd, error); } + void piece_manager::free_buffer(char* buf) + { + m_io_thread.free_buffer(buf); + } + void piece_manager::async_release_files( boost::function const& handler) { diff --git a/libtorrent/src/torrent.cpp b/libtorrent/src/torrent.cpp index efd2b92c2..e9b2cd79e 100755 --- a/libtorrent/src/torrent.cpp +++ b/libtorrent/src/torrent.cpp @@ -1464,9 +1464,6 @@ namespace libtorrent m_policy->connection_closed(*p); p->set_peer_info(0); m_connections.erase(i); -#ifndef NDEBUG - m_policy->check_invariant(); -#endif } catch (std::exception& e) { @@ -2940,4 +2937,3 @@ namespace libtorrent } - diff --git a/libtorrent/src/torrent_info.cpp b/libtorrent/src/torrent_info.cpp index c110aca3c..76c10e572 100755 --- a/libtorrent/src/torrent_info.cpp +++ b/libtorrent/src/torrent_info.cpp @@ -901,4 +901,3 @@ namespace libtorrent } } - diff --git a/libtorrent/src/upnp.cpp b/libtorrent/src/upnp.cpp index 87f950b48..2f5d4a992 100644 --- a/libtorrent/src/upnp.cpp +++ b/libtorrent/src/upnp.cpp @@ -70,7 +70,7 @@ upnp::upnp(io_service& ios, connection_queue& cc , m_io_service(ios) , m_strand(ios) , m_socket(ios, udp::endpoint(address_v4::from_string("239.255.255.250"), 1900) - , m_strand.wrap(bind(&upnp::on_reply, this, _1, _2, _3)), false) + , m_strand.wrap(bind(&upnp::on_reply, self(), _1, _2, _3)), false) , m_broadcast_timer(ios) , m_refresh_timer(ios) , m_disabled(false) @@ -119,7 +119,7 @@ void upnp::discover_device() try ++m_retry_count; m_broadcast_timer.expires_from_now(milliseconds(250 * m_retry_count)); m_broadcast_timer.async_wait(m_strand.wrap(bind(&upnp::resend_request - , this, _1))); + , self(), _1))); #ifdef TORRENT_UPNP_LOGGING m_log << time_now_string() @@ -203,7 +203,7 @@ try try { d.upnp_connection.reset(new http_connection(m_io_service - , m_cc, m_strand.wrap(bind(&upnp::on_upnp_xml, this, _1, _2 + , m_cc, m_strand.wrap(bind(&upnp::on_upnp_xml, self(), _1, _2 , boost::ref(d))))); d.upnp_connection->get(d.url); } @@ -300,7 +300,7 @@ try return; } - std::string url = p.header("location"); + std::string url = p.header("location"); if (url.empty()) { #ifdef TORRENT_UPNP_LOGGING @@ -393,7 +393,7 @@ try try { d.upnp_connection.reset(new http_connection(m_io_service - , m_cc, m_strand.wrap(bind(&upnp::on_upnp_xml, this, _1, _2 + , m_cc, m_strand.wrap(bind(&upnp::on_upnp_xml, self(), _1, _2 , boost::ref(d))))); d.upnp_connection->get(d.url); } @@ -480,9 +480,9 @@ void upnp::map_port(rootdevice& d, int i) assert(d.service_namespace); d.upnp_connection.reset(new http_connection(m_io_service - , m_cc, m_strand.wrap(bind(&upnp::on_upnp_map_response, this, _1, _2 + , m_cc, m_strand.wrap(bind(&upnp::on_upnp_map_response, self(), _1, _2 , boost::ref(d), i)), true - , bind(&upnp::create_port_mapping, this, _1, boost::ref(d), i))); + , bind(&upnp::create_port_mapping, self(), _1, boost::ref(d), i))); d.upnp_connection->start(d.hostname, boost::lexical_cast(d.port) , seconds(10)); @@ -523,9 +523,9 @@ void upnp::unmap_port(rootdevice& d, int i) return; } d.upnp_connection.reset(new http_connection(m_io_service - , m_cc, m_strand.wrap(bind(&upnp::on_upnp_unmap_response, this, _1, _2 + , m_cc, m_strand.wrap(bind(&upnp::on_upnp_unmap_response, self(), _1, _2 , boost::ref(d), i)), true - , bind(&upnp::delete_port_mapping, this, boost::ref(d), i))); + , bind(&upnp::delete_port_mapping, self(), boost::ref(d), i))); d.upnp_connection->start(d.hostname, boost::lexical_cast(d.port) , seconds(10)); @@ -851,7 +851,7 @@ void upnp::on_upnp_map_response(asio::error_code const& e || next_expire > d.mapping[mapping].expires) { m_refresh_timer.expires_at(d.mapping[mapping].expires); - m_refresh_timer.async_wait(m_strand.wrap(bind(&upnp::on_expire, this, _1))); + m_refresh_timer.async_wait(m_strand.wrap(bind(&upnp::on_expire, self(), _1))); } } else @@ -962,7 +962,7 @@ void upnp::on_expire(asio::error_code const& e) try if (next_expire != max_time()) { m_refresh_timer.expires_at(next_expire); - m_refresh_timer.async_wait(m_strand.wrap(bind(&upnp::on_expire, this, _1))); + m_refresh_timer.async_wait(m_strand.wrap(bind(&upnp::on_expire, self(), _1))); } } catch (std::exception&) diff --git a/libtorrent/src/web_peer_connection.cpp b/libtorrent/src/web_peer_connection.cpp index a307fc9cb..bc09b4935 100755 --- a/libtorrent/src/web_peer_connection.cpp +++ b/libtorrent/src/web_peer_connection.cpp @@ -297,7 +297,7 @@ namespace libtorrent (*m_logger) << request << "\n"; #endif - send_buffer(request.c_str(), request.c_str() + request.size()); + send_buffer(request.c_str(), request.size()); } // -------------------------- @@ -387,7 +387,7 @@ namespace libtorrent { // this means we got a redirection request // look for the location header - std::string location = m_parser.header("location"); + std::string location = m_parser.header("location"); if (location.empty()) { @@ -423,7 +423,7 @@ namespace libtorrent throw std::runtime_error("redirecting to " + location); } - std::string server_version = m_parser.header("server"); + std::string const& server_version = m_parser.header("server"); if (!server_version.empty()) { m_server_string = "URL seed @ "; @@ -445,7 +445,7 @@ namespace libtorrent size_type range_end; if (m_parser.status_code() == 206) { - std::stringstream range_str(m_parser.header("content-range")); + std::stringstream range_str(m_parser.header("content-range")); char dummy; std::string bytes; range_str >> bytes >> range_start >> dummy >> range_end; @@ -461,7 +461,7 @@ namespace libtorrent else { range_start = 0; - range_end = m_parser.header("content-length"); + range_end = atol(m_parser.header("content-length").c_str()); if (range_end == -1) { // we should not try this server again. diff --git a/plugins/MoveTorrent/__init__.py b/plugins/MoveTorrent/__init__.py index 4feac325e..315d5cc20 100644 --- a/plugins/MoveTorrent/__init__.py +++ b/plugins/MoveTorrent/__init__.py @@ -18,7 +18,7 @@ plugin_name = _("Move Torrent") plugin_author = "Marcos Pinto" -plugin_version = "0.1" +plugin_version = "0.2" plugin_description = _("This plugin allows users to move the torrent to a \ different directory without having to remove and re-add the torrent. This \ feature can be found by right-clicking on a torrent.\nFurthermore, it \