diff --git a/glade/preferences_dialog.glade b/glade/preferences_dialog.glade
index fc8815df5..c80dee3cc 100644
--- a/glade/preferences_dialog.glade
+++ b/glade/preferences_dialog.glade
@@ -315,108 +315,24 @@
4
2
-
+
True
- True
- The maximum upload rate for all torrents. Set -1 for unlimited.
- 1
- -1 -1 9000 1 10 10
- 1
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ 10
+
+
+ True
+ 0
+ Maximum Upload Rate (KB/s):
+
+
- 1
- 2
3
4
GTK_FILL
-
-
- True
- True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- The maximum download rate for all torrents. Set -1 for unlimited.
- 1
- -1 -1 9000 1 10 10
- 1
-
-
- 1
- 2
- 2
- 3
- GTK_FILL
-
-
-
-
- True
- True
- The maximum number of upload slots. Set -1 for unlimited.
- 1
- -1 -1 1000 1 10 10
- 1
-
-
- 1
- 2
- 1
- 2
- GTK_FILL
-
-
-
-
- True
- True
- The maximum number of connections allowed. Set -1 for unlimited.
- 1
- -1 -1 1000 1 10 10
- 1
-
-
- 1
- 2
- GTK_FILL
-
-
-
-
- True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- 10
-
-
- True
- 0
- Maximum Connections:
-
-
-
-
- GTK_FILL
-
-
-
-
- True
- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
- 10
-
-
- True
- 0
- Upload Slots:
-
-
-
-
- 1
- 2
- GTK_FILL
-
-
True
@@ -437,19 +353,103 @@
-
+
True
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
10
-
+
True
0
- Maximum Upload Rate (KB/s):
+ Upload Slots:
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ 10
+
+
+ True
+ 0
+ Maximum Connections:
+
+
+
+
+ GTK_FILL
+
+
+
+
+ True
+ True
+ The maximum number of connections allowed. Set -1 for unlimited.
+ 1
+ -1 -1 1000 1 10 10
+ 1
+
+
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+ True
+ True
+ The maximum number of upload slots. Set -1 for unlimited.
+ 1
+ -1 -1 1000 1 10 10
+ 1
+
+
+ 1
+ 2
+ 1
+ 2
+ GTK_FILL
+
+
+
+
+ True
+ True
+ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ The maximum download rate for all torrents. Set -1 for unlimited.
+ 1
+ -1 -1 9000 1 10 10
+ 1
+
+
+ 1
+ 2
+ 2
+ 3
+ GTK_FILL
+
+
+
+
+ True
+ True
+ The maximum upload rate for all torrents. Set -1 for unlimited.
+ 1
+ -1 -1 9000 1 10 10
+ 1
+
+
+ 1
+ 2
3
4
GTK_FILL
@@ -758,7 +758,7 @@
True
- False
+ True
UPnP
True
0
@@ -772,7 +772,7 @@
True
- False
+ True
NAT-PMP
True
0
@@ -787,7 +787,7 @@
True
- False
+ True
UT PeX
True
0
@@ -806,7 +806,7 @@
True
- <b>Network Extras</b> - Always on
+ <b>Network Extras</b>
True
diff --git a/libtorrent/include/libtorrent/alert_types.hpp b/libtorrent/include/libtorrent/alert_types.hpp
index e3e23ad05..7b32d2502 100755
--- a/libtorrent/include/libtorrent/alert_types.hpp
+++ b/libtorrent/include/libtorrent/alert_types.hpp
@@ -81,8 +81,6 @@ namespace libtorrent
{ return std::auto_ptr(new tracker_warning_alert(*this)); }
};
-
-
struct TORRENT_EXPORT tracker_reply_alert: torrent_alert
{
tracker_reply_alert(torrent_handle const& h
@@ -186,6 +184,26 @@ namespace libtorrent
{ return std::auto_ptr(new torrent_finished_alert(*this)); }
};
+ struct TORRENT_EXPORT storage_moved_alert: torrent_alert
+ {
+ storage_moved_alert(torrent_handle const& h, std::string const& path)
+ : torrent_alert(h, alert::warning, path)
+ {}
+
+ virtual std::auto_ptr clone() const
+ { return std::auto_ptr(new storage_moved_alert(*this)); }
+ };
+
+ struct TORRENT_EXPORT torrent_paused_alert: torrent_alert
+ {
+ torrent_paused_alert(torrent_handle const& h, std::string const& msg)
+ : torrent_alert(h, alert::warning, msg)
+ {}
+
+ virtual std::auto_ptr clone() const
+ { return std::auto_ptr(new torrent_paused_alert(*this)); }
+ };
+
struct TORRENT_EXPORT url_seed_alert: torrent_alert
{
url_seed_alert(
diff --git a/libtorrent/include/libtorrent/asio.hpp b/libtorrent/include/libtorrent/asio.hpp
index dfad4a6d5..ae6455bdb 100644
--- a/libtorrent/include/libtorrent/asio.hpp
+++ b/libtorrent/include/libtorrent/asio.hpp
@@ -68,6 +68,7 @@
#include "asio/system_error.hpp"
#include "asio/thread.hpp"
#include "asio/time_traits.hpp"
+#include "asio/version.hpp"
#include "asio/write.hpp"
#endif // ASIO_HPP
diff --git a/libtorrent/include/libtorrent/asio/basic_deadline_timer.hpp b/libtorrent/include/libtorrent/asio/basic_deadline_timer.hpp
index a630c67bc..d881f6643 100644
--- a/libtorrent/include/libtorrent/asio/basic_deadline_timer.hpp
+++ b/libtorrent/include/libtorrent/asio/basic_deadline_timer.hpp
@@ -40,8 +40,6 @@ namespace asio {
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
- * @sa @ref deadline_timer_reset
- *
* @par Examples
* Performing a blocking wait:
* @code
@@ -75,6 +73,45 @@ namespace asio {
* // Start an asynchronous wait.
* timer.async_wait(handler);
* @endcode
+ *
+ * @par Changing an active deadline_timer's expiry time
+ *
+ * Changing the expiry time of a timer while there are pending asynchronous
+ * waits causes those wait operations to be cancelled. To ensure that the action
+ * associated with the timer is performed only once, use something like this:
+ * used:
+ *
+ * @code
+ * void on_some_event()
+ * {
+ * if (my_timer.expires_from_now(seconds(5)) > 0)
+ * {
+ * // We managed to cancel the timer. Start new asynchronous wait.
+ * my_timer.async_wait(on_timeout);
+ * }
+ * else
+ * {
+ * // Too late, timer has already expired!
+ * }
+ * }
+ *
+ * void on_timeout(const asio::error_code& e)
+ * {
+ * if (e != asio::error::operation_aborted)
+ * {
+ * // Timer was not cancelled, take necessary action.
+ * }
+ * }
+ * @endcode
+ *
+ * @li The asio::basic_deadline_timer::expires_from_now() function
+ * cancels any pending asynchronous waits, and returns the number of
+ * asynchronous waits that were cancelled. If it returns 0 then you were too
+ * late and the wait handler has already been executed, or will soon be
+ * executed. If it returns 1 then the wait handler was successfully cancelled.
+ *
+ * @li If a wait handler is cancelled, the asio::error_code passed to
+ * it contains the value asio::error::operation_aborted.
*/
template ,
@@ -197,9 +234,6 @@ public:
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
- * See @ref deadline_timer_reset for more information on altering the expiry
- * time of an active timer.
- *
* @param expiry_time The expiry time to be used for the timer.
*
* @return The number of asynchronous operations that were cancelled.
@@ -221,9 +255,6 @@ public:
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
- * See @ref deadline_timer_reset for more information on altering the expiry
- * time of an active timer.
- *
* @param expiry_time The expiry time to be used for the timer.
*
* @param ec Set to indicate what error occurred, if any.
@@ -252,9 +283,6 @@ public:
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
- * See @ref deadline_timer_reset for more information on altering the expiry
- * time of an active timer.
- *
* @param expiry_time The expiry time to be used for the timer.
*
* @return The number of asynchronous operations that were cancelled.
@@ -276,9 +304,6 @@ public:
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
- * See @ref deadline_timer_reset for more information on altering the expiry
- * time of an active timer.
- *
* @param expiry_time The expiry time to be used for the timer.
*
* @param ec Set to indicate what error occurred, if any.
@@ -349,49 +374,6 @@ public:
}
};
-/**
- * @page deadline_timer_reset Changing an active deadline_timer's expiry time
- *
- * Changing the expiry time of a timer while there are pending asynchronous
- * waits causes those wait operations to be cancelled. To ensure that the action
- * associated with the timer is performed only once, use something like this:
- * used:
- *
- * @code
- * void on_some_event()
- * {
- * if (my_timer.expires_from_now(seconds(5)) > 0)
- * {
- * // We managed to cancel the timer. Start new asynchronous wait.
- * my_timer.async_wait(on_timeout);
- * }
- * else
- * {
- * // Too late, timer has already expired!
- * }
- * }
- *
- * void on_timeout(const asio::error_code& e)
- * {
- * if (e != asio::error::operation_aborted)
- * {
- * // Timer was not cancelled, take necessary action.
- * }
- * }
- * @endcode
- *
- * @li The asio::basic_deadline_timer::expires_from_now() function
- * cancels any pending asynchronous waits, and returns the number of
- * asynchronous waits that were cancelled. If it returns 0 then you were too
- * late and the wait handler has already been executed, or will soon be
- * executed. If it returns 1 then the wait handler was successfully cancelled.
- *
- * @li If a wait handler is cancelled, the asio::error_code passed to
- * it contains the value asio::error::operation_aborted.
- *
- * @sa asio::basic_deadline_timer
- */
-
} // namespace asio
#include "asio/detail/pop_options.hpp"
diff --git a/libtorrent/include/libtorrent/asio/buffer.hpp b/libtorrent/include/libtorrent/asio/buffer.hpp
index 69214fdb1..384e8d70a 100644
--- a/libtorrent/include/libtorrent/asio/buffer.hpp
+++ b/libtorrent/include/libtorrent/asio/buffer.hpp
@@ -34,6 +34,14 @@
# endif // defined(_HAS_ITERATOR_DEBUGGING)
#endif // defined(BOOST_MSVC)
+#if defined(__GNUC__)
+# if defined(_GLIBCXX_DEBUG)
+# if !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
+# define ASIO_ENABLE_BUFFER_DEBUGGING
+# endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
+# endif // defined(_GLIBCXX_DEBUG)
+#endif // defined(__GNUC__)
+
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
# include "asio/detail/push_options.hpp"
# include
diff --git a/libtorrent/include/libtorrent/asio/detail/epoll_reactor_fwd.hpp b/libtorrent/include/libtorrent/asio/detail/epoll_reactor_fwd.hpp
index 720d7ca71..87fad6325 100644
--- a/libtorrent/include/libtorrent/asio/detail/epoll_reactor_fwd.hpp
+++ b/libtorrent/include/libtorrent/asio/detail/epoll_reactor_fwd.hpp
@@ -24,6 +24,8 @@
#include
#include "asio/detail/pop_options.hpp"
+#if LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45) // Only kernels >= 2.5.45.
+
// Define this to indicate that epoll is supported on the target platform.
#define ASIO_HAS_EPOLL 1
@@ -36,6 +38,7 @@ class epoll_reactor;
} // namespace detail
} // namespace asio
+#endif // LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45)
#endif // defined(__linux__)
#endif // !defined(ASIO_DISABLE_EPOLL)
diff --git a/libtorrent/include/libtorrent/asio/detail/old_win_sdk_compat.hpp b/libtorrent/include/libtorrent/asio/detail/old_win_sdk_compat.hpp
index da78f956d..2fb957aa9 100644
--- a/libtorrent/include/libtorrent/asio/detail/old_win_sdk_compat.hpp
+++ b/libtorrent/include/libtorrent/asio/detail/old_win_sdk_compat.hpp
@@ -164,6 +164,10 @@ struct addrinfo_emulation
# define IPPROTO_IPV6 41
#endif
+#if !defined(IPV6_UNICAST_HOPS)
+# define IPV6_UNICAST_HOPS 4
+#endif
+
#if !defined(IPV6_MULTICAST_IF)
# define IPV6_MULTICAST_IF 9
#endif
diff --git a/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp b/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp
index b58f62781..d5b8e4fc8 100644
--- a/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp
+++ b/libtorrent/include/libtorrent/asio/detail/reactive_socket_service.hpp
@@ -350,6 +350,22 @@ public:
socket_ops::setsockopt(impl.socket_,
option.level(impl.protocol_), option.name(impl.protocol_),
option.data(impl.protocol_), option.size(impl.protocol_), ec);
+
+#if defined(__MACH__) && defined(__APPLE__) \
+|| defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
+ // To implement portable behaviour for SO_REUSEADDR with UDP sockets we
+ // need to also set SO_REUSEPORT on BSD-based platforms.
+ if (!ec && impl.protocol_.type() == SOCK_DGRAM
+ && option.level(impl.protocol_) == SOL_SOCKET
+ && option.name(impl.protocol_) == SO_REUSEADDR)
+ {
+ asio::error_code ignored_ec;
+ socket_ops::setsockopt(impl.socket_, SOL_SOCKET, SO_REUSEPORT,
+ option.data(impl.protocol_), option.size(impl.protocol_),
+ ignored_ec);
+ }
+#endif
+
return ec;
}
}
@@ -506,6 +522,18 @@ public:
return 0;
}
+ // Make socket non-blocking if user wants non-blocking.
+ if (impl.flags_ & implementation_type::user_set_non_blocking)
+ {
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ return 0;
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+ }
+
// Send the data.
for (;;)
{
@@ -668,6 +696,18 @@ public:
asio::buffer_size(buffer));
}
+ // Make socket non-blocking if user wants non-blocking.
+ if (impl.flags_ & implementation_type::user_set_non_blocking)
+ {
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ return 0;
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+ }
+
// Send the data.
for (;;)
{
@@ -823,6 +863,18 @@ public:
return 0;
}
+ // Make socket non-blocking if user wants non-blocking.
+ if (impl.flags_ & implementation_type::user_set_non_blocking)
+ {
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ return 0;
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+ }
+
// Receive some data.
for (;;)
{
@@ -1005,6 +1057,18 @@ public:
asio::buffer_size(buffer));
}
+ // Make socket non-blocking if user wants non-blocking.
+ if (impl.flags_ & implementation_type::user_set_non_blocking)
+ {
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ return 0;
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+ }
+
// Receive some data.
for (;;)
{
@@ -1160,6 +1224,18 @@ public:
return ec;
}
+ // Make socket non-blocking if user wants non-blocking.
+ if (impl.flags_ & implementation_type::user_set_non_blocking)
+ {
+ if (!(impl.flags_ & implementation_type::internal_non_blocking))
+ {
+ ioctl_arg_type non_blocking = 1;
+ if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
+ return ec;
+ impl.flags_ |= implementation_type::internal_non_blocking;
+ }
+ }
+
// Accept a socket.
for (;;)
{
@@ -1203,6 +1279,14 @@ public:
return ec;
// Fall through to retry operation.
}
+#if defined(EPROTO)
+ else if (ec.value() == EPROTO)
+ {
+ if (impl.flags_ & implementation_type::enable_connection_aborted)
+ return ec;
+ // Fall through to retry operation.
+ }
+#endif // defined(EPROTO)
else
return ec;
@@ -1262,6 +1346,10 @@ public:
if (ec == asio::error::connection_aborted
&& !enable_connection_aborted_)
return false;
+#if defined(EPROTO)
+ if (ec.value() == EPROTO && !enable_connection_aborted_)
+ return false;
+#endif // defined(EPROTO)
// Transfer ownership of the new socket to the peer object.
if (!ec)
diff --git a/libtorrent/include/libtorrent/asio/detail/socket_ops.hpp b/libtorrent/include/libtorrent/asio/detail/socket_ops.hpp
index 166319bb1..4b38c6ee8 100644
--- a/libtorrent/include/libtorrent/asio/detail/socket_ops.hpp
+++ b/libtorrent/include/libtorrent/asio/detail/socket_ops.hpp
@@ -63,7 +63,7 @@ inline socket_type accept(socket_type s, socket_addr_type* addr,
socket_addr_len_type* addrlen, asio::error_code& ec)
{
clear_error(ec);
-#if defined(__MACH__) && defined(__APPLE__)
+#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
socket_type new_s = error_wrapper(::accept(s, addr, addrlen), ec);
if (new_s == invalid_socket)
return new_s;
@@ -295,7 +295,7 @@ inline socket_type socket(int af, int type, int protocol,
}
return s;
-#elif defined(__MACH__) && defined(__APPLE__)
+#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
socket_type s = error_wrapper(::socket(af, type, protocol), ec);
if (s == invalid_socket)
return s;
@@ -318,11 +318,35 @@ inline socket_type socket(int af, int type, int protocol,
inline int setsockopt(socket_type s, int level, int optname,
const void* optval, size_t optlen, asio::error_code& ec)
{
+ if (level == custom_socket_option_level && optname == always_fail_option)
+ {
+ ec = asio::error::invalid_argument;
+ return -1;
+ }
+
+#if defined(__BORLANDC__)
+ // Mysteriously, using the getsockopt and setsockopt functions directly with
+ // Borland C++ results in incorrect values being set and read. The bug can be
+ // worked around by using function addresses resolved with GetProcAddress.
+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+ {
+ typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int);
+ if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt"))
+ {
+ clear_error(ec);
+ return error_wrapper(sso(s, level, optname,
+ reinterpret_cast(optval),
+ static_cast(optlen)), ec);
+ }
+ }
+ ec = asio::error::fault;
+ return -1;
+#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
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__)
@@ -331,8 +355,44 @@ inline int setsockopt(socket_type s, int level, int optname,
inline int getsockopt(socket_type s, int level, int optname, void* optval,
size_t* optlen, asio::error_code& ec)
{
+ if (level == custom_socket_option_level && optname == always_fail_option)
+ {
+ ec = asio::error::invalid_argument;
+ return -1;
+ }
+
+#if defined(__BORLANDC__)
+ // Mysteriously, using the getsockopt and setsockopt functions directly with
+ // Borland C++ results in incorrect values being set and read. The bug can be
+ // worked around by using function addresses resolved with GetProcAddress.
+ if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
+ {
+ typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*);
+ if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt"))
+ {
+ clear_error(ec);
+ int tmp_optlen = static_cast(*optlen);
+ int result = error_wrapper(gso(s, level, optname,
+ reinterpret_cast(optval), &tmp_optlen), ec);
+ *optlen = static_cast(tmp_optlen);
+ if (result != 0 && level == IPPROTO_IPV6 && optname == IPV6_V6ONLY
+ && ec.value() == WSAENOPROTOOPT && *optlen == sizeof(DWORD))
+ {
+ // Dual-stack IPv4/v6 sockets, and the IPV6_V6ONLY socket option, are
+ // only supported on Windows Vista and later. To simplify program logic
+ // we will fake success of getting this option and specify that the
+ // value is non-zero (i.e. true). This corresponds to the behavior of
+ // IPv6 sockets on Windows platforms pre-Vista.
+ *static_cast(optval) = 1;
+ clear_error(ec);
+ }
+ return result;
+ }
+ }
+ ec = asio::error::fault;
+ return -1;
+#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
clear_error(ec);
-#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
int tmp_optlen = static_cast(*optlen);
int result = error_wrapper(::getsockopt(s, level, optname,
reinterpret_cast(optval), &tmp_optlen), ec);
@@ -350,6 +410,7 @@ 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);
diff --git a/libtorrent/include/libtorrent/asio/detail/socket_select_interrupter.hpp b/libtorrent/include/libtorrent/asio/detail/socket_select_interrupter.hpp
index 6117d309d..ba62b12d6 100644
--- a/libtorrent/include/libtorrent/asio/detail/socket_select_interrupter.hpp
+++ b/libtorrent/include/libtorrent/asio/detail/socket_select_interrupter.hpp
@@ -18,6 +18,7 @@
#include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp"
+#include
#include
#include "asio/detail/pop_options.hpp"
@@ -49,8 +50,10 @@ public:
socket_ops::setsockopt(acceptor.get(),
SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);
+ using namespace std; // For memset.
sockaddr_in4_type addr;
socket_addr_len_type 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");
addr.sin_port = 0;
diff --git a/libtorrent/include/libtorrent/asio/detail/socket_types.hpp b/libtorrent/include/libtorrent/asio/detail/socket_types.hpp
index b2a03f2f1..49d1c7fc2 100644
--- a/libtorrent/include/libtorrent/asio/detail/socket_types.hpp
+++ b/libtorrent/include/libtorrent/asio/detail/socket_types.hpp
@@ -169,6 +169,7 @@ const int message_do_not_route = MSG_DONTROUTE;
#endif
const int custom_socket_option_level = 0xA5100000;
const int enable_connection_aborted_option = 1;
+const int always_fail_option = 2;
} // namespace detail
} // namespace asio
diff --git a/libtorrent/include/libtorrent/asio/detail/timer_queue.hpp b/libtorrent/include/libtorrent/asio/detail/timer_queue.hpp
index ab6eac263..af1e36bd5 100644
--- a/libtorrent/include/libtorrent/asio/detail/timer_queue.hpp
+++ b/libtorrent/include/libtorrent/asio/detail/timer_queue.hpp
@@ -309,7 +309,8 @@ private:
swap_heap(index, heap_.size() - 1);
heap_.pop_back();
size_t parent = (index - 1) / 2;
- if (index > 0 && Time_Traits::less_than(t->time_, heap_[parent]->time_))
+ if (index > 0 && Time_Traits::less_than(
+ heap_[index]->time_, heap_[parent]->time_))
up_heap(index);
else
down_heap(index);
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 667553960..007286e8d 100644
--- a/libtorrent/include/libtorrent/asio/detail/win_iocp_socket_service.hpp
+++ b/libtorrent/include/libtorrent/asio/detail/win_iocp_socket_service.hpp
@@ -137,7 +137,8 @@ public:
enum
{
enable_connection_aborted = 1, // User wants connection_aborted errors.
- user_set_linger = 2 // The user set the linger option.
+ user_set_linger = 2, // The user set the linger option.
+ user_set_non_blocking = 4 // The user wants a non-blocking socket.
};
// Flags indicating the current state of the socket.
@@ -200,6 +201,7 @@ public:
void construct(implementation_type& impl)
{
impl.socket_ = invalid_socket;
+ impl.flags_ = 0;
impl.cancel_token_.reset();
impl.safe_cancellation_thread_id_ = 0;
@@ -239,6 +241,7 @@ public:
asio::error_code ignored_ec;
socket_ops::close(impl.socket_, ignored_ec);
impl.socket_ = invalid_socket;
+ impl.flags_ = 0;
impl.cancel_token_.reset();
impl.safe_cancellation_thread_id_ = 0;
}
@@ -274,6 +277,7 @@ public:
iocp_service_.register_handle(sock_as_handle);
impl.socket_ = sock.release();
+ impl.flags_ = 0;
impl.cancel_token_.reset(static_cast(0), noop_deleter());
impl.protocol_ = protocol;
ec = asio::error_code();
@@ -294,6 +298,7 @@ public:
iocp_service_.register_handle(native_socket.as_handle());
impl.socket_ = native_socket;
+ impl.flags_ = 0;
impl.cancel_token_.reset(static_cast(0), noop_deleter());
impl.protocol_ = protocol;
ec = asio::error_code();
@@ -325,6 +330,7 @@ public:
return ec;
impl.socket_ = invalid_socket;
+ impl.flags_ = 0;
impl.cancel_token_.reset();
impl.safe_cancellation_thread_id_ = 0;
}
@@ -534,6 +540,15 @@ public:
socket_ops::ioctl(impl.socket_, command.name(),
static_cast(command.data()), ec);
+
+ if (!ec && command.name() == static_cast(FIONBIO))
+ {
+ if (command.get())
+ impl.flags_ |= implementation_type::user_set_non_blocking;
+ else
+ impl.flags_ &= ~implementation_type::user_set_non_blocking;
+ }
+
return ec;
}
@@ -1774,11 +1789,12 @@ public:
class connect_handler
{
public:
- connect_handler(socket_type socket,
+ connect_handler(socket_type socket, bool user_set_non_blocking,
boost::shared_ptr completed,
asio::io_service& io_service,
reactor_type& reactor, Handler handler)
: socket_(socket),
+ user_set_non_blocking_(user_set_non_blocking),
completed_(completed),
io_service_(io_service),
reactor_(reactor),
@@ -1825,12 +1841,15 @@ public:
return true;
}
- // Make the socket blocking again (the default).
- ioctl_arg_type non_blocking = 0;
- if (socket_ops::ioctl(socket_, FIONBIO, &non_blocking, ec))
+ // Revert socket to blocking mode unless the user requested otherwise.
+ if (!user_set_non_blocking_)
{
- io_service_.post(bind_handler(handler_, ec));
- return true;
+ ioctl_arg_type non_blocking = 0;
+ if (socket_ops::ioctl(socket_, FIONBIO, &non_blocking, ec))
+ {
+ io_service_.post(bind_handler(handler_, ec));
+ return true;
+ }
}
// Post the result of the successful connection operation.
@@ -1841,6 +1860,7 @@ public:
private:
socket_type socket_;
+ bool user_set_non_blocking_;
boost::shared_ptr completed_;
asio::io_service& io_service_;
reactor_type& reactor_;
@@ -1891,6 +1911,13 @@ public:
if (socket_ops::connect(impl.socket_, peer_endpoint.data(),
peer_endpoint.size(), ec) == 0)
{
+ // Revert socket to blocking mode unless the user requested otherwise.
+ if (!(impl.flags_ & implementation_type::user_set_non_blocking))
+ {
+ non_blocking = 0;
+ socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec);
+ }
+
// The connect operation has finished successfully so we need to post the
// handler immediately.
this->io_service().post(bind_handler(handler, ec));
@@ -1903,10 +1930,20 @@ public:
boost::shared_ptr completed(new bool(false));
reactor->start_write_and_except_ops(impl.socket_,
connect_handler(
- impl.socket_, completed, this->io_service(), *reactor, handler));
+ impl.socket_,
+ (impl.flags_ & implementation_type::user_set_non_blocking) != 0,
+ completed, this->io_service(), *reactor, handler));
}
else
{
+ // Revert socket to blocking mode unless the user requested otherwise.
+ if (!(impl.flags_ & implementation_type::user_set_non_blocking))
+ {
+ non_blocking = 0;
+ asio::error_code ignored_ec;
+ socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ignored_ec);
+ }
+
// The connect operation has failed, so post the handler immediately.
this->io_service().post(bind_handler(handler, ec));
}
diff --git a/libtorrent/include/libtorrent/asio/io_service.hpp b/libtorrent/include/libtorrent/asio/io_service.hpp
index 731a7ac9a..b694545db 100644
--- a/libtorrent/include/libtorrent/asio/io_service.hpp
+++ b/libtorrent/include/libtorrent/asio/io_service.hpp
@@ -60,7 +60,40 @@ namespace asio {
* @par Concepts:
* Dispatcher.
*
- * @sa @ref io_service_handler_exception
+ * @par Effect of exceptions thrown from handlers
+ *
+ * If an exception is thrown from a handler, the exception is allowed to
+ * propagate through the throwing thread's invocation of
+ * asio::io_service::run(), asio::io_service::run_one(),
+ * asio::io_service::poll() or asio::io_service::poll_one().
+ * No other threads that are calling any of these functions are affected. It is
+ * then the responsibility of the application to catch the exception.
+ *
+ * After the exception has been caught, the
+ * asio::io_service::run(), asio::io_service::run_one(),
+ * asio::io_service::poll() or asio::io_service::poll_one()
+ * call may be restarted @em without the need for an intervening call to
+ * asio::io_service::reset(). This allows the thread to rejoin the
+ * io_service's thread pool without impacting any other threads in the pool.
+ *
+ * For example:
+ *
+ * @code
+ * asio::io_service io_service;
+ * ...
+ * for (;;)
+ * {
+ * try
+ * {
+ * io_service.run();
+ * break; // run() exited normally
+ * }
+ * catch (my_exception& e)
+ * {
+ * // Deal with exception as appropriate.
+ * }
+ * }
+ * @endcode
*/
class io_service
: private noncopyable
@@ -108,7 +141,9 @@ public:
* more handlers to be dispatched, or until the io_service has been stopped.
*
* Multiple threads may call the run() function to set up a pool of threads
- * from which the io_service may execute handlers.
+ * from which the io_service may execute handlers. All threads that are
+ * waiting in the pool are equivalent and the io_service may choose any one
+ * of them to invoke a handler.
*
* The run() function may be safely called again once it has completed only
* after a call to reset().
@@ -125,7 +160,9 @@ public:
* more handlers to be dispatched, or until the io_service has been stopped.
*
* Multiple threads may call the run() function to set up a pool of threads
- * from which the io_service may execute handlers.
+ * from which the io_service may execute handlers. All threads that are
+ * waiting in the pool are equivalent and the io_service may choose any one
+ * of them to invoke a handler.
*
* The run() function may be safely called again once it has completed only
* after a call to reset().
@@ -456,42 +493,6 @@ public:
}
};
-/**
- * @page io_service_handler_exception Effect of exceptions thrown from handlers
- *
- * If an exception is thrown from a handler, the exception is allowed to
- * propagate through the throwing thread's invocation of
- * asio::io_service::run(), asio::io_service::run_one(),
- * asio::io_service::poll() or asio::io_service::poll_one().
- * No other threads that are calling any of these functions are affected. It is
- * then the responsibility of the application to catch the exception.
- *
- * After the exception has been caught, the
- * asio::io_service::run(), asio::io_service::run_one(),
- * asio::io_service::poll() or asio::io_service::poll_one()
- * call may be restarted @em without the need for an intervening call to
- * asio::io_service::reset(). This allows the thread to rejoin the
- * io_service's thread pool without impacting any other threads in the pool.
- *
- * @par Example
- * @code
- * asio::io_service io_service;
- * ...
- * for (;;)
- * {
- * try
- * {
- * io_service.run();
- * break; // run() exited normally
- * }
- * catch (my_exception& e)
- * {
- * // Deal with exception as appropriate.
- * }
- * }
- * @endcode
- */
-
} // namespace asio
#include "asio/impl/io_service.ipp"
diff --git a/libtorrent/include/libtorrent/asio/ip/basic_resolver_iterator.hpp b/libtorrent/include/libtorrent/asio/ip/basic_resolver_iterator.hpp
index 9edec2b0a..686e4446e 100644
--- a/libtorrent/include/libtorrent/asio/ip/basic_resolver_iterator.hpp
+++ b/libtorrent/include/libtorrent/asio/ip/basic_resolver_iterator.hpp
@@ -19,6 +19,7 @@
#include "asio/detail/push_options.hpp"
#include
+#include
#include
#include
#include
@@ -118,12 +119,12 @@ private:
void increment()
{
- if (++iter_ == values_->end())
+ if (++*iter_ == values_->end())
{
// Reset state to match a default constructed end iterator.
values_.reset();
typedef typename values_type::const_iterator values_iterator_type;
- iter_ = values_iterator_type();
+ iter_.reset();
}
}
@@ -133,17 +134,18 @@ private:
return true;
if (values_ != other.values_)
return false;
- return iter_ == other.iter_;
+ return *iter_ == *other.iter_;
}
const basic_resolver_entry& dereference() const
{
- return *iter_;
+ return **iter_;
}
typedef std::vector > values_type;
+ typedef typename values_type::const_iterator values_iter_type;
boost::shared_ptr values_;
- typename values_type::const_iterator iter_;
+ boost::optional iter_;
};
} // namespace ip
diff --git a/libtorrent/include/libtorrent/asio/ip/detail/socket_option.hpp b/libtorrent/include/libtorrent/asio/ip/detail/socket_option.hpp
index db7f8edc4..a86307077 100644
--- a/libtorrent/include/libtorrent/asio/ip/detail/socket_option.hpp
+++ b/libtorrent/include/libtorrent/asio/ip/detail/socket_option.hpp
@@ -37,6 +37,12 @@ template
class boolean
{
public:
+#if defined(__sun)
+ typedef unsigned char value_type;
+#else
+ typedef int value_type;
+#endif
+
// Default constructor.
boolean()
: value_(0)
@@ -94,14 +100,14 @@ public:
// Get the address of the boolean data.
template
- int* data(const Protocol&)
+ value_type* data(const Protocol&)
{
return &value_;
}
// Get the address of the boolean data.
template
- const int* data(const Protocol&) const
+ const value_type* data(const Protocol&) const
{
return &value_;
}
@@ -122,7 +128,7 @@ public:
}
private:
- int value_;
+ value_type value_;
};
// Helper template for implementing unicast hops options.
diff --git a/libtorrent/include/libtorrent/asio/ip/tcp.hpp b/libtorrent/include/libtorrent/asio/ip/tcp.hpp
index 447210caf..e31844c4d 100644
--- a/libtorrent/include/libtorrent/asio/ip/tcp.hpp
+++ b/libtorrent/include/libtorrent/asio/ip/tcp.hpp
@@ -59,7 +59,7 @@ public:
return tcp(PF_INET);
}
- /// Construct to represent the IPv4 TCP protocol.
+ /// Construct to represent the IPv6 TCP protocol.
static tcp v6()
{
return tcp(PF_INET6);
diff --git a/libtorrent/include/libtorrent/asio/ip/udp.hpp b/libtorrent/include/libtorrent/asio/ip/udp.hpp
index ed3bb8536..e434f74d9 100644
--- a/libtorrent/include/libtorrent/asio/ip/udp.hpp
+++ b/libtorrent/include/libtorrent/asio/ip/udp.hpp
@@ -56,7 +56,7 @@ public:
return udp(PF_INET);
}
- /// Construct to represent the IPv4 UDP protocol.
+ /// Construct to represent the IPv6 UDP protocol.
static udp v6()
{
return udp(PF_INET6);
@@ -80,7 +80,7 @@ public:
return family_;
}
- /// The IPv4 UDP socket type.
+ /// The UDP socket type.
typedef basic_datagram_socket socket;
/// The UDP resolver type.
diff --git a/libtorrent/include/libtorrent/asio/strand.hpp b/libtorrent/include/libtorrent/asio/strand.hpp
index 948921e10..d0869d95d 100644
--- a/libtorrent/include/libtorrent/asio/strand.hpp
+++ b/libtorrent/include/libtorrent/asio/strand.hpp
@@ -54,6 +54,12 @@ public:
}
/// Destructor.
+ /**
+ * Destroys a strand.
+ *
+ * Handlers posted through the strand that have not yet been invoked will
+ * still be dispatched in a way that meets the guarantee of non-concurrency.
+ */
~strand()
{
service_.destroy(impl_);
diff --git a/libtorrent/include/libtorrent/aux_/session_impl.hpp b/libtorrent/include/libtorrent/aux_/session_impl.hpp
index fd24ef8f7..c270d9ffc 100644
--- a/libtorrent/include/libtorrent/aux_/session_impl.hpp
+++ b/libtorrent/include/libtorrent/aux_/session_impl.hpp
@@ -82,10 +82,13 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/lsd.hpp"
#include "libtorrent/socket_type.hpp"
#include "libtorrent/connection_queue.hpp"
+#include "libtorrent/disk_io_thread.hpp"
namespace libtorrent
{
+ namespace fs = boost::filesystem;
+
namespace aux
{
struct session_impl;
@@ -98,7 +101,7 @@ namespace libtorrent
: processing(false), progress(0.f), abort(false) {}
boost::shared_ptr torrent_ptr;
- boost::filesystem::path save_path;
+ fs::path save_path;
sha1_hash info_hash;
@@ -229,6 +232,7 @@ namespace libtorrent
bool is_aborted() const { return m_abort; }
void set_ip_filter(ip_filter const& f);
+ void set_port_filter(port_filter const& f);
bool listen_on(
std::pair const& port_range
@@ -237,7 +241,7 @@ namespace libtorrent
torrent_handle add_torrent(
torrent_info const& ti
- , boost::filesystem::path const& save_path
+ , fs::path const& save_path
, entry const& resume_data
, bool compact_mode
, int block_size
@@ -247,7 +251,7 @@ namespace libtorrent
char const* tracker_url
, sha1_hash const& info_hash
, char const* name
- , boost::filesystem::path const& save_path
+ , fs::path const& save_path
, entry const& resume_data
, bool compact_mode
, int block_size
@@ -304,6 +308,14 @@ namespace libtorrent
{ return m_dht_proxy; }
#endif
+ void start_lsd();
+ void start_natpmp();
+ void start_upnp();
+
+ void stop_lsd();
+ void stop_natpmp();
+ void stop_upnp();
+
// handles delayed alerts
alert_manager m_alerts;
@@ -325,6 +337,9 @@ 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
@@ -348,6 +363,9 @@ namespace libtorrent
// filters incoming connections
ip_filter m_ip_filter;
+
+ // filters outgoing connections
+ port_filter m_port_filter;
// the peer id that is generated at the start of the session
peer_id m_peer_id;
@@ -427,9 +445,9 @@ namespace libtorrent
pe_settings m_pe_settings;
#endif
- natpmp m_natpmp;
- upnp m_upnp;
- lsd m_lsd;
+ boost::shared_ptr m_natpmp;
+ boost::shared_ptr m_upnp;
+ boost::shared_ptr m_lsd;
// the timer used to fire the second_tick
deadline_timer m_timer;
diff --git a/libtorrent/include/libtorrent/bt_peer_connection.hpp b/libtorrent/include/libtorrent/bt_peer_connection.hpp
index 2a5000011..0f5e58e9d 100755
--- a/libtorrent/include/libtorrent/bt_peer_connection.hpp
+++ b/libtorrent/include/libtorrent/bt_peer_connection.hpp
@@ -192,7 +192,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);
+ void write_piece(peer_request const& r, char const* buffer);
void write_handshake();
#ifndef TORRENT_DISABLE_EXTENSIONS
void write_extensions();
diff --git a/libtorrent/include/libtorrent/debug.hpp b/libtorrent/include/libtorrent/debug.hpp
index 39c4b0222..436b695f6 100755
--- a/libtorrent/include/libtorrent/debug.hpp
+++ b/libtorrent/include/libtorrent/debug.hpp
@@ -53,15 +53,16 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent
{
// DEBUG API
+
+ namespace fs = boost::filesystem;
struct logger
{
- logger(boost::filesystem::path const& filename, int instance, bool append = true)
+ logger(fs::path const& filename, int instance, bool append = true)
{
- using namespace boost::filesystem;
- path dir(complete("libtorrent_logs" + boost::lexical_cast(instance)));
- if (!exists(dir)) create_directories(dir);
- m_file.open(dir / filename, std::ios_base::out | (append ? std::ios_base::app : std::ios_base::out));
+ fs::path dir(fs::complete("libtorrent_logs" + boost::lexical_cast(instance)));
+ if (!fs::exists(dir)) fs::create_directories(dir);
+ m_file.open((dir / filename).string().c_str(), std::ios_base::out | (append ? std::ios_base::app : std::ios_base::out));
*this << "\n\n\n*** starting log ***\n";
}
@@ -73,7 +74,7 @@ namespace libtorrent
return *this;
}
- boost::filesystem::ofstream m_file;
+ std::ofstream m_file;
};
}
diff --git a/libtorrent/include/libtorrent/entry.hpp b/libtorrent/include/libtorrent/entry.hpp
index 31a78b972..a1eba5324 100755
--- a/libtorrent/include/libtorrent/entry.hpp
+++ b/libtorrent/include/libtorrent/entry.hpp
@@ -155,6 +155,8 @@ namespace libtorrent
dictionary_type& dict();
const dictionary_type& dict() const;
+ void swap(entry& e);
+
// these functions requires that the entry
// is a dictionary, otherwise they will throw
entry& operator[](char const* key);
diff --git a/libtorrent/include/libtorrent/file.hpp b/libtorrent/include/libtorrent/file.hpp
index d11496b28..bd0d03539 100755
--- a/libtorrent/include/libtorrent/file.hpp
+++ b/libtorrent/include/libtorrent/file.hpp
@@ -52,6 +52,7 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent
{
+ namespace fs = boost::filesystem;
struct TORRENT_EXPORT file_error: std::runtime_error
{
@@ -105,10 +106,10 @@ namespace libtorrent
static const open_mode out;
file();
- file(boost::filesystem::path const& p, open_mode m);
+ file(fs::path const& p, open_mode m);
~file();
- void open(boost::filesystem::path const& p, open_mode m);
+ void open(fs::path const& p, open_mode m);
void close();
void set_size(size_type size);
diff --git a/libtorrent/include/libtorrent/hasher.hpp b/libtorrent/include/libtorrent/hasher.hpp
index 3333edf07..990cbefd8 100755
--- a/libtorrent/include/libtorrent/hasher.hpp
+++ b/libtorrent/include/libtorrent/hasher.hpp
@@ -104,3 +104,4 @@ namespace libtorrent
}
#endif // TORRENT_HASHER_HPP_INCLUDED
+
diff --git a/libtorrent/include/libtorrent/http_stream.hpp b/libtorrent/include/libtorrent/http_stream.hpp
index 2bd124b43..041b7c84f 100644
--- a/libtorrent/include/libtorrent/http_stream.hpp
+++ b/libtorrent/include/libtorrent/http_stream.hpp
@@ -1,36 +1,53 @@
-#include "libtorrent/io.hpp"
-#include "libtorrent/socket.hpp"
-#include
-#include
-#include
-#include
-#include
+/*
+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_HTTP_STREAM_HPP_INCLUDED
+#define TORRENT_HTTP_STREAM_HPP_INCLUDED
+
+#include "libtorrent/proxy_base.hpp"
namespace libtorrent {
-class http_stream : boost::noncopyable
+class http_stream : public proxy_base
{
public:
- typedef stream_socket::lowest_layer_type lowest_layer_type;
- typedef stream_socket::endpoint_type endpoint_type;
- typedef stream_socket::protocol_type protocol_type;
-
explicit http_stream(asio::io_service& io_service)
- : m_sock(io_service)
- , m_resolver(io_service)
+ : proxy_base(io_service)
, m_no_connect(false)
{}
void set_no_connect(bool c) { m_no_connect = c; }
- void set_proxy(std::string hostname, int port)
- {
- m_hostname = hostname;
- m_port = port;
- }
-
void set_username(std::string const& user
, std::string const& password)
{
@@ -38,108 +55,6 @@ public:
m_password = password;
}
- template
- void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
- {
- m_sock.async_read_some(buffers, handler);
- }
-
- template
- std::size_t read_some(Mutable_Buffers const& buffers, asio::error_code& ec)
- {
- return m_sock.read_some(buffers, ec);
- }
-
- template
- std::size_t read_some(Mutable_Buffers const& buffers)
- {
- return m_sock.read_some(buffers);
- }
-
- template
- void io_control(IO_Control_Command& ioc)
- {
- m_sock.io_control(ioc);
- }
-
- template
- void io_control(IO_Control_Command& ioc, asio::error_code& ec)
- {
- m_sock.io_control(ioc, ec);
- }
-
- template
- void async_write_some(Const_Buffers const& buffers, Handler const& handler)
- {
- m_sock.async_write_some(buffers, handler);
- }
-
- void bind(endpoint_type const& endpoint)
- {
- m_sock.bind(endpoint);
- }
-
- template
- void bind(endpoint_type const& endpoint, Error_Handler const& error_handler)
- {
- m_sock.bind(endpoint, error_handler);
- }
-
- void open(protocol_type const& p)
- {
- m_sock.open(p);
- }
-
- template
- void open(protocol_type const& p, Error_Handler const& error_handler)
- {
- m_sock.open(p, error_handler);
- }
-
- void close()
- {
- m_remote_endpoint = endpoint_type();
- m_sock.close();
- }
-
- template
- void close(Error_Handler const& error_handler)
- {
- m_sock.close(error_handler);
- }
-
- endpoint_type remote_endpoint()
- {
- return m_remote_endpoint;
- }
-
- template
- endpoint_type remote_endpoint(Error_Handler const& error_handler)
- {
- return m_remote_endpoint;
- }
-
- endpoint_type local_endpoint()
- {
- return m_sock.local_endpoint();
- }
-
- template
- endpoint_type local_endpoint(Error_Handler const& error_handler)
- {
- return m_sock.local_endpoint(error_handler);
- }
-
- asio::io_service& io_service()
- {
- return m_sock.io_service();
- }
-
- lowest_layer_type& lowest_layer()
- {
- return m_sock.lowest_layer();
- }
-
typedef boost::function handler_type;
template
@@ -171,19 +86,12 @@ private:
void handshake1(asio::error_code const& e, boost::shared_ptr h);
void handshake2(asio::error_code const& e, boost::shared_ptr h);
- stream_socket m_sock;
- // the http proxy
- std::string m_hostname;
- int m_port;
// send and receive buffer
std::vector m_buffer;
// proxy authentication
std::string m_user;
std::string m_password;
- endpoint_type m_remote_endpoint;
-
- tcp::resolver m_resolver;
// this is true if the connection is HTTP based and
// want to talk directly to the proxy
bool m_no_connect;
@@ -191,3 +99,4 @@ private:
}
+#endif
diff --git a/libtorrent/include/libtorrent/ip_filter.hpp b/libtorrent/include/libtorrent/ip_filter.hpp
index 1c62c553b..8b1793c3a 100644
--- a/libtorrent/include/libtorrent/ip_filter.hpp
+++ b/libtorrent/include/libtorrent/ip_filter.hpp
@@ -71,20 +71,82 @@ struct ip_range
namespace detail
{
+ template
+ Addr zero()
+ {
+ typename Addr::bytes_type zero;
+ std::fill(zero.begin(), zero.end(), 0);
+ return Addr(zero);
+ }
+
+ template<>
+ inline boost::uint16_t zero() { return 0; }
+
+ template
+ Addr plus_one(Addr const& a)
+ {
+ typename Addr::bytes_type tmp(a.to_bytes());
+ typedef typename Addr::bytes_type::reverse_iterator iter;
+ for (iter i = tmp.rbegin()
+ , end(tmp.rend()); i != end; ++i)
+ {
+ if (*i < (std::numeric_limits::max)())
+ {
+ *i += 1;
+ break;
+ }
+ *i = 0;
+ }
+ return Addr(tmp);
+ }
+
+ inline boost::uint16_t plus_one(boost::uint16_t val) { return val + 1; }
+
+ template
+ Addr minus_one(Addr const& a)
+ {
+ typename Addr::bytes_type tmp(a.to_bytes());
+ typedef typename Addr::bytes_type::reverse_iterator iter;
+ for (iter i = tmp.rbegin()
+ , end(tmp.rend()); i != end; ++i)
+ {
+ if (*i > 0)
+ {
+ *i -= 1;
+ break;
+ }
+ *i = (std::numeric_limits::max)();
+ }
+ return Addr(tmp);
+ }
+
+ inline boost::uint16_t minus_one(boost::uint16_t val) { return val - 1; }
+
+ template
+ Addr max_addr()
+ {
+ typename Addr::bytes_type tmp;
+ std::fill(tmp.begin(), tmp.end()
+ , (std::numeric_limits::max)());
+ return Addr(tmp);
+ }
+
+ template<>
+ inline boost::uint16_t max_addr()
+ { return (std::numeric_limits::max)(); }
+
// this is the generic implementation of
// a filter for a specific address type.
// it works with IPv4 and IPv6
template
- class TORRENT_EXPORT filter_impl
+ class filter_impl
{
public:
filter_impl()
{
- typename Addr::bytes_type zero;
- std::fill(zero.begin(), zero.end(), 0);
// make the entire ip-range non-blocked
- m_access_list.insert(range(Addr(zero), 0));
+ m_access_list.insert(range(zero(), 0));
}
void add_rule(Addr first, Addr last, int flags)
@@ -134,7 +196,7 @@ namespace detail
if ((j != m_access_list.end()
&& minus_one(j->start) != last)
|| (j == m_access_list.end()
- && last != max_addr()))
+ && last != max_addr()))
{
assert(j == m_access_list.end() || last < minus_one(j->start));
if (last_access != flags)
@@ -170,7 +232,7 @@ namespace detail
++i;
if (i == end)
- r.last = max_addr();
+ r.last = max_addr();
else
r.last = minus_one(i->start);
@@ -181,48 +243,6 @@ namespace detail
private:
- Addr plus_one(Addr const& a) const
- {
- typename Addr::bytes_type tmp(a.to_bytes());
- typedef typename Addr::bytes_type::reverse_iterator iter;
- for (iter i = tmp.rbegin()
- , end(tmp.rend()); i != end; ++i)
- {
- if (*i < (std::numeric_limits::max)())
- {
- *i += 1;
- break;
- }
- *i = 0;
- }
- return Addr(tmp);
- }
-
- Addr minus_one(Addr const& a) const
- {
- typename Addr::bytes_type tmp(a.to_bytes());
- typedef typename Addr::bytes_type::reverse_iterator iter;
- for (iter i = tmp.rbegin()
- , end(tmp.rend()); i != end; ++i)
- {
- if (*i > 0)
- {
- *i -= 1;
- break;
- }
- *i = (std::numeric_limits::max)();
- }
- return Addr(tmp);
- }
-
- Addr max_addr() const
- {
- typename Addr::bytes_type tmp;
- std::fill(tmp.begin(), tmp.end()
- , (std::numeric_limits::max)());
- return Addr(tmp);
- }
-
struct range
{
range(Addr addr, int access = 0): start(addr), access(access) {}
@@ -270,6 +290,24 @@ private:
detail::filter_impl m_filter6;
};
+class TORRENT_EXPORT port_filter
+{
+public:
+
+ enum access_flags
+ {
+ blocked = 1
+ };
+
+ void add_rule(boost::uint16_t first, boost::uint16_t last, int flags);
+ int access(boost::uint16_t port) const;
+
+private:
+
+ detail::filter_impl m_filter;
+
+};
+
}
#endif
diff --git a/libtorrent/include/libtorrent/peer_connection.hpp b/libtorrent/include/libtorrent/peer_connection.hpp
index 9514874fb..b25503a9a 100755
--- a/libtorrent/include/libtorrent/peer_connection.hpp
+++ b/libtorrent/include/libtorrent/peer_connection.hpp
@@ -51,7 +51,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include
#include
#include
-#include
#ifdef _MSC_VER
#pragma warning(pop)
@@ -73,6 +72,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/bandwidth_manager.hpp"
#include "libtorrent/policy.hpp"
#include "libtorrent/socket_type.hpp"
+#include "libtorrent/intrusive_ptr_base.hpp"
// TODO: each time a block is 'taken over'
// from another peer. That peer must be given
@@ -88,20 +88,16 @@ namespace libtorrent
struct session_impl;
}
- TORRENT_EXPORT void intrusive_ptr_add_ref(peer_connection const*);
- TORRENT_EXPORT void intrusive_ptr_release(peer_connection const*);
-
struct TORRENT_EXPORT protocol_error: std::runtime_error
{
protocol_error(const std::string& msg): std::runtime_error(msg) {};
};
class TORRENT_EXPORT peer_connection
- : public boost::noncopyable
+ : public intrusive_ptr_base
+ , public boost::noncopyable
{
friend class invariant_access;
- friend TORRENT_EXPORT void intrusive_ptr_add_ref(peer_connection const*);
- friend TORRENT_EXPORT void intrusive_ptr_release(peer_connection const*);
public:
enum channels
@@ -378,7 +374,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) = 0;
+ virtual void write_piece(peer_request const& r, char const* buffer) = 0;
virtual void on_connected() = 0;
virtual void on_tick() {}
@@ -474,6 +470,9 @@ namespace libtorrent
private:
void fill_send_buffer();
+ void on_disk_read_complete(int ret, disk_io_job const& j, peer_request r);
+ void on_disk_write_complete(int ret, disk_io_job const& j
+ , peer_request r, boost::shared_ptr t);
// the timeout in seconds
int m_timeout;
@@ -503,6 +502,11 @@ namespace libtorrent
// (m_current_send_buffer + 1) % 2 is the
// buffer we're currently waiting for.
int m_current_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
@@ -660,9 +664,6 @@ namespace libtorrent
// the left-over bandwidth (suitable for web seeds).
bool m_non_prioritized;
- // reference counter for intrusive_ptr
- mutable boost::detail::atomic_count m_refs;
-
int m_upload_limit;
int m_download_limit;
@@ -681,6 +682,19 @@ namespace libtorrent
// so that it can be removed from the queue
// once the connection completes
int m_connection_ticket;
+
+ // bytes downloaded since last second
+ // timer timeout; used for determining
+ // approx download rate
+ int m_remote_bytes_dled;
+
+ // approximate peer download rate
+ int m_remote_dl_rate;
+
+ // a timestamp when the remote download rate
+ // was last updated
+ ptime m_remote_dl_update;
+
#ifndef NDEBUG
public:
bool m_in_constructor;
diff --git a/libtorrent/include/libtorrent/peer_id.hpp b/libtorrent/include/libtorrent/peer_id.hpp
index 23a5eb463..b66c1d4bc 100755
--- a/libtorrent/include/libtorrent/peer_id.hpp
+++ b/libtorrent/include/libtorrent/peer_id.hpp
@@ -58,6 +58,7 @@ namespace libtorrent
big_number(std::string const& s)
{
+ assert(s.size() >= 20);
int sl = int(s.size()) < size ? int(s.size()) : size;
std::memcpy(m_number, &s[0], sl);
}
diff --git a/libtorrent/include/libtorrent/peer_info.hpp b/libtorrent/include/libtorrent/peer_info.hpp
index 0f398284b..f8ee2feb6 100755
--- a/libtorrent/include/libtorrent/peer_info.hpp
+++ b/libtorrent/include/libtorrent/peer_info.hpp
@@ -58,8 +58,8 @@ namespace libtorrent
on_parole = 0x200,
seed = 0x400
#ifndef TORRENT_DISABLE_ENCRYPTION
- , rc4_encrypted = 0x200,
- plaintext_encrypted = 0x400
+ , rc4_encrypted = 0x800,
+ plaintext_encrypted = 0x1000
#endif
};
@@ -141,6 +141,9 @@ namespace libtorrent
web_seed = 1
};
int connection_type;
+
+ // approximate peer download rate
+ int remote_dl_rate;
};
}
diff --git a/libtorrent/include/libtorrent/piece_picker.hpp b/libtorrent/include/libtorrent/piece_picker.hpp
index 7b8612909..c52521d0a 100755
--- a/libtorrent/include/libtorrent/piece_picker.hpp
+++ b/libtorrent/include/libtorrent/piece_picker.hpp
@@ -90,14 +90,14 @@ namespace libtorrent
struct block_info
{
- block_info(): num_downloads(0), requested(0), finished(0) {}
+ block_info(): num_downloads(0), state(state_none) {}
// the peer this block was requested or
// downloaded from
tcp::endpoint peer;
// the number of times this block has been downloaded
unsigned num_downloads:14;
- unsigned requested:1;
- unsigned finished:1;
+ enum { state_none, state_requested, state_writing, state_finished };
+ unsigned state:2;
};
// the peers that are downloading this piece
@@ -109,7 +109,7 @@ namespace libtorrent
struct downloading_piece
{
- downloading_piece(): finished(0), requested(0) {}
+ downloading_piece(): finished(0), writing(0), requested(0) {}
piece_state_t state;
// the index of the piece
@@ -118,20 +118,27 @@ namespace libtorrent
// this is a pointer into the m_block_info
// vector owned by the piece_picker
block_info* info;
- boost::uint16_t finished;
- boost::uint16_t requested;
+ // the number of blocks in the finished state
+ boost::int16_t finished;
+ // the number of blocks in the writing state
+ boost::int16_t writing;
+ // the number of blocks in the requested state
+ boost::int16_t requested;
};
piece_picker(int blocks_per_piece
, int total_num_blocks);
+ void get_availability(std::vector& avail) const;
+
void set_sequenced_download_threshold(int sequenced_download_threshold);
// the vector tells which pieces we already have
// and which we don't have.
void files_checked(
- const std::vector& pieces
- , const std::vector& unfinished);
+ std::vector const& pieces
+ , std::vector const& unfinished
+ , std::vector& verify_pieces);
// increases the peer count for the given piece
// (is used when a HAVE or BITFIELD message is received)
@@ -188,12 +195,16 @@ namespace libtorrent
// returns true if any client is currently downloading this
// piece-block, or if it's queued for downloading by some client
// or if it already has been successfully downloaded
- bool is_downloading(piece_block block) const;
+ bool is_requested(piece_block block) const;
+ // returns true if the block has been downloaded
+ bool is_downloaded(piece_block block) const;
+ // returns true if the block has been downloaded and written to disk
bool is_finished(piece_block block) const;
// marks this piece-block as queued for downloading
void mark_as_downloading(piece_block block, tcp::endpoint const& peer
, piece_state_t s);
+ void mark_as_writing(piece_block block, tcp::endpoint const& peer);
void mark_as_finished(piece_block block, tcp::endpoint const& peer);
// if a piece had a hash-failure, it must be restored and
diff --git a/libtorrent/include/libtorrent/policy.hpp b/libtorrent/include/libtorrent/policy.hpp
index 9404aa095..fffc3bfa2 100755
--- a/libtorrent/include/libtorrent/policy.hpp
+++ b/libtorrent/include/libtorrent/policy.hpp
@@ -99,11 +99,11 @@ namespace libtorrent
void piece_finished(int index, bool successfully_verified);
- void block_finished(peer_connection& c, piece_block b);
-
// the peer choked us
void choked(peer_connection& c);
+ int count_choked() const;
+
// the peer unchoked us
void unchoked(peer_connection& c);
diff --git a/libtorrent/include/libtorrent/proxy_base.hpp b/libtorrent/include/libtorrent/proxy_base.hpp
index 4abca18c7..021802dd0 100644
--- a/libtorrent/include/libtorrent/proxy_base.hpp
+++ b/libtorrent/include/libtorrent/proxy_base.hpp
@@ -181,4 +181,3 @@ protected:
#endif
-
diff --git a/libtorrent/include/libtorrent/session.hpp b/libtorrent/include/libtorrent/session.hpp
index 98424690a..52ec62cdb 100755
--- a/libtorrent/include/libtorrent/session.hpp
+++ b/libtorrent/include/libtorrent/session.hpp
@@ -72,8 +72,11 @@ namespace libtorrent
struct torrent_plugin;
class torrent;
class ip_filter;
+ class port_filter;
class connection_queue;
+ namespace fs = boost::filesystem;
+
namespace aux
{
// workaround for microsofts
@@ -135,7 +138,7 @@ namespace libtorrent
// all torrent_handles must be destructed before the session is destructed!
torrent_handle add_torrent(
torrent_info const& ti
- , boost::filesystem::path const& save_path
+ , fs::path const& save_path
, entry const& resume_data = entry()
, bool compact_mode = true
, int block_size = 16 * 1024
@@ -144,7 +147,7 @@ namespace libtorrent
// TODO: deprecated, this is for backwards compatibility only
torrent_handle add_torrent(
entry const& e
- , boost::filesystem::path const& save_path
+ , fs::path const& save_path
, entry const& resume_data = entry()
, bool compact_mode = true
, int block_size = 16 * 1024
@@ -158,7 +161,7 @@ namespace libtorrent
char const* tracker_url
, sha1_hash const& info_hash
, char const* name
- , boost::filesystem::path const& save_path
+ , fs::path const& save_path
, entry const& resume_data = entry()
, bool compact_mode = true
, int block_size = 16 * 1024
@@ -187,8 +190,10 @@ namespace libtorrent
#endif
void set_ip_filter(ip_filter const& f);
+ void set_port_filter(port_filter const& f);
void set_peer_id(peer_id const& pid);
void set_key(int key);
+ peer_id id() const;
bool is_listening() const;
@@ -249,6 +254,16 @@ namespace libtorrent
connection_queue& get_connection_queue();
+ // starts/stops UPnP, NATPMP or LSD port mappers
+ // they are stopped by default
+ void start_lsd();
+ void start_natpmp();
+ void start_upnp();
+
+ void stop_lsd();
+ void stop_natpmp();
+ void stop_upnp();
+
// Resource management used for global limits.
resource_request m_ul_bandwidth_quota;
resource_request m_dl_bandwidth_quota;
diff --git a/libtorrent/include/libtorrent/session_settings.hpp b/libtorrent/include/libtorrent/session_settings.hpp
index c41fca1b7..a8b2091f6 100644
--- a/libtorrent/include/libtorrent/session_settings.hpp
+++ b/libtorrent/include/libtorrent/session_settings.hpp
@@ -54,6 +54,8 @@ namespace libtorrent
// a plain tcp socket is used, and
// the other settings are ignored.
none,
+ // socks4 server, requires username.
+ socks4,
// the hostname and port settings are
// used to connect to the proxy. No
// username or password is sent.
@@ -102,6 +104,8 @@ namespace libtorrent
, connection_speed(20)
, send_redundant_have(false)
, lazy_bitfields(true)
+ , inactivity_timeout(600)
+ , unchoke_interval(20)
#ifndef TORRENT_DISABLE_DHT
, use_dht_as_fallback(true)
#endif
@@ -226,6 +230,18 @@ namespace libtorrent
// from stopping people from seeding.
bool lazy_bitfields;
+ // if a peer is uninteresting and uninterested for longer
+ // than this number of seconds, it will be disconnected.
+ // default is 10 minutes
+ int inactivity_timeout;
+
+ // the number of seconds between chokes/unchokes
+ int unchoke_interval;
+
+ // if this is set, this IP will be reported do the
+ // tracker in the ip= parameter.
+ address announce_ip;
+
#ifndef TORRENT_DISABLE_DHT
// while this is true, the dht will note be used unless the
// tracker is online
diff --git a/libtorrent/include/libtorrent/socket_type.hpp b/libtorrent/include/libtorrent/socket_type.hpp
index f81d12342..9ed8f9a4b 100644
--- a/libtorrent/include/libtorrent/socket_type.hpp
+++ b/libtorrent/include/libtorrent/socket_type.hpp
@@ -34,12 +34,17 @@ POSSIBILITY OF SUCH DAMAGE.
#define TORRENT_SOCKET_TYPE
#include "libtorrent/socks5_stream.hpp"
+#include "libtorrent/socks4_stream.hpp"
#include "libtorrent/http_stream.hpp"
#include "libtorrent/variant_stream.hpp"
namespace libtorrent
{
- typedef variant_stream socket_type;
+ typedef variant_stream<
+ stream_socket
+ , socks5_stream
+ , socks4_stream
+ , http_stream> socket_type;
}
#endif
diff --git a/libtorrent/include/libtorrent/socks5_stream.hpp b/libtorrent/include/libtorrent/socks5_stream.hpp
index 9e8a0d04b..8bfc74c59 100644
--- a/libtorrent/include/libtorrent/socks5_stream.hpp
+++ b/libtorrent/include/libtorrent/socks5_stream.hpp
@@ -1,33 +1,50 @@
-#include "libtorrent/io.hpp"
-#include "libtorrent/socket.hpp"
-#include
-#include
-#include
-#include
-#include
+/*
+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_SOCKS5_STREAM_HPP_INCLUDED
+#define TORRENT_SOCKS5_STREAM_HPP_INCLUDED
+
+#include "libtorrent/proxy_base.hpp"
namespace libtorrent {
-class socks5_stream : boost::noncopyable
+class socks5_stream : public proxy_base
{
public:
- typedef stream_socket::lowest_layer_type lowest_layer_type;
- typedef stream_socket::endpoint_type endpoint_type;
- typedef stream_socket::protocol_type protocol_type;
-
explicit socks5_stream(asio::io_service& io_service)
- : m_sock(io_service)
- , m_resolver(io_service)
+ : proxy_base(io_service)
{}
- void set_proxy(std::string hostname, int port)
- {
- m_hostname = hostname;
- m_port = port;
- }
-
void set_username(std::string const& user
, std::string const& password)
{
@@ -35,108 +52,6 @@ public:
m_password = password;
}
- template
- void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
- {
- m_sock.async_read_some(buffers, handler);
- }
-
- template
- std::size_t read_some(Mutable_Buffers const& buffers, asio::error_code& ec)
- {
- return m_sock.read_some(buffers, ec);
- }
-
- template
- std::size_t read_some(Mutable_Buffers const& buffers)
- {
- return m_sock.read_some(buffers);
- }
-
- template
- void io_control(IO_Control_Command& ioc)
- {
- m_sock.io_control(ioc);
- }
-
- template
- void io_control(IO_Control_Command& ioc, asio::error_code& ec)
- {
- m_sock.io_control(ioc, ec);
- }
-
- template
- void async_write_some(Const_Buffers const& buffers, Handler const& handler)
- {
- m_sock.async_write_some(buffers, handler);
- }
-
- void bind(endpoint_type const& endpoint)
- {
- m_sock.bind(endpoint);
- }
-
- template
- void bind(endpoint_type const& endpoint, Error_Handler const& error_handler)
- {
- m_sock.bind(endpoint, error_handler);
- }
-
- void open(protocol_type const& p)
- {
- m_sock.open(p);
- }
-
- template
- void open(protocol_type const& p, Error_Handler const& error_handler)
- {
- m_sock.open(p, error_handler);
- }
-
- void close()
- {
- m_remote_endpoint = endpoint_type();
- m_sock.close();
- }
-
- template
- void close(Error_Handler const& error_handler)
- {
- m_sock.close(error_handler);
- }
-
- endpoint_type remote_endpoint()
- {
- return m_remote_endpoint;
- }
-
- template
- endpoint_type remote_endpoint(Error_Handler const& error_handler)
- {
- return m_remote_endpoint;
- }
-
- endpoint_type local_endpoint()
- {
- return m_sock.local_endpoint();
- }
-
- template
- endpoint_type local_endpoint(Error_Handler const& error_handler)
- {
- return m_sock.local_endpoint(error_handler);
- }
-
- asio::io_service& io_service()
- {
- return m_sock.io_service();
- }
-
- lowest_layer_type& lowest_layer()
- {
- return m_sock.lowest_layer();
- }
-
typedef boost::function handler_type;
template
@@ -176,20 +91,13 @@ private:
void connect2(asio::error_code const& e, boost::shared_ptr h);
void connect3(asio::error_code const& e, boost::shared_ptr h);
- stream_socket m_sock;
- // the socks5 proxy
- std::string m_hostname;
- int m_port;
// send and receive buffer
std::vector m_buffer;
// proxy authentication
std::string m_user;
std::string m_password;
-
- endpoint_type m_remote_endpoint;
-
- tcp::resolver m_resolver;
};
}
+#endif
diff --git a/libtorrent/include/libtorrent/storage.hpp b/libtorrent/include/libtorrent/storage.hpp
index ccb17cb71..552b6e89f 100755
--- a/libtorrent/include/libtorrent/storage.hpp
+++ b/libtorrent/include/libtorrent/storage.hpp
@@ -41,9 +41,9 @@ POSSIBILITY OF SUCH DAMAGE.
#endif
#include
-#include
#include
#include
+#include
#ifdef _MSC_VER
#pragma warning(pop)
@@ -52,6 +52,9 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/torrent_info.hpp"
#include "libtorrent/piece_picker.hpp"
+#include "libtorrent/intrusive_ptr_base.hpp"
+#include "libtorrent/peer_request.hpp"
+#include "libtorrent/hasher.hpp"
#include "libtorrent/config.hpp"
namespace libtorrent
@@ -61,8 +64,11 @@ namespace libtorrent
struct piece_checker_data;
}
+ namespace fs = boost::filesystem;
+
class session;
struct file_pool;
+ struct disk_io_job;
#if defined(_WIN32) && defined(UNICODE)
@@ -72,11 +78,11 @@ namespace libtorrent
TORRENT_EXPORT std::vector > get_filesizes(
torrent_info const& t
- , boost::filesystem::path p);
+ , fs::path p);
TORRENT_EXPORT bool match_filesizes(
torrent_info const& t
- , boost::filesystem::path p
+ , fs::path p
, std::vector > const& sizes
, bool compact_mode
, std::string* error = 0);
@@ -89,6 +95,15 @@ namespace libtorrent
std::string m_msg;
};
+ struct TORRENT_EXPORT partial_hash
+ {
+ partial_hash(): offset(0) {}
+ // the number of bytes in the piece that has been hashed
+ int offset;
+ // the sha-1 context
+ hasher h;
+ };
+
struct TORRENT_EXPORT storage_interface
{
// create directories and set file sizes
@@ -103,7 +118,7 @@ namespace libtorrent
// may throw file_error if storage for slot hasn't been allocated
virtual void write(const char* buf, int slot, int offset, int size) = 0;
- virtual bool move_storage(boost::filesystem::path save_path) = 0;
+ virtual bool move_storage(fs::path save_path) = 0;
// verify storage dependent fast resume entries
virtual bool verify_resume_data(entry& rd, std::string& error) = 0;
@@ -121,6 +136,9 @@ namespace libtorrent
// in slot3 and the data in slot3 in slot1
virtual void swap_slots3(int slot1, int slot2, int slot3) = 0;
+ // returns the sha1-hash for the data at the given slot
+ virtual sha1_hash hash_for_slot(int slot, partial_hash& h, int piece_size) = 0;
+
// this will close all open files that are opened for
// writing. This is called when a torrent has finished
// downloading.
@@ -129,24 +147,32 @@ namespace libtorrent
};
typedef storage_interface* (&storage_constructor_type)(
- torrent_info const&, boost::filesystem::path const&
+ torrent_info const&, fs::path const&
, file_pool&);
TORRENT_EXPORT storage_interface* default_storage_constructor(torrent_info const& ti
- , boost::filesystem::path const& path, file_pool& fp);
+ , fs::path const& path, file_pool& fp);
// returns true if the filesystem the path relies on supports
// sparse files or automatic zero filling of files.
- TORRENT_EXPORT bool supports_sparse_files(boost::filesystem::path const& p);
+ TORRENT_EXPORT bool supports_sparse_files(fs::path const& p);
- class TORRENT_EXPORT piece_manager : boost::noncopyable
+ struct disk_io_thread;
+
+ class TORRENT_EXPORT piece_manager
+ : public intrusive_ptr_base
+ , boost::noncopyable
{
+ friend class invariant_access;
+ friend struct disk_io_thread;
public:
piece_manager(
- const torrent_info& info
- , const boost::filesystem::path& path
+ boost::shared_ptr const& torrent
+ , torrent_info const& ti
+ , fs::path const& path
, file_pool& fp
+ , disk_io_thread& io
, storage_constructor_type sc);
~piece_manager();
@@ -156,35 +182,38 @@ namespace libtorrent
std::pair check_files(std::vector& pieces
, int& num_pieces, boost::recursive_mutex& mutex);
- void release_files();
-
void write_resume_data(entry& rd) const;
bool verify_resume_data(entry& rd, std::string& error);
- bool is_allocating() const;
- bool allocate_slots(int num_slots, bool abort_on_disk = false);
+ bool is_allocating() const
+ { return m_state == state_allocating; }
+
void mark_failed(int index);
unsigned long piece_crc(
int slot_index
, int block_size
, piece_picker::block_info const* bi);
+
int slot_for_piece(int piece_index) const;
- size_type read(
- char* buf
- , int piece_index
- , int offset
- , int size);
+ void async_read(
+ peer_request const& r
+ , boost::function const& handler);
- void write(
- const char* buf
- , int piece_index
- , int offset
- , int size);
+ void async_write(
+ peer_request const& r
+ , char const* buffer
+ , boost::function const& f);
- boost::filesystem::path const& save_path() const;
- bool move_storage(boost::filesystem::path const&);
+ void async_hash(int piece, boost::function const& f);
+
+ fs::path save_path() const;
+
+ void async_release_files(
+ boost::function const& handler);
+ void async_move_storage(fs::path const& p
+ , boost::function const& handler);
// fills the vector that maps all allocated
// slots to the piece that is stored (or
@@ -192,11 +221,134 @@ namespace libtorrent
// of unassigned pieces and -1 is unallocated
void export_piece_map(std::vector& pieces) const;
- bool compact_allocation() const;
+ bool compact_allocation() const
+ { return m_compact_mode; }
+#ifndef NDEBUG
+ std::string name() const { return m_info.name(); }
+#endif
+
private:
- class impl;
- std::auto_ptr m_pimpl;
+
+ bool allocate_slots(int num_slots, bool abort_on_disk = false);
+
+ int identify_data(
+ const std::vector& piece_data
+ , int current_slot
+ , std::vector& have_pieces
+ , int& num_pieces
+ , const std::multimap& hash_to_piece
+ , boost::recursive_mutex& mutex);
+
+ size_type read_impl(
+ char* buf
+ , int piece_index
+ , int offset
+ , int size);
+
+ void write_impl(
+ const char* buf
+ , int piece_index
+ , int offset
+ , int size);
+
+ sha1_hash hash_for_piece_impl(int piece);
+
+ void release_files_impl();
+
+ bool move_storage_impl(fs::path const& save_path);
+
+ int allocate_slot_for_piece(int piece_index);
+#ifndef NDEBUG
+ void check_invariant() const;
+#ifdef TORRENT_STORAGE_DEBUG
+ void debug_log() const;
+#endif
+#endif
+ boost::scoped_ptr m_storage;
+
+ // if this is true, pieces are always allocated at the
+ // lowest possible slot index. If it is false, pieces
+ // are always written to their final place immediately
+ bool m_compact_mode;
+
+ // if this is true, pieces that haven't been downloaded
+ // will be filled with zeroes. Not filling with zeroes
+ // will not work in some cases (where a seek cannot pass
+ // the end of the file).
+ bool m_fill_mode;
+
+ // a bitmask representing the pieces we have
+ std::vector m_have_piece;
+
+ torrent_info const& m_info;
+
+ // slots that haven't had any file storage allocated
+ std::vector m_unallocated_slots;
+ // slots that have file storage, but isn't assigned to a piece
+ std::vector m_free_slots;
+
+ enum
+ {
+ has_no_slot = -3 // the piece has no storage
+ };
+
+ // maps piece indices to slots. If a piece doesn't
+ // have any storage, it is set to 'has_no_slot'
+ std::vector m_piece_to_slot;
+
+ enum
+ {
+ unallocated = -1, // the slot is unallocated
+ unassigned = -2 // the slot is allocated but not assigned to a piece
+ };
+
+ // maps slots to piece indices, if a slot doesn't have a piece
+ // it can either be 'unassigned' or 'unallocated'
+ std::vector m_slot_to_piece;
+
+ fs::path m_save_path;
+
+ mutable boost::recursive_mutex m_mutex;
+
+ bool m_allocating;
+ boost::mutex m_allocating_monitor;
+ boost::condition m_allocating_condition;
+
+ // these states are used while checking/allocating the torrent
+
+ enum {
+ // the default initial state
+ state_none,
+ // the file checking is complete
+ state_finished,
+ // creating the directories
+ state_create_files,
+ // checking the files
+ state_full_check,
+ // allocating files (in non-compact mode)
+ state_allocating
+ } m_state;
+ int m_current_slot;
+
+ std::vector m_piece_data;
+
+ // this maps a piece hash to piece index. It will be
+ // build the first time it is used (to save time if it
+ // isn't needed)
+ std::multimap m_hash_to_piece;
+
+ std::map m_piece_hasher;
+
+ disk_io_thread& m_io_thread;
+
+ // the reason for this to be a void pointer
+ // is to avoid creating a dependency on the
+ // torrent. This shared_ptr is here only
+ // to keep the torrent object alive until
+ // the piece_manager destructs. This is because
+ // the torrent_info object is owned by the torrent.
+ boost::shared_ptr m_torrent;
};
}
diff --git a/libtorrent/include/libtorrent/time.hpp b/libtorrent/include/libtorrent/time.hpp
index 2470522c0..3c51bdc00 100644
--- a/libtorrent/include/libtorrent/time.hpp
+++ b/libtorrent/include/libtorrent/time.hpp
@@ -51,7 +51,8 @@ namespace libtorrent
}
}
-#if (!defined (__MACH__) && !defined (_WIN32) && !defined(_POSIX_MONOTONIC_CLOCK) || _POSIX_MONOTONIC_CLOCK < 0) || defined (TORRENT_USE_BOOST_DATE_TIME)
+#if (!defined (__MACH__) && !defined (_WIN32) && (!defined(_POSIX_MONOTONIC_CLOCK) \
+ || _POSIX_MONOTONIC_CLOCK < 0)) || defined (TORRENT_USE_BOOST_DATE_TIME)
#include
@@ -99,8 +100,12 @@ namespace libtorrent
inline bool is_negative(time_duration dt) { return dt.diff < 0; }
inline bool operator<(time_duration lhs, time_duration rhs)
{ return lhs.diff < rhs.diff; }
+ inline bool operator<=(time_duration lhs, time_duration rhs)
+ { return lhs.diff <= rhs.diff; }
inline bool operator>(time_duration lhs, time_duration rhs)
{ return lhs.diff > rhs.diff; }
+ inline bool operator>=(time_duration lhs, time_duration rhs)
+ { return lhs.diff >= rhs.diff; }
// libtorrent time type
struct ptime
@@ -381,3 +386,4 @@ namespace libtorrent
#endif
#endif
+
diff --git a/libtorrent/include/libtorrent/torrent.hpp b/libtorrent/include/libtorrent/torrent.hpp
index 8943b0db9..9c9a5d034 100755
--- a/libtorrent/include/libtorrent/torrent.hpp
+++ b/libtorrent/include/libtorrent/torrent.hpp
@@ -68,6 +68,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/escape_string.hpp"
#include "libtorrent/bandwidth_manager.hpp"
#include "libtorrent/storage.hpp"
+#include "libtorrent/hasher.hpp"
namespace libtorrent
{
@@ -84,6 +85,8 @@ namespace libtorrent
struct piece_checker_data;
}
+ namespace fs = boost::filesystem;
+
// a torrent is a class that holds information
// for a specific download. It updates itself against
// the tracker
@@ -96,7 +99,7 @@ namespace libtorrent
aux::session_impl& ses
, aux::checker_impl& checker
, torrent_info const& tf
- , boost::filesystem::path const& save_path
+ , fs::path const& save_path
, tcp::endpoint const& net_interface
, bool compact_mode
, int block_size
@@ -111,7 +114,7 @@ namespace libtorrent
, char const* tracker_url
, sha1_hash const& info_hash
, char const* name
- , boost::filesystem::path const& save_path
+ , fs::path const& save_path
, tcp::endpoint const& net_interface
, bool compact_mode
, int block_size
@@ -184,6 +187,8 @@ namespace libtorrent
void filter_files(std::vector const& files);
// ============ end deprecation =============
+ void piece_availability(std::vector& avail) const;
+
void set_piece_priority(int index, int priority);
int piece_priority(int index) const;
@@ -422,11 +427,12 @@ namespace libtorrent
// completed() is called immediately after it.
void finished();
- bool verify_piece(int piece_index);
+ void async_verify_piece(int piece_index, boost::function const&);
// this is called from the peer_connection
// each time a piece has failed the hash
// test
+ void piece_finished(int index, bool passed_hash_check);
void piece_failed(int index);
void received_redundant_data(int num_bytes)
{ assert(num_bytes > 0); m_total_redundant_bytes += num_bytes; }
@@ -446,17 +452,15 @@ namespace libtorrent
- m_num_pieces - m_picker->num_filtered() == 0;
}
- boost::filesystem::path save_path() const;
+ fs::path save_path() const;
alert_manager& alerts() const;
piece_picker& picker()
{
- assert(!is_seed());
assert(m_picker.get());
return *m_picker;
}
bool has_picker() const
{
- assert((valid_metadata() && !is_seed()) == bool(m_picker.get() != 0));
return m_picker.get() != 0;
}
policy& get_policy()
@@ -503,14 +507,14 @@ namespace libtorrent
void set_max_uploads(int limit);
void set_max_connections(int limit);
- bool move_storage(boost::filesystem::path const& save_path);
+ void move_storage(fs::path const& save_path);
// unless this returns true, new connections must wait
// with their initialization.
bool ready_for_connections() const
{ return m_connections_initialized; }
bool valid_metadata() const
- { return m_storage.get() != 0; }
+ { return m_torrent_file.is_valid(); }
// parses the info section from the given
// bencoded tree and moves the torrent
@@ -519,6 +523,12 @@ namespace libtorrent
void set_metadata(entry const&);
private:
+
+ void on_files_released(int ret, disk_io_job const& j);
+ void on_storage_moved(int ret, disk_io_job const& j);
+
+ void on_piece_verified(int ret, disk_io_job const& j
+ , boost::function f);
void try_next_tracker();
int prioritize_tracker(int tracker_index);
@@ -552,7 +562,27 @@ namespace libtorrent
// if this pointer is 0, the torrent is in
// a state where the metadata hasn't been
// received yet.
- boost::scoped_ptr m_storage;
+ // the piece_manager keeps the torrent object
+ // alive by holding a shared_ptr to it and
+ // the torrent keeps the piece manager alive
+ // with this intrusive_ptr. This cycle is
+ // broken when torrent::abort() is called
+ // Then the torrent releases the piece_manager
+ // and when the piece_manager is complete with all
+ // outstanding disk io jobs (that keeps
+ // the piece_manager alive) it will destruct
+ // and release the torrent file. The reason for
+ // this is that the torrent_info is used by
+ // the piece_manager, and stored in the
+ // torrent, so the torrent cannot destruct
+ // before the piece_manager.
+ boost::intrusive_ptr m_owning_storage;
+
+ // this is a weak (non owninig) pointer to
+ // the piece_manager. This is used after the torrent
+ // has been aborted, and it can no longer own
+ // the object.
+ piece_manager* m_storage;
// the time of next tracker request
ptime m_next_request;
@@ -689,7 +719,7 @@ namespace libtorrent
// are opened through
tcp::endpoint m_net_interface;
- boost::filesystem::path m_save_path;
+ fs::path m_save_path;
// determines the storage state for this torrent.
const bool m_compact_mode;
diff --git a/libtorrent/include/libtorrent/torrent_handle.hpp b/libtorrent/include/libtorrent/torrent_handle.hpp
index cb4b892d2..b5e6bdc17 100755
--- a/libtorrent/include/libtorrent/torrent_handle.hpp
+++ b/libtorrent/include/libtorrent/torrent_handle.hpp
@@ -54,6 +54,8 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent
{
+ namespace fs = boost::filesystem;
+
namespace aux
{
struct session_impl;
@@ -202,15 +204,22 @@ namespace libtorrent
int block_size;
};
+ struct TORRENT_EXPORT block_info
+ {
+ enum block_state_t
+ { none, requested, writing, finished };
+
+ tcp::endpoint peer;
+ unsigned state:2;
+ unsigned num_downloads:14;
+ };
+
struct TORRENT_EXPORT partial_piece_info
{
enum { max_blocks_per_piece = 256 };
int piece_index;
int blocks_in_piece;
- std::bitset requested_blocks;
- std::bitset finished_blocks;
- tcp::endpoint peer[max_blocks_per_piece];
- int num_downloads[max_blocks_per_piece];
+ block_info blocks[max_blocks_per_piece];
enum state_t { none, slow, medium, fast };
state_t piece_state;
};
@@ -269,6 +278,8 @@ namespace libtorrent
// ================ end deprecation ============
+ void piece_availability(std::vector& avail) const;
+
// priority must be within the range [0, 7]
void piece_priority(int index, int priority) const;
int piece_priority(int index) const;
@@ -321,7 +332,7 @@ namespace libtorrent
// the ratio is uploaded / downloaded. less than 1 is not allowed
void set_ratio(float up_down_ratio) const;
- boost::filesystem::path save_path() const;
+ fs::path save_path() const;
// -1 means unlimited unchokes
void set_max_uploads(int max_uploads) const;
@@ -333,7 +344,7 @@ namespace libtorrent
, std::string const& password) const;
// post condition: save_path() == save_path if true is returned
- bool move_storage(boost::filesystem::path const& save_path) const;
+ void move_storage(fs::path const& save_path) const;
const sha1_hash& info_hash() const
{ return m_info_hash; }
diff --git a/libtorrent/include/libtorrent/torrent_info.hpp b/libtorrent/include/libtorrent/torrent_info.hpp
index d26f9f1f2..e52024255 100755
--- a/libtorrent/include/libtorrent/torrent_info.hpp
+++ b/libtorrent/include/libtorrent/torrent_info.hpp
@@ -62,16 +62,18 @@ namespace libtorrent
namespace pt = boost::posix_time;
namespace gr = boost::gregorian;
+ namespace fs = boost::filesystem;
+
struct TORRENT_EXPORT file_entry
{
- boost::filesystem::path path;
+ fs::path path;
size_type offset; // the offset of this file inside the torrent
size_type size; // the size of this file
// if the path was incorrectly encoded, this is
// the origianal corrupt encoded string. It is
// preserved in order to be able to reproduce
// the correct info-hash
- boost::shared_ptr orig_path;
+ boost::shared_ptr orig_path;
};
struct TORRENT_EXPORT file_slice
@@ -109,7 +111,7 @@ namespace libtorrent
void set_piece_size(int size);
void set_hash(int index, sha1_hash const& h);
void add_tracker(std::string const& url, int tier = 0);
- void add_file(boost::filesystem::path file, size_type size);
+ void add_file(fs::path file, size_type size);
void add_url_seed(std::string const& url);
std::vector map_block(int piece, size_type offset, int size) const;
@@ -192,6 +194,8 @@ namespace libtorrent
// used by seeds
void seed_free();
+ void swap(torrent_info& ti);
+
private:
void read_torrent_info(const entry& libtorrent);
diff --git a/libtorrent/include/libtorrent/tracker_manager.hpp b/libtorrent/include/libtorrent/tracker_manager.hpp
index a4d24f751..1435ceda6 100755
--- a/libtorrent/include/libtorrent/tracker_manager.hpp
+++ b/libtorrent/include/libtorrent/tracker_manager.hpp
@@ -62,6 +62,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/config.hpp"
#include "libtorrent/time.hpp"
#include "libtorrent/connection_queue.hpp"
+#include "libtorrent/intrusive_ptr_base.hpp"
namespace libtorrent
{
@@ -148,15 +149,10 @@ namespace libtorrent
, request_callback* requester
, int maximum_tracker_response_length);
- TORRENT_EXPORT void intrusive_ptr_add_ref(timeout_handler const*);
- TORRENT_EXPORT void intrusive_ptr_release(timeout_handler const*);
-
struct TORRENT_EXPORT timeout_handler
- : boost::noncopyable
+ : intrusive_ptr_base
+ , boost::noncopyable
{
- friend TORRENT_EXPORT void intrusive_ptr_add_ref(timeout_handler const*);
- friend TORRENT_EXPORT void intrusive_ptr_release(timeout_handler const*);
-
timeout_handler(asio::strand& str);
void set_timeout(int completion_timeout, int read_timeout);
@@ -187,7 +183,6 @@ namespace libtorrent
typedef boost::mutex mutex_t;
mutable mutex_t m_mutex;
- mutable int m_refs;
};
struct TORRENT_EXPORT tracker_connection
diff --git a/libtorrent/include/libtorrent/web_peer_connection.hpp b/libtorrent/include/libtorrent/web_peer_connection.hpp
index a84f2e6ff..ba7450c0a 100755
--- a/libtorrent/include/libtorrent/web_peer_connection.hpp
+++ b/libtorrent/include/libtorrent/web_peer_connection.hpp
@@ -123,7 +123,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) {}
+ void write_piece(peer_request const& r, char const* buffer) { assert(false); }
void write_keepalive() {}
void on_connected();
diff --git a/libtorrent/src/Makefile.am b/libtorrent/src/Makefile.am
index 4c04b2863..97e74ee25 100644
--- a/libtorrent/src/Makefile.am
+++ b/libtorrent/src/Makefile.am
@@ -21,7 +21,9 @@ torrent_info.cpp tracker_manager.cpp http_connection.cpp \
http_tracker_connection.cpp udp_tracker_connection.cpp \
alert.cpp identify_client.cpp ip_filter.cpp file.cpp metadata_transfer.cpp \
logger.cpp file_pool.cpp ut_pex.cpp lsd.cpp upnp.cpp instantiate_connection.cpp \
-socks5_stream.cpp http_stream.cpp connection_queue.cpp $(kademlia_sources)
+socks5_stream.cpp socks4_stream.cpp http_stream.cpp connection_queue.cpp \
+disk_io_thread.cpp \
+$(kademlia_sources)
noinst_HEADERS = \
$(top_srcdir)/include/libtorrent/alert.hpp \
@@ -34,6 +36,7 @@ $(top_srcdir)/include/libtorrent/bencode.hpp \
$(top_srcdir)/include/libtorrent/buffer.hpp \
$(top_srcdir)/include/libtorrent/connection_queue.hpp \
$(top_srcdir)/include/libtorrent/debug.hpp \
+$(top_srcdir)/include/libtorrent/disk_io_thread.hpp \
$(top_srcdir)/include/libtorrent/entry.hpp \
$(top_srcdir)/include/libtorrent/escape_string.hpp \
$(top_srcdir)/include/libtorrent/extensions.hpp \
@@ -50,6 +53,7 @@ $(top_srcdir)/include/libtorrent/session_settings.hpp \
$(top_srcdir)/include/libtorrent/http_tracker_connection.hpp \
$(top_srcdir)/include/libtorrent/identify_client.hpp \
$(top_srcdir)/include/libtorrent/instantiate_connection.hpp \
+$(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 \
@@ -72,6 +76,7 @@ $(top_srcdir)/include/libtorrent/session.hpp \
$(top_srcdir)/include/libtorrent/size_type.hpp \
$(top_srcdir)/include/libtorrent/socket.hpp \
$(top_srcdir)/include/libtorrent/socket_type.hpp \
+$(top_srcdir)/include/libtorrent/socks4_stream.hpp \
$(top_srcdir)/include/libtorrent/socks5_stream.hpp \
$(top_srcdir)/include/libtorrent/stat.hpp \
$(top_srcdir)/include/libtorrent/storage.hpp \
diff --git a/libtorrent/src/bt_peer_connection.cpp b/libtorrent/src/bt_peer_connection.cpp
index e2e2fe537..55eec74c2 100755
--- a/libtorrent/src/bt_peer_connection.cpp
+++ b/libtorrent/src/bt_peer_connection.cpp
@@ -277,6 +277,8 @@ namespace libtorrent
void bt_peer_connection::write_pe1_2_dhkey()
{
+ INVARIANT_CHECK;
+
assert(!m_encrypted);
assert(!m_rc4_encrypted);
assert(!m_DH_key_exchange.get());
@@ -305,6 +307,8 @@ namespace libtorrent
void bt_peer_connection::write_pe3_sync()
{
+ INVARIANT_CHECK;
+
assert (!m_encrypted);
assert (!m_rc4_encrypted);
assert (is_local());
@@ -383,6 +387,8 @@ namespace libtorrent
void bt_peer_connection::write_pe4_sync(int crypto_select)
{
+ INVARIANT_CHECK;
+
assert(!is_local());
assert(!m_encrypted);
assert(!m_rc4_encrypted);
@@ -415,6 +421,8 @@ namespace libtorrent
void bt_peer_connection::write_pe_vc_cryptofield(buffer::interval& write_buf,
int crypto_field, int pad_size)
{
+ INVARIANT_CHECK;
+
assert(crypto_field <= 0x03 && crypto_field > 0);
assert(pad_size == 0); // pad not used yet
// vc,crypto_field,len(pad),pad, (len(ia))
@@ -444,6 +452,8 @@ namespace libtorrent
void bt_peer_connection::init_pe_RC4_handler(char const* secret, sha1_hash const& stream_key)
{
+ INVARIANT_CHECK;
+
assert(secret);
hasher h;
@@ -483,8 +493,9 @@ namespace libtorrent
assert (begin);
assert (end);
assert (end > begin);
+ assert (!m_rc4_encrypted || m_encrypted);
- if (m_rc4_encrypted && m_encrypted)
+ if (m_rc4_encrypted)
m_RC4_handler->encrypt(begin, end - begin);
peer_connection::send_buffer(begin, end);
@@ -492,7 +503,9 @@ namespace libtorrent
buffer::interval bt_peer_connection::allocate_send_buffer(int size)
{
- if (m_rc4_encrypted && m_encrypted)
+ assert(!m_rc4_encrypted || m_encrypted);
+
+ if (m_rc4_encrypted)
{
m_enc_send_buffer = peer_connection::allocate_send_buffer(size);
return m_enc_send_buffer;
@@ -506,7 +519,9 @@ namespace libtorrent
void bt_peer_connection::setup_send()
{
- if (m_rc4_encrypted && m_encrypted)
+ assert(!m_rc4_encrypted || m_encrypted);
+
+ if (m_rc4_encrypted)
{
assert (m_enc_send_buffer.begin);
assert (m_enc_send_buffer.end);
@@ -1129,6 +1144,7 @@ namespace libtorrent
{
INVARIANT_CHECK;
+ assert(!in_handshake());
boost::shared_ptr t = associated_torrent().lock();
assert(t);
assert(m_sent_bitfield == false);
@@ -1319,7 +1335,7 @@ namespace libtorrent
send_buffer(msg, msg + packet_size);
}
- void bt_peer_connection::write_piece(peer_request const& r)
+ void bt_peer_connection::write_piece(peer_request const& r, char const* buffer)
{
INVARIANT_CHECK;
@@ -1334,9 +1350,7 @@ namespace libtorrent
detail::write_uint8(msg_piece, i.begin);
detail::write_int32(r.piece, i.begin);
detail::write_int32(r.start, i.begin);
-
- t->filesystem().read(
- i.begin, r.piece, r.start, r.length);
+ std::memcpy(i.begin, buffer, r.length);
assert(i.begin + r.length == i.end);
@@ -1357,10 +1371,11 @@ namespace libtorrent
return p.connection != m_pc
&& p.connection
&& p.connection->pid() == m_id
- && !p.connection->pid().is_all_zeros();
+ && !p.connection->pid().is_all_zeros()
+ && p.ip.address() == m_pc->remote().address();
}
- peer_id m_id;
+ peer_id const& m_id;
peer_connection const* m_pc;
};
}
@@ -1382,6 +1397,7 @@ namespace libtorrent
m_statistics.received_bytes(0, bytes_transferred);
#ifndef TORRENT_DISABLE_ENCRYPTION
+ assert(in_handshake() || !m_rc4_encrypted || m_encrypted);
if (m_rc4_encrypted && m_encrypted)
{
buffer::interval wr_buf = wr_recv_buffer();
@@ -1781,6 +1797,9 @@ namespace libtorrent
{
recv_buffer.begin += pad_size;
int len_ia = detail::read_int16(recv_buffer.begin);
+
+ if (len_ia < 0) throw protocol_error("invalid len_ia in handshake");
+
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << " len(IA) : " << len_ia << "\n";
#endif
@@ -1972,8 +1991,6 @@ namespace libtorrent
, (char*)info_hash.begin());
attach_to_torrent(info_hash);
- t = associated_torrent().lock();
- assert(t);
}
else
{
@@ -1990,17 +2007,15 @@ namespace libtorrent
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << " info_hash received\n";
#endif
- t = associated_torrent().lock();
- assert(t);
}
- // Respond with handshake and bitfield
+ t = associated_torrent().lock();
+ assert(t);
+
if (!is_local())
{
write_handshake();
}
- if (t->valid_metadata())
- write_bitfield(t->pieces());
assert(t->get_policy().has_connection(this));
@@ -2130,6 +2145,8 @@ namespace libtorrent
m_state = read_packet_size;
reset_recv_buffer(4);
+ if (t->valid_metadata())
+ write_bitfield(t->pieces());
assert(!packet_finished());
return;
@@ -2239,8 +2256,10 @@ namespace libtorrent
void bt_peer_connection::check_invariant() const
{
#ifndef TORRENT_DISABLE_ENCRYPTION
- assert(bool(m_state == read_pe_dhkey) == bool(m_DH_key_exchange)
- || !is_local());
+ assert( (bool(m_state != read_pe_dhkey) || m_DH_key_exchange.get())
+ || !is_local());
+
+ assert(!m_rc4_encrypted || m_RC4_handler.get());
#endif
if (!m_in_constructor)
peer_connection::check_invariant();
@@ -2258,4 +2277,3 @@ namespace libtorrent
}
-
diff --git a/libtorrent/src/entry.cpp b/libtorrent/src/entry.cpp
index 6506ed4c2..16dffc275 100755
--- a/libtorrent/src/entry.cpp
+++ b/libtorrent/src/entry.cpp
@@ -278,6 +278,12 @@ namespace libtorrent
}
}
+ void entry::swap(entry& e)
+ {
+ // not implemented
+ assert(false);
+ }
+
void entry::print(std::ostream& os, int indent) const
{
assert(indent >= 0);
diff --git a/libtorrent/src/file.cpp b/libtorrent/src/file.cpp
index 71bc795a4..515406a46 100755
--- a/libtorrent/src/file.cpp
+++ b/libtorrent/src/file.cpp
@@ -82,8 +82,6 @@ BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);
#endif
-namespace fs = boost::filesystem;
-
namespace
{
enum { mode_in = 1, mode_out = 2 };
@@ -130,6 +128,8 @@ namespace
namespace libtorrent
{
+ namespace fs = boost::filesystem;
+
const file::open_mode file::in(mode_in);
const file::open_mode file::out(mode_out);
@@ -248,15 +248,15 @@ namespace libtorrent
void set_size(size_type s)
{
size_type pos = tell();
- seek(1, 0);
+ seek(s - 1);
char dummy = 0;
read(&dummy, 1);
- seek(1, 0);
+ seek(s - 1);
write(&dummy, 1);
- seek(pos, 1);
+ seek(pos);
}
- size_type seek(size_type offset, int m)
+ size_type seek(size_type offset, int m = 1)
{
assert(m_open_mode);
assert(m_fd != -1);
@@ -303,13 +303,13 @@ namespace libtorrent
file::file() : m_impl(new impl()) {}
- file::file(boost::filesystem::path const& p, file::open_mode m)
+ file::file(fs::path const& p, file::open_mode m)
: m_impl(new impl(p, m.m_mask))
{}
file::~file() {}
- void file::open(boost::filesystem::path const& p, file::open_mode m)
+ void file::open(fs::path const& p, file::open_mode m)
{
m_impl->open(p, m.m_mask);
}
diff --git a/libtorrent/src/http_connection.cpp b/libtorrent/src/http_connection.cpp
index ba1592898..53798cae1 100644
--- a/libtorrent/src/http_connection.cpp
+++ b/libtorrent/src/http_connection.cpp
@@ -237,7 +237,7 @@ void http_connection::on_read(asio::error_code const& e
data = m_parser.get_body().begin;
size = m_parser.get_body().left();
}
- m_handler(asio::error_code(), m_parser, data, size);
+ m_handler(e, m_parser, data, size);
return;
}
diff --git a/libtorrent/src/http_tracker_connection.cpp b/libtorrent/src/http_tracker_connection.cpp
index cc039f198..936f8292a 100755
--- a/libtorrent/src/http_tracker_connection.cpp
+++ b/libtorrent/src/http_tracker_connection.cpp
@@ -411,6 +411,12 @@ namespace libtorrent
std::min(req.num_want, 999));
m_send_buffer += '&';
}
+ if (m_settings.announce_ip != address() && !url_has_argument(request, "ip"))
+ {
+ m_send_buffer += "ip=";
+ m_send_buffer += m_settings.announce_ip.to_string();
+ m_send_buffer += '&';
+ }
#ifndef TORRENT_DISABLE_ENCRYPTION
m_send_buffer += "supportcrypto=1&";
diff --git a/libtorrent/src/identify_client.cpp b/libtorrent/src/identify_client.cpp
index cf837a05b..44be2d60f 100755
--- a/libtorrent/src/identify_client.cpp
+++ b/libtorrent/src/identify_client.cpp
@@ -197,7 +197,7 @@ namespace
, {"XT", "XanTorrent"}
, {"XX", "Xtorrent"}
, {"ZT", "ZipTorrent"}
- , {"lt", "libTorrent (libtorrent.rakshasa.no/}"}
+ , {"lt", "rTorrent"}
, {"pX", "pHoeniX"}
, {"qB", "qBittorrent"}
};
diff --git a/libtorrent/src/instantiate_connection.cpp b/libtorrent/src/instantiate_connection.cpp
index ff4efbc59..43b70f40d 100644
--- a/libtorrent/src/instantiate_connection.cpp
+++ b/libtorrent/src/instantiate_connection.cpp
@@ -67,6 +67,12 @@ namespace libtorrent
if (ps.type == proxy_settings::socks5_pw)
s->get().set_username(ps.username, ps.password);
}
+ else if (ps.type == proxy_settings::socks4)
+ {
+ s->instantiate();
+ s->get().set_proxy(ps.hostname, ps.port);
+ s->get().set_username(ps.username);
+ }
else
{
throw std::runtime_error("unsupported proxy type");
diff --git a/libtorrent/src/ip_filter.cpp b/libtorrent/src/ip_filter.cpp
index 92ea711c7..cf368c4d1 100644
--- a/libtorrent/src/ip_filter.cpp
+++ b/libtorrent/src/ip_filter.cpp
@@ -69,6 +69,15 @@ namespace libtorrent
, m_filter6.export_filter());
}
+ void port_filter::add_rule(boost::uint16_t first, boost::uint16_t last, int flags)
+ {
+ m_filter.add_rule(first, last, flags);
+ }
+
+ int port_filter::access(boost::uint16_t port) const
+ {
+ return m_filter.access(port);
+ }
/*
void ip_filter::print() const
{
diff --git a/libtorrent/src/logger.cpp b/libtorrent/src/logger.cpp
index 6881c5e7b..b33816a59 100644
--- a/libtorrent/src/logger.cpp
+++ b/libtorrent/src/logger.cpp
@@ -53,17 +53,20 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/peer_request.hpp"
#include "libtorrent/peer_connection.hpp"
-namespace libtorrent { namespace
+namespace libtorrent {
+
+namespace fs = boost::filesystem;
+
+namespace
{
struct logger_peer_plugin : peer_plugin
{
logger_peer_plugin(std::string const& filename)
{
- using namespace boost::filesystem;
- path dir(complete("libtorrent_ext_logs"));
- if (!exists(dir)) create_directories(dir);
- m_file.open(dir / filename, std::ios_base::out | std::ios_base::out);
+ fs::path dir(fs::complete("libtorrent_ext_logs"));
+ if (!fs::exists(dir)) fs::create_directories(dir);
+ m_file.open((dir / filename).string().c_str(), std::ios_base::out | std::ios_base::out);
m_file << "\n\n\n";
log_timestamp();
m_file << "*** starting log ***\n";
@@ -201,7 +204,7 @@ namespace libtorrent { namespace
}
private:
- boost::filesystem::ofstream m_file;
+ std::ofstream m_file;
};
struct logger_plugin : torrent_plugin
diff --git a/libtorrent/src/metadata_transfer.cpp b/libtorrent/src/metadata_transfer.cpp
index fe308f926..97635cdb9 100644
--- a/libtorrent/src/metadata_transfer.cpp
+++ b/libtorrent/src/metadata_transfer.cpp
@@ -38,8 +38,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include
#include
-#include
-#include
#ifdef _MSC_VER
#pragma warning(pop)
@@ -56,6 +54,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/torrent.hpp"
#include "libtorrent/extensions.hpp"
#include "libtorrent/extensions/metadata_transfer.hpp"
+#include "libtorrent/alert_types.hpp"
namespace libtorrent { namespace
{
@@ -176,14 +175,13 @@ namespace libtorrent { namespace
, false);
m_metadata_progress = 0;
m_metadata_size = 0;
- // TODO: allow plugins to post alerts
-/*
- if (m_ses.m_alerts.should_post(alert::info))
+
+ if (m_torrent.alerts().should_post(alert::info))
{
- m_ses.m_alerts.post_alert(metadata_failed_alert(
- get_handle(), "invalid metadata received from swarm"));
+ m_torrent.alerts().post_alert(metadata_failed_alert(
+ m_torrent.get_handle(), "invalid metadata received from swarm"));
}
-*/
+
return false;
}
diff --git a/libtorrent/src/peer_connection.cpp b/libtorrent/src/peer_connection.cpp
index db70d2e1c..08f448fce 100755
--- a/libtorrent/src/peer_connection.cpp
+++ b/libtorrent/src/peer_connection.cpp
@@ -59,21 +59,6 @@ using libtorrent::aux::session_impl;
namespace libtorrent
{
- void intrusive_ptr_add_ref(peer_connection const* c)
- {
- assert(c->m_refs >= 0);
- assert(c != 0);
- ++c->m_refs;
- }
-
- void intrusive_ptr_release(peer_connection const* c)
- {
- assert(c->m_refs > 0);
- assert(c != 0);
- if (--c->m_refs == 0)
- delete c;
- }
-
// outbound connection
peer_connection::peer_connection(
session_impl& ses
@@ -94,6 +79,7 @@ namespace libtorrent
, 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())
@@ -122,12 +108,14 @@ namespace libtorrent
, m_prefer_whole_pieces(false)
, m_request_large_blocks(false)
, m_non_prioritized(false)
- , m_refs(0)
, m_upload_limit(resource_request::inf)
, m_download_limit(resource_request::inf)
, m_peer_info(peerinfo)
, m_speed(slow)
, m_connection_ticket(-1)
+ , m_remote_bytes_dled(0)
+ , m_remote_dl_rate(0)
+ , m_remote_dl_update(time_now())
#ifndef NDEBUG
, m_in_constructor(true)
#endif
@@ -167,6 +155,7 @@ namespace libtorrent
, 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())
@@ -193,11 +182,13 @@ namespace libtorrent
, m_prefer_whole_pieces(false)
, m_request_large_blocks(false)
, m_non_prioritized(false)
- , m_refs(0)
, m_upload_limit(resource_request::inf)
, m_download_limit(resource_request::inf)
, m_peer_info(peerinfo)
, m_speed(slow)
+ , m_remote_bytes_dled(0)
+ , m_remote_dl_rate(0)
+ , m_remote_dl_update(time_now())
#ifndef NDEBUG
, m_in_constructor(true)
#endif
@@ -742,8 +733,18 @@ namespace libtorrent
&& !is_interesting()
&& t->picker().piece_priority(index) != 0)
t->get_policy().peer_is_interesting(*this);
- }
+ // this will disregard all have messages we get within
+ // the first two seconds. Since some clients implements
+ // lazy bitfields, these will not be reliable to use
+ // for an estimated peer download rate.
+ if (!peer_info_struct() || time_now() - peer_info_struct()->connected > seconds(2))
+ {
+ // update bytes downloaded since last timer
+ m_remote_bytes_dled += t->torrent_file().piece_size(index);
+ }
+ }
+
if (is_seed())
{
assert(m_peer_info);
@@ -1012,7 +1013,7 @@ namespace libtorrent
for (std::vector::const_iterator i =
dl_queue.begin(); i != dl_queue.end(); ++i)
{
- assert(i->finished < blocks_per_piece);
+ assert(i->finished <= blocks_per_piece);
}
}
}
@@ -1076,7 +1077,6 @@ namespace libtorrent
piece_picker& picker = t->picker();
piece_manager& fs = t->filesystem();
- policy& pol = t->get_policy();
std::vector finished_blocks;
piece_block block_finished(p.piece, p.start / t->block_size());
@@ -1125,13 +1125,12 @@ namespace libtorrent
}
else
{
- // cancel the block from the
+/* // cancel the block from the
// peer that has taken over it.
boost::optional peer
= t->picker().get_downloader(block_finished);
- if (peer)
+ if (peer && t->picker().is_requested(block_finished))
{
- assert(!t->picker().is_finished(block_finished));
peer_connection* pc = t->connection_for(*peer);
if (pc && pc != this)
{
@@ -1140,7 +1139,7 @@ namespace libtorrent
}
}
else
- {
+*/ {
if (t->alerts().should_post(alert::debug))
{
t->alerts().post_alert(
@@ -1153,15 +1152,28 @@ namespace libtorrent
(*m_logger) << " *** The block we just got was not in the "
"request queue ***\n";
#endif
+ t->received_redundant_data(p.length);
+ if (!has_peer_choked())
+ {
+ request_a_block(*t, *this);
+ send_block_requests();
+ }
+ return;
}
}
+ assert(picker.is_requested(block_finished));
+
// if the block we got is already finished, then ignore it
- if (picker.is_finished(block_finished))
+ if (picker.is_downloaded(block_finished))
{
- t->received_redundant_data(t->block_size());
- pol.block_finished(*this, block_finished);
- send_block_requests();
+ t->received_redundant_data(p.length);
+
+ if (!has_peer_choked())
+ {
+ request_a_block(*t, *this);
+ send_block_requests();
+ }
if (request_peer && !request_peer->has_peer_choked() && !t->is_seed())
{
@@ -1171,107 +1183,73 @@ namespace libtorrent
return;
}
- fs.write(data, p.piece, p.start, p.length);
-
- picker.mark_as_finished(block_finished, m_remote);
-
- try
- {
- pol.block_finished(*this, block_finished);
- send_block_requests();
- }
- catch (std::exception const&) {}
-
+ fs.async_write(p, data, bind(&peer_connection::on_disk_write_complete
+ , self(), _1, _2, p, t));
+ picker.mark_as_writing(block_finished, m_remote);
+
if (request_peer && !request_peer->has_peer_choked() && !t->is_seed())
{
request_a_block(*t, *request_peer);
request_peer->send_block_requests();
}
+ }
+
+ void peer_connection::on_disk_write_complete(int ret, disk_io_job const& j
+ , peer_request p, boost::shared_ptr t)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ if (ret == -1 || !t)
+ {
+ if (!t)
+ {
+ m_ses.connection_failed(m_socket, remote(), j.str.c_str());
+ return;
+ }
+
+ if (t->alerts().should_post(alert::fatal))
+ {
+ std::string err = "torrent paused: disk write error, " + j.str;
+ t->alerts().post_alert(file_error_alert(t->get_handle(), err));
+ }
+ t->pause();
+ return;
+ }
+
+ if (t->is_seed()) return;
+
+ piece_picker& picker = t->picker();
+
+ assert(p.piece == j.piece);
+ assert(p.start == j.offset);
+ piece_block block_finished(p.piece, p.start / t->block_size());
+ picker.mark_as_finished(block_finished, m_remote);
+
+ if (!has_peer_choked() && !t->is_seed() && !m_torrent.expired())
+ {
+ // this is a free function defined in policy.cpp
+ request_a_block(*t, *this);
+ try
+ {
+ send_block_requests();
+ }
+ catch (std::exception const&) {}
+ }
+
#ifndef NDEBUG
try
{
#endif
- bool was_seed = t->is_seed();
- bool was_finished = picker.num_filtered() + t->num_pieces()
- == t->torrent_file().num_pieces();
-
// did we just finish the piece?
if (picker.is_piece_finished(p.piece))
{
#ifndef NDEBUG
check_postcondition post_checker2_(t, false);
#endif
- bool verified = t->verify_piece(p.piece);
- if (verified)
- {
- // the following call may cause picker to become invalid
- // in case we just became a seed
- t->announce_piece(p.piece);
- assert(t->valid_metadata());
- // if we just became a seed, picker is now invalid, since it
- // is deallocated by the torrent once it starts seeding
- if (!was_finished
- && (t->is_seed()
- || picker.num_filtered() + t->num_pieces()
- == t->torrent_file().num_pieces()))
- {
- // torrent finished
- // i.e. all the pieces we're interested in have
- // been downloaded. Release the files (they will open
- // in read only mode if needed)
- try { t->finished(); }
- catch (std::exception& e)
- {
-#ifndef NDEBUG
- std::cerr << e.what() << std::endl;
- assert(false);
-#endif
- }
- }
- }
- else
- {
- t->piece_failed(p.piece);
- }
-
-#ifndef NDEBUG
- try
- {
-#endif
-
- pol.piece_finished(p.piece, verified);
-
-#ifndef NDEBUG
- }
- catch (std::exception const& e)
- {
- std::cerr << e.what() << std::endl;
- assert(false);
- }
-#endif
-
-#ifndef NDEBUG
- try
- {
-#endif
-
- if (!was_seed && t->is_seed())
- {
- assert(verified);
- t->completed();
- }
-
-#ifndef NDEBUG
- }
- catch (std::exception const& e)
- {
- std::cerr << e.what() << std::endl;
- assert(false);
- }
-#endif
-
+ t->async_verify_piece(p.piece, bind(&torrent::piece_finished, t
+ , p.piece, _1));
}
#ifndef NDEBUG
@@ -1350,7 +1328,7 @@ namespace libtorrent
assert(block.piece_index < t->torrent_file().num_pieces());
assert(block.block_index >= 0);
assert(block.block_index < t->torrent_file().piece_size(block.piece_index));
- assert(!t->picker().is_downloading(block));
+ assert(!t->picker().is_requested(block));
piece_picker::piece_state_t state;
peer_speed_t speed = peer_speed();
@@ -1376,7 +1354,7 @@ namespace libtorrent
assert(block.piece_index < t->torrent_file().num_pieces());
assert(block.block_index >= 0);
assert(block.block_index < t->torrent_file().piece_size(block.piece_index));
- assert(t->picker().is_downloading(block));
+ assert(t->picker().is_requested(block));
t->picker().abort_download(block);
@@ -1603,6 +1581,8 @@ namespace libtorrent
void peer_connection::disconnect()
{
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
boost::intrusive_ptr me(this);
INVARIANT_CHECK;
@@ -1753,12 +1733,14 @@ namespace libtorrent
p.failcount = peer_info_struct()->failcount;
p.num_hashfails = peer_info_struct()->hashfails;
p.flags |= peer_info_struct()->on_parole ? peer_info::on_parole : 0;
+ p.remote_dl_rate = m_remote_dl_rate;
}
else
{
p.source = 0;
p.failcount = 0;
p.num_hashfails = 0;
+ p.remote_dl_rate = 0;
}
p.send_buffer_size = send_buffer_size();
@@ -1868,8 +1850,11 @@ namespace libtorrent
m_assume_fifo = true;
- request_a_block(*t, *this);
- send_block_requests();
+ if (!has_peer_choked())
+ {
+ request_a_block(*t, *this);
+ send_block_requests();
+ }
}
}
@@ -1915,6 +1900,21 @@ namespace libtorrent
, m_upload_limit));
}
+ // update once every minute
+ if (now - m_remote_dl_update >= seconds(60))
+ {
+ float factor = 0.6666666666667f;
+
+ if (m_remote_dl_rate == 0) factor = 0.0f;
+
+ m_remote_dl_rate =
+ (m_remote_dl_rate * factor) +
+ ((m_remote_bytes_dled * (1.0f-factor)) / 60.f);
+
+ m_remote_bytes_dled = 0;
+ m_remote_dl_update = now;
+ }
+
fill_send_buffer();
/*
size_type diff = share_diff();
@@ -1970,7 +1970,7 @@ namespace libtorrent
else if (buffer_size_watermark > 80 * 1024) buffer_size_watermark = 80 * 1024;
while (!m_requests.empty()
- && (send_buffer_size() < buffer_size_watermark)
+ && (send_buffer_size() + m_reading_bytes < buffer_size_watermark)
&& !m_choked)
{
assert(t->valid_metadata());
@@ -1982,16 +1982,12 @@ namespace libtorrent
assert(r.start + r.length <= t->torrent_file().piece_size(r.piece));
assert(r.length > 0 && r.start >= 0);
- write_piece(r);
-
-#ifdef TORRENT_VERBOSE_LOGGING
- (*m_logger) << time_now_string()
- << " ==> PIECE [ piece: " << r.piece << " | s: " << r.start
- << " | l: " << r.length << " ]\n";
-#endif
+ t->filesystem().async_read(r, bind(&peer_connection::on_disk_read_complete
+ , self(), _1, _2, r));
+ m_reading_bytes += r.length;
m_requests.erase(m_requests.begin());
-
+/*
if (m_requests.empty()
&& m_num_invalid_requests > 0
&& is_peer_interested()
@@ -2004,9 +2000,49 @@ namespace libtorrent
send_choke();
send_unchoke();
}
+*/
}
}
+ void peer_connection::on_disk_read_complete(int ret, disk_io_job const& j, peer_request r)
+ {
+ session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
+
+ m_reading_bytes -= r.length;
+
+ if (ret != r.length || m_torrent.expired())
+ {
+ boost::shared_ptr t = m_torrent.lock();
+ if (!t)
+ {
+ m_ses.connection_failed(m_socket, remote(), j.str.c_str());
+ return;
+ }
+
+ if (t->alerts().should_post(alert::fatal))
+ {
+ std::string err = "torrent paused: disk read error";
+ if (!j.str.empty())
+ {
+ err += ", ";
+ err += j.str;
+ }
+ t->alerts().post_alert(file_error_alert(t->get_handle(), err));
+ }
+ t->pause();
+ return;
+ }
+
+#ifdef TORRENT_VERBOSE_LOGGING
+ (*m_logger) << time_now_string()
+ << " ==> PIECE [ piece: " << r.piece << " | s: " << r.start
+ << " | l: " << r.length << " ]\n";
+#endif
+
+ write_piece(r, j.buffer);
+ setup_send();
+ }
+
void peer_connection::assign_bandwidth(int channel, int amount)
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
@@ -2599,11 +2635,13 @@ namespace libtorrent
time_duration d2;
d1 = now - m_became_uninterested;
d2 = now - m_became_uninteresting;
- // TODO: these timeouts should be user settable
+ time_duration time_limit = seconds(
+ m_ses.settings().inactivity_timeout);
+
if (!m_interesting
&& !m_peer_interested
- && d1 > minutes(10)
- && d2 > minutes(10))
+ && d1 > time_limit
+ && d2 > time_limit)
{
return true;
}
@@ -2663,3 +2701,4 @@ namespace libtorrent
}
}
+
diff --git a/libtorrent/src/piece_picker.cpp b/libtorrent/src/piece_picker.cpp
index cf6eb4a0e..bd568210f 100755
--- a/libtorrent/src/piece_picker.cpp
+++ b/libtorrent/src/piece_picker.cpp
@@ -88,8 +88,9 @@ namespace libtorrent
// pieces is a bitmask with the pieces we have
void piece_picker::files_checked(
- const std::vector& pieces
- , const std::vector& unfinished)
+ std::vector const& pieces
+ , std::vector const& unfinished
+ , std::vector& verify_pieces)
{
#ifndef NDEBUG
m_files_checked_called = true;
@@ -118,14 +119,12 @@ namespace libtorrent
tcp::endpoint peer;
for (int j = 0; j < m_blocks_per_piece; ++j)
{
- if (i->info[j].finished)
+ if (i->info[j].state == block_info::state_finished)
mark_as_finished(piece_block(i->index, j), peer);
}
if (is_piece_finished(i->index))
{
- // TODO: handle this case by verifying the
- // piece and either accept it or discard it
- assert(false);
+ verify_pieces.push_back(i->index);
}
}
}
@@ -212,8 +211,7 @@ namespace libtorrent
for (int i = 0; i < m_blocks_per_piece; ++i)
{
ret.info[i].num_downloads = 0;
- ret.info[i].requested = 0;
- ret.info[i].finished = 0;
+ ret.info[i].state = block_info::state_none;
ret.info[i].peer = tcp::endpoint();
}
return ret;
@@ -258,25 +256,28 @@ namespace libtorrent
int num_blocks = blocks_in_piece(i->index);
int num_requested = 0;
int num_finished = 0;
+ int num_writing = 0;
for (int k = 0; k < num_blocks; ++k)
{
- if (i->info[k].finished)
+ if (i->info[k].state == block_info::state_finished)
{
++num_finished;
- assert(i->info[k].requested);
- ++num_requested;
continue;
}
- if (i->info[k].requested)
+ if (i->info[k].state == block_info::state_requested)
{
++num_requested;
blocks_requested = true;
}
+ if (i->info[k].state == block_info::state_writing)
+ {
+ ++num_writing;
+ }
}
assert(blocks_requested == (i->state != none));
assert(num_requested == i->requested);
+ assert(num_writing == i->writing);
assert(num_finished == i->finished);
- assert(num_finished <= num_requested);
}
@@ -1070,8 +1071,7 @@ namespace libtorrent
for (int j = 0; j < num_blocks_in_piece; ++j)
{
piece_picker::block_info const& info = p.info[j];
- if ((info.finished == 1
- || info.requested == 1)
+ if (info.state != piece_picker::block_info::state_none
&& info.peer != peer
&& info.peer != tcp::endpoint())
{
@@ -1089,6 +1089,9 @@ namespace libtorrent
, int num_blocks, bool prefer_whole_pieces
, tcp::endpoint peer, piece_state_t speed) const
{
+ // if we have less than 1% of the pieces, ignore speed priorities and just try
+ // to finish any downloading piece
+ bool ignore_speed_categories = (m_num_have * 100 / m_piece_map.size()) < 1;
for (std::vector::const_iterator i = piece_list.begin();
i != piece_list.end(); ++i)
{
@@ -1098,10 +1101,6 @@ namespace libtorrent
// if the peer doesn't have the piece
// skip it
if (!pieces[*i]) continue;
-
- // if we have less than 1% of the pieces, ignore speed priorities and just try
- // to finish any downloading piece
- bool ignore_speed_categories = (m_num_have * 100 / m_piece_map.size()) < 1;
int num_blocks_in_piece = blocks_in_piece(*i);
@@ -1130,8 +1129,10 @@ namespace libtorrent
for (int j = 0; j < num_blocks_in_piece; ++j)
{
block_info const& info = p->info[j];
- if (info.finished) continue;
- if (info.requested
+ if (info.state == block_info::state_finished
+ || info.state == block_info::state_writing)
+ continue;
+ if (info.state == block_info::state_requested
&& info.peer == peer) continue;
backup_blocks.push_back(piece_block(*i, j));
}
@@ -1142,9 +1143,13 @@ namespace libtorrent
{
// ignore completed blocks
block_info const& info = p->info[j];
- if (info.finished) continue;
+ if (info.state == block_info::state_finished
+ || info.state == block_info::state_writing)
+ continue;
// ignore blocks requested from this peer already
- if (info.requested && info.peer == peer) continue;
+ if (info.state == block_info::state_requested
+ && info.peer == peer)
+ continue;
// if the piece is fast and the peer is slow, or vice versa,
// add the block as a backup.
// override this behavior if all the other blocks
@@ -1169,7 +1174,7 @@ namespace libtorrent
// blocks that have not been requested from any
// other peer.
interesting_blocks.push_back(piece_block(*i, j));
- if (p->info[j].requested == 0)
+ if (p->info[j].state == block_info::state_none)
{
// we have found a block that's free to download
num_blocks--;
@@ -1217,11 +1222,18 @@ namespace libtorrent
int max_blocks = blocks_in_piece(index);
if ((int)i->finished < max_blocks) return false;
- assert((int)i->requested == max_blocks);
+#ifndef NDEBUG
+ for (int k = 0; k < max_blocks; ++k)
+ {
+ assert(i->info[k].state == block_info::state_finished);
+ }
+#endif
+
+ assert((int)i->finished == max_blocks);
return true;
}
- bool piece_picker::is_downloading(piece_block block) const
+ bool piece_picker::is_requested(piece_block block) const
{
assert(block.piece_index >= 0);
assert(block.block_index >= 0);
@@ -1235,7 +1247,22 @@ namespace libtorrent
, has_index(block.piece_index));
assert(i != m_downloads.end());
- return i->info[block.block_index].requested;
+ return i->info[block.block_index].state == block_info::state_requested;
+ }
+
+ bool piece_picker::is_downloaded(piece_block block) const
+ {
+ assert(block.piece_index >= 0);
+ assert(block.block_index >= 0);
+ assert(block.piece_index < (int)m_piece_map.size());
+
+ if (m_piece_map[block.piece_index].index == piece_pos::we_have_index) return true;
+ if (m_piece_map[block.piece_index].downloading == 0) return false;
+ std::vector::const_iterator i
+ = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
+ assert(i != m_downloads.end());
+ return i->info[block.block_index].state == block_info::state_finished
+ || i->info[block.block_index].state == block_info::state_writing;
}
bool piece_picker::is_finished(piece_block block) const
@@ -1249,7 +1276,7 @@ namespace libtorrent
std::vector::const_iterator i
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
assert(i != m_downloads.end());
- return i->info[block.block_index].finished;
+ return i->info[block.block_index].state == block_info::state_finished;
}
@@ -1274,7 +1301,7 @@ namespace libtorrent
dp.state = state;
dp.index = block.piece_index;
block_info& info = dp.info[block.block_index];
- info.requested = 1;
+ info.state = block_info::state_requested;
info.peer = peer;
++dp.requested;
}
@@ -1284,15 +1311,26 @@ namespace libtorrent
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
assert(i != m_downloads.end());
block_info& info = i->info[block.block_index];
- assert(info.requested == 0);
+ assert(info.state == block_info::state_none);
info.peer = peer;
- info.requested = 1;
+ info.state = block_info::state_requested;
++i->requested;
if (i->state == none) i->state = state;
}
}
- void piece_picker::mark_as_finished(piece_block block, const tcp::endpoint& peer)
+ void piece_picker::get_availability(std::vector& avail) const
+ {
+ TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+
+ avail.resize(m_piece_map.size());
+ std::vector::iterator j = avail.begin();
+ for (std::vector::const_iterator i = m_piece_map.begin()
+ , end(m_piece_map.end()); i != end; ++i, ++j)
+ *j = i->peer_count;
+ }
+
+ void piece_picker::mark_as_writing(piece_block block, tcp::endpoint const& peer)
{
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
@@ -1302,10 +1340,11 @@ namespace libtorrent
assert(block.block_index < blocks_in_piece(block.piece_index));
piece_pos& p = m_piece_map[block.piece_index];
- int prio = p.priority(m_sequenced_download_threshold);
+ assert(p.downloading);
- if (p.downloading == 0)
+/* if (p.downloading == 0)
{
+ int prio = p.priority(m_sequenced_download_threshold);
p.downloading = 1;
if (prio > 0) move(prio, p.index);
else assert(p.priority(m_sequenced_download_threshold) == 0);
@@ -1314,25 +1353,84 @@ namespace libtorrent
dp.state = none;
dp.index = block.piece_index;
block_info& info = dp.info[block.block_index];
- info.requested = 1;
- info.finished = 1;
- ++dp.requested;
- ++dp.finished;
- dp.info[block.block_index].peer = peer;
+ info.peer = peer;
+ if (info.state == block_info::state_requested) --dp.requested;
+ assert(dp.requested >= 0);
+ assert (info.state != block_info::state_finished);
+ assert (info.state != block_info::state_writing);
+ if (info.state != block_info::state_requested) ++dp.writing;
+ info.state = block_info::state_writing;
+ }
+ else
+*/ {
+ std::vector::iterator i
+ = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
+ assert(i != m_downloads.end());
+ block_info& info = i->info[block.block_index];
+ info.peer == peer;
+ assert(info.state == block_info::state_requested);
+ if (info.state == block_info::state_requested) --i->requested;
+ assert(i->requested >= 0);
+ assert (info.state != block_info::state_writing);
+ ++i->writing;
+ info.state = block_info::state_writing;
+
+ if (i->requested == 0)
+ {
+ // there are no blocks requested in this piece.
+ // remove the fast/slow state from it
+ i->state = none;
+ }
+ }
+ }
+
+ void piece_picker::mark_as_finished(piece_block block, tcp::endpoint const& peer)
+ {
+ assert(block.piece_index >= 0);
+ assert(block.block_index >= 0);
+ assert(block.piece_index < (int)m_piece_map.size());
+ assert(block.block_index < blocks_in_piece(block.piece_index));
+
+ piece_pos& p = m_piece_map[block.piece_index];
+
+ if (p.downloading == 0)
+ {
+ TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+
+ assert(peer == tcp::endpoint());
+ int prio = p.priority(m_sequenced_download_threshold);
+ p.downloading = 1;
+ if (prio > 0) move(prio, p.index);
+ else assert(p.priority(m_sequenced_download_threshold) == 0);
+
+ downloading_piece& dp = add_download_piece();
+ dp.state = none;
+ dp.index = block.piece_index;
+ block_info& info = dp.info[block.block_index];
+ info.peer = peer;
+ assert(info.state == block_info::state_none);
+// if (info.state == block_info::state_writing) --dp.writing;
+// assert(dp.writing >= 0);
+ if (info.state != block_info::state_finished) ++dp.finished;
+ info.state = block_info::state_finished;
}
else
{
+ TORRENT_PIECE_PICKER_INVARIANT_CHECK;
+
std::vector::iterator i
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
assert(i != m_downloads.end());
block_info& info = i->info[block.block_index];
info.peer = peer;
- if (!info.requested) ++i->requested;
- info.requested = 1;
- if (!info.finished) ++i->finished;
- info.finished = 1;
+ assert(info.state == block_info::state_writing
+ || peer == tcp::endpoint());
+ if (info.state == block_info::state_writing) --i->writing;
+ assert(i->writing >= 0);
+ ++i->finished;
+ info.state = block_info::state_finished;
- if (i->requested == i->finished)
+ if (i->requested == 0)
{
// there are no blocks requested in this piece.
// remove the fast/slow state from it
@@ -1367,8 +1465,7 @@ namespace libtorrent
assert(block.block_index >= 0);
- if (i->info[block.block_index].requested == false
- || i->info[block.block_index].requested == true)
+ if (i->info[block.block_index].state == block_info::state_none)
return boost::optional();
return boost::optional(i->info[block.block_index].peer);
@@ -1394,17 +1491,17 @@ namespace libtorrent
, m_downloads.end(), has_index(block.piece_index));
assert(i != m_downloads.end());
- if (i->info[block.block_index].finished)
+ if (i->info[block.block_index].state == block_info::state_finished
+ || i->info[block.block_index].state == block_info::state_writing)
{
- assert(i->info[block.block_index].requested);
return;
}
assert(block.block_index < blocks_in_piece(block.piece_index));
- assert(i->info[block.block_index].requested);
+ assert(i->info[block.block_index].state == block_info::state_requested);
// clear this block as being downloaded
- i->info[block.block_index].requested = false;
+ i->info[block.block_index].state = block_info::state_none;
--i->requested;
// clear the downloader of this block
@@ -1412,7 +1509,7 @@ namespace libtorrent
// if there are no other blocks in this piece
// that's being downloaded, remove it from the list
- if (i->requested == 0)
+ if (i->requested + i->finished + i->writing == 0)
{
erase_download_piece(i);
piece_pos& p = m_piece_map[block.piece_index];
@@ -1423,7 +1520,7 @@ namespace libtorrent
assert(std::find_if(m_downloads.begin(), m_downloads.end()
, has_index(block.piece_index)) == m_downloads.end());
}
- else if (i->requested == i->finished)
+ else if (i->requested == 0)
{
// there are no blocks requested in this piece.
// remove the fast/slow state from it
diff --git a/libtorrent/src/policy.cpp b/libtorrent/src/policy.cpp
index 61bdd5748..eca5ba613 100755
--- a/libtorrent/src/policy.cpp
+++ b/libtorrent/src/policy.cpp
@@ -142,7 +142,19 @@ namespace
bool operator()(policy::peer const& p) const
{ return p.ip.address() == m_ip.address(); }
- tcp::endpoint m_ip;
+ tcp::endpoint const& m_ip;
+ };
+
+ struct match_peer_id
+ {
+ match_peer_id(peer_id const& id_)
+ : m_id(id_)
+ {}
+
+ bool operator()(policy::peer const& p) const
+ { return p.connection && p.connection->pid() == m_id; }
+
+ peer_id const& m_id;
};
struct match_peer_connection
@@ -152,9 +164,13 @@ namespace
{}
bool operator()(policy::peer const& p) const
- { return p.connection == &m_conn; }
+ {
+ return p.connection == &m_conn
+ || (p.ip == m_conn.remote()
+ && p.type == policy::peer::connectable);
+ }
- const peer_connection& m_conn;
+ peer_connection const& m_conn;
};
@@ -230,7 +246,7 @@ namespace libtorrent
for (std::vector::iterator i = interesting_pieces.begin();
i != interesting_pieces.end(); ++i)
{
- if (p.is_downloading(*i))
+ if (p.is_requested(*i))
{
busy_pieces.push_back(*i);
continue;
@@ -524,6 +540,8 @@ namespace libtorrent
int max_failcount = m_torrent->settings().max_failcount;
int min_reconnect_time = m_torrent->settings().min_reconnect_time;
+ aux::session_impl& ses = m_torrent->session();
+
for (iterator i = m_peers.begin(); i != m_peers.end(); ++i)
{
if (i->connection) continue;
@@ -533,6 +551,8 @@ namespace libtorrent
if (i->failcount >= max_failcount) continue;
if (now - i->connected < seconds(i->failcount * min_reconnect_time))
continue;
+ if (ses.m_port_filter.access(i->ip.port()) & port_filter::blocked)
+ continue;
assert(i->connected <= now);
@@ -846,12 +866,13 @@ namespace libtorrent
--m_num_unchoked;
} while (m_num_unchoked > m_torrent->m_uploads_quota.given);
}
- else
+ // this should prevent the choke/unchoke
+ // problem, since it will not unchoke unless
+ // there actually are any choked peers
+ else if (count_choked() > 0)
{
// optimistic unchoke. trade the 'worst'
// unchoked peer with one of the choked
- // TODO: This rotation should happen
- // far less frequent than this!
assert(m_num_unchoked <= m_torrent->num_peers());
iterator p = find_unchoke_candidate();
if (p != m_peers.end())
@@ -871,6 +892,22 @@ namespace libtorrent
}
}
+ int policy::count_choked() const
+ {
+ int ret = 0;
+ for (const_iterator i = m_peers.begin();
+ i != m_peers.end(); ++i)
+ {
+ if (!i->connection
+ || i->connection->is_connecting()
+ || i->connection->is_disconnecting()
+ || !i->connection->is_peer_interested())
+ continue;
+ if (i->connection->is_choked()) ++ret;
+ }
+ return ret;
+ }
+
void policy::new_connection(peer_connection& c)
{
assert(!c.is_local());
@@ -902,7 +939,10 @@ namespace libtorrent
if (m_torrent->settings().allow_multiple_connections_per_ip)
{
- i = m_peers.end();
+ i = std::find_if(
+ m_peers.begin()
+ , m_peers.end()
+ , match_peer_connection(c));
}
else
{
@@ -968,13 +1008,29 @@ namespace libtorrent
if(remote.address() == address() || remote.port() == 0)
return;
+ aux::session_impl& ses = m_torrent->session();
+
+ port_filter const& pf = ses.m_port_filter;
+ if (pf.access(remote.port()) & port_filter::blocked)
+ {
+ if (ses.m_alerts.should_post(alert::info))
+ {
+ ses.m_alerts.post_alert(peer_blocked_alert(remote.address()
+ , "outgoing port blocked, peer not added to peer list"));
+ }
+ return;
+ }
+
try
{
iterator i;
if (m_torrent->settings().allow_multiple_connections_per_ip)
{
- i = m_peers.end();
+ i = std::find_if(
+ m_peers.begin()
+ , m_peers.end()
+ , match_peer_id(pid));
}
else
{
@@ -986,8 +1042,6 @@ namespace libtorrent
if (i == m_peers.end())
{
- aux::session_impl& ses = m_torrent->session();
-
// if the IP is blocked, don't add it
if (ses.m_ip_filter.access(remote.address()) & ip_filter::blocked)
{
@@ -1095,18 +1149,6 @@ namespace libtorrent
}
}
- // TODO: we must be able to get interested
- // in a peer again, if a piece fails that
- // this peer has.
- void policy::block_finished(peer_connection& c, piece_block)
- {
- INVARIANT_CHECK;
-
- // if the peer hasn't choked us, ask for another piece
- if (!c.has_peer_choked() && !m_torrent->is_seed())
- request_a_block(*m_torrent, c);
- }
-
// this is called when we are unchoked by a peer
// i.e. a peer lets us know that we will receive
// data from now on
@@ -1167,6 +1209,7 @@ namespace libtorrent
c.add_free_upload(-diff);
}
}
+/*
if (!c.is_choked())
{
c.send_choke();
@@ -1175,6 +1218,7 @@ namespace libtorrent
if (m_torrent->is_seed()) seed_unchoke_one_peer();
else unchoke_one_peer();
}
+*/
}
bool policy::unchoke_one_peer()
diff --git a/libtorrent/src/session.cpp b/libtorrent/src/session.cpp
index 45711b122..485c90d62 100755
--- a/libtorrent/src/session.cpp
+++ b/libtorrent/src/session.cpp
@@ -143,10 +143,20 @@ namespace libtorrent
m_impl->set_ip_filter(f);
}
+ void session::set_port_filter(port_filter const& f)
+ {
+ m_impl->set_port_filter(f);
+ }
+
void session::set_peer_id(peer_id const& id)
{
m_impl->set_peer_id(id);
}
+
+ peer_id session::id() const
+ {
+ return m_impl->get_peer_id();
+ }
void session::set_key(int key)
{
@@ -167,7 +177,7 @@ namespace libtorrent
// if the torrent already exists, this will throw duplicate_torrent
torrent_handle session::add_torrent(
torrent_info const& ti
- , boost::filesystem::path const& save_path
+ , fs::path const& save_path
, entry const& resume_data
, bool compact_mode
, int block_size
@@ -181,7 +191,7 @@ namespace libtorrent
char const* tracker_url
, sha1_hash const& info_hash
, char const* name
- , boost::filesystem::path const& save_path
+ , fs::path const& save_path
, entry const& e
, bool compact_mode
, int block_size
@@ -372,6 +382,36 @@ namespace libtorrent
m_impl->set_severity_level(s);
}
+ void session::start_lsd()
+ {
+ m_impl->start_lsd();
+ }
+
+ void session::start_natpmp()
+ {
+ m_impl->start_natpmp();
+ }
+
+ void session::start_upnp()
+ {
+ m_impl->start_upnp();
+ }
+
+ void session::stop_lsd()
+ {
+ m_impl->stop_lsd();
+ }
+
+ void session::stop_natpmp()
+ {
+ m_impl->stop_natpmp();
+ }
+
+ void session::stop_upnp()
+ {
+ m_impl->stop_upnp();
+ }
+
connection_queue& session::get_connection_queue()
{
return m_impl->m_half_open;
diff --git a/libtorrent/src/session_impl.cpp b/libtorrent/src/session_impl.cpp
index 9244255bc..1a744ab44 100755
--- a/libtorrent/src/session_impl.cpp
+++ b/libtorrent/src/session_impl.cpp
@@ -81,7 +81,11 @@ using boost::bind;
using boost::mutex;
using libtorrent::aux::session_impl;
-namespace libtorrent { namespace detail
+namespace libtorrent {
+
+namespace fs = boost::filesystem;
+
+namespace detail
{
std::string generate_auth_string(std::string const& user
@@ -412,7 +416,6 @@ namespace libtorrent { namespace detail
for (std::deque >::iterator i
= m_processing.begin(); i != m_processing.end(); ++i)
{
-
if ((*i)->info_hash == info_hash) return i->get();
}
@@ -494,13 +497,6 @@ namespace libtorrent { namespace detail
, m_dht_same_port(true)
, m_external_udp_port(0)
#endif
- , m_natpmp(m_io_service, m_listen_interface.address()
- , bind(&session_impl::on_port_mapping, this, _1, _2, _3))
- , m_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))
- , m_lsd(m_io_service, m_listen_interface.address()
- , bind(&session_impl::on_lsd_peer, this, _1, _2))
, m_timer(m_io_service)
, m_next_connect_torrent(0)
, m_checker_impl(*this)
@@ -589,6 +585,12 @@ namespace libtorrent { namespace detail
m_checker_impl.m_abort = true;
}
+ void session_impl::set_port_filter(port_filter const& f)
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ m_port_filter = f;
+ }
+
void session_impl::set_ip_filter(ip_filter const& f)
{
mutex_t::scoped_lock l(m_mutex);
@@ -600,13 +602,9 @@ namespace libtorrent { namespace detail
= m_connections.begin(); i != m_connections.end();)
{
tcp::endpoint sender;
- try {
- sender = i->first->remote_endpoint();
- } catch (asio::system_error& e) {
- i++;
- continue;
- }
- if (m_ip_filter.access(sender.address()) & ip_filter::blocked)
+ try { sender = i->first->remote_endpoint(); }
+ catch (std::exception&) { sender = i->second->remote(); }
+ if (m_ip_filter.access(sender.address()) & ip_filter::blocked)
{
#if defined(TORRENT_VERBOSE_LOGGING)
(*i->second->m_logger) << "*** CONNECTION FILTERED\n";
@@ -630,6 +628,9 @@ namespace libtorrent { namespace detail
mutex_t::scoped_lock l(m_mutex);
assert(s.connection_speed > 0);
assert(s.file_pool_size > 0);
+
+ // less than 5 seconds unchoke interval is insane
+ assert(s.unchoke_interval >= 5);
m_settings = s;
m_files.resize(m_settings.file_pool_size);
// replace all occurances of '\n' with ' '.
@@ -1087,8 +1088,10 @@ namespace libtorrent { namespace detail
{
session_impl::mutex_t::scoped_lock l(m_mutex);
open_listen_port();
- m_natpmp.set_mappings(m_listen_interface.port(), 0);
- m_upnp.set_mappings(m_listen_interface.port(), 0);
+ if (m_natpmp.get())
+ m_natpmp->set_mappings(m_listen_interface.port(), 0);
+ if (m_upnp.get())
+ m_upnp->set_mappings(m_listen_interface.port(), 0);
}
ptime timer = time_now();
@@ -1113,8 +1116,10 @@ namespace libtorrent { namespace detail
deadline_timer tracker_timer(m_io_service);
// this will remove the port mappings
- m_natpmp.close();
- m_upnp.close();
+ if (m_natpmp.get())
+ m_natpmp->close();
+ if (m_upnp.get())
+ m_upnp->close();
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_logger) << time_now_string() << " locking mutex\n";
@@ -1276,7 +1281,7 @@ namespace libtorrent { namespace detail
torrent_handle session_impl::add_torrent(
torrent_info const& ti
- , boost::filesystem::path const& save_path
+ , fs::path const& save_path
, entry const& resume_data
, bool compact_mode
, int block_size
@@ -1367,7 +1372,7 @@ namespace libtorrent { namespace detail
char const* tracker_url
, sha1_hash const& info_hash
, char const* name
- , boost::filesystem::path const& save_path
+ , fs::path const& save_path
, entry const&
, bool compact_mode
, int block_size
@@ -1524,13 +1529,18 @@ namespace libtorrent { namespace detail
if (new_listen_address)
{
- m_natpmp.rebind(new_interface.address());
- m_upnp.rebind(new_interface.address());
- m_lsd.rebind(new_interface.address());
+ if (m_natpmp.get())
+ m_natpmp->rebind(new_interface.address());
+ if (m_upnp.get())
+ m_upnp->rebind(new_interface.address());
+ if (m_lsd.get())
+ m_lsd->rebind(new_interface.address());
}
- m_natpmp.set_mappings(m_listen_interface.port(), 0);
- m_upnp.set_mappings(m_listen_interface.port(), 0);
+ if (m_natpmp.get())
+ m_natpmp->set_mappings(m_listen_interface.port(), 0);
+ if (m_upnp.get())
+ m_upnp->set_mappings(m_listen_interface.port(), 0);
#ifndef TORRENT_DISABLE_DHT
if ((new_listen_address || m_dht_same_port) && m_dht)
@@ -1540,8 +1550,10 @@ namespace libtorrent { namespace detail
// the listen interface changed, rebind the dht listen socket as well
m_dht->rebind(new_interface.address()
, m_dht_settings.service_port);
- m_natpmp.set_mappings(0, m_dht_settings.service_port);
- m_upnp.set_mappings(0, m_dht_settings.service_port);
+ if (m_natpmp.get())
+ m_natpmp->set_mappings(0, m_dht_settings.service_port);
+ if (m_upnp.get())
+ m_upnp->set_mappings(0, m_dht_settings.service_port);
}
#endif
@@ -1563,7 +1575,8 @@ namespace libtorrent { namespace detail
{
mutex_t::scoped_lock l(m_mutex);
// use internal listen port for local peers
- m_lsd.announce(ih, m_listen_interface.port());
+ if (m_lsd.get())
+ m_lsd->announce(ih, m_listen_interface.port());
}
void session_impl::on_lsd_peer(tcp::endpoint peer, sha1_hash const& ih)
@@ -1683,8 +1696,10 @@ namespace libtorrent { namespace detail
m_dht_settings.service_port = m_listen_interface.port();
}
m_external_udp_port = m_dht_settings.service_port;
- m_natpmp.set_mappings(0, m_dht_settings.service_port);
- m_upnp.set_mappings(0, m_dht_settings.service_port);
+ if (m_natpmp.get())
+ m_natpmp->set_mappings(0, m_dht_settings.service_port);
+ if (m_upnp.get())
+ m_upnp->set_mappings(0, m_dht_settings.service_port);
m_dht = new dht::dht_tracker(m_io_service
, m_dht_settings, m_listen_interface.address()
, startup_state);
@@ -1714,8 +1729,10 @@ namespace libtorrent { namespace detail
{
m_dht->rebind(m_listen_interface.address()
, settings.service_port);
- m_natpmp.set_mappings(0, m_dht_settings.service_port);
- m_upnp.set_mappings(0, m_dht_settings.service_port);
+ if (m_natpmp.get())
+ m_natpmp->set_mappings(0, m_dht_settings.service_port);
+ if (m_upnp.get())
+ m_upnp->set_mappings(0, m_dht_settings.service_port);
m_external_udp_port = settings.service_port;
}
m_dht_settings = settings;
@@ -1896,6 +1913,69 @@ namespace libtorrent { namespace detail
mutex_t::scoped_lock l(m_mutex);
return m_dl_bandwidth_manager.throttle();
}
+
+
+ void session_impl::start_lsd()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ m_lsd.reset(new lsd(m_io_service
+ , m_listen_interface.address()
+ , bind(&session_impl::on_lsd_peer, this, _1, _2)));
+ }
+
+ void session_impl::start_natpmp()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ m_natpmp.reset(new natpmp(m_io_service
+ , m_listen_interface.address()
+ , bind(&session_impl::on_port_mapping
+ , this, _1, _2, _3)));
+
+ m_natpmp->set_mappings(m_listen_interface.port(),
+#ifndef TORRENT_DISABLE_DHT
+ m_dht ? m_dht_settings.service_port :
+#endif
+ 0);
+ }
+
+ void session_impl::start_upnp()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ m_upnp.reset(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)));
+
+ m_upnp->set_mappings(m_listen_interface.port(),
+#ifndef TORRENT_DISABLE_DHT
+ m_dht ? m_dht_settings.service_port :
+#endif
+ 0);
+ }
+
+ void session_impl::stop_lsd()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ m_lsd.reset();
+ }
+
+ void session_impl::stop_natpmp()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ if (m_natpmp.get())
+ m_natpmp->close();
+ m_natpmp.reset();
+ }
+
+ void session_impl::stop_upnp()
+ {
+ mutex_t::scoped_lock l(m_mutex);
+ if (m_upnp.get())
+ m_upnp->close();
+ m_upnp.reset();
+ }
+
#ifndef NDEBUG
void session_impl::check_invariant(const char *place)
@@ -2033,12 +2113,13 @@ namespace libtorrent { namespace detail
for (int j = 0; j < num_bitmask_bytes; ++j)
{
unsigned char bits = bitmask[j];
- for (int k = 0; k < 8; ++k)
+ int num_bits = std::min(num_blocks_per_piece - j*8, 8);
+ for (int k = 0; k < num_bits; ++k)
{
const int bit = j * 8 + k;
if (bits & (1 << k))
{
- p.info[bit].finished = true;
+ p.info[bit].state = piece_picker::block_info::state_finished;
++p.finished;
}
}
diff --git a/libtorrent/src/storage.cpp b/libtorrent/src/storage.cpp
index 0623dfeb6..f0f2241c0 100755
--- a/libtorrent/src/storage.cpp
+++ b/libtorrent/src/storage.cpp
@@ -127,7 +127,7 @@ namespace
using namespace boost::filesystem;
// based on code from Boost.Fileystem
- bool create_directories_win(const path& ph)
+ bool create_directories_win(const fs::path& ph)
{
if (ph.empty() || exists(ph))
{
@@ -147,7 +147,7 @@ namespace
return true;
}
- bool exists_win( const path & ph )
+ bool exists_win( const fs::path & ph )
{
std::wstring wpath(safe_convert(ph.string()));
if(::GetFileAttributes( wpath.c_str() ) == 0xFFFFFFFF)
@@ -167,7 +167,7 @@ namespace
return true;
}
- boost::intmax_t file_size_win( const path & ph )
+ boost::intmax_t file_size_win( const fs::path & ph )
{
std::wstring wpath(safe_convert(ph.string()));
// by now, intmax_t is 64-bits on all Windows compilers
@@ -187,7 +187,7 @@ namespace
+ fad.nFileSizeLow;
}
- std::time_t last_write_time_win( const path & ph )
+ std::time_t last_write_time_win( const fs::path & ph )
{
struct _stat path_stat;
std::wstring wph(safe_convert(ph.native_file_string()));
@@ -198,8 +198,8 @@ namespace
return path_stat.st_mtime;
}
- void rename_win( const path & old_path,
- const path & new_path )
+ void rename_win( const fs::path & old_path,
+ const fs::path & new_path )
{
std::wstring wold_path(safe_convert(old_path.string()));
std::wstring wnew_path(safe_convert(new_path.string()));
@@ -214,14 +214,13 @@ namespace
#endif
#if BOOST_VERSION < 103200
-bool operator<(boost::filesystem::path const& lhs
- , boost::filesystem::path const& rhs)
+bool operator<(fs::path const& lhs, fs::path const& rhs)
{
return lhs.string() < rhs.string();
}
#endif
-using namespace boost::filesystem;
+namespace fs = boost::filesystem;
using boost::bind;
using namespace ::boost::multi_index;
using boost::multi_index::multi_index_container;
@@ -244,7 +243,7 @@ namespace libtorrent
{
std::vector > get_filesizes(
- torrent_info const& t, path p)
+ torrent_info const& t, fs::path p)
{
p = complete(p);
std::vector > sizes;
@@ -255,11 +254,16 @@ namespace libtorrent
std::time_t time = 0;
try
{
- path f = p / i->path;
#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION < 103400
+ fs::path f = p / i->path;
size = file_size_win(f);
time = last_write_time_win(f);
+#elif defined(_WIN32) && defined(UNICODE)
+ fs::wpath f = safe_convert((p / i->path).string());
+ size = file_size(f);
+ time = last_write_time(f);
#else
+ fs::path f = p / i->path;
size = file_size(f);
time = last_write_time(f);
#endif
@@ -278,7 +282,7 @@ namespace libtorrent
// still be a correct subset of the actual data on disk.
bool match_filesizes(
torrent_info const& t
- , path p
+ , fs::path p
, std::vector > const& sizes
, bool compact_mode
, std::string* error)
@@ -299,17 +303,22 @@ namespace libtorrent
std::time_t time = 0;
try
{
- path f = p / i->path;
#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION < 103400
+ fs::path f = p / i->path;
size = file_size_win(f);
time = last_write_time_win(f);
+#elif defined(_WIN32) && defined(UNICODE)
+ fs::wpath f = safe_convert((p / i->path).string());
+ size = file_size(f);
+ time = last_write_time(f);
#else
+ fs::path f = p / i->path;
size = file_size(f);
time = last_write_time(f);
#endif
}
catch (std::exception&) {}
- if (size != s->first
+ if ((compact_mode && size != s->first)
|| (!compact_mode && size < s->first))
{
if (error) *error = "filesize mismatch for file '"
@@ -319,7 +328,7 @@ namespace libtorrent
+ " bytes";
return false;
}
- if (time != s->second
+ if ((compact_mode && time != s->second)
|| (!compact_mode && time < s->second))
{
if (error) *error = "timestamp mismatch for file '"
@@ -371,19 +380,19 @@ namespace libtorrent
class storage : public storage_interface, thread_safe_storage, boost::noncopyable
{
public:
- storage(torrent_info const& info, path const& path, file_pool& fp)
+ storage(torrent_info const& info, fs::path const& path, file_pool& fp)
: thread_safe_storage(info.num_pieces())
, m_info(info)
, m_files(fp)
{
assert(info.begin_files() != info.end_files());
- m_save_path = complete(path);
+ m_save_path = fs::complete(path);
assert(m_save_path.is_complete());
}
void release_files();
void initialize(bool allocate_files);
- bool move_storage(path save_path);
+ bool move_storage(fs::path save_path);
size_type read(char* buf, int slot, int offset, int size);
void write(const char* buf, int slot, int offset, int size);
void move_slot(int src_slot, int dst_slot);
@@ -391,6 +400,7 @@ namespace libtorrent
void swap_slots3(int slot1, int slot2, int slot3);
bool verify_resume_data(entry& rd, std::string& error);
void write_resume_data(entry& rd) const;
+ sha1_hash hash_for_slot(int slot, partial_hash& ph, int piece_size);
size_type read_impl(char* buf, int slot, int offset, int size, bool fill_zero);
@@ -400,7 +410,7 @@ namespace libtorrent
}
torrent_info const& m_info;
- path m_save_path;
+ fs::path m_save_path;
// the file pool is typically stored in
// the session, to make all storage
// instances use the same pool
@@ -410,23 +420,53 @@ namespace libtorrent
std::vector m_scratch_buffer;
};
+ sha1_hash storage::hash_for_slot(int slot, partial_hash& ph, int piece_size)
+ {
+#ifndef NDEBUG
+ hasher partial;
+ hasher whole;
+ int slot_size1 = piece_size;
+ m_scratch_buffer.resize(slot_size1);
+ read_impl(&m_scratch_buffer[0], slot, 0, slot_size1, true);
+ if (ph.offset > 0)
+ partial.update(&m_scratch_buffer[0], ph.offset);
+ whole.update(&m_scratch_buffer[0], slot_size1);
+ hasher partial_copy = ph.h;
+ assert(ph.offset == 0 || partial_copy.final() == partial.final());
+#endif
+ int slot_size = piece_size - ph.offset;
+ if (slot_size == 0) return ph.h.final();
+ m_scratch_buffer.resize(slot_size);
+ read_impl(&m_scratch_buffer[0], slot, ph.offset, slot_size, true);
+ ph.h.update(&m_scratch_buffer[0], slot_size);
+ sha1_hash ret = ph.h.final();
+ assert(whole.final() == ret);
+ return ret;
+ }
+
void storage::initialize(bool allocate_files)
{
// first, create all missing directories
- path last_path;
+ fs::path last_path;
for (torrent_info::file_iterator file_iter = m_info.begin_files(),
end_iter = m_info.end_files(); file_iter != end_iter; ++file_iter)
{
- path dir = (m_save_path / file_iter->path).branch_path();
+ fs::path dir = (m_save_path / file_iter->path).branch_path();
if (dir != last_path)
{
- last_path = dir;
#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION < 103400
+ last_path = dir;
if (!exists_win(last_path))
create_directories_win(last_path);
+#elif defined(_WIN32) && defined(UNICODE)
+ last_path = dir;
+ fs::wpath wp = safe_convert(last_path.string());
+ if (!exists(wp))
+ create_directories(wp);
#else
+ last_path = dir;
if (!exists(last_path))
create_directories(last_path);
#endif
@@ -537,23 +577,30 @@ namespace libtorrent
}
// returns true on success
- bool storage::move_storage(path save_path)
+ bool storage::move_storage(fs::path save_path)
{
- path old_path;
- path new_path;
+#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400
+ fs::wpath old_path;
+ fs::wpath new_path;
+#else
+ fs::path old_path;
+ fs::path new_path;
+#endif
save_path = complete(save_path);
#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION < 103400
std::wstring wsave_path(safe_convert(save_path.native_file_string()));
if (!exists_win(save_path))
- {
CreateDirectory(wsave_path.c_str(), 0);
- }
else if ((GetFileAttributes(wsave_path.c_str()) & FILE_ATTRIBUTE_DIRECTORY) == 0)
- {
return false;
- }
+#elif defined(_WIN32) && defined(UNICODE)
+ fs::wpath wp = safe_convert(save_path.string());
+ if (!exists(wp))
+ create_directory(wp);
+ else if (!is_directory(wp))
+ return false;
#else
if (!exists(save_path))
create_directory(save_path);
@@ -563,13 +610,19 @@ namespace libtorrent
m_files.release(this);
+#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400
+ old_path = safe_convert((m_save_path / m_info.name()).string());
+ new_path = safe_convert((save_path / m_info.name()).string());
+#else
old_path = m_save_path / m_info.name();
new_path = save_path / m_info.name();
+#endif
try
{
#if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION < 103400
rename_win(old_path, new_path);
+ rename(old_path, new_path);
#else
rename(old_path, new_path);
#endif
@@ -772,7 +825,7 @@ namespace libtorrent
// this file was empty, don't increment the slice counter
if (read_bytes > 0) ++counter;
#endif
- path path = m_save_path / file_iter->path;
+ fs::path path = m_save_path / file_iter->path;
file_offset = 0;
in = m_files.open_file(
@@ -820,7 +873,7 @@ namespace libtorrent
assert(file_iter != m_info.end_files());
}
- path p(m_save_path / file_iter->path);
+ fs::path p(m_save_path / file_iter->path);
boost::shared_ptr out = m_files.open_file(
this, p, file::out | file::in);
@@ -884,13 +937,13 @@ namespace libtorrent
if (left_to_write > 0)
{
- #ifndef NDEBUG
+#ifndef NDEBUG
if (write_bytes > 0) ++counter;
- #endif
+#endif
++file_iter;
assert(file_iter != m_info.end_files());
- path p = m_save_path / file_iter->path;
+ fs::path p = m_save_path / file_iter->path;
file_offset = 0;
out = m_files.open_file(
this, p, file::out | file::in);
@@ -901,12 +954,12 @@ namespace libtorrent
}
storage_interface* default_storage_constructor(torrent_info const& ti
- , boost::filesystem::path const& path, file_pool& fp)
+ , fs::path const& path, file_pool& fp)
{
return new storage(ti, path, fp);
}
- bool supports_sparse_files(path const& p)
+ bool supports_sparse_files(fs::path const& p)
{
assert(p.is_complete());
#if defined(_WIN32)
@@ -930,7 +983,7 @@ namespace libtorrent
#if defined(__APPLE__) || defined(__linux__)
// find the last existing directory of the save path
- path query_path = p;
+ fs::path query_path = p;
while (!query_path.empty() && !exists(query_path))
query_path = query_path.branch_path();
#endif
@@ -1004,215 +1057,141 @@ namespace libtorrent
// -- piece_manager -----------------------------------------------------
- class piece_manager::impl
- {
- friend class invariant_access;
- public:
-
- impl(
- torrent_info const& info
- , path const& path
- , file_pool& fp
- , storage_constructor_type sc);
-
- bool check_fastresume(
- aux::piece_checker_data& d
- , std::vector& pieces
- , int& num_pieces
- , bool compact_mode);
-
- std::pair check_files(
- std::vector& pieces
- , int& num_pieces, boost::recursive_mutex& mutex);
-
- void release_files();
-
- bool allocate_slots(int num_slots, bool abort_on_disk = false);
- void mark_failed(int index);
- unsigned long piece_crc(
- int slot_index
- , int block_size
- , piece_picker::block_info const* bi);
-
- int slot_for_piece(int piece_index) const;
-
- size_type read(
- char* buf
- , int piece_index
- , int offset
- , int size);
-
- void write(
- const char* buf
- , int piece_index
- , int offset
- , int size);
-
- path const& save_path() const
- { return m_save_path; }
-
- bool move_storage(path save_path)
- {
- if (m_storage->move_storage(save_path))
- {
- m_save_path = complete(save_path);
- return true;
- }
- return false;
- }
-
- void export_piece_map(std::vector& p) const;
-
- // returns the slot currently associated with the given
- // piece or assigns the given piece_index to a free slot
-
- int identify_data(
- const std::vector& piece_data
- , int current_slot
- , std::vector& have_pieces
- , int& num_pieces
- , const std::multimap& hash_to_piece
- , boost::recursive_mutex& mutex);
-
- int allocate_slot_for_piece(int piece_index);
-#ifndef NDEBUG
- void check_invariant() const;
-#ifdef TORRENT_STORAGE_DEBUG
- void debug_log() const;
-#endif
-#endif
- boost::scoped_ptr m_storage;
-
- // if this is true, pieces are always allocated at the
- // lowest possible slot index. If it is false, pieces
- // are always written to their final place immediately
- bool m_compact_mode;
-
- // if this is true, pieces that haven't been downloaded
- // will be filled with zeroes. Not filling with zeroes
- // will not work in some cases (where a seek cannot pass
- // the end of the file).
- bool m_fill_mode;
-
- // a bitmask representing the pieces we have
- std::vector m_have_piece;
-
- torrent_info const& m_info;
-
- // slots that haven't had any file storage allocated
- std::vector m_unallocated_slots;
- // slots that have file storage, but isn't assigned to a piece
- std::vector m_free_slots;
-
- enum
- {
- has_no_slot = -3 // the piece has no storage
- };
-
- // maps piece indices to slots. If a piece doesn't
- // have any storage, it is set to 'has_no_slot'
- std::vector m_piece_to_slot;
-
- enum
- {
- unallocated = -1, // the slot is unallocated
- unassigned = -2 // the slot is allocated but not assigned to a piece
- };
-
- // maps slots to piece indices, if a slot doesn't have a piece
- // it can either be 'unassigned' or 'unallocated'
- std::vector m_slot_to_piece;
-
- path m_save_path;
-
- mutable boost::recursive_mutex m_mutex;
-
- bool m_allocating;
- boost::mutex m_allocating_monitor;
- boost::condition m_allocating_condition;
-
- // these states are used while checking/allocating the torrent
-
- enum {
- // the default initial state
- state_none,
- // the file checking is complete
- state_finished,
- // creating the directories
- state_create_files,
- // checking the files
- state_full_check,
- // allocating files (in non-compact mode)
- state_allocating
- } m_state;
- int m_current_slot;
-
- std::vector m_piece_data;
-
- // this maps a piece hash to piece index. It will be
- // build the first time it is used (to save time if it
- // isn't needed)
- std::multimap m_hash_to_piece;
- };
-
- piece_manager::impl::impl(
- torrent_info const& info
- , path const& save_path
+ piece_manager::piece_manager(
+ boost::shared_ptr const& torrent
+ , torrent_info const& ti
+ , fs::path const& save_path
, file_pool& fp
+ , disk_io_thread& io
, storage_constructor_type sc)
- : m_storage(sc(info, save_path, fp))
+ : m_storage(sc(ti, save_path, fp))
, m_compact_mode(false)
, m_fill_mode(true)
- , m_info(info)
+ , m_info(ti)
, m_save_path(complete(save_path))
, m_allocating(false)
+ , m_io_thread(io)
+ , m_torrent(torrent)
{
m_fill_mode = !supports_sparse_files(save_path);
}
- piece_manager::piece_manager(
- torrent_info const& info
- , path const& save_path
- , file_pool& fp
- , storage_constructor_type sc)
- : m_pimpl(new impl(info, save_path, fp, sc))
- {
- }
-
piece_manager::~piece_manager()
{
}
void piece_manager::write_resume_data(entry& rd) const
{
- m_pimpl->m_storage->write_resume_data(rd);
+ m_storage->write_resume_data(rd);
}
bool piece_manager::verify_resume_data(entry& rd, std::string& error)
{
- return m_pimpl->m_storage->verify_resume_data(rd, error);
+ return m_storage->verify_resume_data(rd, error);
}
- void piece_manager::release_files()
+ void piece_manager::async_release_files(
+ boost::function const& handler)
{
- m_pimpl->release_files();
+ disk_io_job j;
+ j.storage = this;
+ j.action = disk_io_job::release_files;
+ m_io_thread.add_job(j, handler);
}
- void piece_manager::impl::release_files()
+ void piece_manager::async_move_storage(fs::path const& p
+ , boost::function const& handler)
{
- // synchronization ------------------------------------------------------
- boost::recursive_mutex::scoped_lock lock(m_mutex);
- // ----------------------------------------------------------------------
+ disk_io_job j;
+ j.storage = this;
+ j.action = disk_io_job::move_storage;
+ j.str = p.string();
+ m_io_thread.add_job(j, handler);
+ }
+ void piece_manager::async_read(
+ peer_request const& r
+ , boost::function const& handler)
+ {
+ disk_io_job j;
+ j.storage = this;
+ j.action = disk_io_job::read;
+ j.piece = r.piece;
+ j.offset = r.start;
+ j.buffer_size = r.length;
+ m_io_thread.add_job(j, handler);
+ }
+
+ void piece_manager::async_write(
+ peer_request const& r
+ , char const* buffer
+ , boost::function const& handler)
+ {
+ assert(r.length <= 16 * 1024);
+
+ disk_io_job j;
+ j.storage = this;
+ j.action = disk_io_job::write;
+ j.piece = r.piece;
+ j.offset = r.start;
+ j.buffer_size = r.length;
+ j.buffer = m_io_thread.allocate_buffer();
+ if (j.buffer == 0) throw file_error("out of memory");
+ std::memcpy(j.buffer, buffer, j.buffer_size);
+ m_io_thread.add_job(j, handler);
+ }
+
+ void piece_manager::async_hash(int piece
+ , boost::function const& handler)
+ {
+ disk_io_job j;
+ j.storage = this;
+ j.action = disk_io_job::hash;
+ j.piece = piece;
+
+ m_io_thread.add_job(j, handler);
+ }
+
+ fs::path piece_manager::save_path() const
+ {
+ boost::recursive_mutex::scoped_lock l(m_mutex);
+ return m_save_path;
+ }
+
+ sha1_hash piece_manager::hash_for_piece_impl(int piece)
+ {
+ partial_hash ph;
+
+ std::map::iterator i = m_piece_hasher.find(piece);
+ if (i != m_piece_hasher.end())
+ {
+ ph = i->second;
+ m_piece_hasher.erase(i);
+ }
+
+ int slot = m_piece_to_slot[piece];
+ assert(slot != has_no_slot);
+ return m_storage->hash_for_slot(slot, ph, m_info.piece_size(piece));
+ }
+
+ void piece_manager::release_files_impl()
+ {
m_storage->release_files();
}
- void piece_manager::impl::export_piece_map(
+ bool piece_manager::move_storage_impl(fs::path const& save_path)
+ {
+ if (m_storage->move_storage(save_path))
+ {
+ m_save_path = fs::complete(save_path);
+ return true;
+ }
+ return false;
+ }
+ void piece_manager::export_piece_map(
std::vector& p) const
{
- // synchronization ------------------------------------------------------
boost::recursive_mutex::scoped_lock lock(m_mutex);
- // ----------------------------------------------------------------------
INVARIANT_CHECK;
@@ -1232,20 +1211,9 @@ namespace libtorrent
}
}
- bool piece_manager::compact_allocation() const
- { return m_pimpl->m_compact_mode; }
-
- void piece_manager::export_piece_map(
- std::vector& p) const
+ void piece_manager::mark_failed(int piece_index)
{
- m_pimpl->export_piece_map(p);
- }
-
- void piece_manager::impl::mark_failed(int piece_index)
- {
- // synchronization ------------------------------------------------------
boost::recursive_mutex::scoped_lock lock(m_mutex);
- // ----------------------------------------------------------------------
INVARIANT_CHECK;
@@ -1261,37 +1229,13 @@ namespace libtorrent
m_free_slots.push_back(slot_index);
}
- void piece_manager::mark_failed(int index)
- {
- m_pimpl->mark_failed(index);
- }
-
- bool piece_manager::is_allocating() const
- {
- return m_pimpl->m_state
- == impl::state_allocating;
- }
-
int piece_manager::slot_for_piece(int piece_index) const
- {
- return m_pimpl->slot_for_piece(piece_index);
- }
-
- int piece_manager::impl::slot_for_piece(int piece_index) const
{
assert(piece_index >= 0 && piece_index < m_info.num_pieces());
return m_piece_to_slot[piece_index];
}
unsigned long piece_manager::piece_crc(
- int index
- , int block_size
- , piece_picker::block_info const* bi)
- {
- return m_pimpl->piece_crc(index, block_size, bi);
- }
-
- unsigned long piece_manager::impl::piece_crc(
int slot_index
, int block_size
, piece_picker::block_info const* bi)
@@ -1309,7 +1253,7 @@ namespace libtorrent
for (int i = 0; i < num_blocks-1; ++i)
{
- if (!bi[i].finished) continue;
+ if (!bi[i].state == piece_picker::block_info::state_finished) continue;
m_storage->read(
&buf[0]
, slot_index
@@ -1317,7 +1261,7 @@ namespace libtorrent
, block_size);
crc.update(&buf[0], block_size);
}
- if (bi[num_blocks - 1].finished)
+ if (bi[num_blocks - 1].state == piece_picker::block_info::state_finished)
{
m_storage->read(
&buf[0]
@@ -1333,7 +1277,7 @@ namespace libtorrent
return 0;
}
- size_type piece_manager::impl::read(
+ size_type piece_manager::read_impl(
char* buf
, int piece_index
, int offset
@@ -1350,16 +1294,7 @@ namespace libtorrent
return m_storage->read(buf, slot, offset, size);
}
- size_type piece_manager::read(
- char* buf
- , int piece_index
- , int offset
- , int size)
- {
- return m_pimpl->read(buf, piece_index, offset, size);
- }
-
- void piece_manager::impl::write(
+ void piece_manager::write_impl(
const char* buf
, int piece_index
, int offset
@@ -1369,21 +1304,34 @@ namespace libtorrent
assert(offset >= 0);
assert(size > 0);
assert(piece_index >= 0 && piece_index < (int)m_piece_to_slot.size());
+
+ if (offset == 0)
+ {
+ partial_hash& ph = m_piece_hasher[piece_index];
+ assert(ph.offset == 0);
+ ph.offset = size;
+ ph.h.update(buf, size);
+ }
+ else
+ {
+ std::map::iterator i = m_piece_hasher.find(piece_index);
+ if (i != m_piece_hasher.end())
+ {
+ assert(i->second.offset > 0);
+ if (offset == i->second.offset)
+ {
+ i->second.offset += size;
+ i->second.h.update(buf, size);
+ }
+ }
+ }
+
int slot = allocate_slot_for_piece(piece_index);
assert(slot >= 0 && slot < (int)m_slot_to_piece.size());
m_storage->write(buf, slot, offset, size);
}
- void piece_manager::write(
- const char* buf
- , int piece_index
- , int offset
- , int size)
- {
- m_pimpl->write(buf, piece_index, offset, size);
- }
-
- int piece_manager::impl::identify_data(
+ int piece_manager::identify_data(
const std::vector& piece_data
, int current_slot
, std::vector& have_pieces
@@ -1447,6 +1395,8 @@ namespace libtorrent
, matching_pieces.end()
, current_slot) != matching_pieces.end())
{
+ // the current slot is among the matching pieces, so
+ // we will assume that the piece is in the right place
const int piece_index = current_slot;
// lock because we're writing to have_pieces
@@ -1542,18 +1492,17 @@ namespace libtorrent
// if it is, use it and return true. If it
// isn't return false and the full check
// will be run
- bool piece_manager::impl::check_fastresume(
+ bool piece_manager::check_fastresume(
aux::piece_checker_data& data
, std::vector& pieces
, int& num_pieces, bool compact_mode)
{
- assert(m_info.piece_length() > 0);
- // synchronization ------------------------------------------------------
boost::recursive_mutex::scoped_lock lock(m_mutex);
- // ----------------------------------------------------------------------
INVARIANT_CHECK;
+ assert(m_info.piece_length() > 0);
+
m_compact_mode = compact_mode;
// This will corrupt the storage
@@ -1613,45 +1562,77 @@ namespace libtorrent
m_unallocated_slots.push_back(i);
}
- if (!m_compact_mode && !m_unallocated_slots.empty())
+ if (m_unallocated_slots.empty())
{
- m_state = state_allocating;
+ m_state = state_create_files;
return false;
}
- else
+
+ if (m_compact_mode)
{
- m_state = state_finished;
- return true;
+ m_state = state_create_files;
+ return false;
}
}
- m_state = state_create_files;
+ m_state = state_full_check;
return false;
}
+/*
+ state chart:
+
+ check_fastresume()
+
+ | |
+ | v
+ | +------------+
+ | | full_check |
+ | +------------+
+ | |
+ | v
+ | +------------+
+ | | allocating |
+ | +------------+
+ | |
+ | v
+ | +--------------+
+ |->| create_files |
+ +--------------+
+ |
+ v
+ +----------+
+ | finished |
+ +----------+
+*/
+
+
// performs the full check and full allocation
// (if necessary). returns true if finished and
// false if it should be called again
// the second return value is the progress the
// file check is at. 0 is nothing done, and 1
// is finished
- std::pair piece_manager::impl::check_files(
+ std::pair piece_manager::check_files(
std::vector& pieces, int& num_pieces, boost::recursive_mutex& mutex)
{
assert(num_pieces == std::count(pieces.begin(), pieces.end(), true));
if (m_state == state_allocating)
{
- if (m_compact_mode)
+ if (m_compact_mode || m_unallocated_slots.empty())
{
- m_state = state_finished;
- return std::make_pair(true, 1.f);
+ m_state = state_create_files;
+ return std::make_pair(false, 1.f);
}
- if (m_unallocated_slots.empty())
+ if (int(m_unallocated_slots.size()) == m_info.num_pieces()
+ && !m_fill_mode)
{
- m_state = state_finished;
- return std::make_pair(true, 1.f);
+ // if there is not a single file on disk, just
+ // create the files
+ m_state = state_create_files;
+ return std::make_pair(false, 1.f);
}
// if we're not in compact mode, make sure the
@@ -1682,10 +1663,18 @@ namespace libtorrent
{
m_storage->initialize(!m_fill_mode && !m_compact_mode);
- m_current_slot = 0;
- m_state = state_full_check;
- m_piece_data.resize(int(m_info.piece_length()));
- return std::make_pair(false, 0.f);
+ if (!m_unallocated_slots.empty() && !m_compact_mode)
+ {
+ assert(!m_fill_mode);
+ std::vector().swap(m_unallocated_slots);
+ std::fill(m_slot_to_piece.begin(), m_slot_to_piece.end(), int(unassigned));
+ m_free_slots.resize(m_info.num_pieces());
+ for (int i = 0; i < m_info.num_pieces(); ++i)
+ m_free_slots[i] = i;
+ }
+
+ m_state = state_finished;
+ return std::make_pair(true, 1.f);
}
assert(m_state == state_full_check);
@@ -1696,7 +1685,18 @@ namespace libtorrent
try
{
+ // initialization for the full check
+ if (m_hash_to_piece.empty())
+ {
+ m_current_slot = 0;
+ for (int i = 0; i < m_info.num_pieces(); ++i)
+ {
+ m_hash_to_piece.insert(std::make_pair(m_info.hash_for_piece(i), i));
+ }
+ std::fill(pieces.begin(), pieces.end(), false);
+ }
+ m_piece_data.resize(int(m_info.piece_length()));
int piece_size = int(m_info.piece_size(m_current_slot));
int num_read = m_storage->read(&m_piece_data[0]
, m_current_slot, 0, piece_size);
@@ -1705,14 +1705,6 @@ namespace libtorrent
if (num_read != piece_size)
throw file_error("");
- if (m_hash_to_piece.empty())
- {
- for (int i = 0; i < m_info.num_pieces(); ++i)
- {
- m_hash_to_piece.insert(std::make_pair(m_info.hash_for_piece(i), i));
- }
- }
-
int piece_index = identify_data(m_piece_data, m_current_slot
, pieces, num_pieces, m_hash_to_piece, mutex);
@@ -1949,26 +1941,9 @@ namespace libtorrent
return std::make_pair(false, (float)m_current_slot / m_info.num_pieces());
}
- bool piece_manager::check_fastresume(
- aux::piece_checker_data& d, std::vector& pieces
- , int& num_pieces, bool compact_mode)
+ int piece_manager::allocate_slot_for_piece(int piece_index)
{
- return m_pimpl->check_fastresume(d, pieces, num_pieces, compact_mode);
- }
-
- std::pair piece_manager::check_files(
- std::vector& pieces
- , int& num_pieces
- , boost::recursive_mutex& mutex)
- {
- return m_pimpl->check_files(pieces, num_pieces, mutex);
- }
-
- int piece_manager::impl::allocate_slot_for_piece(int piece_index)
- {
- // synchronization ------------------------------------------------------
boost::recursive_mutex::scoped_lock lock(m_mutex);
- // ----------------------------------------------------------------------
// INVARIANT_CHECK;
@@ -2075,56 +2050,11 @@ namespace libtorrent
return slot_index;
}
- namespace
- {
- // this is used to notify potential other
- // threads that the allocation-function has exited
- struct allocation_syncronization
- {
- allocation_syncronization(
- bool& flag
- , boost::condition& cond
- , boost::mutex& monitor)
- : m_flag(flag)
- , m_cond(cond)
- , m_monitor(monitor)
- {
- boost::mutex::scoped_lock lock(m_monitor);
-
- while (m_flag)
- m_cond.wait(lock);
-
- m_flag = true;
- }
-
- ~allocation_syncronization()
- {
- boost::mutex::scoped_lock lock(m_monitor);
- m_flag = false;
- m_cond.notify_one();
- }
-
- bool& m_flag;
- boost::condition& m_cond;
- boost::mutex& m_monitor;
- };
-
- }
-
- bool piece_manager::impl::allocate_slots(int num_slots, bool abort_on_disk)
+ bool piece_manager::allocate_slots(int num_slots, bool abort_on_disk)
{
assert(num_slots > 0);
- // this object will syncronize the allocation with
- // potential other threads
- allocation_syncronization sync_obj(
- m_allocating
- , m_allocating_condition
- , m_allocating_monitor);
-
- // synchronization ------------------------------------------------------
boost::recursive_mutex::scoped_lock lock(m_mutex);
- // ----------------------------------------------------------------------
// INVARIANT_CHECK;
@@ -2175,27 +2105,10 @@ namespace libtorrent
return written;
}
- bool piece_manager::allocate_slots(int num_slots, bool abort_on_disk)
- {
- return m_pimpl->allocate_slots(num_slots, abort_on_disk);
- }
-
- path const& piece_manager::save_path() const
- {
- return m_pimpl->save_path();
- }
-
- bool piece_manager::move_storage(path const& save_path)
- {
- return m_pimpl->move_storage(save_path);
- }
-
#ifndef NDEBUG
- void piece_manager::impl::check_invariant() const
+ void piece_manager::check_invariant() const
{
- // synchronization ------------------------------------------------------
boost::recursive_mutex::scoped_lock lock(m_mutex);
- // ----------------------------------------------------------------------
if (m_piece_to_slot.empty()) return;
assert((int)m_piece_to_slot.size() == m_info.num_pieces());
@@ -2303,7 +2216,7 @@ namespace libtorrent
}
#ifdef TORRENT_STORAGE_DEBUG
- void piece_manager::impl::debug_log() const
+ void piece_manager::debug_log() const
{
std::stringstream s;
diff --git a/libtorrent/src/torrent.cpp b/libtorrent/src/torrent.cpp
index f50ad0b01..2ac6d1895 100755
--- a/libtorrent/src/torrent.cpp
+++ b/libtorrent/src/torrent.cpp
@@ -77,7 +77,6 @@ using namespace libtorrent;
using boost::tuples::tuple;
using boost::tuples::get;
using boost::tuples::make_tuple;
-using boost::filesystem::complete;
using boost::bind;
using boost::mutex;
using libtorrent::aux::session_impl;
@@ -147,11 +146,12 @@ namespace
namespace libtorrent
{
+
torrent::torrent(
session_impl& ses
, aux::checker_impl& checker
, torrent_info const& tf
- , boost::filesystem::path const& save_path
+ , fs::path const& save_path
, tcp::endpoint const& net_interface
, bool compact_mode
, int block_size
@@ -174,7 +174,9 @@ namespace libtorrent
, m_resolve_countries(false)
#endif
, m_announce_timer(ses.m_io_service)
+#ifndef TORRENT_DISABLE_DHT
, m_last_dht_announce(time_now() - minutes(15))
+#endif
, m_policy()
, m_ses(ses)
, m_checker(checker)
@@ -202,8 +204,6 @@ namespace libtorrent
m_initial_done = 0;
#endif
- INVARIANT_CHECK;
-
m_uploads_quota.min = 2;
m_connections_quota.min = 2;
// this will be corrected the next time the main session
@@ -212,7 +212,6 @@ namespace libtorrent
m_uploads_quota.max = std::numeric_limits::max();
m_connections_quota.max = std::numeric_limits