major lt upgrade to trunk and turn on options for upnp, natpmp and utpex

This commit is contained in:
Marcos Pinto 2007-06-15 21:45:53 +00:00
parent cdf34e92e9
commit 55e5b75e54
71 changed files with 2283 additions and 1426 deletions

View File

@ -315,108 +315,24 @@
<property name="n_rows">4</property> <property name="n_rows">4</property>
<property name="n_columns">2</property> <property name="n_columns">2</property>
<child> <child>
<widget class="GtkSpinButton" id="spin_max_upload"> <widget class="GtkAlignment" id="alignment18">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="tooltip" translatable="yes">The maximum upload rate for all torrents. Set -1 for unlimited.</property> <property name="right_padding">10</property>
<property name="xalign">1</property> <child>
<property name="adjustment">-1 -1 9000 1 10 10</property> <widget class="GtkLabel" id="label55">
<property name="climb_rate">1</property> <property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Maximum Upload Rate (KB/s):</property>
</widget>
</child>
</widget> </widget>
<packing> <packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property> <property name="top_attach">3</property>
<property name="bottom_attach">4</property> <property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property> <property name="x_options">GTK_FILL</property>
</packing> </packing>
</child> </child>
<child>
<widget class="GtkSpinButton" id="spin_max_download">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="tooltip" translatable="yes">The maximum download rate for all torrents. Set -1 for unlimited.</property>
<property name="xalign">1</property>
<property name="adjustment">-1 -1 9000 1 10 10</property>
<property name="climb_rate">1</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="spin_num_upload">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip" translatable="yes">The maximum number of upload slots. Set -1 for unlimited.</property>
<property name="xalign">1</property>
<property name="adjustment">-1 -1 1000 1 10 10</property>
<property name="climb_rate">1</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="spin_num_download">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip" translatable="yes">The maximum number of connections allowed. Set -1 for unlimited.</property>
<property name="xalign">1</property>
<property name="adjustment">-1 -1 1000 1 10 10</property>
<property name="climb_rate">1</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment4">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="right_padding">10</property>
<child>
<widget class="GtkLabel" id="label54">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Maximum Connections:</property>
</widget>
</child>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment5">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="right_padding">10</property>
<child>
<widget class="GtkLabel" id="label53">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Upload Slots:</property>
</widget>
</child>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child> <child>
<widget class="GtkAlignment" id="alignment14"> <widget class="GtkAlignment" id="alignment14">
<property name="visible">True</property> <property name="visible">True</property>
@ -437,19 +353,103 @@
</packing> </packing>
</child> </child>
<child> <child>
<widget class="GtkAlignment" id="alignment18"> <widget class="GtkAlignment" id="alignment5">
<property name="visible">True</property> <property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="right_padding">10</property> <property name="right_padding">10</property>
<child> <child>
<widget class="GtkLabel" id="label55"> <widget class="GtkLabel" id="label53">
<property name="visible">True</property> <property name="visible">True</property>
<property name="xalign">0</property> <property name="xalign">0</property>
<property name="label" translatable="yes">Maximum Upload Rate (KB/s):</property> <property name="label" translatable="yes">Upload Slots:</property>
</widget> </widget>
</child> </child>
</widget> </widget>
<packing> <packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment4">
<property name="visible">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="right_padding">10</property>
<child>
<widget class="GtkLabel" id="label54">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Maximum Connections:</property>
</widget>
</child>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="spin_num_download">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip" translatable="yes">The maximum number of connections allowed. Set -1 for unlimited.</property>
<property name="xalign">1</property>
<property name="adjustment">-1 -1 1000 1 10 10</property>
<property name="climb_rate">1</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="spin_num_upload">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip" translatable="yes">The maximum number of upload slots. Set -1 for unlimited.</property>
<property name="xalign">1</property>
<property name="adjustment">-1 -1 1000 1 10 10</property>
<property name="climb_rate">1</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="spin_max_download">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="tooltip" translatable="yes">The maximum download rate for all torrents. Set -1 for unlimited.</property>
<property name="xalign">1</property>
<property name="adjustment">-1 -1 9000 1 10 10</property>
<property name="climb_rate">1</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkSpinButton" id="spin_max_upload">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip" translatable="yes">The maximum upload rate for all torrents. Set -1 for unlimited.</property>
<property name="xalign">1</property>
<property name="adjustment">-1 -1 9000 1 10 10</property>
<property name="climb_rate">1</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property> <property name="top_attach">3</property>
<property name="bottom_attach">4</property> <property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property> <property name="x_options">GTK_FILL</property>
@ -758,7 +758,7 @@
<child> <child>
<widget class="GtkCheckButton" id="chk_upnp"> <widget class="GtkCheckButton" id="chk_upnp">
<property name="visible">True</property> <property name="visible">True</property>
<property name="sensitive">False</property> <property name="can_focus">True</property>
<property name="label" translatable="yes">UPnP</property> <property name="label" translatable="yes">UPnP</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="response_id">0</property> <property name="response_id">0</property>
@ -772,7 +772,7 @@
<child> <child>
<widget class="GtkCheckButton" id="chk_natpmp"> <widget class="GtkCheckButton" id="chk_natpmp">
<property name="visible">True</property> <property name="visible">True</property>
<property name="sensitive">False</property> <property name="can_focus">True</property>
<property name="label" translatable="yes">NAT-PMP</property> <property name="label" translatable="yes">NAT-PMP</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="response_id">0</property> <property name="response_id">0</property>
@ -787,7 +787,7 @@
<child> <child>
<widget class="GtkCheckButton" id="chk_utpex"> <widget class="GtkCheckButton" id="chk_utpex">
<property name="visible">True</property> <property name="visible">True</property>
<property name="sensitive">False</property> <property name="can_focus">True</property>
<property name="label" translatable="yes">UT PeX</property> <property name="label" translatable="yes">UT PeX</property>
<property name="use_underline">True</property> <property name="use_underline">True</property>
<property name="response_id">0</property> <property name="response_id">0</property>
@ -806,7 +806,7 @@
<child> <child>
<widget class="GtkLabel" id="label17"> <widget class="GtkLabel" id="label17">
<property name="visible">True</property> <property name="visible">True</property>
<property name="label" translatable="yes">&lt;b&gt;Network Extras&lt;/b&gt; - Always on</property> <property name="label" translatable="yes">&lt;b&gt;Network Extras&lt;/b&gt;</property>
<property name="use_markup">True</property> <property name="use_markup">True</property>
</widget> </widget>
<packing> <packing>

View File

@ -81,8 +81,6 @@ namespace libtorrent
{ return std::auto_ptr<alert>(new tracker_warning_alert(*this)); } { return std::auto_ptr<alert>(new tracker_warning_alert(*this)); }
}; };
struct TORRENT_EXPORT tracker_reply_alert: torrent_alert struct TORRENT_EXPORT tracker_reply_alert: torrent_alert
{ {
tracker_reply_alert(torrent_handle const& h tracker_reply_alert(torrent_handle const& h
@ -186,6 +184,26 @@ namespace libtorrent
{ return std::auto_ptr<alert>(new torrent_finished_alert(*this)); } { return std::auto_ptr<alert>(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<alert> clone() const
{ return std::auto_ptr<alert>(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<alert> clone() const
{ return std::auto_ptr<alert>(new torrent_paused_alert(*this)); }
};
struct TORRENT_EXPORT url_seed_alert: torrent_alert struct TORRENT_EXPORT url_seed_alert: torrent_alert
{ {
url_seed_alert( url_seed_alert(

View File

@ -68,6 +68,7 @@
#include "asio/system_error.hpp" #include "asio/system_error.hpp"
#include "asio/thread.hpp" #include "asio/thread.hpp"
#include "asio/time_traits.hpp" #include "asio/time_traits.hpp"
#include "asio/version.hpp"
#include "asio/write.hpp" #include "asio/write.hpp"
#endif // ASIO_HPP #endif // ASIO_HPP

View File

@ -40,8 +40,6 @@ namespace asio {
* @e Distinct @e objects: Safe.@n * @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe. * @e Shared @e objects: Unsafe.
* *
* @sa @ref deadline_timer_reset
*
* @par Examples * @par Examples
* Performing a blocking wait: * Performing a blocking wait:
* @code * @code
@ -75,6 +73,45 @@ namespace asio {
* // Start an asynchronous wait. * // Start an asynchronous wait.
* timer.async_wait(handler); * timer.async_wait(handler);
* @endcode * @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 <typename Time, template <typename Time,
typename TimeTraits = asio::time_traits<Time>, typename TimeTraits = asio::time_traits<Time>,
@ -197,9 +234,6 @@ public:
* operations will be cancelled. The handler for each cancelled operation will * operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code. * 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 expiry_time The expiry time to be used for the timer.
* *
* @return The number of asynchronous operations that were cancelled. * @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 * operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code. * 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 expiry_time The expiry time to be used for the timer.
* *
* @param ec Set to indicate what error occurred, if any. * @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 * operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code. * 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 expiry_time The expiry time to be used for the timer.
* *
* @return The number of asynchronous operations that were cancelled. * @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 * operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code. * 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 expiry_time The expiry time to be used for the timer.
* *
* @param ec Set to indicate what error occurred, if any. * @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 } // namespace asio
#include "asio/detail/pop_options.hpp" #include "asio/detail/pop_options.hpp"

View File

@ -34,6 +34,14 @@
# endif // defined(_HAS_ITERATOR_DEBUGGING) # endif // defined(_HAS_ITERATOR_DEBUGGING)
#endif // defined(BOOST_MSVC) #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) #if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
# include "asio/detail/push_options.hpp" # include "asio/detail/push_options.hpp"
# include <boost/function.hpp> # include <boost/function.hpp>

View File

@ -24,6 +24,8 @@
#include <linux/version.h> #include <linux/version.h>
#include "asio/detail/pop_options.hpp" #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 this to indicate that epoll is supported on the target platform.
#define ASIO_HAS_EPOLL 1 #define ASIO_HAS_EPOLL 1
@ -36,6 +38,7 @@ class epoll_reactor;
} // namespace detail } // namespace detail
} // namespace asio } // namespace asio
#endif // LINUX_VERSION_CODE >= KERNEL_VERSION (2,5,45)
#endif // defined(__linux__) #endif // defined(__linux__)
#endif // !defined(ASIO_DISABLE_EPOLL) #endif // !defined(ASIO_DISABLE_EPOLL)

View File

@ -164,6 +164,10 @@ struct addrinfo_emulation
# define IPPROTO_IPV6 41 # define IPPROTO_IPV6 41
#endif #endif
#if !defined(IPV6_UNICAST_HOPS)
# define IPV6_UNICAST_HOPS 4
#endif
#if !defined(IPV6_MULTICAST_IF) #if !defined(IPV6_MULTICAST_IF)
# define IPV6_MULTICAST_IF 9 # define IPV6_MULTICAST_IF 9
#endif #endif

View File

@ -350,6 +350,22 @@ public:
socket_ops::setsockopt(impl.socket_, socket_ops::setsockopt(impl.socket_,
option.level(impl.protocol_), option.name(impl.protocol_), option.level(impl.protocol_), option.name(impl.protocol_),
option.data(impl.protocol_), option.size(impl.protocol_), ec); 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; return ec;
} }
} }
@ -506,6 +522,18 @@ public:
return 0; 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. // Send the data.
for (;;) for (;;)
{ {
@ -668,6 +696,18 @@ public:
asio::buffer_size(buffer)); 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. // Send the data.
for (;;) for (;;)
{ {
@ -823,6 +863,18 @@ public:
return 0; 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. // Receive some data.
for (;;) for (;;)
{ {
@ -1005,6 +1057,18 @@ public:
asio::buffer_size(buffer)); 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. // Receive some data.
for (;;) for (;;)
{ {
@ -1160,6 +1224,18 @@ public:
return ec; 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. // Accept a socket.
for (;;) for (;;)
{ {
@ -1203,6 +1279,14 @@ public:
return ec; return ec;
// Fall through to retry operation. // 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 else
return ec; return ec;
@ -1262,6 +1346,10 @@ public:
if (ec == asio::error::connection_aborted if (ec == asio::error::connection_aborted
&& !enable_connection_aborted_) && !enable_connection_aborted_)
return false; 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. // Transfer ownership of the new socket to the peer object.
if (!ec) if (!ec)

View File

@ -63,7 +63,7 @@ inline socket_type accept(socket_type s, socket_addr_type* addr,
socket_addr_len_type* addrlen, asio::error_code& ec) socket_addr_len_type* addrlen, asio::error_code& ec)
{ {
clear_error(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); socket_type new_s = error_wrapper(::accept(s, addr, addrlen), ec);
if (new_s == invalid_socket) if (new_s == invalid_socket)
return new_s; return new_s;
@ -295,7 +295,7 @@ inline socket_type socket(int af, int type, int protocol,
} }
return s; return s;
#elif defined(__MACH__) && defined(__APPLE__) #elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
socket_type s = error_wrapper(::socket(af, type, protocol), ec); socket_type s = error_wrapper(::socket(af, type, protocol), ec);
if (s == invalid_socket) if (s == invalid_socket)
return s; 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, inline int setsockopt(socket_type s, int level, int optname,
const void* optval, size_t optlen, asio::error_code& ec) 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<const char*>(optval),
static_cast<int>(optlen)), ec);
}
}
ec = asio::error::fault;
return -1;
#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
clear_error(ec); clear_error(ec);
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
return error_wrapper(::setsockopt(s, level, optname, return error_wrapper(::setsockopt(s, level, optname,
reinterpret_cast<const char*>(optval), static_cast<int>(optlen)), ec); reinterpret_cast<const char*>(optval), static_cast<int>(optlen)), ec);
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
clear_error(ec);
return error_wrapper(::setsockopt(s, level, optname, optval, return error_wrapper(::setsockopt(s, level, optname, optval,
static_cast<socklen_t>(optlen)), ec); static_cast<socklen_t>(optlen)), ec);
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #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, inline int getsockopt(socket_type s, int level, int optname, void* optval,
size_t* optlen, asio::error_code& ec) 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<int>(*optlen);
int result = error_wrapper(gso(s, level, optname,
reinterpret_cast<char*>(optval), &tmp_optlen), ec);
*optlen = static_cast<size_t>(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<DWORD*>(optval) = 1;
clear_error(ec);
}
return result;
}
}
ec = asio::error::fault;
return -1;
#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
clear_error(ec); clear_error(ec);
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
int tmp_optlen = static_cast<int>(*optlen); int tmp_optlen = static_cast<int>(*optlen);
int result = error_wrapper(::getsockopt(s, level, optname, int result = error_wrapper(::getsockopt(s, level, optname,
reinterpret_cast<char*>(optval), &tmp_optlen), ec); reinterpret_cast<char*>(optval), &tmp_optlen), ec);
@ -350,6 +410,7 @@ inline int getsockopt(socket_type s, int level, int optname, void* optval,
} }
return result; return result;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__) #else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
clear_error(ec);
socklen_t tmp_optlen = static_cast<socklen_t>(*optlen); socklen_t tmp_optlen = static_cast<socklen_t>(*optlen);
int result = error_wrapper(::getsockopt(s, level, optname, int result = error_wrapper(::getsockopt(s, level, optname,
optval, &tmp_optlen), ec); optval, &tmp_optlen), ec);

View File

@ -18,6 +18,7 @@
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
#include <cstdlib>
#include <boost/throw_exception.hpp> #include <boost/throw_exception.hpp>
#include "asio/detail/pop_options.hpp" #include "asio/detail/pop_options.hpp"
@ -49,8 +50,10 @@ public:
socket_ops::setsockopt(acceptor.get(), socket_ops::setsockopt(acceptor.get(),
SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec); SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt), ec);
using namespace std; // For memset.
sockaddr_in4_type addr; sockaddr_in4_type addr;
socket_addr_len_type addr_len = sizeof(addr); socket_addr_len_type addr_len = sizeof(addr);
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET; addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = 0; addr.sin_port = 0;

View File

@ -169,6 +169,7 @@ const int message_do_not_route = MSG_DONTROUTE;
#endif #endif
const int custom_socket_option_level = 0xA5100000; const int custom_socket_option_level = 0xA5100000;
const int enable_connection_aborted_option = 1; const int enable_connection_aborted_option = 1;
const int always_fail_option = 2;
} // namespace detail } // namespace detail
} // namespace asio } // namespace asio

View File

@ -309,7 +309,8 @@ private:
swap_heap(index, heap_.size() - 1); swap_heap(index, heap_.size() - 1);
heap_.pop_back(); heap_.pop_back();
size_t parent = (index - 1) / 2; 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); up_heap(index);
else else
down_heap(index); down_heap(index);

View File

@ -137,7 +137,8 @@ public:
enum enum
{ {
enable_connection_aborted = 1, // User wants connection_aborted errors. 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. // Flags indicating the current state of the socket.
@ -200,6 +201,7 @@ public:
void construct(implementation_type& impl) void construct(implementation_type& impl)
{ {
impl.socket_ = invalid_socket; impl.socket_ = invalid_socket;
impl.flags_ = 0;
impl.cancel_token_.reset(); impl.cancel_token_.reset();
impl.safe_cancellation_thread_id_ = 0; impl.safe_cancellation_thread_id_ = 0;
@ -239,6 +241,7 @@ public:
asio::error_code ignored_ec; asio::error_code ignored_ec;
socket_ops::close(impl.socket_, ignored_ec); socket_ops::close(impl.socket_, ignored_ec);
impl.socket_ = invalid_socket; impl.socket_ = invalid_socket;
impl.flags_ = 0;
impl.cancel_token_.reset(); impl.cancel_token_.reset();
impl.safe_cancellation_thread_id_ = 0; impl.safe_cancellation_thread_id_ = 0;
} }
@ -274,6 +277,7 @@ public:
iocp_service_.register_handle(sock_as_handle); iocp_service_.register_handle(sock_as_handle);
impl.socket_ = sock.release(); impl.socket_ = sock.release();
impl.flags_ = 0;
impl.cancel_token_.reset(static_cast<void*>(0), noop_deleter()); impl.cancel_token_.reset(static_cast<void*>(0), noop_deleter());
impl.protocol_ = protocol; impl.protocol_ = protocol;
ec = asio::error_code(); ec = asio::error_code();
@ -294,6 +298,7 @@ public:
iocp_service_.register_handle(native_socket.as_handle()); iocp_service_.register_handle(native_socket.as_handle());
impl.socket_ = native_socket; impl.socket_ = native_socket;
impl.flags_ = 0;
impl.cancel_token_.reset(static_cast<void*>(0), noop_deleter()); impl.cancel_token_.reset(static_cast<void*>(0), noop_deleter());
impl.protocol_ = protocol; impl.protocol_ = protocol;
ec = asio::error_code(); ec = asio::error_code();
@ -325,6 +330,7 @@ public:
return ec; return ec;
impl.socket_ = invalid_socket; impl.socket_ = invalid_socket;
impl.flags_ = 0;
impl.cancel_token_.reset(); impl.cancel_token_.reset();
impl.safe_cancellation_thread_id_ = 0; impl.safe_cancellation_thread_id_ = 0;
} }
@ -534,6 +540,15 @@ public:
socket_ops::ioctl(impl.socket_, command.name(), socket_ops::ioctl(impl.socket_, command.name(),
static_cast<ioctl_arg_type*>(command.data()), ec); static_cast<ioctl_arg_type*>(command.data()), ec);
if (!ec && command.name() == static_cast<int>(FIONBIO))
{
if (command.get())
impl.flags_ |= implementation_type::user_set_non_blocking;
else
impl.flags_ &= ~implementation_type::user_set_non_blocking;
}
return ec; return ec;
} }
@ -1774,11 +1789,12 @@ public:
class connect_handler class connect_handler
{ {
public: public:
connect_handler(socket_type socket, connect_handler(socket_type socket, bool user_set_non_blocking,
boost::shared_ptr<bool> completed, boost::shared_ptr<bool> completed,
asio::io_service& io_service, asio::io_service& io_service,
reactor_type& reactor, Handler handler) reactor_type& reactor, Handler handler)
: socket_(socket), : socket_(socket),
user_set_non_blocking_(user_set_non_blocking),
completed_(completed), completed_(completed),
io_service_(io_service), io_service_(io_service),
reactor_(reactor), reactor_(reactor),
@ -1825,12 +1841,15 @@ public:
return true; return true;
} }
// Make the socket blocking again (the default). // Revert socket to blocking mode unless the user requested otherwise.
ioctl_arg_type non_blocking = 0; if (!user_set_non_blocking_)
if (socket_ops::ioctl(socket_, FIONBIO, &non_blocking, ec))
{ {
io_service_.post(bind_handler(handler_, ec)); ioctl_arg_type non_blocking = 0;
return true; 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. // Post the result of the successful connection operation.
@ -1841,6 +1860,7 @@ public:
private: private:
socket_type socket_; socket_type socket_;
bool user_set_non_blocking_;
boost::shared_ptr<bool> completed_; boost::shared_ptr<bool> completed_;
asio::io_service& io_service_; asio::io_service& io_service_;
reactor_type& reactor_; reactor_type& reactor_;
@ -1891,6 +1911,13 @@ public:
if (socket_ops::connect(impl.socket_, peer_endpoint.data(), if (socket_ops::connect(impl.socket_, peer_endpoint.data(),
peer_endpoint.size(), ec) == 0) 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 // The connect operation has finished successfully so we need to post the
// handler immediately. // handler immediately.
this->io_service().post(bind_handler(handler, ec)); this->io_service().post(bind_handler(handler, ec));
@ -1903,10 +1930,20 @@ public:
boost::shared_ptr<bool> completed(new bool(false)); boost::shared_ptr<bool> completed(new bool(false));
reactor->start_write_and_except_ops(impl.socket_, reactor->start_write_and_except_ops(impl.socket_,
connect_handler<Handler>( connect_handler<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 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. // The connect operation has failed, so post the handler immediately.
this->io_service().post(bind_handler(handler, ec)); this->io_service().post(bind_handler(handler, ec));
} }

View File

@ -60,7 +60,40 @@ namespace asio {
* @par Concepts: * @par Concepts:
* Dispatcher. * 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 class io_service
: private noncopyable : private noncopyable
@ -108,7 +141,9 @@ public:
* more handlers to be dispatched, or until the io_service has been stopped. * 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 * 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 * The run() function may be safely called again once it has completed only
* after a call to reset(). * after a call to reset().
@ -125,7 +160,9 @@ public:
* more handlers to be dispatched, or until the io_service has been stopped. * 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 * 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 * The run() function may be safely called again once it has completed only
* after a call to reset(). * 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 } // namespace asio
#include "asio/impl/io_service.ipp" #include "asio/impl/io_service.ipp"

View File

@ -19,6 +19,7 @@
#include "asio/detail/push_options.hpp" #include "asio/detail/push_options.hpp"
#include <boost/iterator/iterator_facade.hpp> #include <boost/iterator/iterator_facade.hpp>
#include <boost/optional.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <cstring> #include <cstring>
#include <string> #include <string>
@ -118,12 +119,12 @@ private:
void increment() void increment()
{ {
if (++iter_ == values_->end()) if (++*iter_ == values_->end())
{ {
// Reset state to match a default constructed end iterator. // Reset state to match a default constructed end iterator.
values_.reset(); values_.reset();
typedef typename values_type::const_iterator values_iterator_type; typedef typename values_type::const_iterator values_iterator_type;
iter_ = values_iterator_type(); iter_.reset();
} }
} }
@ -133,17 +134,18 @@ private:
return true; return true;
if (values_ != other.values_) if (values_ != other.values_)
return false; return false;
return iter_ == other.iter_; return *iter_ == *other.iter_;
} }
const basic_resolver_entry<InternetProtocol>& dereference() const const basic_resolver_entry<InternetProtocol>& dereference() const
{ {
return *iter_; return **iter_;
} }
typedef std::vector<basic_resolver_entry<InternetProtocol> > values_type; typedef std::vector<basic_resolver_entry<InternetProtocol> > values_type;
typedef typename values_type::const_iterator values_iter_type;
boost::shared_ptr<values_type> values_; boost::shared_ptr<values_type> values_;
typename values_type::const_iterator iter_; boost::optional<values_iter_type> iter_;
}; };
} // namespace ip } // namespace ip

View File

@ -37,6 +37,12 @@ template <int IPv4_Level, int IPv4_Name, int IPv6_Level, int IPv6_Name>
class boolean class boolean
{ {
public: public:
#if defined(__sun)
typedef unsigned char value_type;
#else
typedef int value_type;
#endif
// Default constructor. // Default constructor.
boolean() boolean()
: value_(0) : value_(0)
@ -94,14 +100,14 @@ public:
// Get the address of the boolean data. // Get the address of the boolean data.
template <typename Protocol> template <typename Protocol>
int* data(const Protocol&) value_type* data(const Protocol&)
{ {
return &value_; return &value_;
} }
// Get the address of the boolean data. // Get the address of the boolean data.
template <typename Protocol> template <typename Protocol>
const int* data(const Protocol&) const const value_type* data(const Protocol&) const
{ {
return &value_; return &value_;
} }
@ -122,7 +128,7 @@ public:
} }
private: private:
int value_; value_type value_;
}; };
// Helper template for implementing unicast hops options. // Helper template for implementing unicast hops options.

View File

@ -59,7 +59,7 @@ public:
return tcp(PF_INET); return tcp(PF_INET);
} }
/// Construct to represent the IPv4 TCP protocol. /// Construct to represent the IPv6 TCP protocol.
static tcp v6() static tcp v6()
{ {
return tcp(PF_INET6); return tcp(PF_INET6);

View File

@ -56,7 +56,7 @@ public:
return udp(PF_INET); return udp(PF_INET);
} }
/// Construct to represent the IPv4 UDP protocol. /// Construct to represent the IPv6 UDP protocol.
static udp v6() static udp v6()
{ {
return udp(PF_INET6); return udp(PF_INET6);
@ -80,7 +80,7 @@ public:
return family_; return family_;
} }
/// The IPv4 UDP socket type. /// The UDP socket type.
typedef basic_datagram_socket<udp> socket; typedef basic_datagram_socket<udp> socket;
/// The UDP resolver type. /// The UDP resolver type.

View File

@ -54,6 +54,12 @@ public:
} }
/// Destructor. /// 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() ~strand()
{ {
service_.destroy(impl_); service_.destroy(impl_);

View File

@ -82,10 +82,13 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/lsd.hpp" #include "libtorrent/lsd.hpp"
#include "libtorrent/socket_type.hpp" #include "libtorrent/socket_type.hpp"
#include "libtorrent/connection_queue.hpp" #include "libtorrent/connection_queue.hpp"
#include "libtorrent/disk_io_thread.hpp"
namespace libtorrent namespace libtorrent
{ {
namespace fs = boost::filesystem;
namespace aux namespace aux
{ {
struct session_impl; struct session_impl;
@ -98,7 +101,7 @@ namespace libtorrent
: processing(false), progress(0.f), abort(false) {} : processing(false), progress(0.f), abort(false) {}
boost::shared_ptr<torrent> torrent_ptr; boost::shared_ptr<torrent> torrent_ptr;
boost::filesystem::path save_path; fs::path save_path;
sha1_hash info_hash; sha1_hash info_hash;
@ -229,6 +232,7 @@ namespace libtorrent
bool is_aborted() const { return m_abort; } bool is_aborted() const { return m_abort; }
void set_ip_filter(ip_filter const& f); void set_ip_filter(ip_filter const& f);
void set_port_filter(port_filter const& f);
bool listen_on( bool listen_on(
std::pair<int, int> const& port_range std::pair<int, int> const& port_range
@ -237,7 +241,7 @@ namespace libtorrent
torrent_handle add_torrent( torrent_handle add_torrent(
torrent_info const& ti torrent_info const& ti
, boost::filesystem::path const& save_path , fs::path const& save_path
, entry const& resume_data , entry const& resume_data
, bool compact_mode , bool compact_mode
, int block_size , int block_size
@ -247,7 +251,7 @@ namespace libtorrent
char const* tracker_url char const* tracker_url
, sha1_hash const& info_hash , sha1_hash const& info_hash
, char const* name , char const* name
, boost::filesystem::path const& save_path , fs::path const& save_path
, entry const& resume_data , entry const& resume_data
, bool compact_mode , bool compact_mode
, int block_size , int block_size
@ -304,6 +308,14 @@ namespace libtorrent
{ return m_dht_proxy; } { return m_dht_proxy; }
#endif #endif
void start_lsd();
void start_natpmp();
void start_upnp();
void stop_lsd();
void stop_natpmp();
void stop_upnp();
// handles delayed alerts // handles delayed alerts
alert_manager m_alerts; alert_manager m_alerts;
@ -325,6 +337,9 @@ namespace libtorrent
// when they are destructed. // when they are destructed.
file_pool m_files; file_pool m_files;
// handles disk io requests asynchronously
disk_io_thread m_disk_thread;
// this is a list of half-open tcp connections // this is a list of half-open tcp connections
// (only outgoing connections) // (only outgoing connections)
// this has to be one of the last // this has to be one of the last
@ -348,6 +363,9 @@ namespace libtorrent
// filters incoming connections // filters incoming connections
ip_filter m_ip_filter; 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 // the peer id that is generated at the start of the session
peer_id m_peer_id; peer_id m_peer_id;
@ -427,9 +445,9 @@ namespace libtorrent
pe_settings m_pe_settings; pe_settings m_pe_settings;
#endif #endif
natpmp m_natpmp; boost::shared_ptr<natpmp> m_natpmp;
upnp m_upnp; boost::shared_ptr<upnp> m_upnp;
lsd m_lsd; boost::shared_ptr<lsd> m_lsd;
// the timer used to fire the second_tick // the timer used to fire the second_tick
deadline_timer m_timer; deadline_timer m_timer;

View File

@ -192,7 +192,7 @@ namespace libtorrent
void write_cancel(peer_request const& r); void write_cancel(peer_request const& r);
void write_bitfield(std::vector<bool> const& bitfield); void write_bitfield(std::vector<bool> const& bitfield);
void write_have(int index); 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(); void write_handshake();
#ifndef TORRENT_DISABLE_EXTENSIONS #ifndef TORRENT_DISABLE_EXTENSIONS
void write_extensions(); void write_extensions();

View File

@ -53,15 +53,16 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
// DEBUG API // DEBUG API
namespace fs = boost::filesystem;
struct logger 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; fs::path dir(fs::complete("libtorrent_logs" + boost::lexical_cast<std::string>(instance)));
path dir(complete("libtorrent_logs" + boost::lexical_cast<std::string>(instance))); if (!fs::exists(dir)) fs::create_directories(dir);
if (!exists(dir)) create_directories(dir); m_file.open((dir / filename).string().c_str(), std::ios_base::out | (append ? std::ios_base::app : std::ios_base::out));
m_file.open(dir / filename, std::ios_base::out | (append ? std::ios_base::app : std::ios_base::out));
*this << "\n\n\n*** starting log ***\n"; *this << "\n\n\n*** starting log ***\n";
} }
@ -73,7 +74,7 @@ namespace libtorrent
return *this; return *this;
} }
boost::filesystem::ofstream m_file; std::ofstream m_file;
}; };
} }

View File

@ -155,6 +155,8 @@ namespace libtorrent
dictionary_type& dict(); dictionary_type& dict();
const dictionary_type& dict() const; const dictionary_type& dict() const;
void swap(entry& e);
// these functions requires that the entry // these functions requires that the entry
// is a dictionary, otherwise they will throw // is a dictionary, otherwise they will throw
entry& operator[](char const* key); entry& operator[](char const* key);

View File

@ -52,6 +52,7 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
namespace fs = boost::filesystem;
struct TORRENT_EXPORT file_error: std::runtime_error struct TORRENT_EXPORT file_error: std::runtime_error
{ {
@ -105,10 +106,10 @@ namespace libtorrent
static const open_mode out; static const open_mode out;
file(); file();
file(boost::filesystem::path const& p, open_mode m); file(fs::path const& p, open_mode m);
~file(); ~file();
void open(boost::filesystem::path const& p, open_mode m); void open(fs::path const& p, open_mode m);
void close(); void close();
void set_size(size_type size); void set_size(size_type size);

View File

@ -104,3 +104,4 @@ namespace libtorrent
} }
#endif // TORRENT_HASHER_HPP_INCLUDED #endif // TORRENT_HASHER_HPP_INCLUDED

View File

@ -1,36 +1,53 @@
#include "libtorrent/io.hpp" /*
#include "libtorrent/socket.hpp"
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/function.hpp>
#include <asio/read.hpp>
#include <asio/write.hpp>
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 { namespace libtorrent {
class http_stream : boost::noncopyable class http_stream : public proxy_base
{ {
public: 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) explicit http_stream(asio::io_service& io_service)
: m_sock(io_service) : proxy_base(io_service)
, m_resolver(io_service)
, m_no_connect(false) , m_no_connect(false)
{} {}
void set_no_connect(bool c) { m_no_connect = c; } 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 void set_username(std::string const& user
, std::string const& password) , std::string const& password)
{ {
@ -38,108 +55,6 @@ public:
m_password = password; m_password = password;
} }
template <class Mutable_Buffers, class Handler>
void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
{
m_sock.async_read_some(buffers, handler);
}
template <class Mutable_Buffers>
std::size_t read_some(Mutable_Buffers const& buffers, asio::error_code& ec)
{
return m_sock.read_some(buffers, ec);
}
template <class Mutable_Buffers>
std::size_t read_some(Mutable_Buffers const& buffers)
{
return m_sock.read_some(buffers);
}
template <class IO_Control_Command>
void io_control(IO_Control_Command& ioc)
{
m_sock.io_control(ioc);
}
template <class IO_Control_Command>
void io_control(IO_Control_Command& ioc, asio::error_code& ec)
{
m_sock.io_control(ioc, ec);
}
template <class Const_Buffers, class Handler>
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 <class Error_Handler>
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 <class Error_Handler>
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 <class Error_Handler>
void close(Error_Handler const& error_handler)
{
m_sock.close(error_handler);
}
endpoint_type remote_endpoint()
{
return m_remote_endpoint;
}
template <class Error_Handler>
endpoint_type remote_endpoint(Error_Handler const& error_handler)
{
return m_remote_endpoint;
}
endpoint_type local_endpoint()
{
return m_sock.local_endpoint();
}
template <class Error_Handler>
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<void(asio::error_code const&)> handler_type; typedef boost::function<void(asio::error_code const&)> handler_type;
template <class Handler> template <class Handler>
@ -171,19 +86,12 @@ private:
void handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h); void handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h);
void handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h); void handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h);
stream_socket m_sock;
// the http proxy
std::string m_hostname;
int m_port;
// send and receive buffer // send and receive buffer
std::vector<char> m_buffer; std::vector<char> m_buffer;
// proxy authentication // proxy authentication
std::string m_user; std::string m_user;
std::string m_password; std::string m_password;
endpoint_type m_remote_endpoint;
tcp::resolver m_resolver;
// this is true if the connection is HTTP based and // this is true if the connection is HTTP based and
// want to talk directly to the proxy // want to talk directly to the proxy
bool m_no_connect; bool m_no_connect;
@ -191,3 +99,4 @@ private:
} }
#endif

View File

@ -71,20 +71,82 @@ struct ip_range
namespace detail namespace detail
{ {
template<class Addr>
Addr zero()
{
typename Addr::bytes_type zero;
std::fill(zero.begin(), zero.end(), 0);
return Addr(zero);
}
template<>
inline boost::uint16_t zero<boost::uint16_t>() { return 0; }
template<class Addr>
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<typename iter::value_type>::max)())
{
*i += 1;
break;
}
*i = 0;
}
return Addr(tmp);
}
inline boost::uint16_t plus_one(boost::uint16_t val) { return val + 1; }
template<class Addr>
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<typename iter::value_type>::max)();
}
return Addr(tmp);
}
inline boost::uint16_t minus_one(boost::uint16_t val) { return val - 1; }
template<class Addr>
Addr max_addr()
{
typename Addr::bytes_type tmp;
std::fill(tmp.begin(), tmp.end()
, (std::numeric_limits<typename Addr::bytes_type::value_type>::max)());
return Addr(tmp);
}
template<>
inline boost::uint16_t max_addr<boost::uint16_t>()
{ return (std::numeric_limits<boost::uint16_t>::max)(); }
// this is the generic implementation of // this is the generic implementation of
// a filter for a specific address type. // a filter for a specific address type.
// it works with IPv4 and IPv6 // it works with IPv4 and IPv6
template<class Addr> template<class Addr>
class TORRENT_EXPORT filter_impl class filter_impl
{ {
public: public:
filter_impl() filter_impl()
{ {
typename Addr::bytes_type zero;
std::fill(zero.begin(), zero.end(), 0);
// make the entire ip-range non-blocked // make the entire ip-range non-blocked
m_access_list.insert(range(Addr(zero), 0)); m_access_list.insert(range(zero<Addr>(), 0));
} }
void add_rule(Addr first, Addr last, int flags) void add_rule(Addr first, Addr last, int flags)
@ -134,7 +196,7 @@ namespace detail
if ((j != m_access_list.end() if ((j != m_access_list.end()
&& minus_one(j->start) != last) && minus_one(j->start) != last)
|| (j == m_access_list.end() || (j == m_access_list.end()
&& last != max_addr())) && last != max_addr<Addr>()))
{ {
assert(j == m_access_list.end() || last < minus_one(j->start)); assert(j == m_access_list.end() || last < minus_one(j->start));
if (last_access != flags) if (last_access != flags)
@ -170,7 +232,7 @@ namespace detail
++i; ++i;
if (i == end) if (i == end)
r.last = max_addr(); r.last = max_addr<Addr>();
else else
r.last = minus_one(i->start); r.last = minus_one(i->start);
@ -181,48 +243,6 @@ namespace detail
private: 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<typename iter::value_type>::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<typename iter::value_type>::max)();
}
return Addr(tmp);
}
Addr max_addr() const
{
typename Addr::bytes_type tmp;
std::fill(tmp.begin(), tmp.end()
, (std::numeric_limits<typename Addr::bytes_type::value_type>::max)());
return Addr(tmp);
}
struct range struct range
{ {
range(Addr addr, int access = 0): start(addr), access(access) {} range(Addr addr, int access = 0): start(addr), access(access) {}
@ -270,6 +290,24 @@ private:
detail::filter_impl<address_v6> m_filter6; detail::filter_impl<address_v6> 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<boost::uint16_t> m_filter;
};
} }
#endif #endif

View File

@ -51,7 +51,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/array.hpp> #include <boost/array.hpp>
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <boost/cstdint.hpp> #include <boost/cstdint.hpp>
#include <boost/detail/atomic_count.hpp>
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
@ -73,6 +72,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/bandwidth_manager.hpp" #include "libtorrent/bandwidth_manager.hpp"
#include "libtorrent/policy.hpp" #include "libtorrent/policy.hpp"
#include "libtorrent/socket_type.hpp" #include "libtorrent/socket_type.hpp"
#include "libtorrent/intrusive_ptr_base.hpp"
// TODO: each time a block is 'taken over' // TODO: each time a block is 'taken over'
// from another peer. That peer must be given // from another peer. That peer must be given
@ -88,20 +88,16 @@ namespace libtorrent
struct session_impl; 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 struct TORRENT_EXPORT protocol_error: std::runtime_error
{ {
protocol_error(const std::string& msg): std::runtime_error(msg) {}; protocol_error(const std::string& msg): std::runtime_error(msg) {};
}; };
class TORRENT_EXPORT peer_connection class TORRENT_EXPORT peer_connection
: public boost::noncopyable : public intrusive_ptr_base<peer_connection>
, public boost::noncopyable
{ {
friend class invariant_access; 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: public:
enum channels enum channels
@ -378,7 +374,7 @@ namespace libtorrent
virtual void write_cancel(peer_request const& r) = 0; virtual void write_cancel(peer_request const& r) = 0;
virtual void write_have(int index) = 0; virtual void write_have(int index) = 0;
virtual void write_keepalive() = 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_connected() = 0;
virtual void on_tick() {} virtual void on_tick() {}
@ -474,6 +470,9 @@ namespace libtorrent
private: private:
void fill_send_buffer(); 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<torrent> t);
// the timeout in seconds // the timeout in seconds
int m_timeout; int m_timeout;
@ -503,6 +502,11 @@ namespace libtorrent
// (m_current_send_buffer + 1) % 2 is the // (m_current_send_buffer + 1) % 2 is the
// buffer we're currently waiting for. // buffer we're currently waiting for.
int m_current_send_buffer; 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 // if the sending buffer doesn't finish in one send
// operation, this is the position within that buffer // operation, this is the position within that buffer
@ -660,9 +664,6 @@ namespace libtorrent
// the left-over bandwidth (suitable for web seeds). // the left-over bandwidth (suitable for web seeds).
bool m_non_prioritized; bool m_non_prioritized;
// reference counter for intrusive_ptr
mutable boost::detail::atomic_count m_refs;
int m_upload_limit; int m_upload_limit;
int m_download_limit; int m_download_limit;
@ -681,6 +682,19 @@ namespace libtorrent
// so that it can be removed from the queue // so that it can be removed from the queue
// once the connection completes // once the connection completes
int m_connection_ticket; 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 #ifndef NDEBUG
public: public:
bool m_in_constructor; bool m_in_constructor;

View File

@ -58,6 +58,7 @@ namespace libtorrent
big_number(std::string const& s) big_number(std::string const& s)
{ {
assert(s.size() >= 20);
int sl = int(s.size()) < size ? int(s.size()) : size; int sl = int(s.size()) < size ? int(s.size()) : size;
std::memcpy(m_number, &s[0], sl); std::memcpy(m_number, &s[0], sl);
} }

View File

@ -58,8 +58,8 @@ namespace libtorrent
on_parole = 0x200, on_parole = 0x200,
seed = 0x400 seed = 0x400
#ifndef TORRENT_DISABLE_ENCRYPTION #ifndef TORRENT_DISABLE_ENCRYPTION
, rc4_encrypted = 0x200, , rc4_encrypted = 0x800,
plaintext_encrypted = 0x400 plaintext_encrypted = 0x1000
#endif #endif
}; };
@ -141,6 +141,9 @@ namespace libtorrent
web_seed = 1 web_seed = 1
}; };
int connection_type; int connection_type;
// approximate peer download rate
int remote_dl_rate;
}; };
} }

View File

@ -90,14 +90,14 @@ namespace libtorrent
struct block_info 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 // the peer this block was requested or
// downloaded from // downloaded from
tcp::endpoint peer; tcp::endpoint peer;
// the number of times this block has been downloaded // the number of times this block has been downloaded
unsigned num_downloads:14; unsigned num_downloads:14;
unsigned requested:1; enum { state_none, state_requested, state_writing, state_finished };
unsigned finished:1; unsigned state:2;
}; };
// the peers that are downloading this piece // the peers that are downloading this piece
@ -109,7 +109,7 @@ namespace libtorrent
struct downloading_piece struct downloading_piece
{ {
downloading_piece(): finished(0), requested(0) {} downloading_piece(): finished(0), writing(0), requested(0) {}
piece_state_t state; piece_state_t state;
// the index of the piece // the index of the piece
@ -118,20 +118,27 @@ namespace libtorrent
// this is a pointer into the m_block_info // this is a pointer into the m_block_info
// vector owned by the piece_picker // vector owned by the piece_picker
block_info* info; block_info* info;
boost::uint16_t finished; // the number of blocks in the finished state
boost::uint16_t requested; 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 piece_picker(int blocks_per_piece
, int total_num_blocks); , int total_num_blocks);
void get_availability(std::vector<int>& avail) const;
void set_sequenced_download_threshold(int sequenced_download_threshold); void set_sequenced_download_threshold(int sequenced_download_threshold);
// the vector tells which pieces we already have // the vector tells which pieces we already have
// and which we don't have. // and which we don't have.
void files_checked( void files_checked(
const std::vector<bool>& pieces std::vector<bool> const& pieces
, const std::vector<downloading_piece>& unfinished); , std::vector<downloading_piece> const& unfinished
, std::vector<int>& verify_pieces);
// increases the peer count for the given piece // increases the peer count for the given piece
// (is used when a HAVE or BITFIELD message is received) // (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 // returns true if any client is currently downloading this
// piece-block, or if it's queued for downloading by some client // piece-block, or if it's queued for downloading by some client
// or if it already has been successfully downloaded // 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; bool is_finished(piece_block block) const;
// marks this piece-block as queued for downloading // marks this piece-block as queued for downloading
void mark_as_downloading(piece_block block, tcp::endpoint const& peer void mark_as_downloading(piece_block block, tcp::endpoint const& peer
, piece_state_t s); , 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); void mark_as_finished(piece_block block, tcp::endpoint const& peer);
// if a piece had a hash-failure, it must be restored and // if a piece had a hash-failure, it must be restored and

View File

@ -99,11 +99,11 @@ namespace libtorrent
void piece_finished(int index, bool successfully_verified); void piece_finished(int index, bool successfully_verified);
void block_finished(peer_connection& c, piece_block b);
// the peer choked us // the peer choked us
void choked(peer_connection& c); void choked(peer_connection& c);
int count_choked() const;
// the peer unchoked us // the peer unchoked us
void unchoked(peer_connection& c); void unchoked(peer_connection& c);

View File

@ -181,4 +181,3 @@ protected:
#endif #endif

View File

@ -72,8 +72,11 @@ namespace libtorrent
struct torrent_plugin; struct torrent_plugin;
class torrent; class torrent;
class ip_filter; class ip_filter;
class port_filter;
class connection_queue; class connection_queue;
namespace fs = boost::filesystem;
namespace aux namespace aux
{ {
// workaround for microsofts // workaround for microsofts
@ -135,7 +138,7 @@ namespace libtorrent
// all torrent_handles must be destructed before the session is destructed! // all torrent_handles must be destructed before the session is destructed!
torrent_handle add_torrent( torrent_handle add_torrent(
torrent_info const& ti torrent_info const& ti
, boost::filesystem::path const& save_path , fs::path const& save_path
, entry const& resume_data = entry() , entry const& resume_data = entry()
, bool compact_mode = true , bool compact_mode = true
, int block_size = 16 * 1024 , int block_size = 16 * 1024
@ -144,7 +147,7 @@ namespace libtorrent
// TODO: deprecated, this is for backwards compatibility only // TODO: deprecated, this is for backwards compatibility only
torrent_handle add_torrent( torrent_handle add_torrent(
entry const& e entry const& e
, boost::filesystem::path const& save_path , fs::path const& save_path
, entry const& resume_data = entry() , entry const& resume_data = entry()
, bool compact_mode = true , bool compact_mode = true
, int block_size = 16 * 1024 , int block_size = 16 * 1024
@ -158,7 +161,7 @@ namespace libtorrent
char const* tracker_url char const* tracker_url
, sha1_hash const& info_hash , sha1_hash const& info_hash
, char const* name , char const* name
, boost::filesystem::path const& save_path , fs::path const& save_path
, entry const& resume_data = entry() , entry const& resume_data = entry()
, bool compact_mode = true , bool compact_mode = true
, int block_size = 16 * 1024 , int block_size = 16 * 1024
@ -187,8 +190,10 @@ namespace libtorrent
#endif #endif
void set_ip_filter(ip_filter const& f); 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_peer_id(peer_id const& pid);
void set_key(int key); void set_key(int key);
peer_id id() const;
bool is_listening() const; bool is_listening() const;
@ -249,6 +254,16 @@ namespace libtorrent
connection_queue& get_connection_queue(); 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 management used for global limits.
resource_request m_ul_bandwidth_quota; resource_request m_ul_bandwidth_quota;
resource_request m_dl_bandwidth_quota; resource_request m_dl_bandwidth_quota;

View File

@ -54,6 +54,8 @@ namespace libtorrent
// a plain tcp socket is used, and // a plain tcp socket is used, and
// the other settings are ignored. // the other settings are ignored.
none, none,
// socks4 server, requires username.
socks4,
// the hostname and port settings are // the hostname and port settings are
// used to connect to the proxy. No // used to connect to the proxy. No
// username or password is sent. // username or password is sent.
@ -102,6 +104,8 @@ namespace libtorrent
, connection_speed(20) , connection_speed(20)
, send_redundant_have(false) , send_redundant_have(false)
, lazy_bitfields(true) , lazy_bitfields(true)
, inactivity_timeout(600)
, unchoke_interval(20)
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT
, use_dht_as_fallback(true) , use_dht_as_fallback(true)
#endif #endif
@ -226,6 +230,18 @@ namespace libtorrent
// from stopping people from seeding. // from stopping people from seeding.
bool lazy_bitfields; 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 #ifndef TORRENT_DISABLE_DHT
// while this is true, the dht will note be used unless the // while this is true, the dht will note be used unless the
// tracker is online // tracker is online

View File

@ -34,12 +34,17 @@ POSSIBILITY OF SUCH DAMAGE.
#define TORRENT_SOCKET_TYPE #define TORRENT_SOCKET_TYPE
#include "libtorrent/socks5_stream.hpp" #include "libtorrent/socks5_stream.hpp"
#include "libtorrent/socks4_stream.hpp"
#include "libtorrent/http_stream.hpp" #include "libtorrent/http_stream.hpp"
#include "libtorrent/variant_stream.hpp" #include "libtorrent/variant_stream.hpp"
namespace libtorrent namespace libtorrent
{ {
typedef variant_stream<stream_socket, socks5_stream, http_stream> socket_type; typedef variant_stream<
stream_socket
, socks5_stream
, socks4_stream
, http_stream> socket_type;
} }
#endif #endif

View File

@ -1,33 +1,50 @@
#include "libtorrent/io.hpp" /*
#include "libtorrent/socket.hpp"
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/function.hpp>
#include <asio/read.hpp>
#include <asio/write.hpp>
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 { namespace libtorrent {
class socks5_stream : boost::noncopyable class socks5_stream : public proxy_base
{ {
public: 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) explicit socks5_stream(asio::io_service& io_service)
: m_sock(io_service) : proxy_base(io_service)
, m_resolver(io_service)
{} {}
void set_proxy(std::string hostname, int port)
{
m_hostname = hostname;
m_port = port;
}
void set_username(std::string const& user void set_username(std::string const& user
, std::string const& password) , std::string const& password)
{ {
@ -35,108 +52,6 @@ public:
m_password = password; m_password = password;
} }
template <class Mutable_Buffers, class Handler>
void async_read_some(Mutable_Buffers const& buffers, Handler const& handler)
{
m_sock.async_read_some(buffers, handler);
}
template <class Mutable_Buffers>
std::size_t read_some(Mutable_Buffers const& buffers, asio::error_code& ec)
{
return m_sock.read_some(buffers, ec);
}
template <class Mutable_Buffers>
std::size_t read_some(Mutable_Buffers const& buffers)
{
return m_sock.read_some(buffers);
}
template <class IO_Control_Command>
void io_control(IO_Control_Command& ioc)
{
m_sock.io_control(ioc);
}
template <class IO_Control_Command>
void io_control(IO_Control_Command& ioc, asio::error_code& ec)
{
m_sock.io_control(ioc, ec);
}
template <class Const_Buffers, class Handler>
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 <class Error_Handler>
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 <class Error_Handler>
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 <class Error_Handler>
void close(Error_Handler const& error_handler)
{
m_sock.close(error_handler);
}
endpoint_type remote_endpoint()
{
return m_remote_endpoint;
}
template <class Error_Handler>
endpoint_type remote_endpoint(Error_Handler const& error_handler)
{
return m_remote_endpoint;
}
endpoint_type local_endpoint()
{
return m_sock.local_endpoint();
}
template <class Error_Handler>
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<void(asio::error_code const&)> handler_type; typedef boost::function<void(asio::error_code const&)> handler_type;
template <class Handler> template <class Handler>
@ -176,20 +91,13 @@ private:
void connect2(asio::error_code const& e, boost::shared_ptr<handler_type> h); void connect2(asio::error_code const& e, boost::shared_ptr<handler_type> h);
void connect3(asio::error_code const& e, boost::shared_ptr<handler_type> h); void connect3(asio::error_code const& e, boost::shared_ptr<handler_type> h);
stream_socket m_sock;
// the socks5 proxy
std::string m_hostname;
int m_port;
// send and receive buffer // send and receive buffer
std::vector<char> m_buffer; std::vector<char> m_buffer;
// proxy authentication // proxy authentication
std::string m_user; std::string m_user;
std::string m_password; std::string m_password;
endpoint_type m_remote_endpoint;
tcp::resolver m_resolver;
}; };
} }
#endif

View File

@ -41,9 +41,9 @@ POSSIBILITY OF SUCH DAMAGE.
#endif #endif
#include <boost/limits.hpp> #include <boost/limits.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/filesystem/path.hpp>
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
@ -52,6 +52,9 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/torrent_info.hpp" #include "libtorrent/torrent_info.hpp"
#include "libtorrent/piece_picker.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" #include "libtorrent/config.hpp"
namespace libtorrent namespace libtorrent
@ -61,8 +64,11 @@ namespace libtorrent
struct piece_checker_data; struct piece_checker_data;
} }
namespace fs = boost::filesystem;
class session; class session;
struct file_pool; struct file_pool;
struct disk_io_job;
#if defined(_WIN32) && defined(UNICODE) #if defined(_WIN32) && defined(UNICODE)
@ -72,11 +78,11 @@ namespace libtorrent
TORRENT_EXPORT std::vector<std::pair<size_type, std::time_t> > get_filesizes( TORRENT_EXPORT std::vector<std::pair<size_type, std::time_t> > get_filesizes(
torrent_info const& t torrent_info const& t
, boost::filesystem::path p); , fs::path p);
TORRENT_EXPORT bool match_filesizes( TORRENT_EXPORT bool match_filesizes(
torrent_info const& t torrent_info const& t
, boost::filesystem::path p , fs::path p
, std::vector<std::pair<size_type, std::time_t> > const& sizes , std::vector<std::pair<size_type, std::time_t> > const& sizes
, bool compact_mode , bool compact_mode
, std::string* error = 0); , std::string* error = 0);
@ -89,6 +95,15 @@ namespace libtorrent
std::string m_msg; 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 struct TORRENT_EXPORT storage_interface
{ {
// create directories and set file sizes // create directories and set file sizes
@ -103,7 +118,7 @@ namespace libtorrent
// may throw file_error if storage for slot hasn't been allocated // 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 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 // verify storage dependent fast resume entries
virtual bool verify_resume_data(entry& rd, std::string& error) = 0; 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 // in slot3 and the data in slot3 in slot1
virtual void swap_slots3(int slot1, int slot2, int slot3) = 0; 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 // this will close all open files that are opened for
// writing. This is called when a torrent has finished // writing. This is called when a torrent has finished
// downloading. // downloading.
@ -129,24 +147,32 @@ namespace libtorrent
}; };
typedef storage_interface* (&storage_constructor_type)( typedef storage_interface* (&storage_constructor_type)(
torrent_info const&, boost::filesystem::path const& torrent_info const&, fs::path const&
, file_pool&); , file_pool&);
TORRENT_EXPORT storage_interface* default_storage_constructor(torrent_info const& ti 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 // returns true if the filesystem the path relies on supports
// sparse files or automatic zero filling of files. // 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<piece_manager>
, boost::noncopyable
{ {
friend class invariant_access;
friend struct disk_io_thread;
public: public:
piece_manager( piece_manager(
const torrent_info& info boost::shared_ptr<void> const& torrent
, const boost::filesystem::path& path , torrent_info const& ti
, fs::path const& path
, file_pool& fp , file_pool& fp
, disk_io_thread& io
, storage_constructor_type sc); , storage_constructor_type sc);
~piece_manager(); ~piece_manager();
@ -156,35 +182,38 @@ namespace libtorrent
std::pair<bool, float> check_files(std::vector<bool>& pieces std::pair<bool, float> check_files(std::vector<bool>& pieces
, int& num_pieces, boost::recursive_mutex& mutex); , int& num_pieces, boost::recursive_mutex& mutex);
void release_files();
void write_resume_data(entry& rd) const; void write_resume_data(entry& rd) const;
bool verify_resume_data(entry& rd, std::string& error); bool verify_resume_data(entry& rd, std::string& error);
bool is_allocating() const; bool is_allocating() const
bool allocate_slots(int num_slots, bool abort_on_disk = false); { return m_state == state_allocating; }
void mark_failed(int index); void mark_failed(int index);
unsigned long piece_crc( unsigned long piece_crc(
int slot_index int slot_index
, int block_size , int block_size
, piece_picker::block_info const* bi); , piece_picker::block_info const* bi);
int slot_for_piece(int piece_index) const; int slot_for_piece(int piece_index) const;
size_type read( void async_read(
char* buf peer_request const& r
, int piece_index , boost::function<void(int, disk_io_job const&)> const& handler);
, int offset
, int size);
void write( void async_write(
const char* buf peer_request const& r
, int piece_index , char const* buffer
, int offset , boost::function<void(int, disk_io_job const&)> const& f);
, int size);
boost::filesystem::path const& save_path() const; void async_hash(int piece, boost::function<void(int, disk_io_job const&)> const& f);
bool move_storage(boost::filesystem::path const&);
fs::path save_path() const;
void async_release_files(
boost::function<void(int, disk_io_job const&)> const& handler);
void async_move_storage(fs::path const& p
, boost::function<void(int, disk_io_job const&)> const& handler);
// fills the vector that maps all allocated // fills the vector that maps all allocated
// slots to the piece that is stored (or // slots to the piece that is stored (or
@ -192,11 +221,134 @@ namespace libtorrent
// of unassigned pieces and -1 is unallocated // of unassigned pieces and -1 is unallocated
void export_piece_map(std::vector<int>& pieces) const; void export_piece_map(std::vector<int>& 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: private:
class impl;
std::auto_ptr<impl> m_pimpl; bool allocate_slots(int num_slots, bool abort_on_disk = false);
int identify_data(
const std::vector<char>& piece_data
, int current_slot
, std::vector<bool>& have_pieces
, int& num_pieces
, const std::multimap<sha1_hash, int>& 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<storage_interface> 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<bool> m_have_piece;
torrent_info const& m_info;
// slots that haven't had any file storage allocated
std::vector<int> m_unallocated_slots;
// slots that have file storage, but isn't assigned to a piece
std::vector<int> 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<int> 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<int> 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<char> 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<sha1_hash, int> m_hash_to_piece;
std::map<int, partial_hash> 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<void> m_torrent;
}; };
} }

View File

@ -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 <boost/date_time/posix_time/posix_time_types.hpp> #include <boost/date_time/posix_time/posix_time_types.hpp>
@ -99,8 +100,12 @@ namespace libtorrent
inline bool is_negative(time_duration dt) { return dt.diff < 0; } inline bool is_negative(time_duration dt) { return dt.diff < 0; }
inline bool operator<(time_duration lhs, time_duration rhs) inline bool operator<(time_duration lhs, time_duration rhs)
{ return lhs.diff < rhs.diff; } { 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) inline bool operator>(time_duration lhs, time_duration rhs)
{ return lhs.diff > rhs.diff; } { return lhs.diff > rhs.diff; }
inline bool operator>=(time_duration lhs, time_duration rhs)
{ return lhs.diff >= rhs.diff; }
// libtorrent time type // libtorrent time type
struct ptime struct ptime
@ -381,3 +386,4 @@ namespace libtorrent
#endif #endif
#endif #endif

View File

@ -68,6 +68,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/escape_string.hpp" #include "libtorrent/escape_string.hpp"
#include "libtorrent/bandwidth_manager.hpp" #include "libtorrent/bandwidth_manager.hpp"
#include "libtorrent/storage.hpp" #include "libtorrent/storage.hpp"
#include "libtorrent/hasher.hpp"
namespace libtorrent namespace libtorrent
{ {
@ -84,6 +85,8 @@ namespace libtorrent
struct piece_checker_data; struct piece_checker_data;
} }
namespace fs = boost::filesystem;
// a torrent is a class that holds information // a torrent is a class that holds information
// for a specific download. It updates itself against // for a specific download. It updates itself against
// the tracker // the tracker
@ -96,7 +99,7 @@ namespace libtorrent
aux::session_impl& ses aux::session_impl& ses
, aux::checker_impl& checker , aux::checker_impl& checker
, torrent_info const& tf , torrent_info const& tf
, boost::filesystem::path const& save_path , fs::path const& save_path
, tcp::endpoint const& net_interface , tcp::endpoint const& net_interface
, bool compact_mode , bool compact_mode
, int block_size , int block_size
@ -111,7 +114,7 @@ namespace libtorrent
, char const* tracker_url , char const* tracker_url
, sha1_hash const& info_hash , sha1_hash const& info_hash
, char const* name , char const* name
, boost::filesystem::path const& save_path , fs::path const& save_path
, tcp::endpoint const& net_interface , tcp::endpoint const& net_interface
, bool compact_mode , bool compact_mode
, int block_size , int block_size
@ -184,6 +187,8 @@ namespace libtorrent
void filter_files(std::vector<bool> const& files); void filter_files(std::vector<bool> const& files);
// ============ end deprecation ============= // ============ end deprecation =============
void piece_availability(std::vector<int>& avail) const;
void set_piece_priority(int index, int priority); void set_piece_priority(int index, int priority);
int piece_priority(int index) const; int piece_priority(int index) const;
@ -422,11 +427,12 @@ namespace libtorrent
// completed() is called immediately after it. // completed() is called immediately after it.
void finished(); void finished();
bool verify_piece(int piece_index); void async_verify_piece(int piece_index, boost::function<void(bool)> const&);
// this is called from the peer_connection // this is called from the peer_connection
// each time a piece has failed the hash // each time a piece has failed the hash
// test // test
void piece_finished(int index, bool passed_hash_check);
void piece_failed(int index); void piece_failed(int index);
void received_redundant_data(int num_bytes) void received_redundant_data(int num_bytes)
{ assert(num_bytes > 0); m_total_redundant_bytes += 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; - m_num_pieces - m_picker->num_filtered() == 0;
} }
boost::filesystem::path save_path() const; fs::path save_path() const;
alert_manager& alerts() const; alert_manager& alerts() const;
piece_picker& picker() piece_picker& picker()
{ {
assert(!is_seed());
assert(m_picker.get()); assert(m_picker.get());
return *m_picker; return *m_picker;
} }
bool has_picker() const bool has_picker() const
{ {
assert((valid_metadata() && !is_seed()) == bool(m_picker.get() != 0));
return m_picker.get() != 0; return m_picker.get() != 0;
} }
policy& get_policy() policy& get_policy()
@ -503,14 +507,14 @@ namespace libtorrent
void set_max_uploads(int limit); void set_max_uploads(int limit);
void set_max_connections(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 // unless this returns true, new connections must wait
// with their initialization. // with their initialization.
bool ready_for_connections() const bool ready_for_connections() const
{ return m_connections_initialized; } { return m_connections_initialized; }
bool valid_metadata() const bool valid_metadata() const
{ return m_storage.get() != 0; } { return m_torrent_file.is_valid(); }
// parses the info section from the given // parses the info section from the given
// bencoded tree and moves the torrent // bencoded tree and moves the torrent
@ -519,6 +523,12 @@ namespace libtorrent
void set_metadata(entry const&); void set_metadata(entry const&);
private: 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<void(bool)> f);
void try_next_tracker(); void try_next_tracker();
int prioritize_tracker(int tracker_index); int prioritize_tracker(int tracker_index);
@ -552,7 +562,27 @@ namespace libtorrent
// if this pointer is 0, the torrent is in // if this pointer is 0, the torrent is in
// a state where the metadata hasn't been // a state where the metadata hasn't been
// received yet. // received yet.
boost::scoped_ptr<piece_manager> 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<piece_manager> 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 // the time of next tracker request
ptime m_next_request; ptime m_next_request;
@ -689,7 +719,7 @@ namespace libtorrent
// are opened through // are opened through
tcp::endpoint m_net_interface; tcp::endpoint m_net_interface;
boost::filesystem::path m_save_path; fs::path m_save_path;
// determines the storage state for this torrent. // determines the storage state for this torrent.
const bool m_compact_mode; const bool m_compact_mode;

View File

@ -54,6 +54,8 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
namespace fs = boost::filesystem;
namespace aux namespace aux
{ {
struct session_impl; struct session_impl;
@ -202,15 +204,22 @@ namespace libtorrent
int block_size; 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 struct TORRENT_EXPORT partial_piece_info
{ {
enum { max_blocks_per_piece = 256 }; enum { max_blocks_per_piece = 256 };
int piece_index; int piece_index;
int blocks_in_piece; int blocks_in_piece;
std::bitset<max_blocks_per_piece> requested_blocks; block_info blocks[max_blocks_per_piece];
std::bitset<max_blocks_per_piece> finished_blocks;
tcp::endpoint peer[max_blocks_per_piece];
int num_downloads[max_blocks_per_piece];
enum state_t { none, slow, medium, fast }; enum state_t { none, slow, medium, fast };
state_t piece_state; state_t piece_state;
}; };
@ -269,6 +278,8 @@ namespace libtorrent
// ================ end deprecation ============ // ================ end deprecation ============
void piece_availability(std::vector<int>& avail) const;
// priority must be within the range [0, 7] // priority must be within the range [0, 7]
void piece_priority(int index, int priority) const; void piece_priority(int index, int priority) const;
int piece_priority(int index) const; int piece_priority(int index) const;
@ -321,7 +332,7 @@ namespace libtorrent
// the ratio is uploaded / downloaded. less than 1 is not allowed // the ratio is uploaded / downloaded. less than 1 is not allowed
void set_ratio(float up_down_ratio) const; void set_ratio(float up_down_ratio) const;
boost::filesystem::path save_path() const; fs::path save_path() const;
// -1 means unlimited unchokes // -1 means unlimited unchokes
void set_max_uploads(int max_uploads) const; void set_max_uploads(int max_uploads) const;
@ -333,7 +344,7 @@ namespace libtorrent
, std::string const& password) const; , std::string const& password) const;
// post condition: save_path() == save_path if true is returned // 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 const sha1_hash& info_hash() const
{ return m_info_hash; } { return m_info_hash; }

View File

@ -62,16 +62,18 @@ namespace libtorrent
namespace pt = boost::posix_time; namespace pt = boost::posix_time;
namespace gr = boost::gregorian; namespace gr = boost::gregorian;
namespace fs = boost::filesystem;
struct TORRENT_EXPORT file_entry 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 offset; // the offset of this file inside the torrent
size_type size; // the size of this file size_type size; // the size of this file
// if the path was incorrectly encoded, this is // if the path was incorrectly encoded, this is
// the origianal corrupt encoded string. It is // the origianal corrupt encoded string. It is
// preserved in order to be able to reproduce // preserved in order to be able to reproduce
// the correct info-hash // the correct info-hash
boost::shared_ptr<const boost::filesystem::path> orig_path; boost::shared_ptr<const fs::path> orig_path;
}; };
struct TORRENT_EXPORT file_slice struct TORRENT_EXPORT file_slice
@ -109,7 +111,7 @@ namespace libtorrent
void set_piece_size(int size); void set_piece_size(int size);
void set_hash(int index, sha1_hash const& h); void set_hash(int index, sha1_hash const& h);
void add_tracker(std::string const& url, int tier = 0); 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); void add_url_seed(std::string const& url);
std::vector<file_slice> map_block(int piece, size_type offset, int size) const; std::vector<file_slice> map_block(int piece, size_type offset, int size) const;
@ -192,6 +194,8 @@ namespace libtorrent
// used by seeds // used by seeds
void seed_free(); void seed_free();
void swap(torrent_info& ti);
private: private:
void read_torrent_info(const entry& libtorrent); void read_torrent_info(const entry& libtorrent);

View File

@ -62,6 +62,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#include "libtorrent/time.hpp" #include "libtorrent/time.hpp"
#include "libtorrent/connection_queue.hpp" #include "libtorrent/connection_queue.hpp"
#include "libtorrent/intrusive_ptr_base.hpp"
namespace libtorrent namespace libtorrent
{ {
@ -148,15 +149,10 @@ namespace libtorrent
, request_callback* requester , request_callback* requester
, int maximum_tracker_response_length); , 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 struct TORRENT_EXPORT timeout_handler
: boost::noncopyable : intrusive_ptr_base<timeout_handler>
, 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); timeout_handler(asio::strand& str);
void set_timeout(int completion_timeout, int read_timeout); void set_timeout(int completion_timeout, int read_timeout);
@ -187,7 +183,6 @@ namespace libtorrent
typedef boost::mutex mutex_t; typedef boost::mutex mutex_t;
mutable mutex_t m_mutex; mutable mutex_t m_mutex;
mutable int m_refs;
}; };
struct TORRENT_EXPORT tracker_connection struct TORRENT_EXPORT tracker_connection

View File

@ -123,7 +123,7 @@ namespace libtorrent
void write_request(peer_request const& r); void write_request(peer_request const& r);
void write_cancel(peer_request const& r) {} void write_cancel(peer_request const& r) {}
void write_have(int index) {} 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 write_keepalive() {}
void on_connected(); void on_connected();

View File

@ -21,7 +21,9 @@ torrent_info.cpp tracker_manager.cpp http_connection.cpp \
http_tracker_connection.cpp udp_tracker_connection.cpp \ http_tracker_connection.cpp udp_tracker_connection.cpp \
alert.cpp identify_client.cpp ip_filter.cpp file.cpp metadata_transfer.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 \ 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 = \ noinst_HEADERS = \
$(top_srcdir)/include/libtorrent/alert.hpp \ $(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/buffer.hpp \
$(top_srcdir)/include/libtorrent/connection_queue.hpp \ $(top_srcdir)/include/libtorrent/connection_queue.hpp \
$(top_srcdir)/include/libtorrent/debug.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/entry.hpp \
$(top_srcdir)/include/libtorrent/escape_string.hpp \ $(top_srcdir)/include/libtorrent/escape_string.hpp \
$(top_srcdir)/include/libtorrent/extensions.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/http_tracker_connection.hpp \
$(top_srcdir)/include/libtorrent/identify_client.hpp \ $(top_srcdir)/include/libtorrent/identify_client.hpp \
$(top_srcdir)/include/libtorrent/instantiate_connection.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/invariant_check.hpp \
$(top_srcdir)/include/libtorrent/io.hpp \ $(top_srcdir)/include/libtorrent/io.hpp \
$(top_srcdir)/include/libtorrent/ip_filter.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/size_type.hpp \
$(top_srcdir)/include/libtorrent/socket.hpp \ $(top_srcdir)/include/libtorrent/socket.hpp \
$(top_srcdir)/include/libtorrent/socket_type.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/socks5_stream.hpp \
$(top_srcdir)/include/libtorrent/stat.hpp \ $(top_srcdir)/include/libtorrent/stat.hpp \
$(top_srcdir)/include/libtorrent/storage.hpp \ $(top_srcdir)/include/libtorrent/storage.hpp \

View File

@ -277,6 +277,8 @@ namespace libtorrent
void bt_peer_connection::write_pe1_2_dhkey() void bt_peer_connection::write_pe1_2_dhkey()
{ {
INVARIANT_CHECK;
assert(!m_encrypted); assert(!m_encrypted);
assert(!m_rc4_encrypted); assert(!m_rc4_encrypted);
assert(!m_DH_key_exchange.get()); assert(!m_DH_key_exchange.get());
@ -305,6 +307,8 @@ namespace libtorrent
void bt_peer_connection::write_pe3_sync() void bt_peer_connection::write_pe3_sync()
{ {
INVARIANT_CHECK;
assert (!m_encrypted); assert (!m_encrypted);
assert (!m_rc4_encrypted); assert (!m_rc4_encrypted);
assert (is_local()); assert (is_local());
@ -383,6 +387,8 @@ namespace libtorrent
void bt_peer_connection::write_pe4_sync(int crypto_select) void bt_peer_connection::write_pe4_sync(int crypto_select)
{ {
INVARIANT_CHECK;
assert(!is_local()); assert(!is_local());
assert(!m_encrypted); assert(!m_encrypted);
assert(!m_rc4_encrypted); assert(!m_rc4_encrypted);
@ -415,6 +421,8 @@ namespace libtorrent
void bt_peer_connection::write_pe_vc_cryptofield(buffer::interval& write_buf, void bt_peer_connection::write_pe_vc_cryptofield(buffer::interval& write_buf,
int crypto_field, int pad_size) int crypto_field, int pad_size)
{ {
INVARIANT_CHECK;
assert(crypto_field <= 0x03 && crypto_field > 0); assert(crypto_field <= 0x03 && crypto_field > 0);
assert(pad_size == 0); // pad not used yet assert(pad_size == 0); // pad not used yet
// vc,crypto_field,len(pad),pad, (len(ia)) // 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) void bt_peer_connection::init_pe_RC4_handler(char const* secret, sha1_hash const& stream_key)
{ {
INVARIANT_CHECK;
assert(secret); assert(secret);
hasher h; hasher h;
@ -483,8 +493,9 @@ namespace libtorrent
assert (begin); assert (begin);
assert (end); assert (end);
assert (end > begin); 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); m_RC4_handler->encrypt(begin, end - begin);
peer_connection::send_buffer(begin, end); peer_connection::send_buffer(begin, end);
@ -492,7 +503,9 @@ namespace libtorrent
buffer::interval bt_peer_connection::allocate_send_buffer(int size) 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); m_enc_send_buffer = peer_connection::allocate_send_buffer(size);
return m_enc_send_buffer; return m_enc_send_buffer;
@ -506,7 +519,9 @@ namespace libtorrent
void bt_peer_connection::setup_send() 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.begin);
assert (m_enc_send_buffer.end); assert (m_enc_send_buffer.end);
@ -1129,6 +1144,7 @@ namespace libtorrent
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
assert(!in_handshake());
boost::shared_ptr<torrent> t = associated_torrent().lock(); boost::shared_ptr<torrent> t = associated_torrent().lock();
assert(t); assert(t);
assert(m_sent_bitfield == false); assert(m_sent_bitfield == false);
@ -1319,7 +1335,7 @@ namespace libtorrent
send_buffer(msg, msg + packet_size); 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; INVARIANT_CHECK;
@ -1334,9 +1350,7 @@ namespace libtorrent
detail::write_uint8(msg_piece, i.begin); detail::write_uint8(msg_piece, i.begin);
detail::write_int32(r.piece, i.begin); detail::write_int32(r.piece, i.begin);
detail::write_int32(r.start, i.begin); detail::write_int32(r.start, i.begin);
std::memcpy(i.begin, buffer, r.length);
t->filesystem().read(
i.begin, r.piece, r.start, r.length);
assert(i.begin + r.length == i.end); assert(i.begin + r.length == i.end);
@ -1357,10 +1371,11 @@ namespace libtorrent
return p.connection != m_pc return p.connection != m_pc
&& p.connection && p.connection
&& p.connection->pid() == m_id && 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; peer_connection const* m_pc;
}; };
} }
@ -1382,6 +1397,7 @@ namespace libtorrent
m_statistics.received_bytes(0, bytes_transferred); m_statistics.received_bytes(0, bytes_transferred);
#ifndef TORRENT_DISABLE_ENCRYPTION #ifndef TORRENT_DISABLE_ENCRYPTION
assert(in_handshake() || !m_rc4_encrypted || m_encrypted);
if (m_rc4_encrypted && m_encrypted) if (m_rc4_encrypted && m_encrypted)
{ {
buffer::interval wr_buf = wr_recv_buffer(); buffer::interval wr_buf = wr_recv_buffer();
@ -1781,6 +1797,9 @@ namespace libtorrent
{ {
recv_buffer.begin += pad_size; recv_buffer.begin += pad_size;
int len_ia = detail::read_int16(recv_buffer.begin); 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 #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << " len(IA) : " << len_ia << "\n"; (*m_logger) << " len(IA) : " << len_ia << "\n";
#endif #endif
@ -1972,8 +1991,6 @@ namespace libtorrent
, (char*)info_hash.begin()); , (char*)info_hash.begin());
attach_to_torrent(info_hash); attach_to_torrent(info_hash);
t = associated_torrent().lock();
assert(t);
} }
else else
{ {
@ -1990,17 +2007,15 @@ namespace libtorrent
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << " info_hash received\n"; (*m_logger) << " info_hash received\n";
#endif #endif
t = associated_torrent().lock();
assert(t);
} }
// Respond with handshake and bitfield t = associated_torrent().lock();
assert(t);
if (!is_local()) if (!is_local())
{ {
write_handshake(); write_handshake();
} }
if (t->valid_metadata())
write_bitfield(t->pieces());
assert(t->get_policy().has_connection(this)); assert(t->get_policy().has_connection(this));
@ -2130,6 +2145,8 @@ namespace libtorrent
m_state = read_packet_size; m_state = read_packet_size;
reset_recv_buffer(4); reset_recv_buffer(4);
if (t->valid_metadata())
write_bitfield(t->pieces());
assert(!packet_finished()); assert(!packet_finished());
return; return;
@ -2239,8 +2256,10 @@ namespace libtorrent
void bt_peer_connection::check_invariant() const void bt_peer_connection::check_invariant() const
{ {
#ifndef TORRENT_DISABLE_ENCRYPTION #ifndef TORRENT_DISABLE_ENCRYPTION
assert(bool(m_state == read_pe_dhkey) == bool(m_DH_key_exchange) assert( (bool(m_state != read_pe_dhkey) || m_DH_key_exchange.get())
|| !is_local()); || !is_local());
assert(!m_rc4_encrypted || m_RC4_handler.get());
#endif #endif
if (!m_in_constructor) if (!m_in_constructor)
peer_connection::check_invariant(); peer_connection::check_invariant();
@ -2258,4 +2277,3 @@ namespace libtorrent
} }

View File

@ -278,6 +278,12 @@ namespace libtorrent
} }
} }
void entry::swap(entry& e)
{
// not implemented
assert(false);
}
void entry::print(std::ostream& os, int indent) const void entry::print(std::ostream& os, int indent) const
{ {
assert(indent >= 0); assert(indent >= 0);

View File

@ -82,8 +82,6 @@ BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);
#endif #endif
namespace fs = boost::filesystem;
namespace namespace
{ {
enum { mode_in = 1, mode_out = 2 }; enum { mode_in = 1, mode_out = 2 };
@ -130,6 +128,8 @@ namespace
namespace libtorrent namespace libtorrent
{ {
namespace fs = boost::filesystem;
const file::open_mode file::in(mode_in); const file::open_mode file::in(mode_in);
const file::open_mode file::out(mode_out); const file::open_mode file::out(mode_out);
@ -248,15 +248,15 @@ namespace libtorrent
void set_size(size_type s) void set_size(size_type s)
{ {
size_type pos = tell(); size_type pos = tell();
seek(1, 0); seek(s - 1);
char dummy = 0; char dummy = 0;
read(&dummy, 1); read(&dummy, 1);
seek(1, 0); seek(s - 1);
write(&dummy, 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_open_mode);
assert(m_fd != -1); assert(m_fd != -1);
@ -303,13 +303,13 @@ namespace libtorrent
file::file() : m_impl(new impl()) {} 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)) : m_impl(new impl(p, m.m_mask))
{} {}
file::~file() {} 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); m_impl->open(p, m.m_mask);
} }

View File

@ -237,7 +237,7 @@ void http_connection::on_read(asio::error_code const& e
data = m_parser.get_body().begin; data = m_parser.get_body().begin;
size = m_parser.get_body().left(); size = m_parser.get_body().left();
} }
m_handler(asio::error_code(), m_parser, data, size); m_handler(e, m_parser, data, size);
return; return;
} }

View File

@ -411,6 +411,12 @@ namespace libtorrent
std::min(req.num_want, 999)); std::min(req.num_want, 999));
m_send_buffer += '&'; 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 #ifndef TORRENT_DISABLE_ENCRYPTION
m_send_buffer += "supportcrypto=1&"; m_send_buffer += "supportcrypto=1&";

View File

@ -197,7 +197,7 @@ namespace
, {"XT", "XanTorrent"} , {"XT", "XanTorrent"}
, {"XX", "Xtorrent"} , {"XX", "Xtorrent"}
, {"ZT", "ZipTorrent"} , {"ZT", "ZipTorrent"}
, {"lt", "libTorrent (libtorrent.rakshasa.no/}"} , {"lt", "rTorrent"}
, {"pX", "pHoeniX"} , {"pX", "pHoeniX"}
, {"qB", "qBittorrent"} , {"qB", "qBittorrent"}
}; };

View File

@ -67,6 +67,12 @@ namespace libtorrent
if (ps.type == proxy_settings::socks5_pw) if (ps.type == proxy_settings::socks5_pw)
s->get<socks5_stream>().set_username(ps.username, ps.password); s->get<socks5_stream>().set_username(ps.username, ps.password);
} }
else if (ps.type == proxy_settings::socks4)
{
s->instantiate<socks4_stream>();
s->get<socks4_stream>().set_proxy(ps.hostname, ps.port);
s->get<socks4_stream>().set_username(ps.username);
}
else else
{ {
throw std::runtime_error("unsupported proxy type"); throw std::runtime_error("unsupported proxy type");

View File

@ -69,6 +69,15 @@ namespace libtorrent
, m_filter6.export_filter()); , 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 void ip_filter::print() const
{ {

View File

@ -53,17 +53,20 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/peer_request.hpp" #include "libtorrent/peer_request.hpp"
#include "libtorrent/peer_connection.hpp" #include "libtorrent/peer_connection.hpp"
namespace libtorrent { namespace namespace libtorrent {
namespace fs = boost::filesystem;
namespace
{ {
struct logger_peer_plugin : peer_plugin struct logger_peer_plugin : peer_plugin
{ {
logger_peer_plugin(std::string const& filename) logger_peer_plugin(std::string const& filename)
{ {
using namespace boost::filesystem; fs::path dir(fs::complete("libtorrent_ext_logs"));
path dir(complete("libtorrent_ext_logs")); if (!fs::exists(dir)) fs::create_directories(dir);
if (!exists(dir)) create_directories(dir); m_file.open((dir / filename).string().c_str(), std::ios_base::out | std::ios_base::out);
m_file.open(dir / filename, std::ios_base::out | std::ios_base::out);
m_file << "\n\n\n"; m_file << "\n\n\n";
log_timestamp(); log_timestamp();
m_file << "*** starting log ***\n"; m_file << "*** starting log ***\n";
@ -201,7 +204,7 @@ namespace libtorrent { namespace
} }
private: private:
boost::filesystem::ofstream m_file; std::ofstream m_file;
}; };
struct logger_plugin : torrent_plugin struct logger_plugin : torrent_plugin

View File

@ -38,8 +38,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/convenience.hpp>
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
@ -56,6 +54,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/torrent.hpp" #include "libtorrent/torrent.hpp"
#include "libtorrent/extensions.hpp" #include "libtorrent/extensions.hpp"
#include "libtorrent/extensions/metadata_transfer.hpp" #include "libtorrent/extensions/metadata_transfer.hpp"
#include "libtorrent/alert_types.hpp"
namespace libtorrent { namespace namespace libtorrent { namespace
{ {
@ -176,14 +175,13 @@ namespace libtorrent { namespace
, false); , false);
m_metadata_progress = 0; m_metadata_progress = 0;
m_metadata_size = 0; m_metadata_size = 0;
// TODO: allow plugins to post alerts
/* if (m_torrent.alerts().should_post(alert::info))
if (m_ses.m_alerts.should_post(alert::info))
{ {
m_ses.m_alerts.post_alert(metadata_failed_alert( m_torrent.alerts().post_alert(metadata_failed_alert(
get_handle(), "invalid metadata received from swarm")); m_torrent.get_handle(), "invalid metadata received from swarm"));
} }
*/
return false; return false;
} }

View File

@ -59,21 +59,6 @@ using libtorrent::aux::session_impl;
namespace libtorrent 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 // outbound connection
peer_connection::peer_connection( peer_connection::peer_connection(
session_impl& ses session_impl& ses
@ -94,6 +79,7 @@ namespace libtorrent
, m_packet_size(0) , m_packet_size(0)
, m_recv_pos(0) , m_recv_pos(0)
, m_current_send_buffer(0) , m_current_send_buffer(0)
, m_reading_bytes(0)
, m_write_pos(0) , m_write_pos(0)
, m_last_receive(time_now()) , m_last_receive(time_now())
, m_last_sent(time_now()) , m_last_sent(time_now())
@ -122,12 +108,14 @@ namespace libtorrent
, m_prefer_whole_pieces(false) , m_prefer_whole_pieces(false)
, m_request_large_blocks(false) , m_request_large_blocks(false)
, m_non_prioritized(false) , m_non_prioritized(false)
, m_refs(0)
, m_upload_limit(resource_request::inf) , m_upload_limit(resource_request::inf)
, m_download_limit(resource_request::inf) , m_download_limit(resource_request::inf)
, m_peer_info(peerinfo) , m_peer_info(peerinfo)
, m_speed(slow) , m_speed(slow)
, m_connection_ticket(-1) , m_connection_ticket(-1)
, m_remote_bytes_dled(0)
, m_remote_dl_rate(0)
, m_remote_dl_update(time_now())
#ifndef NDEBUG #ifndef NDEBUG
, m_in_constructor(true) , m_in_constructor(true)
#endif #endif
@ -167,6 +155,7 @@ namespace libtorrent
, m_packet_size(0) , m_packet_size(0)
, m_recv_pos(0) , m_recv_pos(0)
, m_current_send_buffer(0) , m_current_send_buffer(0)
, m_reading_bytes(0)
, m_write_pos(0) , m_write_pos(0)
, m_last_receive(time_now()) , m_last_receive(time_now())
, m_last_sent(time_now()) , m_last_sent(time_now())
@ -193,11 +182,13 @@ namespace libtorrent
, m_prefer_whole_pieces(false) , m_prefer_whole_pieces(false)
, m_request_large_blocks(false) , m_request_large_blocks(false)
, m_non_prioritized(false) , m_non_prioritized(false)
, m_refs(0)
, m_upload_limit(resource_request::inf) , m_upload_limit(resource_request::inf)
, m_download_limit(resource_request::inf) , m_download_limit(resource_request::inf)
, m_peer_info(peerinfo) , m_peer_info(peerinfo)
, m_speed(slow) , m_speed(slow)
, m_remote_bytes_dled(0)
, m_remote_dl_rate(0)
, m_remote_dl_update(time_now())
#ifndef NDEBUG #ifndef NDEBUG
, m_in_constructor(true) , m_in_constructor(true)
#endif #endif
@ -742,8 +733,18 @@ namespace libtorrent
&& !is_interesting() && !is_interesting()
&& t->picker().piece_priority(index) != 0) && t->picker().piece_priority(index) != 0)
t->get_policy().peer_is_interesting(*this); 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()) if (is_seed())
{ {
assert(m_peer_info); assert(m_peer_info);
@ -1012,7 +1013,7 @@ namespace libtorrent
for (std::vector<piece_picker::downloading_piece>::const_iterator i = for (std::vector<piece_picker::downloading_piece>::const_iterator i =
dl_queue.begin(); i != dl_queue.end(); ++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_picker& picker = t->picker();
piece_manager& fs = t->filesystem(); piece_manager& fs = t->filesystem();
policy& pol = t->get_policy();
std::vector<piece_block> finished_blocks; std::vector<piece_block> finished_blocks;
piece_block block_finished(p.piece, p.start / t->block_size()); piece_block block_finished(p.piece, p.start / t->block_size());
@ -1125,13 +1125,12 @@ namespace libtorrent
} }
else else
{ {
// cancel the block from the /* // cancel the block from the
// peer that has taken over it. // peer that has taken over it.
boost::optional<tcp::endpoint> peer boost::optional<tcp::endpoint> peer
= t->picker().get_downloader(block_finished); = 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); peer_connection* pc = t->connection_for(*peer);
if (pc && pc != this) if (pc && pc != this)
{ {
@ -1140,7 +1139,7 @@ namespace libtorrent
} }
} }
else else
{ */ {
if (t->alerts().should_post(alert::debug)) if (t->alerts().should_post(alert::debug))
{ {
t->alerts().post_alert( t->alerts().post_alert(
@ -1153,15 +1152,28 @@ namespace libtorrent
(*m_logger) << " *** The block we just got was not in the " (*m_logger) << " *** The block we just got was not in the "
"request queue ***\n"; "request queue ***\n";
#endif #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 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()); t->received_redundant_data(p.length);
pol.block_finished(*this, block_finished);
send_block_requests(); if (!has_peer_choked())
{
request_a_block(*t, *this);
send_block_requests();
}
if (request_peer && !request_peer->has_peer_choked() && !t->is_seed()) if (request_peer && !request_peer->has_peer_choked() && !t->is_seed())
{ {
@ -1171,107 +1183,73 @@ namespace libtorrent
return; return;
} }
fs.write(data, p.piece, p.start, p.length); fs.async_write(p, data, bind(&peer_connection::on_disk_write_complete
, self(), _1, _2, p, t));
picker.mark_as_finished(block_finished, m_remote); picker.mark_as_writing(block_finished, m_remote);
try
{
pol.block_finished(*this, block_finished);
send_block_requests();
}
catch (std::exception const&) {}
if (request_peer && !request_peer->has_peer_choked() && !t->is_seed()) if (request_peer && !request_peer->has_peer_choked() && !t->is_seed())
{ {
request_a_block(*t, *request_peer); request_a_block(*t, *request_peer);
request_peer->send_block_requests(); 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<torrent> 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 #ifndef NDEBUG
try try
{ {
#endif #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? // did we just finish the piece?
if (picker.is_piece_finished(p.piece)) if (picker.is_piece_finished(p.piece))
{ {
#ifndef NDEBUG #ifndef NDEBUG
check_postcondition post_checker2_(t, false); check_postcondition post_checker2_(t, false);
#endif #endif
bool verified = t->verify_piece(p.piece); t->async_verify_piece(p.piece, bind(&torrent::piece_finished, t
if (verified) , p.piece, _1));
{
// 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
} }
#ifndef NDEBUG #ifndef NDEBUG
@ -1350,7 +1328,7 @@ namespace libtorrent
assert(block.piece_index < t->torrent_file().num_pieces()); assert(block.piece_index < t->torrent_file().num_pieces());
assert(block.block_index >= 0); assert(block.block_index >= 0);
assert(block.block_index < t->torrent_file().piece_size(block.piece_index)); 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; piece_picker::piece_state_t state;
peer_speed_t speed = peer_speed(); peer_speed_t speed = peer_speed();
@ -1376,7 +1354,7 @@ namespace libtorrent
assert(block.piece_index < t->torrent_file().num_pieces()); assert(block.piece_index < t->torrent_file().num_pieces());
assert(block.block_index >= 0); assert(block.block_index >= 0);
assert(block.block_index < t->torrent_file().piece_size(block.piece_index)); 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); t->picker().abort_download(block);
@ -1603,6 +1581,8 @@ namespace libtorrent
void peer_connection::disconnect() void peer_connection::disconnect()
{ {
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
boost::intrusive_ptr<peer_connection> me(this); boost::intrusive_ptr<peer_connection> me(this);
INVARIANT_CHECK; INVARIANT_CHECK;
@ -1753,12 +1733,14 @@ namespace libtorrent
p.failcount = peer_info_struct()->failcount; p.failcount = peer_info_struct()->failcount;
p.num_hashfails = peer_info_struct()->hashfails; p.num_hashfails = peer_info_struct()->hashfails;
p.flags |= peer_info_struct()->on_parole ? peer_info::on_parole : 0; p.flags |= peer_info_struct()->on_parole ? peer_info::on_parole : 0;
p.remote_dl_rate = m_remote_dl_rate;
} }
else else
{ {
p.source = 0; p.source = 0;
p.failcount = 0; p.failcount = 0;
p.num_hashfails = 0; p.num_hashfails = 0;
p.remote_dl_rate = 0;
} }
p.send_buffer_size = send_buffer_size(); p.send_buffer_size = send_buffer_size();
@ -1868,8 +1850,11 @@ namespace libtorrent
m_assume_fifo = true; m_assume_fifo = true;
request_a_block(*t, *this); if (!has_peer_choked())
send_block_requests(); {
request_a_block(*t, *this);
send_block_requests();
}
} }
} }
@ -1915,6 +1900,21 @@ namespace libtorrent
, m_upload_limit)); , 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(); fill_send_buffer();
/* /*
size_type diff = share_diff(); size_type diff = share_diff();
@ -1970,7 +1970,7 @@ namespace libtorrent
else if (buffer_size_watermark > 80 * 1024) buffer_size_watermark = 80 * 1024; else if (buffer_size_watermark > 80 * 1024) buffer_size_watermark = 80 * 1024;
while (!m_requests.empty() while (!m_requests.empty()
&& (send_buffer_size() < buffer_size_watermark) && (send_buffer_size() + m_reading_bytes < buffer_size_watermark)
&& !m_choked) && !m_choked)
{ {
assert(t->valid_metadata()); assert(t->valid_metadata());
@ -1982,16 +1982,12 @@ namespace libtorrent
assert(r.start + r.length <= t->torrent_file().piece_size(r.piece)); assert(r.start + r.length <= t->torrent_file().piece_size(r.piece));
assert(r.length > 0 && r.start >= 0); assert(r.length > 0 && r.start >= 0);
write_piece(r); t->filesystem().async_read(r, bind(&peer_connection::on_disk_read_complete
, self(), _1, _2, r));
#ifdef TORRENT_VERBOSE_LOGGING m_reading_bytes += r.length;
(*m_logger) << time_now_string()
<< " ==> PIECE [ piece: " << r.piece << " | s: " << r.start
<< " | l: " << r.length << " ]\n";
#endif
m_requests.erase(m_requests.begin()); m_requests.erase(m_requests.begin());
/*
if (m_requests.empty() if (m_requests.empty()
&& m_num_invalid_requests > 0 && m_num_invalid_requests > 0
&& is_peer_interested() && is_peer_interested()
@ -2004,9 +2000,49 @@ namespace libtorrent
send_choke(); send_choke();
send_unchoke(); 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<torrent> 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) void peer_connection::assign_bandwidth(int channel, int amount)
{ {
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
@ -2599,11 +2635,13 @@ namespace libtorrent
time_duration d2; time_duration d2;
d1 = now - m_became_uninterested; d1 = now - m_became_uninterested;
d2 = now - m_became_uninteresting; 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 if (!m_interesting
&& !m_peer_interested && !m_peer_interested
&& d1 > minutes(10) && d1 > time_limit
&& d2 > minutes(10)) && d2 > time_limit)
{ {
return true; return true;
} }
@ -2663,3 +2701,4 @@ namespace libtorrent
} }
} }

View File

@ -88,8 +88,9 @@ namespace libtorrent
// pieces is a bitmask with the pieces we have // pieces is a bitmask with the pieces we have
void piece_picker::files_checked( void piece_picker::files_checked(
const std::vector<bool>& pieces std::vector<bool> const& pieces
, const std::vector<downloading_piece>& unfinished) , std::vector<downloading_piece> const& unfinished
, std::vector<int>& verify_pieces)
{ {
#ifndef NDEBUG #ifndef NDEBUG
m_files_checked_called = true; m_files_checked_called = true;
@ -118,14 +119,12 @@ namespace libtorrent
tcp::endpoint peer; tcp::endpoint peer;
for (int j = 0; j < m_blocks_per_piece; ++j) 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); mark_as_finished(piece_block(i->index, j), peer);
} }
if (is_piece_finished(i->index)) if (is_piece_finished(i->index))
{ {
// TODO: handle this case by verifying the verify_pieces.push_back(i->index);
// piece and either accept it or discard it
assert(false);
} }
} }
} }
@ -212,8 +211,7 @@ namespace libtorrent
for (int i = 0; i < m_blocks_per_piece; ++i) for (int i = 0; i < m_blocks_per_piece; ++i)
{ {
ret.info[i].num_downloads = 0; ret.info[i].num_downloads = 0;
ret.info[i].requested = 0; ret.info[i].state = block_info::state_none;
ret.info[i].finished = 0;
ret.info[i].peer = tcp::endpoint(); ret.info[i].peer = tcp::endpoint();
} }
return ret; return ret;
@ -258,25 +256,28 @@ namespace libtorrent
int num_blocks = blocks_in_piece(i->index); int num_blocks = blocks_in_piece(i->index);
int num_requested = 0; int num_requested = 0;
int num_finished = 0; int num_finished = 0;
int num_writing = 0;
for (int k = 0; k < num_blocks; ++k) for (int k = 0; k < num_blocks; ++k)
{ {
if (i->info[k].finished) if (i->info[k].state == block_info::state_finished)
{ {
++num_finished; ++num_finished;
assert(i->info[k].requested);
++num_requested;
continue; continue;
} }
if (i->info[k].requested) if (i->info[k].state == block_info::state_requested)
{ {
++num_requested; ++num_requested;
blocks_requested = true; blocks_requested = true;
} }
if (i->info[k].state == block_info::state_writing)
{
++num_writing;
}
} }
assert(blocks_requested == (i->state != none)); assert(blocks_requested == (i->state != none));
assert(num_requested == i->requested); assert(num_requested == i->requested);
assert(num_writing == i->writing);
assert(num_finished == i->finished); 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) for (int j = 0; j < num_blocks_in_piece; ++j)
{ {
piece_picker::block_info const& info = p.info[j]; piece_picker::block_info const& info = p.info[j];
if ((info.finished == 1 if (info.state != piece_picker::block_info::state_none
|| info.requested == 1)
&& info.peer != peer && info.peer != peer
&& info.peer != tcp::endpoint()) && info.peer != tcp::endpoint())
{ {
@ -1089,6 +1089,9 @@ namespace libtorrent
, int num_blocks, bool prefer_whole_pieces , int num_blocks, bool prefer_whole_pieces
, tcp::endpoint peer, piece_state_t speed) const , 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<int>::const_iterator i = piece_list.begin(); for (std::vector<int>::const_iterator i = piece_list.begin();
i != piece_list.end(); ++i) i != piece_list.end(); ++i)
{ {
@ -1098,10 +1101,6 @@ namespace libtorrent
// if the peer doesn't have the piece // if the peer doesn't have the piece
// skip it // skip it
if (!pieces[*i]) continue; 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); 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) for (int j = 0; j < num_blocks_in_piece; ++j)
{ {
block_info const& info = p->info[j]; block_info const& info = p->info[j];
if (info.finished) continue; if (info.state == block_info::state_finished
if (info.requested || info.state == block_info::state_writing)
continue;
if (info.state == block_info::state_requested
&& info.peer == peer) continue; && info.peer == peer) continue;
backup_blocks.push_back(piece_block(*i, j)); backup_blocks.push_back(piece_block(*i, j));
} }
@ -1142,9 +1143,13 @@ namespace libtorrent
{ {
// ignore completed blocks // ignore completed blocks
block_info const& info = p->info[j]; 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 // 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, // if the piece is fast and the peer is slow, or vice versa,
// add the block as a backup. // add the block as a backup.
// override this behavior if all the other blocks // override this behavior if all the other blocks
@ -1169,7 +1174,7 @@ namespace libtorrent
// blocks that have not been requested from any // blocks that have not been requested from any
// other peer. // other peer.
interesting_blocks.push_back(piece_block(*i, j)); 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 // we have found a block that's free to download
num_blocks--; num_blocks--;
@ -1217,11 +1222,18 @@ namespace libtorrent
int max_blocks = blocks_in_piece(index); int max_blocks = blocks_in_piece(index);
if ((int)i->finished < max_blocks) return false; 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; 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.piece_index >= 0);
assert(block.block_index >= 0); assert(block.block_index >= 0);
@ -1235,7 +1247,22 @@ namespace libtorrent
, has_index(block.piece_index)); , has_index(block.piece_index));
assert(i != m_downloads.end()); 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<downloading_piece>::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 bool piece_picker::is_finished(piece_block block) const
@ -1249,7 +1276,7 @@ namespace libtorrent
std::vector<downloading_piece>::const_iterator i std::vector<downloading_piece>::const_iterator i
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index)); = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
assert(i != m_downloads.end()); 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.state = state;
dp.index = block.piece_index; dp.index = block.piece_index;
block_info& info = dp.info[block.block_index]; block_info& info = dp.info[block.block_index];
info.requested = 1; info.state = block_info::state_requested;
info.peer = peer; info.peer = peer;
++dp.requested; ++dp.requested;
} }
@ -1284,15 +1311,26 @@ namespace libtorrent
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index)); = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
assert(i != m_downloads.end()); assert(i != m_downloads.end());
block_info& info = i->info[block.block_index]; block_info& info = i->info[block.block_index];
assert(info.requested == 0); assert(info.state == block_info::state_none);
info.peer = peer; info.peer = peer;
info.requested = 1; info.state = block_info::state_requested;
++i->requested; ++i->requested;
if (i->state == none) i->state = state; 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<int>& avail) const
{
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
avail.resize(m_piece_map.size());
std::vector<int>::iterator j = avail.begin();
for (std::vector<piece_pos>::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; TORRENT_PIECE_PICKER_INVARIANT_CHECK;
@ -1302,10 +1340,11 @@ namespace libtorrent
assert(block.block_index < blocks_in_piece(block.piece_index)); assert(block.block_index < blocks_in_piece(block.piece_index));
piece_pos& p = m_piece_map[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; p.downloading = 1;
if (prio > 0) move(prio, p.index); if (prio > 0) move(prio, p.index);
else assert(p.priority(m_sequenced_download_threshold) == 0); else assert(p.priority(m_sequenced_download_threshold) == 0);
@ -1314,25 +1353,84 @@ namespace libtorrent
dp.state = none; dp.state = none;
dp.index = block.piece_index; dp.index = block.piece_index;
block_info& info = dp.info[block.block_index]; block_info& info = dp.info[block.block_index];
info.requested = 1; info.peer = peer;
info.finished = 1; if (info.state == block_info::state_requested) --dp.requested;
++dp.requested; assert(dp.requested >= 0);
++dp.finished; assert (info.state != block_info::state_finished);
dp.info[block.block_index].peer = peer; 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<downloading_piece>::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 else
{ {
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
std::vector<downloading_piece>::iterator i std::vector<downloading_piece>::iterator i
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index)); = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
assert(i != m_downloads.end()); assert(i != m_downloads.end());
block_info& info = i->info[block.block_index]; block_info& info = i->info[block.block_index];
info.peer = peer; info.peer = peer;
if (!info.requested) ++i->requested; assert(info.state == block_info::state_writing
info.requested = 1; || peer == tcp::endpoint());
if (!info.finished) ++i->finished; if (info.state == block_info::state_writing) --i->writing;
info.finished = 1; 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. // there are no blocks requested in this piece.
// remove the fast/slow state from it // remove the fast/slow state from it
@ -1367,8 +1465,7 @@ namespace libtorrent
assert(block.block_index >= 0); assert(block.block_index >= 0);
if (i->info[block.block_index].requested == false if (i->info[block.block_index].state == block_info::state_none)
|| i->info[block.block_index].requested == true)
return boost::optional<tcp::endpoint>(); return boost::optional<tcp::endpoint>();
return boost::optional<tcp::endpoint>(i->info[block.block_index].peer); return boost::optional<tcp::endpoint>(i->info[block.block_index].peer);
@ -1394,17 +1491,17 @@ namespace libtorrent
, m_downloads.end(), has_index(block.piece_index)); , m_downloads.end(), has_index(block.piece_index));
assert(i != m_downloads.end()); 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; return;
} }
assert(block.block_index < blocks_in_piece(block.piece_index)); 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 // 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; --i->requested;
// clear the downloader of this block // clear the downloader of this block
@ -1412,7 +1509,7 @@ namespace libtorrent
// if there are no other blocks in this piece // if there are no other blocks in this piece
// that's being downloaded, remove it from the list // 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); erase_download_piece(i);
piece_pos& p = m_piece_map[block.piece_index]; 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() assert(std::find_if(m_downloads.begin(), m_downloads.end()
, has_index(block.piece_index)) == 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. // there are no blocks requested in this piece.
// remove the fast/slow state from it // remove the fast/slow state from it

View File

@ -142,7 +142,19 @@ namespace
bool operator()(policy::peer const& p) const bool operator()(policy::peer const& p) const
{ return p.ip.address() == m_ip.address(); } { 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 struct match_peer_connection
@ -152,9 +164,13 @@ namespace
{} {}
bool operator()(policy::peer const& p) const 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<piece_block>::iterator i = interesting_pieces.begin(); for (std::vector<piece_block>::iterator i = interesting_pieces.begin();
i != interesting_pieces.end(); ++i) i != interesting_pieces.end(); ++i)
{ {
if (p.is_downloading(*i)) if (p.is_requested(*i))
{ {
busy_pieces.push_back(*i); busy_pieces.push_back(*i);
continue; continue;
@ -524,6 +540,8 @@ namespace libtorrent
int max_failcount = m_torrent->settings().max_failcount; int max_failcount = m_torrent->settings().max_failcount;
int min_reconnect_time = m_torrent->settings().min_reconnect_time; 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) for (iterator i = m_peers.begin(); i != m_peers.end(); ++i)
{ {
if (i->connection) continue; if (i->connection) continue;
@ -533,6 +551,8 @@ namespace libtorrent
if (i->failcount >= max_failcount) continue; if (i->failcount >= max_failcount) continue;
if (now - i->connected < seconds(i->failcount * min_reconnect_time)) if (now - i->connected < seconds(i->failcount * min_reconnect_time))
continue; continue;
if (ses.m_port_filter.access(i->ip.port()) & port_filter::blocked)
continue;
assert(i->connected <= now); assert(i->connected <= now);
@ -846,12 +866,13 @@ namespace libtorrent
--m_num_unchoked; --m_num_unchoked;
} while (m_num_unchoked > m_torrent->m_uploads_quota.given); } 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' // optimistic unchoke. trade the 'worst'
// unchoked peer with one of the choked // 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()); assert(m_num_unchoked <= m_torrent->num_peers());
iterator p = find_unchoke_candidate(); iterator p = find_unchoke_candidate();
if (p != m_peers.end()) 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) void policy::new_connection(peer_connection& c)
{ {
assert(!c.is_local()); assert(!c.is_local());
@ -902,7 +939,10 @@ namespace libtorrent
if (m_torrent->settings().allow_multiple_connections_per_ip) 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 else
{ {
@ -968,13 +1008,29 @@ namespace libtorrent
if(remote.address() == address() || remote.port() == 0) if(remote.address() == address() || remote.port() == 0)
return; 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 try
{ {
iterator i; iterator i;
if (m_torrent->settings().allow_multiple_connections_per_ip) 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 else
{ {
@ -986,8 +1042,6 @@ namespace libtorrent
if (i == m_peers.end()) if (i == m_peers.end())
{ {
aux::session_impl& ses = m_torrent->session();
// if the IP is blocked, don't add it // if the IP is blocked, don't add it
if (ses.m_ip_filter.access(remote.address()) & ip_filter::blocked) 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 // this is called when we are unchoked by a peer
// i.e. a peer lets us know that we will receive // i.e. a peer lets us know that we will receive
// data from now on // data from now on
@ -1167,6 +1209,7 @@ namespace libtorrent
c.add_free_upload(-diff); c.add_free_upload(-diff);
} }
} }
/*
if (!c.is_choked()) if (!c.is_choked())
{ {
c.send_choke(); c.send_choke();
@ -1175,6 +1218,7 @@ namespace libtorrent
if (m_torrent->is_seed()) seed_unchoke_one_peer(); if (m_torrent->is_seed()) seed_unchoke_one_peer();
else unchoke_one_peer(); else unchoke_one_peer();
} }
*/
} }
bool policy::unchoke_one_peer() bool policy::unchoke_one_peer()

View File

@ -143,10 +143,20 @@ namespace libtorrent
m_impl->set_ip_filter(f); 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) void session::set_peer_id(peer_id const& id)
{ {
m_impl->set_peer_id(id); m_impl->set_peer_id(id);
} }
peer_id session::id() const
{
return m_impl->get_peer_id();
}
void session::set_key(int key) void session::set_key(int key)
{ {
@ -167,7 +177,7 @@ namespace libtorrent
// if the torrent already exists, this will throw duplicate_torrent // if the torrent already exists, this will throw duplicate_torrent
torrent_handle session::add_torrent( torrent_handle session::add_torrent(
torrent_info const& ti torrent_info const& ti
, boost::filesystem::path const& save_path , fs::path const& save_path
, entry const& resume_data , entry const& resume_data
, bool compact_mode , bool compact_mode
, int block_size , int block_size
@ -181,7 +191,7 @@ namespace libtorrent
char const* tracker_url char const* tracker_url
, sha1_hash const& info_hash , sha1_hash const& info_hash
, char const* name , char const* name
, boost::filesystem::path const& save_path , fs::path const& save_path
, entry const& e , entry const& e
, bool compact_mode , bool compact_mode
, int block_size , int block_size
@ -372,6 +382,36 @@ namespace libtorrent
m_impl->set_severity_level(s); 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() connection_queue& session::get_connection_queue()
{ {
return m_impl->m_half_open; return m_impl->m_half_open;

View File

@ -81,7 +81,11 @@ using boost::bind;
using boost::mutex; using boost::mutex;
using libtorrent::aux::session_impl; 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 std::string generate_auth_string(std::string const& user
@ -412,7 +416,6 @@ namespace libtorrent { namespace detail
for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i for (std::deque<boost::shared_ptr<piece_checker_data> >::iterator i
= m_processing.begin(); i != m_processing.end(); ++i) = m_processing.begin(); i != m_processing.end(); ++i)
{ {
if ((*i)->info_hash == info_hash) return i->get(); if ((*i)->info_hash == info_hash) return i->get();
} }
@ -494,13 +497,6 @@ namespace libtorrent { namespace detail
, m_dht_same_port(true) , m_dht_same_port(true)
, m_external_udp_port(0) , m_external_udp_port(0)
#endif #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_timer(m_io_service)
, m_next_connect_torrent(0) , m_next_connect_torrent(0)
, m_checker_impl(*this) , m_checker_impl(*this)
@ -589,6 +585,12 @@ namespace libtorrent { namespace detail
m_checker_impl.m_abort = true; 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) void session_impl::set_ip_filter(ip_filter const& f)
{ {
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
@ -600,13 +602,9 @@ namespace libtorrent { namespace detail
= m_connections.begin(); i != m_connections.end();) = m_connections.begin(); i != m_connections.end();)
{ {
tcp::endpoint sender; tcp::endpoint sender;
try { try { sender = i->first->remote_endpoint(); }
sender = i->first->remote_endpoint(); catch (std::exception&) { sender = i->second->remote(); }
} catch (asio::system_error& e) { if (m_ip_filter.access(sender.address()) & ip_filter::blocked)
i++;
continue;
}
if (m_ip_filter.access(sender.address()) & ip_filter::blocked)
{ {
#if defined(TORRENT_VERBOSE_LOGGING) #if defined(TORRENT_VERBOSE_LOGGING)
(*i->second->m_logger) << "*** CONNECTION FILTERED\n"; (*i->second->m_logger) << "*** CONNECTION FILTERED\n";
@ -630,6 +628,9 @@ namespace libtorrent { namespace detail
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
assert(s.connection_speed > 0); assert(s.connection_speed > 0);
assert(s.file_pool_size > 0); assert(s.file_pool_size > 0);
// less than 5 seconds unchoke interval is insane
assert(s.unchoke_interval >= 5);
m_settings = s; m_settings = s;
m_files.resize(m_settings.file_pool_size); m_files.resize(m_settings.file_pool_size);
// replace all occurances of '\n' with ' '. // replace all occurances of '\n' with ' '.
@ -1087,8 +1088,10 @@ namespace libtorrent { namespace detail
{ {
session_impl::mutex_t::scoped_lock l(m_mutex); session_impl::mutex_t::scoped_lock l(m_mutex);
open_listen_port(); open_listen_port();
m_natpmp.set_mappings(m_listen_interface.port(), 0); if (m_natpmp.get())
m_upnp.set_mappings(m_listen_interface.port(), 0); 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(); ptime timer = time_now();
@ -1113,8 +1116,10 @@ namespace libtorrent { namespace detail
deadline_timer tracker_timer(m_io_service); deadline_timer tracker_timer(m_io_service);
// this will remove the port mappings // this will remove the port mappings
m_natpmp.close(); if (m_natpmp.get())
m_upnp.close(); m_natpmp->close();
if (m_upnp.get())
m_upnp->close();
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_logger) << time_now_string() << " locking mutex\n"; (*m_logger) << time_now_string() << " locking mutex\n";
@ -1276,7 +1281,7 @@ namespace libtorrent { namespace detail
torrent_handle session_impl::add_torrent( torrent_handle session_impl::add_torrent(
torrent_info const& ti torrent_info const& ti
, boost::filesystem::path const& save_path , fs::path const& save_path
, entry const& resume_data , entry const& resume_data
, bool compact_mode , bool compact_mode
, int block_size , int block_size
@ -1367,7 +1372,7 @@ namespace libtorrent { namespace detail
char const* tracker_url char const* tracker_url
, sha1_hash const& info_hash , sha1_hash const& info_hash
, char const* name , char const* name
, boost::filesystem::path const& save_path , fs::path const& save_path
, entry const& , entry const&
, bool compact_mode , bool compact_mode
, int block_size , int block_size
@ -1524,13 +1529,18 @@ namespace libtorrent { namespace detail
if (new_listen_address) if (new_listen_address)
{ {
m_natpmp.rebind(new_interface.address()); if (m_natpmp.get())
m_upnp.rebind(new_interface.address()); m_natpmp->rebind(new_interface.address());
m_lsd.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); if (m_natpmp.get())
m_upnp.set_mappings(m_listen_interface.port(), 0); 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 #ifndef TORRENT_DISABLE_DHT
if ((new_listen_address || m_dht_same_port) && m_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 // the listen interface changed, rebind the dht listen socket as well
m_dht->rebind(new_interface.address() m_dht->rebind(new_interface.address()
, m_dht_settings.service_port); , m_dht_settings.service_port);
m_natpmp.set_mappings(0, m_dht_settings.service_port); if (m_natpmp.get())
m_upnp.set_mappings(0, m_dht_settings.service_port); 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 #endif
@ -1563,7 +1575,8 @@ namespace libtorrent { namespace detail
{ {
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
// use internal listen port for local peers // 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) 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_dht_settings.service_port = m_listen_interface.port();
} }
m_external_udp_port = m_dht_settings.service_port; m_external_udp_port = m_dht_settings.service_port;
m_natpmp.set_mappings(0, m_dht_settings.service_port); if (m_natpmp.get())
m_upnp.set_mappings(0, m_dht_settings.service_port); 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 = new dht::dht_tracker(m_io_service
, m_dht_settings, m_listen_interface.address() , m_dht_settings, m_listen_interface.address()
, startup_state); , startup_state);
@ -1714,8 +1729,10 @@ namespace libtorrent { namespace detail
{ {
m_dht->rebind(m_listen_interface.address() m_dht->rebind(m_listen_interface.address()
, settings.service_port); , settings.service_port);
m_natpmp.set_mappings(0, m_dht_settings.service_port); if (m_natpmp.get())
m_upnp.set_mappings(0, m_dht_settings.service_port); 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_external_udp_port = settings.service_port;
} }
m_dht_settings = settings; m_dht_settings = settings;
@ -1896,6 +1913,69 @@ namespace libtorrent { namespace detail
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
return m_dl_bandwidth_manager.throttle(); 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 #ifndef NDEBUG
void session_impl::check_invariant(const char *place) 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) for (int j = 0; j < num_bitmask_bytes; ++j)
{ {
unsigned char bits = bitmask[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; const int bit = j * 8 + k;
if (bits & (1 << k)) if (bits & (1 << k))
{ {
p.info[bit].finished = true; p.info[bit].state = piece_picker::block_info::state_finished;
++p.finished; ++p.finished;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -77,7 +77,6 @@ using namespace libtorrent;
using boost::tuples::tuple; using boost::tuples::tuple;
using boost::tuples::get; using boost::tuples::get;
using boost::tuples::make_tuple; using boost::tuples::make_tuple;
using boost::filesystem::complete;
using boost::bind; using boost::bind;
using boost::mutex; using boost::mutex;
using libtorrent::aux::session_impl; using libtorrent::aux::session_impl;
@ -147,11 +146,12 @@ namespace
namespace libtorrent namespace libtorrent
{ {
torrent::torrent( torrent::torrent(
session_impl& ses session_impl& ses
, aux::checker_impl& checker , aux::checker_impl& checker
, torrent_info const& tf , torrent_info const& tf
, boost::filesystem::path const& save_path , fs::path const& save_path
, tcp::endpoint const& net_interface , tcp::endpoint const& net_interface
, bool compact_mode , bool compact_mode
, int block_size , int block_size
@ -174,7 +174,9 @@ namespace libtorrent
, m_resolve_countries(false) , m_resolve_countries(false)
#endif #endif
, m_announce_timer(ses.m_io_service) , m_announce_timer(ses.m_io_service)
#ifndef TORRENT_DISABLE_DHT
, m_last_dht_announce(time_now() - minutes(15)) , m_last_dht_announce(time_now() - minutes(15))
#endif
, m_policy() , m_policy()
, m_ses(ses) , m_ses(ses)
, m_checker(checker) , m_checker(checker)
@ -202,8 +204,6 @@ namespace libtorrent
m_initial_done = 0; m_initial_done = 0;
#endif #endif
INVARIANT_CHECK;
m_uploads_quota.min = 2; m_uploads_quota.min = 2;
m_connections_quota.min = 2; m_connections_quota.min = 2;
// this will be corrected the next time the main session // this will be corrected the next time the main session
@ -212,7 +212,6 @@ namespace libtorrent
m_uploads_quota.max = std::numeric_limits<int>::max(); m_uploads_quota.max = std::numeric_limits<int>::max();
m_connections_quota.max = std::numeric_limits<int>::max(); m_connections_quota.max = std::numeric_limits<int>::max();
m_policy.reset(new policy(this)); m_policy.reset(new policy(this));
init();
} }
@ -222,7 +221,7 @@ namespace libtorrent
, char const* tracker_url , char const* tracker_url
, sha1_hash const& info_hash , sha1_hash const& info_hash
, char const* name , char const* name
, boost::filesystem::path const& save_path , fs::path const& save_path
, tcp::endpoint const& net_interface , tcp::endpoint const& net_interface
, bool compact_mode , bool compact_mode
, int block_size , int block_size
@ -245,7 +244,9 @@ namespace libtorrent
, m_resolve_countries(false) , m_resolve_countries(false)
#endif #endif
, m_announce_timer(ses.m_io_service) , m_announce_timer(ses.m_io_service)
#ifndef TORRENT_DISABLE_DHT
, m_last_dht_announce(time_now() - minutes(15)) , m_last_dht_announce(time_now() - minutes(15))
#endif
, m_policy() , m_policy()
, m_ses(ses) , m_ses(ses)
, m_checker(checker) , m_checker(checker)
@ -295,6 +296,7 @@ namespace libtorrent
void torrent::start() void torrent::start()
{ {
boost::weak_ptr<torrent> self(shared_from_this()); boost::weak_ptr<torrent> self(shared_from_this());
if (m_torrent_file.is_valid()) init();
m_announce_timer.expires_from_now(seconds(1)); m_announce_timer.expires_from_now(seconds(1));
m_announce_timer.async_wait(m_ses.m_strand.wrap( m_announce_timer.async_wait(m_ses.m_strand.wrap(
bind(&torrent::on_announce_disp, self, _1))); bind(&torrent::on_announce_disp, self, _1)));
@ -327,8 +329,7 @@ namespace libtorrent
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_ses.is_aborted()) assert(m_abort);
m_abort = true;
if (!m_connections.empty()) if (!m_connections.empty())
disconnect_all(); disconnect_all();
} }
@ -347,17 +348,20 @@ namespace libtorrent
} }
#endif #endif
// this may not be called from a constructor because of the call to
// shared_from_this()
void torrent::init() void torrent::init()
{ {
INVARIANT_CHECK;
assert(m_torrent_file.is_valid()); assert(m_torrent_file.is_valid());
assert(m_torrent_file.num_files() > 0); assert(m_torrent_file.num_files() > 0);
assert(m_torrent_file.total_size() >= 0); assert(m_torrent_file.total_size() >= 0);
m_have_pieces.resize(m_torrent_file.num_pieces(), false); m_have_pieces.resize(m_torrent_file.num_pieces(), false);
m_storage.reset(new piece_manager(m_torrent_file, m_save_path // the shared_from_this() will create an intentional
, m_ses.m_files, m_storage_constructor)); // cycle of ownership, se the hpp file for description.
m_owning_storage = new piece_manager(shared_from_this(), m_torrent_file
, m_save_path, m_ses.m_files, m_ses.m_disk_thread, m_storage_constructor);
m_storage = m_owning_storage.get();
m_block_size = calculate_block_size(m_torrent_file, m_default_block_size); m_block_size = calculate_block_size(m_torrent_file, m_default_block_size);
m_picker.reset(new piece_picker( m_picker.reset(new piece_picker(
static_cast<int>(m_torrent_file.piece_length() / m_block_size) static_cast<int>(m_torrent_file.piece_length() / m_block_size)
@ -558,7 +562,6 @@ namespace libtorrent
bind(&torrent::on_peer_name_lookup, shared_from_this(), _1, _2, i->pid))); bind(&torrent::on_peer_name_lookup, shared_from_this(), _1, _2, i->pid)));
} }
} }
m_policy->pulse();
if (m_ses.m_alerts.should_post(alert::info)) if (m_ses.m_alerts.should_post(alert::info))
{ {
@ -687,7 +690,7 @@ namespace libtorrent
int corr = 0; int corr = 0;
int index = i->index; int index = i->index;
assert(!m_have_pieces[index]); assert(!m_have_pieces[index]);
assert(i->finished < m_picker->blocks_in_piece(index)); assert(i->finished <= m_picker->blocks_in_piece(index));
#ifndef NDEBUG #ifndef NDEBUG
for (std::vector<piece_picker::downloading_piece>::const_iterator j = boost::next(i); for (std::vector<piece_picker::downloading_piece>::const_iterator j = boost::next(i);
@ -699,17 +702,17 @@ namespace libtorrent
for (int j = 0; j < blocks_per_piece; ++j) for (int j = 0; j < blocks_per_piece; ++j)
{ {
assert(i->info[j].finished == 0 || i->info[j].finished == 1); assert(m_picker->is_finished(piece_block(index, j)) == (i->info[j].state == piece_picker::block_info::state_finished));
assert(m_picker->is_finished(piece_block(index, j)) == i->info[j].finished); corr += (i->info[j].state == piece_picker::block_info::state_finished) * m_block_size;
corr += i->info[j].finished * m_block_size;
assert(index != last_piece || j < m_picker->blocks_in_last_piece() assert(index != last_piece || j < m_picker->blocks_in_last_piece()
|| i->info[j].finished == 0); || i->info[j].state != piece_picker::block_info::state_finished);
} }
// correction if this was the last piece // correction if this was the last piece
// and if we have the last block // and if we have the last block
if (i->index == last_piece if (i->index == last_piece
&& i->info[m_picker->blocks_in_last_piece()-1].finished) && i->info[m_picker->blocks_in_last_piece()-1].state
== piece_picker::block_info::state_finished)
{ {
corr -= m_block_size; corr -= m_block_size;
corr += m_torrent_file.piece_size(last_piece) % m_block_size; corr += m_torrent_file.piece_size(last_piece) % m_block_size;
@ -719,8 +722,8 @@ namespace libtorrent
wanted_done += corr; wanted_done += corr;
} }
assert(total_done < m_torrent_file.total_size()); assert(total_done <= m_torrent_file.total_size());
assert(wanted_done < m_torrent_file.total_size()); assert(wanted_done <= m_torrent_file.total_size());
std::map<piece_block, int> downloading_piece; std::map<piece_block, int> downloading_piece;
for (const_peer_iterator i = begin(); i != end(); ++i) for (const_peer_iterator i = begin(); i != end(); ++i)
@ -784,7 +787,7 @@ namespace libtorrent
std::cerr << " " << i->index << " "; std::cerr << " " << i->index << " ";
for (int j = 0; j < blocks_per_piece; ++j) for (int j = 0; j < blocks_per_piece; ++j)
{ {
std::cerr << i->info[j].finished; std::cerr << (i->info[j].state == piece_picker::block_info::state_finished ? "1" : "0");
} }
std::cerr << std::endl; std::cerr << std::endl;
} }
@ -800,8 +803,8 @@ namespace libtorrent
} }
assert(total_done < m_torrent_file.total_size()); assert(total_done <= m_torrent_file.total_size());
assert(wanted_done < m_torrent_file.total_size()); assert(wanted_done <= m_torrent_file.total_size());
#endif #endif
@ -809,6 +812,84 @@ namespace libtorrent
return make_tuple(total_done, wanted_done); return make_tuple(total_done, wanted_done);
} }
void torrent::piece_finished(int index, bool passed_hash_check)
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
bool was_seed = is_seed();
bool was_finished = m_picker->num_filtered() + num_pieces()
== torrent_file().num_pieces();
if (passed_hash_check)
{
// the following call may cause picker to become invalid
// in case we just became a seed
announce_piece(index);
assert(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
&& (is_seed()
|| m_picker->num_filtered() + num_pieces()
== 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 { finished(); }
catch (std::exception& e)
{
#ifndef NDEBUG
std::cerr << e.what() << std::endl;
assert(false);
#endif
}
}
}
else
{
piece_failed(index);
}
#ifndef NDEBUG
try
{
#endif
m_policy->piece_finished(index, passed_hash_check);
#ifndef NDEBUG
}
catch (std::exception const& e)
{
std::cerr << e.what() << std::endl;
assert(false);
}
#endif
#ifndef NDEBUG
try
{
#endif
if (!was_seed && is_seed())
{
assert(passed_hash_check);
completed();
}
#ifndef NDEBUG
}
catch (std::exception const& e)
{
std::cerr << e.what() << std::endl;
assert(false);
}
#endif
}
void torrent::piece_failed(int index) void torrent::piece_failed(int index)
{ {
// if the last piece fails the peer connection will still // if the last piece fails the peer connection will still
@ -818,7 +899,8 @@ namespace libtorrent
// (total_done == m_torrent_file.total_size()) => is_seed() // (total_done == m_torrent_file.total_size()) => is_seed()
// INVARIANT_CHECK; // INVARIANT_CHECK;
assert(m_storage.get()); assert(m_storage);
assert(m_storage->refcount() > 0);
assert(m_picker.get()); assert(m_picker.get());
assert(index >= 0); assert(index >= 0);
assert(index < m_torrent_file.num_pieces()); assert(index < m_torrent_file.num_pieces());
@ -907,6 +989,7 @@ namespace libtorrent
// start with redownloading the pieces that the client // start with redownloading the pieces that the client
// that has sent the least number of pieces // that has sent the least number of pieces
m_picker->restore_piece(index); m_picker->restore_piece(index);
assert(m_storage);
m_storage->mark_failed(index); m_storage->mark_failed(index);
assert(m_have_pieces[index] == false); assert(m_have_pieces[index] == false);
@ -924,7 +1007,19 @@ namespace libtorrent
// disconnect all peers and close all // disconnect all peers and close all
// files belonging to the torrents // files belonging to the torrents
disconnect_all(); disconnect_all();
if (m_storage.get()) m_storage->release_files(); if (m_owning_storage.get()) m_storage->async_release_files(
bind(&torrent::on_files_released, shared_from_this(), _1, _2));
m_owning_storage = 0;
}
void torrent::on_files_released(int ret, disk_io_job const& j)
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
if (alerts().should_post(alert::warning))
{
alerts().post_alert(torrent_paused_alert(get_handle(), "torrent paused"));
}
} }
void torrent::announce_piece(int index) void torrent::announce_piece(int index)
@ -981,7 +1076,19 @@ namespace libtorrent
return m_username + ":" + m_password; return m_username + ":" + m_password;
} }
void torrent::piece_availability(std::vector<int>& avail) const
{
INVARIANT_CHECK;
assert(valid_metadata());
if (is_seed())
{
avail.clear();
return;
}
m_picker->get_availability(avail);
}
void torrent::set_piece_priority(int index, int priority) void torrent::set_piece_priority(int index, int priority)
{ {
@ -1713,8 +1820,13 @@ namespace libtorrent
void torrent::set_metadata(entry const& metadata) void torrent::set_metadata(entry const& metadata)
{ {
INVARIANT_CHECK;
assert(!m_torrent_file.is_valid());
m_torrent_file.parse_info_section(metadata); m_torrent_file.parse_info_section(metadata);
init();
boost::mutex::scoped_lock(m_checker.m_mutex); boost::mutex::scoped_lock(m_checker.m_mutex);
boost::shared_ptr<aux::piece_checker_data> d( boost::shared_ptr<aux::piece_checker_data> d(
@ -1928,7 +2040,9 @@ namespace libtorrent
std::for_each(seeds.begin(), seeds.end() std::for_each(seeds.begin(), seeds.end()
, bind(&peer_connection::disconnect, _1)); , bind(&peer_connection::disconnect, _1));
m_storage->release_files(); assert(m_storage);
m_storage->async_release_files(
bind(&torrent::on_files_released, shared_from_this(), _1, _2));
} }
// called when torrent is complete (all pieces downloaded) // called when torrent is complete (all pieces downloaded)
@ -2004,17 +2118,12 @@ namespace libtorrent
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (!m_storage.get()) assert(valid_metadata());
{
// this means we have received the metadata through the
// metadata extension, and we have to initialize
init();
}
assert(m_storage.get());
bool done = true; bool done = true;
try try
{ {
assert(m_storage);
assert(m_owning_storage.get());
done = m_storage->check_fastresume(data, m_have_pieces, m_num_pieces done = m_storage->check_fastresume(data, m_have_pieces, m_num_pieces
, m_compact_mode); , m_compact_mode);
} }
@ -2043,11 +2152,12 @@ namespace libtorrent
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
assert(m_storage.get()); assert(m_owning_storage.get());
std::pair<bool, float> progress(true, 1.f); std::pair<bool, float> progress(true, 1.f);
try try
{ {
assert(m_storage);
progress = m_storage->check_files(m_have_pieces, m_num_pieces progress = m_storage->check_files(m_have_pieces, m_num_pieces
, m_ses.m_mutex); , m_ses.m_mutex);
} }
@ -2082,9 +2192,19 @@ namespace libtorrent
if (!is_seed()) if (!is_seed())
{ {
m_picker->files_checked(m_have_pieces, unfinished_pieces); // this is filled in with pieces that needs to be checked
// against its hashes.
std::vector<int> verify_pieces;
m_picker->files_checked(m_have_pieces, unfinished_pieces, verify_pieces);
if (m_sequenced_download_threshold > 0) if (m_sequenced_download_threshold > 0)
picker().set_sequenced_download_threshold(m_sequenced_download_threshold); picker().set_sequenced_download_threshold(m_sequenced_download_threshold);
while (!verify_pieces.empty())
{
int piece = verify_pieces.back();
verify_pieces.pop_back();
async_verify_piece(piece, bind(&torrent::piece_finished
, shared_from_this(), piece, _1));
}
} }
#ifndef TORRENT_DISABLE_EXTENSIONS #ifndef TORRENT_DISABLE_EXTENSIONS
@ -2137,34 +2257,45 @@ namespace libtorrent
return m_ses.m_alerts; return m_ses.m_alerts;
} }
boost::filesystem::path torrent::save_path() const fs::path torrent::save_path() const
{ {
return m_save_path; if (m_owning_storage.get())
return m_owning_storage->save_path();
else
return m_save_path;
} }
bool torrent::move_storage(boost::filesystem::path const& save_path) void torrent::move_storage(fs::path const& save_path)
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
bool ret = true; if (m_owning_storage.get())
if (m_storage.get())
{ {
ret = m_storage->move_storage(save_path); m_owning_storage->async_move_storage(save_path
m_save_path = m_storage->save_path(); , bind(&torrent::on_storage_moved, shared_from_this(), _1, _2));
} }
else else
{ {
m_save_path = save_path; m_save_path = save_path;
} }
return ret; }
void torrent::on_storage_moved(int ret, disk_io_job const& j)
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
if (alerts().should_post(alert::warning))
{
alerts().post_alert(storage_moved_alert(get_handle(), j.str));
}
} }
piece_manager& torrent::filesystem() piece_manager& torrent::filesystem()
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
assert(m_storage.get()); assert(m_owning_storage.get());
return *m_storage; return *m_owning_storage;
} }
@ -2198,11 +2329,11 @@ namespace libtorrent
if (valid_metadata()) if (valid_metadata())
{ {
assert(int(m_have_pieces.size()) == m_torrent_file.num_pieces()); assert(m_abort || int(m_have_pieces.size()) == m_torrent_file.num_pieces());
} }
else else
{ {
assert(m_have_pieces.empty()); assert(m_abort || m_have_pieces.empty());
} }
size_type total_done = quantized_bytes_done(); size_type total_done = quantized_bytes_done();
@ -2321,7 +2452,14 @@ namespace libtorrent
m_just_paused = true; m_just_paused = true;
// this will make the storage close all // this will make the storage close all
// files and flush all cached data // files and flush all cached data
if (m_storage.get()) m_storage->release_files(); if (m_owning_storage.get())
{
assert(m_storage);
// TOOD: add a callback which posts
// an alert for the client to sync. with
m_storage->async_release_files(
bind(&torrent::on_files_released, shared_from_this(), _1, _2));
}
} }
void torrent::resume() void torrent::resume()
@ -2448,33 +2586,31 @@ namespace libtorrent
m_time_scaler--; m_time_scaler--;
if (m_time_scaler <= 0) if (m_time_scaler <= 0)
{ {
m_time_scaler = 10; m_time_scaler = settings().unchoke_interval;
m_policy->pulse(); m_policy->pulse();
} }
} }
bool torrent::verify_piece(int piece_index) void torrent::async_verify_piece(int piece_index, boost::function<void(bool)> const& f)
{ {
// INVARIANT_CHECK; INVARIANT_CHECK;
assert(m_storage.get()); assert(m_storage);
assert(m_storage->refcount() > 0);
assert(piece_index >= 0); assert(piece_index >= 0);
assert(piece_index < m_torrent_file.num_pieces()); assert(piece_index < m_torrent_file.num_pieces());
assert(piece_index < (int)m_have_pieces.size()); assert(piece_index < (int)m_have_pieces.size());
int size = static_cast<int>(m_torrent_file.piece_size(piece_index)); m_storage->async_hash(piece_index, bind(&torrent::on_piece_verified
std::vector<char> buffer(size); , shared_from_this(), _1, _2, f));
assert(size > 0); }
m_storage->read(&buffer[0], piece_index, 0, size);
hasher h; void torrent::on_piece_verified(int ret, disk_io_job const& j
h.update(&buffer[0], size); , boost::function<void(bool)> f)
sha1_hash digest = h.final(); {
sha1_hash h(j.str);
if (m_torrent_file.hash_for_piece(piece_index) != digest) session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
return false; f(m_torrent_file.hash_for_piece(j.piece) == h);
return true;
} }
const tcp::endpoint& torrent::current_tracker() const const tcp::endpoint& torrent::current_tracker() const
@ -2483,7 +2619,7 @@ namespace libtorrent
} }
bool torrent::is_allocating() const bool torrent::is_allocating() const
{ return m_storage.get() && m_storage->is_allocating(); } { return m_owning_storage.get() && m_owning_storage->is_allocating(); }
void torrent::file_progress(std::vector<float>& fp) const void torrent::file_progress(std::vector<float>& fp) const
{ {
@ -2533,8 +2669,8 @@ namespace libtorrent
torrent_status st; torrent_status st;
st.num_peers = (int)std::count_if(m_connections.begin(), m_connections.end(), st.num_peers = (int)std::count_if(m_connections.begin(), m_connections.end(),
boost::bind<bool>(std::logical_not<bool>(), boost::bind(&peer_connection::is_connecting, !boost::bind(&peer_connection::is_connecting
boost::bind(&std::map<tcp::endpoint,peer_connection*>::value_type::second, _1)))); , boost::bind(&std::map<tcp::endpoint,peer_connection*>::value_type::second, _1)));
st.num_complete = m_complete; st.num_complete = m_complete;
st.num_incomplete = m_incomplete; st.num_incomplete = m_incomplete;
@ -2635,7 +2771,6 @@ namespace libtorrent
} }
else if (st.total_wanted_done == st.total_wanted) else if (st.total_wanted_done == st.total_wanted)
{ {
assert(st.total_done != m_torrent_file.total_size());
st.state = torrent_status::finished; st.state = torrent_status::finished;
} }
else else
@ -2655,10 +2790,10 @@ namespace libtorrent
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
return (int)std::count_if(m_connections.begin(), m_connections.end(), return (int)std::count_if(m_connections.begin(), m_connections.end()
boost::bind(&peer_connection::is_seed, , boost::bind(&peer_connection::is_seed
boost::bind(&std::map<tcp::endpoint , boost::bind(&std::map<tcp::endpoint
,peer_connection*>::value_type::second, _1))); , peer_connection*>::value_type::second, _1)));
} }
void torrent::tracker_request_timed_out( void torrent::tracker_request_timed_out(

View File

@ -80,6 +80,8 @@ using libtorrent::aux::session_impl;
namespace libtorrent namespace libtorrent
{ {
namespace fs = boost::filesystem;
namespace namespace
{ {
void throw_invalid_handle() void throw_invalid_handle()
@ -205,12 +207,12 @@ namespace libtorrent
, bind(&torrent::download_limit, _1)); , bind(&torrent::download_limit, _1));
} }
bool torrent_handle::move_storage( void torrent_handle::move_storage(
boost::filesystem::path const& save_path) const fs::path const& save_path) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
return call_member<bool>(m_ses, m_chk, m_info_hash call_member<void>(m_ses, m_chk, m_info_hash
, bind(&torrent::move_storage, _1, save_path)); , bind(&torrent::move_storage, _1, save_path));
} }
@ -352,6 +354,14 @@ namespace libtorrent
} }
void torrent_handle::piece_availability(std::vector<int>& avail) const
{
INVARIANT_CHECK;
call_member<void>(m_ses, m_chk, m_info_hash
, bind(&torrent::piece_availability, _1, boost::ref(avail)));
}
void torrent_handle::piece_priority(int index, int priority) const void torrent_handle::piece_priority(int index, int priority) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
@ -556,9 +566,12 @@ namespace libtorrent
for (int j = 0; j < num_bitmask_bytes; ++j) for (int j = 0; j < num_bitmask_bytes; ++j)
{ {
unsigned char v = 0; unsigned char v = 0;
for (int k = 0; k < 8; ++k) int bits = std::min(num_blocks_per_piece - j*8, 8);
v |= i->info[j*8+k].finished?(1 << k):0; for (int k = 0; k < bits; ++k)
v |= (i->info[j*8+k].state == piece_picker::block_info::state_finished)
? (1 << k) : 0;
bitmask.insert(bitmask.end(), v); bitmask.insert(bitmask.end(), v);
assert(bits == 8 || j == num_bitmask_bytes - 1);
} }
piece_struct["bitmask"] = bitmask; piece_struct["bitmask"] = bitmask;
@ -608,11 +621,11 @@ namespace libtorrent
} }
boost::filesystem::path torrent_handle::save_path() const fs::path torrent_handle::save_path() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
return call_member<boost::filesystem::path>(m_ses, m_chk, m_info_hash return call_member<fs::path>(m_ses, m_chk, m_info_hash
, bind(&torrent::save_path, _1)); , bind(&torrent::save_path, _1));
} }
@ -717,7 +730,7 @@ namespace libtorrent
{ {
peer_connection* peer = i->second; peer_connection* peer = i->second;
// peers that haven't finished the handshake should // incoming peers that haven't finished the handshake should
// not be included in this list // not be included in this list
if (peer->associated_torrent().expired()) continue; if (peer->associated_torrent().expired()) continue;
@ -760,10 +773,9 @@ namespace libtorrent
pi.blocks_in_piece = p.blocks_in_piece(i->index); pi.blocks_in_piece = p.blocks_in_piece(i->index);
for (int j = 0; j < pi.blocks_in_piece; ++j) for (int j = 0; j < pi.blocks_in_piece; ++j)
{ {
pi.peer[j] = i->info[j].peer; pi.blocks[j].peer = i->info[j].peer;
pi.num_downloads[j] = i->info[j].num_downloads; pi.blocks[j].num_downloads = i->info[j].num_downloads;
pi.finished_blocks[j] = i->info[j].finished; pi.blocks[j].state = i->info[j].state;
pi.requested_blocks[j] = i->info[j].requested;
} }
pi.piece_index = i->index; pi.piece_index = i->index;
queue.push_back(pi); queue.push_back(pi);

View File

@ -62,10 +62,12 @@ namespace pt = boost::posix_time;
namespace gr = boost::gregorian; namespace gr = boost::gregorian;
using namespace libtorrent; using namespace libtorrent;
using namespace boost::filesystem;
namespace namespace
{ {
namespace fs = boost::filesystem;
void convert_to_utf8(std::string& str, unsigned char chr) void convert_to_utf8(std::string& str, unsigned char chr)
{ {
str += 0xc0 | ((chr & 0xff) >> 6); str += 0xc0 | ((chr & 0xff) >> 6);
@ -153,7 +155,7 @@ namespace
// encoded string // encoded string
if (!valid_encoding) if (!valid_encoding)
{ {
target.orig_path.reset(new path(target.path)); target.orig_path.reset(new fs::path(target.path));
target.path = tmp_path; target.path = tmp_path;
} }
} }
@ -203,8 +205,8 @@ namespace
offset += target.back().size; offset += target.back().size;
} }
} }
/*
void remove_dir(path& p) void remove_dir(fs::path& p)
{ {
assert(p.begin() != p.end()); assert(p.begin() != p.end());
path tmp; path tmp;
@ -212,6 +214,7 @@ namespace
tmp /= *i; tmp /= *i;
p = tmp; p = tmp;
} }
*/
} }
namespace libtorrent namespace libtorrent
@ -277,6 +280,29 @@ namespace libtorrent
torrent_info::~torrent_info() torrent_info::~torrent_info()
{} {}
void torrent_info::swap(torrent_info& ti)
{
using std::swap;
m_urls.swap(ti.m_urls);
m_url_seeds.swap(ti.m_url_seeds);
swap(m_piece_length, ti.m_piece_length);
m_piece_hash.swap(ti.m_piece_hash);
m_files.swap(ti.m_files);
m_nodes.swap(ti.m_nodes);
swap(m_num_pieces, ti.m_num_pieces);
swap(m_info_hash, ti.m_info_hash);
m_name.swap(ti.m_name);
swap(m_creation_date, ti.m_creation_date);
m_comment.swap(ti.m_comment);
m_created_by.swap(ti.m_created_by);
swap(m_multifile, ti.m_multifile);
swap(m_private, ti.m_private);
m_extra_info.swap(ti.m_extra_info);
#ifndef NDEBUG
swap(m_half_metadata, ti.m_half_metadata);
#endif
}
void torrent_info::set_piece_size(int size) void torrent_info::set_piece_size(int size)
{ {
// make sure the size is an even power of 2 // make sure the size is an even power of 2
@ -323,7 +349,7 @@ namespace libtorrent
else else
{ m_name = info["name"].string(); } { m_name = info["name"].string(); }
path tmp = m_name; fs::path tmp = m_name;
if (tmp.is_complete()) throw std::runtime_error("torrent contains " if (tmp.is_complete()) throw std::runtime_error("torrent contains "
"a file with an absolute path: '" + m_name + "'"); "a file with an absolute path: '" + m_name + "'");
if (tmp.has_branch_path()) throw std::runtime_error( if (tmp.has_branch_path()) throw std::runtime_error(
@ -526,9 +552,9 @@ namespace libtorrent
, bind(&announce_entry::tier, _1), bind(&announce_entry::tier, _2))); , bind(&announce_entry::tier, _1), bind(&announce_entry::tier, _2)));
} }
void torrent_info::add_file(boost::filesystem::path file, size_type size) void torrent_info::add_file(fs::path file, size_type size)
{ {
assert(file.begin() != file.end()); // assert(file.begin() != file.end());
if (!file.has_branch_path()) if (!file.has_branch_path())
{ {
@ -589,8 +615,6 @@ namespace libtorrent
entry torrent_info::create_info_metadata() const entry torrent_info::create_info_metadata() const
{ {
namespace fs = boost::filesystem;
// you have to add files to the torrent first // you have to add files to the torrent first
assert(!m_files.empty()); assert(!m_files.empty());
@ -650,8 +674,6 @@ namespace libtorrent
{ {
assert(m_piece_length > 0); assert(m_piece_length > 0);
namespace fs = boost::filesystem;
if ((m_urls.empty() && m_nodes.empty()) || m_files.empty()) if ((m_urls.empty() && m_nodes.empty()) || m_files.empty())
{ {
// TODO: throw something here // TODO: throw something here

View File

@ -289,28 +289,6 @@ namespace libtorrent
return ret; return ret;
} }
void intrusive_ptr_add_ref(timeout_handler const* c)
{
assert(c != 0);
assert(c->m_refs >= 0);
timeout_handler::mutex_t::scoped_lock l(c->m_mutex);
++c->m_refs;
}
void intrusive_ptr_release(timeout_handler const* c)
{
assert(c != 0);
assert(c->m_refs > 0);
timeout_handler::mutex_t::scoped_lock l(c->m_mutex);
--c->m_refs;
if (c->m_refs == 0)
{
l.unlock();
delete c;
}
}
timeout_handler::timeout_handler(asio::strand& str) timeout_handler::timeout_handler(asio::strand& str)
: m_strand(str) : m_strand(str)
, m_start_time(time_now()) , m_start_time(time_now())
@ -318,7 +296,6 @@ namespace libtorrent
, m_timeout(str.io_service()) , m_timeout(str.io_service())
, m_completion_timeout(0) , m_completion_timeout(0)
, m_read_timeout(0) , m_read_timeout(0)
, m_refs(0)
{} {}
void timeout_handler::set_timeout(int completion_timeout, int read_timeout) void timeout_handler::set_timeout(int completion_timeout, int read_timeout)
@ -467,8 +444,19 @@ namespace libtorrent
++start; ++start;
} }
std::string::iterator port_pos std::string::iterator port_pos;
= std::find(start, url.end(), ':');
// this is for IPv6 addresses
if (start != url.end() && *start == '[')
{
port_pos = std::find(start, url.end(), ']');
if (port_pos == url.end()) throw std::runtime_error("invalid hostname syntax");
port_pos = std::find(port_pos, url.end(), ':');
}
else
{
port_pos = std::find(start, url.end(), ':');
}
if (port_pos < end) if (port_pos < end)
{ {

View File

@ -307,7 +307,10 @@ namespace libtorrent
// event // event
detail::write_int32(req.event, out); detail::write_int32(req.event, out);
// ip address // ip address
detail::write_int32(0, out); if (m_settings.announce_ip != address() && m_settings.announce_ip.is_v4())
detail::write_uint32(m_settings.announce_ip.to_v4().to_ulong(), out);
else
detail::write_int32(0, out);
// key // key
detail::write_int32(req.key, out); detail::write_int32(req.key, out);
// num_want // num_want

View File

@ -160,6 +160,7 @@ deluge_core = Extension('deluge_core',
'libtorrent/src/bandwidth_manager.cpp', 'libtorrent/src/bandwidth_manager.cpp',
'libtorrent/src/bt_peer_connection.cpp', 'libtorrent/src/bt_peer_connection.cpp',
'libtorrent/src/connection_queue.cpp', 'libtorrent/src/connection_queue.cpp',
'libtorrent/src/disk_io_thread.cpp',
'libtorrent/src/entry.cpp', 'libtorrent/src/entry.cpp',
'libtorrent/src/escape_string.cpp', 'libtorrent/src/escape_string.cpp',
'libtorrent/src/file.cpp', 'libtorrent/src/file.cpp',
@ -181,6 +182,7 @@ deluge_core = Extension('deluge_core',
'libtorrent/src/session.cpp', 'libtorrent/src/session.cpp',
'libtorrent/src/session_impl.cpp', 'libtorrent/src/session_impl.cpp',
'libtorrent/src/sha1.cpp', 'libtorrent/src/sha1.cpp',
'libtorrent/src/socks4_stream.cpp',
'libtorrent/src/socks5_stream.cpp', 'libtorrent/src/socks5_stream.cpp',
'libtorrent/src/stat.cpp', 'libtorrent/src/stat.cpp',
'libtorrent/src/storage.cpp', 'libtorrent/src/storage.cpp',

View File

@ -71,7 +71,10 @@ PREF_FUNCTIONS = {
"max_active_torrents" : None, # no need for a function, applied constantly "max_active_torrents" : None, # no need for a function, applied constantly
"auto_seed_ratio" : None, # no need for a function, applied constantly "auto_seed_ratio" : None, # no need for a function, applied constantly
"max_download_rate_bps" : deluge_core.set_download_rate_limit, "max_download_rate_bps" : deluge_core.set_download_rate_limit,
"max_upload_rate_bps" : deluge_core.set_upload_rate_limit "max_upload_rate_bps" : deluge_core.set_upload_rate_limit,
"use_upnp" : deluge_core.use_upnp,
"use_natpmp" : deluge_core.use_natpmp,
"use_utpex" : deluge_core.use_utpex
} }
STATE_MESSAGES = ( "Queued", STATE_MESSAGES = ( "Queued",
@ -443,6 +446,7 @@ class Manager:
# altering max_active_torrents), or just from time to time # altering max_active_torrents), or just from time to time
# ___ALL queuing code should be in this function, and ONLY here___ # ___ALL queuing code should be in this function, and ONLY here___
def apply_queue(self, efficient = True): def apply_queue(self, efficient = True):
print "applying queue";
# Handle autoseeding - downqueue as needed # Handle autoseeding - downqueue as needed
if self.get_pref('auto_seed_ratio') > 0: if self.get_pref('auto_seed_ratio') > 0:
for unique_ID in self.unique_IDs: for unique_ID in self.unique_IDs:
@ -781,3 +785,6 @@ class Manager:
# Adds an IP range (as two dotted quad strings) to the filter # Adds an IP range (as two dotted quad strings) to the filter
def add_range_to_ip_filter(self, start, end): def add_range_to_ip_filter(self, start, end):
return deluge_core.add_range_to_IP_filter(start, end) return deluge_core.add_range_to_IP_filter(start, end)
def netextras(self, proto, action):
return deluge_core.netextras(proto, action)

View File

@ -338,7 +338,6 @@ static PyObject *torrent_init(PyObject *self, PyObject *args)
M_ses->set_severity_level(alert::debug); M_ses->set_severity_level(alert::debug);
M_ses->add_extension(&libtorrent::create_metadata_plugin); M_ses->add_extension(&libtorrent::create_metadata_plugin);
M_ses->add_extension(&libtorrent::create_ut_pex_plugin);
M_constants = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i}", M_constants = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i}",
"EVENT_NULL", EVENT_NULL, "EVENT_NULL", EVENT_NULL,
@ -1228,6 +1227,56 @@ static PyObject *torrent_add_range_to_IP_filter(PyObject *self, PyObject *args)
Py_INCREF(Py_None); return Py_None; Py_INCREF(Py_None); return Py_None;
} }
static PyObject *torrent_use_upnp(PyObject *self, PyObject *args)
{
python_long action;
PyArg_ParseTuple(args, "i", &action);
if (action){
printf("Starting UPnP\r\n");
M_ses->start_upnp();
}
else{
printf("Stopping natpmp\r\n");
M_ses->stop_upnp();
}
Py_INCREF(Py_None); return Py_None;
}
static PyObject *torrent_use_natpmp(PyObject *self, PyObject *args)
{
python_long action;
PyArg_ParseTuple(args, "i", &action);
if (action){
printf("Starting NAT-PMP\r\n");
M_ses->start_natpmp();
}
else{
printf("Stopping NAT-PMP\r\n");
M_ses->stop_natpmp();
}
Py_INCREF(Py_None); return Py_None;
}
static PyObject *torrent_use_utpex(PyObject *self, PyObject *args)
{
python_long action;
PyArg_ParseTuple(args, "i", &action);
if (action){
printf("Starting UTPEX\r\n");
M_ses->add_extension(&libtorrent::create_ut_pex_plugin);
}
Py_INCREF(Py_None); return Py_None;
}
static PyObject *torrent_pe_settings(PyObject *self, PyObject *args) static PyObject *torrent_pe_settings(PyObject *self, PyObject *args)
{ {
M_pe_settings = new pe_settings(); M_pe_settings = new pe_settings();
@ -1284,6 +1333,9 @@ static PyMethodDef deluge_core_methods[] =
{"create_torrent", torrent_create_torrent, METH_VARARGS, "."}, {"create_torrent", torrent_create_torrent, METH_VARARGS, "."},
{"reset_IP_filter", torrent_reset_IP_filter, METH_VARARGS, "."}, {"reset_IP_filter", torrent_reset_IP_filter, METH_VARARGS, "."},
{"add_range_to_IP_filter", torrent_add_range_to_IP_filter, METH_VARARGS, "."}, {"add_range_to_IP_filter", torrent_add_range_to_IP_filter, METH_VARARGS, "."},
{"use_upnp", torrent_use_upnp, METH_VARARGS, "."},
{"use_natpmp", torrent_use_natpmp, METH_VARARGS, "."},
{"use_utpex", torrent_use_utpex, METH_VARARGS, "."},
{NULL} {NULL}
}; };

View File

@ -53,6 +53,9 @@ class PreferencesDlg:
self.glade.get_widget("combo_encout").set_active(self.preferences.get("encout_state", int, default=common.EncState.enabled)) self.glade.get_widget("combo_encout").set_active(self.preferences.get("encout_state", int, default=common.EncState.enabled))
self.glade.get_widget("combo_enclevel").set_active(self.preferences.get("enclevel_type", int, default=common.EncLevel.both)) self.glade.get_widget("combo_enclevel").set_active(self.preferences.get("enclevel_type", int, default=common.EncLevel.both))
self.glade.get_widget("chk_pref_rc4").set_active(self.preferences.get("pref_rc4", bool, default=True)) self.glade.get_widget("chk_pref_rc4").set_active(self.preferences.get("pref_rc4", bool, default=True))
self.glade.get_widget("chk_upnp").set_active(self.preferences.get("use_upnp", bool, default=True))
self.glade.get_widget("chk_natpmp").set_active(self.preferences.get("use_natpmp", bool, default=True))
self.glade.get_widget("chk_utpex").set_active(self.preferences.get("use_utpex", bool, default=True))
self.glade.get_widget("chk_use_tray").set_active(self.preferences.get("enable_system_tray", bool, default=True)) self.glade.get_widget("chk_use_tray").set_active(self.preferences.get("enable_system_tray", bool, default=True))
self.glade.get_widget("chk_min_on_close").set_active(self.preferences.get("close_to_tray", bool, default=False)) self.glade.get_widget("chk_min_on_close").set_active(self.preferences.get("close_to_tray", bool, default=False))
self.glade.get_widget("chk_lock_tray").set_active(self.preferences.get("lock_tray", bool, default=False)) self.glade.get_widget("chk_lock_tray").set_active(self.preferences.get("lock_tray", bool, default=False))
@ -90,6 +93,9 @@ class PreferencesDlg:
self.preferences.set("encout_state", self.glade.get_widget("combo_encout").get_active()) self.preferences.set("encout_state", self.glade.get_widget("combo_encout").get_active())
self.preferences.set("enclevel_type", self.glade.get_widget("combo_enclevel").get_active()) self.preferences.set("enclevel_type", self.glade.get_widget("combo_enclevel").get_active())
self.preferences.set("pref_rc4", self.glade.get_widget("chk_pref_rc4").get_active()) self.preferences.set("pref_rc4", self.glade.get_widget("chk_pref_rc4").get_active())
self.preferences.set("use_upnp", self.glade.get_widget("chk_upnp").get_active())
self.preferences.set("use_natpmp", self.glade.get_widget("chk_natpmp").get_active())
self.preferences.set("use_utpex", self.glade.get_widget("chk_utpex").get_active())
self.preferences.set("system_tray", self.glade.get_widget("chk_use_tray").get_active()) self.preferences.set("system_tray", self.glade.get_widget("chk_use_tray").get_active())
self.preferences.set("close_to_tray", self.glade.get_widget("chk_min_on_close").get_active()) self.preferences.set("close_to_tray", self.glade.get_widget("chk_min_on_close").get_active())
self.preferences.set("lock_tray", self.glade.get_widget("chk_lock_tray").get_active()) self.preferences.set("lock_tray", self.glade.get_widget("chk_lock_tray").get_active())

View File

@ -76,6 +76,9 @@ DEFAULT_PREFS = {
"tray_passwd" : "", "tray_passwd" : "",
"use_compact_storage" : False, "use_compact_storage" : False,
"use_default_dir" : False, "use_default_dir" : False,
"use_natpmp" : False,
"use_upnp" : False,
"use_utpex" : False,
"window_height" : 480, "window_height" : 480,
"window_maximized" : False, "window_maximized" : False,
"window_pane_position" : -1, "window_pane_position" : -1,