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_columns">2</property>
<child>
<widget class="GtkSpinButton" id="spin_max_upload">
<widget class="GtkAlignment" id="alignment18">
<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>
<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="label55">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Maximum Upload Rate (KB/s):</property>
</widget>
</child>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</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_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>
<widget class="GtkAlignment" id="alignment14">
<property name="visible">True</property>
@ -437,19 +353,103 @@
</packing>
</child>
<child>
<widget class="GtkAlignment" id="alignment18">
<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="label55">
<widget class="GtkLabel" id="label53">
<property name="visible">True</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>
</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>
<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="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
@ -758,7 +758,7 @@
<child>
<widget class="GtkCheckButton" id="chk_upnp">
<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="use_underline">True</property>
<property name="response_id">0</property>
@ -772,7 +772,7 @@
<child>
<widget class="GtkCheckButton" id="chk_natpmp">
<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="use_underline">True</property>
<property name="response_id">0</property>
@ -787,7 +787,7 @@
<child>
<widget class="GtkCheckButton" id="chk_utpex">
<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="use_underline">True</property>
<property name="response_id">0</property>
@ -806,7 +806,7 @@
<child>
<widget class="GtkLabel" id="label17">
<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>
</widget>
<packing>

View File

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

View File

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

View File

@ -40,8 +40,6 @@ namespace asio {
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @sa @ref deadline_timer_reset
*
* @par Examples
* Performing a blocking wait:
* @code
@ -75,6 +73,45 @@ namespace asio {
* // Start an asynchronous wait.
* timer.async_wait(handler);
* @endcode
*
* @par Changing an active deadline_timer's expiry time
*
* Changing the expiry time of a timer while there are pending asynchronous
* waits causes those wait operations to be cancelled. To ensure that the action
* associated with the timer is performed only once, use something like this:
* used:
*
* @code
* void on_some_event()
* {
* if (my_timer.expires_from_now(seconds(5)) > 0)
* {
* // We managed to cancel the timer. Start new asynchronous wait.
* my_timer.async_wait(on_timeout);
* }
* else
* {
* // Too late, timer has already expired!
* }
* }
*
* void on_timeout(const asio::error_code& e)
* {
* if (e != asio::error::operation_aborted)
* {
* // Timer was not cancelled, take necessary action.
* }
* }
* @endcode
*
* @li The asio::basic_deadline_timer::expires_from_now() function
* cancels any pending asynchronous waits, and returns the number of
* asynchronous waits that were cancelled. If it returns 0 then you were too
* late and the wait handler has already been executed, or will soon be
* executed. If it returns 1 then the wait handler was successfully cancelled.
*
* @li If a wait handler is cancelled, the asio::error_code passed to
* it contains the value asio::error::operation_aborted.
*/
template <typename Time,
typename TimeTraits = asio::time_traits<Time>,
@ -197,9 +234,6 @@ public:
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* See @ref deadline_timer_reset for more information on altering the expiry
* time of an active timer.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @return The number of asynchronous operations that were cancelled.
@ -221,9 +255,6 @@ public:
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* See @ref deadline_timer_reset for more information on altering the expiry
* time of an active timer.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @param ec Set to indicate what error occurred, if any.
@ -252,9 +283,6 @@ public:
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* See @ref deadline_timer_reset for more information on altering the expiry
* time of an active timer.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @return The number of asynchronous operations that were cancelled.
@ -276,9 +304,6 @@ public:
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* See @ref deadline_timer_reset for more information on altering the expiry
* time of an active timer.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @param ec Set to indicate what error occurred, if any.
@ -349,49 +374,6 @@ public:
}
};
/**
* @page deadline_timer_reset Changing an active deadline_timer's expiry time
*
* Changing the expiry time of a timer while there are pending asynchronous
* waits causes those wait operations to be cancelled. To ensure that the action
* associated with the timer is performed only once, use something like this:
* used:
*
* @code
* void on_some_event()
* {
* if (my_timer.expires_from_now(seconds(5)) > 0)
* {
* // We managed to cancel the timer. Start new asynchronous wait.
* my_timer.async_wait(on_timeout);
* }
* else
* {
* // Too late, timer has already expired!
* }
* }
*
* void on_timeout(const asio::error_code& e)
* {
* if (e != asio::error::operation_aborted)
* {
* // Timer was not cancelled, take necessary action.
* }
* }
* @endcode
*
* @li The asio::basic_deadline_timer::expires_from_now() function
* cancels any pending asynchronous waits, and returns the number of
* asynchronous waits that were cancelled. If it returns 0 then you were too
* late and the wait handler has already been executed, or will soon be
* executed. If it returns 1 then the wait handler was successfully cancelled.
*
* @li If a wait handler is cancelled, the asio::error_code passed to
* it contains the value asio::error::operation_aborted.
*
* @sa asio::basic_deadline_timer
*/
} // namespace asio
#include "asio/detail/pop_options.hpp"

View File

@ -34,6 +34,14 @@
# endif // defined(_HAS_ITERATOR_DEBUGGING)
#endif // defined(BOOST_MSVC)
#if defined(__GNUC__)
# if defined(_GLIBCXX_DEBUG)
# if !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
# define ASIO_ENABLE_BUFFER_DEBUGGING
# endif // !defined(ASIO_DISABLE_BUFFER_DEBUGGING)
# endif // defined(_GLIBCXX_DEBUG)
#endif // defined(__GNUC__)
#if defined(ASIO_ENABLE_BUFFER_DEBUGGING)
# include "asio/detail/push_options.hpp"
# include <boost/function.hpp>

View File

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

View File

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

View File

@ -350,6 +350,22 @@ public:
socket_ops::setsockopt(impl.socket_,
option.level(impl.protocol_), option.name(impl.protocol_),
option.data(impl.protocol_), option.size(impl.protocol_), ec);
#if defined(__MACH__) && defined(__APPLE__) \
|| defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
// To implement portable behaviour for SO_REUSEADDR with UDP sockets we
// need to also set SO_REUSEPORT on BSD-based platforms.
if (!ec && impl.protocol_.type() == SOCK_DGRAM
&& option.level(impl.protocol_) == SOL_SOCKET
&& option.name(impl.protocol_) == SO_REUSEADDR)
{
asio::error_code ignored_ec;
socket_ops::setsockopt(impl.socket_, SOL_SOCKET, SO_REUSEPORT,
option.data(impl.protocol_), option.size(impl.protocol_),
ignored_ec);
}
#endif
return ec;
}
}
@ -506,6 +522,18 @@ public:
return 0;
}
// Make socket non-blocking if user wants non-blocking.
if (impl.flags_ & implementation_type::user_set_non_blocking)
{
if (!(impl.flags_ & implementation_type::internal_non_blocking))
{
ioctl_arg_type non_blocking = 1;
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
return 0;
impl.flags_ |= implementation_type::internal_non_blocking;
}
}
// Send the data.
for (;;)
{
@ -668,6 +696,18 @@ public:
asio::buffer_size(buffer));
}
// Make socket non-blocking if user wants non-blocking.
if (impl.flags_ & implementation_type::user_set_non_blocking)
{
if (!(impl.flags_ & implementation_type::internal_non_blocking))
{
ioctl_arg_type non_blocking = 1;
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
return 0;
impl.flags_ |= implementation_type::internal_non_blocking;
}
}
// Send the data.
for (;;)
{
@ -823,6 +863,18 @@ public:
return 0;
}
// Make socket non-blocking if user wants non-blocking.
if (impl.flags_ & implementation_type::user_set_non_blocking)
{
if (!(impl.flags_ & implementation_type::internal_non_blocking))
{
ioctl_arg_type non_blocking = 1;
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
return 0;
impl.flags_ |= implementation_type::internal_non_blocking;
}
}
// Receive some data.
for (;;)
{
@ -1005,6 +1057,18 @@ public:
asio::buffer_size(buffer));
}
// Make socket non-blocking if user wants non-blocking.
if (impl.flags_ & implementation_type::user_set_non_blocking)
{
if (!(impl.flags_ & implementation_type::internal_non_blocking))
{
ioctl_arg_type non_blocking = 1;
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
return 0;
impl.flags_ |= implementation_type::internal_non_blocking;
}
}
// Receive some data.
for (;;)
{
@ -1160,6 +1224,18 @@ public:
return ec;
}
// Make socket non-blocking if user wants non-blocking.
if (impl.flags_ & implementation_type::user_set_non_blocking)
{
if (!(impl.flags_ & implementation_type::internal_non_blocking))
{
ioctl_arg_type non_blocking = 1;
if (socket_ops::ioctl(impl.socket_, FIONBIO, &non_blocking, ec))
return ec;
impl.flags_ |= implementation_type::internal_non_blocking;
}
}
// Accept a socket.
for (;;)
{
@ -1203,6 +1279,14 @@ public:
return ec;
// Fall through to retry operation.
}
#if defined(EPROTO)
else if (ec.value() == EPROTO)
{
if (impl.flags_ & implementation_type::enable_connection_aborted)
return ec;
// Fall through to retry operation.
}
#endif // defined(EPROTO)
else
return ec;
@ -1262,6 +1346,10 @@ public:
if (ec == asio::error::connection_aborted
&& !enable_connection_aborted_)
return false;
#if defined(EPROTO)
if (ec.value() == EPROTO && !enable_connection_aborted_)
return false;
#endif // defined(EPROTO)
// Transfer ownership of the new socket to the peer object.
if (!ec)

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)
{
clear_error(ec);
#if defined(__MACH__) && defined(__APPLE__)
#if defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
socket_type new_s = error_wrapper(::accept(s, addr, addrlen), ec);
if (new_s == invalid_socket)
return new_s;
@ -295,7 +295,7 @@ inline socket_type socket(int af, int type, int protocol,
}
return s;
#elif defined(__MACH__) && defined(__APPLE__)
#elif defined(__MACH__) && defined(__APPLE__) || defined(__FreeBSD__)
socket_type s = error_wrapper(::socket(af, type, protocol), ec);
if (s == invalid_socket)
return s;
@ -318,11 +318,35 @@ inline socket_type socket(int af, int type, int protocol,
inline int setsockopt(socket_type s, int level, int optname,
const void* optval, size_t optlen, asio::error_code& ec)
{
if (level == custom_socket_option_level && optname == always_fail_option)
{
ec = asio::error::invalid_argument;
return -1;
}
#if defined(__BORLANDC__)
// Mysteriously, using the getsockopt and setsockopt functions directly with
// Borland C++ results in incorrect values being set and read. The bug can be
// worked around by using function addresses resolved with GetProcAddress.
if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
{
typedef int (WSAAPI *sso_t)(SOCKET, int, int, const char*, int);
if (sso_t sso = (sso_t)::GetProcAddress(winsock_module, "setsockopt"))
{
clear_error(ec);
return error_wrapper(sso(s, level, optname,
reinterpret_cast<const char*>(optval),
static_cast<int>(optlen)), ec);
}
}
ec = asio::error::fault;
return -1;
#elif defined(BOOST_WINDOWS) || defined(__CYGWIN__)
clear_error(ec);
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
return error_wrapper(::setsockopt(s, level, optname,
reinterpret_cast<const char*>(optval), static_cast<int>(optlen)), ec);
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
clear_error(ec);
return error_wrapper(::setsockopt(s, level, optname, optval,
static_cast<socklen_t>(optlen)), ec);
#endif // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
@ -331,8 +355,44 @@ inline int setsockopt(socket_type s, int level, int optname,
inline int getsockopt(socket_type s, int level, int optname, void* optval,
size_t* optlen, asio::error_code& ec)
{
if (level == custom_socket_option_level && optname == always_fail_option)
{
ec = asio::error::invalid_argument;
return -1;
}
#if defined(__BORLANDC__)
// Mysteriously, using the getsockopt and setsockopt functions directly with
// Borland C++ results in incorrect values being set and read. The bug can be
// worked around by using function addresses resolved with GetProcAddress.
if (HMODULE winsock_module = ::GetModuleHandleA("ws2_32"))
{
typedef int (WSAAPI *gso_t)(SOCKET, int, int, char*, int*);
if (gso_t gso = (gso_t)::GetProcAddress(winsock_module, "getsockopt"))
{
clear_error(ec);
int tmp_optlen = static_cast<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);
#if defined(BOOST_WINDOWS) || defined(__CYGWIN__)
int tmp_optlen = static_cast<int>(*optlen);
int result = error_wrapper(::getsockopt(s, level, optname,
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;
#else // defined(BOOST_WINDOWS) || defined(__CYGWIN__)
clear_error(ec);
socklen_t tmp_optlen = static_cast<socklen_t>(*optlen);
int result = error_wrapper(::getsockopt(s, level, optname,
optval, &tmp_optlen), ec);

View File

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

View File

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

View File

@ -309,7 +309,8 @@ private:
swap_heap(index, heap_.size() - 1);
heap_.pop_back();
size_t parent = (index - 1) / 2;
if (index > 0 && Time_Traits::less_than(t->time_, heap_[parent]->time_))
if (index > 0 && Time_Traits::less_than(
heap_[index]->time_, heap_[parent]->time_))
up_heap(index);
else
down_heap(index);

View File

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

View File

@ -60,7 +60,40 @@ namespace asio {
* @par Concepts:
* Dispatcher.
*
* @sa @ref io_service_handler_exception
* @par Effect of exceptions thrown from handlers
*
* If an exception is thrown from a handler, the exception is allowed to
* propagate through the throwing thread's invocation of
* asio::io_service::run(), asio::io_service::run_one(),
* asio::io_service::poll() or asio::io_service::poll_one().
* No other threads that are calling any of these functions are affected. It is
* then the responsibility of the application to catch the exception.
*
* After the exception has been caught, the
* asio::io_service::run(), asio::io_service::run_one(),
* asio::io_service::poll() or asio::io_service::poll_one()
* call may be restarted @em without the need for an intervening call to
* asio::io_service::reset(). This allows the thread to rejoin the
* io_service's thread pool without impacting any other threads in the pool.
*
* For example:
*
* @code
* asio::io_service io_service;
* ...
* for (;;)
* {
* try
* {
* io_service.run();
* break; // run() exited normally
* }
* catch (my_exception& e)
* {
* // Deal with exception as appropriate.
* }
* }
* @endcode
*/
class io_service
: private noncopyable
@ -108,7 +141,9 @@ public:
* more handlers to be dispatched, or until the io_service has been stopped.
*
* Multiple threads may call the run() function to set up a pool of threads
* from which the io_service may execute handlers.
* from which the io_service may execute handlers. All threads that are
* waiting in the pool are equivalent and the io_service may choose any one
* of them to invoke a handler.
*
* The run() function may be safely called again once it has completed only
* after a call to reset().
@ -125,7 +160,9 @@ public:
* more handlers to be dispatched, or until the io_service has been stopped.
*
* Multiple threads may call the run() function to set up a pool of threads
* from which the io_service may execute handlers.
* from which the io_service may execute handlers. All threads that are
* waiting in the pool are equivalent and the io_service may choose any one
* of them to invoke a handler.
*
* The run() function may be safely called again once it has completed only
* after a call to reset().
@ -456,42 +493,6 @@ public:
}
};
/**
* @page io_service_handler_exception Effect of exceptions thrown from handlers
*
* If an exception is thrown from a handler, the exception is allowed to
* propagate through the throwing thread's invocation of
* asio::io_service::run(), asio::io_service::run_one(),
* asio::io_service::poll() or asio::io_service::poll_one().
* No other threads that are calling any of these functions are affected. It is
* then the responsibility of the application to catch the exception.
*
* After the exception has been caught, the
* asio::io_service::run(), asio::io_service::run_one(),
* asio::io_service::poll() or asio::io_service::poll_one()
* call may be restarted @em without the need for an intervening call to
* asio::io_service::reset(). This allows the thread to rejoin the
* io_service's thread pool without impacting any other threads in the pool.
*
* @par Example
* @code
* asio::io_service io_service;
* ...
* for (;;)
* {
* try
* {
* io_service.run();
* break; // run() exited normally
* }
* catch (my_exception& e)
* {
* // Deal with exception as appropriate.
* }
* }
* @endcode
*/
} // namespace asio
#include "asio/impl/io_service.ipp"

View File

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

View File

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

View File

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

View File

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

View File

@ -54,6 +54,12 @@ public:
}
/// Destructor.
/**
* Destroys a strand.
*
* Handlers posted through the strand that have not yet been invoked will
* still be dispatched in a way that meets the guarantee of non-concurrency.
*/
~strand()
{
service_.destroy(impl_);

View File

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

View File

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

View File

@ -54,14 +54,15 @@ namespace libtorrent
{
// DEBUG API
namespace fs = boost::filesystem;
struct logger
{
logger(boost::filesystem::path const& filename, int instance, bool append = true)
logger(fs::path const& filename, int instance, bool append = true)
{
using namespace boost::filesystem;
path dir(complete("libtorrent_logs" + boost::lexical_cast<std::string>(instance)));
if (!exists(dir)) create_directories(dir);
m_file.open(dir / filename, std::ios_base::out | (append ? std::ios_base::app : std::ios_base::out));
fs::path dir(fs::complete("libtorrent_logs" + boost::lexical_cast<std::string>(instance)));
if (!fs::exists(dir)) fs::create_directories(dir);
m_file.open((dir / filename).string().c_str(), std::ios_base::out | (append ? std::ios_base::app : std::ios_base::out));
*this << "\n\n\n*** starting log ***\n";
}
@ -73,7 +74,7 @@ namespace libtorrent
return *this;
}
boost::filesystem::ofstream m_file;
std::ofstream m_file;
};
}

View File

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

View File

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

View File

@ -104,3 +104,4 @@ namespace libtorrent
}
#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 {
class http_stream : boost::noncopyable
class http_stream : public proxy_base
{
public:
typedef stream_socket::lowest_layer_type lowest_layer_type;
typedef stream_socket::endpoint_type endpoint_type;
typedef stream_socket::protocol_type protocol_type;
explicit http_stream(asio::io_service& io_service)
: m_sock(io_service)
, m_resolver(io_service)
: proxy_base(io_service)
, m_no_connect(false)
{}
void set_no_connect(bool c) { m_no_connect = c; }
void set_proxy(std::string hostname, int port)
{
m_hostname = hostname;
m_port = port;
}
void set_username(std::string const& user
, std::string const& password)
{
@ -38,108 +55,6 @@ public:
m_password = password;
}
template <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;
template <class Handler>
@ -171,19 +86,12 @@ private:
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);
stream_socket m_sock;
// the http proxy
std::string m_hostname;
int m_port;
// send and receive buffer
std::vector<char> m_buffer;
// proxy authentication
std::string m_user;
std::string m_password;
endpoint_type m_remote_endpoint;
tcp::resolver m_resolver;
// this is true if the connection is HTTP based and
// want to talk directly to the proxy
bool m_no_connect;
@ -191,3 +99,4 @@ private:
}
#endif

View File

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

View File

@ -51,7 +51,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/array.hpp>
#include <boost/optional.hpp>
#include <boost/cstdint.hpp>
#include <boost/detail/atomic_count.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
@ -73,6 +72,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/bandwidth_manager.hpp"
#include "libtorrent/policy.hpp"
#include "libtorrent/socket_type.hpp"
#include "libtorrent/intrusive_ptr_base.hpp"
// TODO: each time a block is 'taken over'
// from another peer. That peer must be given
@ -88,20 +88,16 @@ namespace libtorrent
struct session_impl;
}
TORRENT_EXPORT void intrusive_ptr_add_ref(peer_connection const*);
TORRENT_EXPORT void intrusive_ptr_release(peer_connection const*);
struct TORRENT_EXPORT protocol_error: std::runtime_error
{
protocol_error(const std::string& msg): std::runtime_error(msg) {};
};
class TORRENT_EXPORT peer_connection
: public boost::noncopyable
: public intrusive_ptr_base<peer_connection>
, public boost::noncopyable
{
friend class invariant_access;
friend TORRENT_EXPORT void intrusive_ptr_add_ref(peer_connection const*);
friend TORRENT_EXPORT void intrusive_ptr_release(peer_connection const*);
public:
enum channels
@ -378,7 +374,7 @@ namespace libtorrent
virtual void write_cancel(peer_request const& r) = 0;
virtual void write_have(int index) = 0;
virtual void write_keepalive() = 0;
virtual void write_piece(peer_request const& r) = 0;
virtual void write_piece(peer_request const& r, char const* buffer) = 0;
virtual void on_connected() = 0;
virtual void on_tick() {}
@ -474,6 +470,9 @@ namespace libtorrent
private:
void fill_send_buffer();
void on_disk_read_complete(int ret, disk_io_job const& j, peer_request r);
void on_disk_write_complete(int ret, disk_io_job const& j
, peer_request r, boost::shared_ptr<torrent> t);
// the timeout in seconds
int m_timeout;
@ -504,6 +503,11 @@ namespace libtorrent
// buffer we're currently waiting for.
int m_current_send_buffer;
// the number of bytes we are currently reading
// from disk, that will be added to the send
// buffer as soon as they complete
int m_reading_bytes;
// if the sending buffer doesn't finish in one send
// operation, this is the position within that buffer
// where the next operation should continue
@ -660,9 +664,6 @@ namespace libtorrent
// the left-over bandwidth (suitable for web seeds).
bool m_non_prioritized;
// reference counter for intrusive_ptr
mutable boost::detail::atomic_count m_refs;
int m_upload_limit;
int m_download_limit;
@ -681,6 +682,19 @@ namespace libtorrent
// so that it can be removed from the queue
// once the connection completes
int m_connection_ticket;
// bytes downloaded since last second
// timer timeout; used for determining
// approx download rate
int m_remote_bytes_dled;
// approximate peer download rate
int m_remote_dl_rate;
// a timestamp when the remote download rate
// was last updated
ptime m_remote_dl_update;
#ifndef NDEBUG
public:
bool m_in_constructor;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -72,8 +72,11 @@ namespace libtorrent
struct torrent_plugin;
class torrent;
class ip_filter;
class port_filter;
class connection_queue;
namespace fs = boost::filesystem;
namespace aux
{
// workaround for microsofts
@ -135,7 +138,7 @@ namespace libtorrent
// all torrent_handles must be destructed before the session is destructed!
torrent_handle add_torrent(
torrent_info const& ti
, boost::filesystem::path const& save_path
, fs::path const& save_path
, entry const& resume_data = entry()
, bool compact_mode = true
, int block_size = 16 * 1024
@ -144,7 +147,7 @@ namespace libtorrent
// TODO: deprecated, this is for backwards compatibility only
torrent_handle add_torrent(
entry const& e
, boost::filesystem::path const& save_path
, fs::path const& save_path
, entry const& resume_data = entry()
, bool compact_mode = true
, int block_size = 16 * 1024
@ -158,7 +161,7 @@ namespace libtorrent
char const* tracker_url
, sha1_hash const& info_hash
, char const* name
, boost::filesystem::path const& save_path
, fs::path const& save_path
, entry const& resume_data = entry()
, bool compact_mode = true
, int block_size = 16 * 1024
@ -187,8 +190,10 @@ namespace libtorrent
#endif
void set_ip_filter(ip_filter const& f);
void set_port_filter(port_filter const& f);
void set_peer_id(peer_id const& pid);
void set_key(int key);
peer_id id() const;
bool is_listening() const;
@ -249,6 +254,16 @@ namespace libtorrent
connection_queue& get_connection_queue();
// starts/stops UPnP, NATPMP or LSD port mappers
// they are stopped by default
void start_lsd();
void start_natpmp();
void start_upnp();
void stop_lsd();
void stop_natpmp();
void stop_upnp();
// Resource management used for global limits.
resource_request m_ul_bandwidth_quota;
resource_request m_dl_bandwidth_quota;

View File

@ -54,6 +54,8 @@ namespace libtorrent
// a plain tcp socket is used, and
// the other settings are ignored.
none,
// socks4 server, requires username.
socks4,
// the hostname and port settings are
// used to connect to the proxy. No
// username or password is sent.
@ -102,6 +104,8 @@ namespace libtorrent
, connection_speed(20)
, send_redundant_have(false)
, lazy_bitfields(true)
, inactivity_timeout(600)
, unchoke_interval(20)
#ifndef TORRENT_DISABLE_DHT
, use_dht_as_fallback(true)
#endif
@ -226,6 +230,18 @@ namespace libtorrent
// from stopping people from seeding.
bool lazy_bitfields;
// if a peer is uninteresting and uninterested for longer
// than this number of seconds, it will be disconnected.
// default is 10 minutes
int inactivity_timeout;
// the number of seconds between chokes/unchokes
int unchoke_interval;
// if this is set, this IP will be reported do the
// tracker in the ip= parameter.
address announce_ip;
#ifndef TORRENT_DISABLE_DHT
// while this is true, the dht will note be used unless the
// tracker is online

View File

@ -34,12 +34,17 @@ POSSIBILITY OF SUCH DAMAGE.
#define TORRENT_SOCKET_TYPE
#include "libtorrent/socks5_stream.hpp"
#include "libtorrent/socks4_stream.hpp"
#include "libtorrent/http_stream.hpp"
#include "libtorrent/variant_stream.hpp"
namespace libtorrent
{
typedef variant_stream<stream_socket, socks5_stream, http_stream> socket_type;
typedef variant_stream<
stream_socket
, socks5_stream
, socks4_stream
, http_stream> socket_type;
}
#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 {
class socks5_stream : boost::noncopyable
class socks5_stream : public proxy_base
{
public:
typedef stream_socket::lowest_layer_type lowest_layer_type;
typedef stream_socket::endpoint_type endpoint_type;
typedef stream_socket::protocol_type protocol_type;
explicit socks5_stream(asio::io_service& io_service)
: m_sock(io_service)
, m_resolver(io_service)
: proxy_base(io_service)
{}
void set_proxy(std::string hostname, int port)
{
m_hostname = hostname;
m_port = port;
}
void set_username(std::string const& user
, std::string const& password)
{
@ -35,108 +52,6 @@ public:
m_password = password;
}
template <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;
template <class Handler>
@ -176,20 +91,13 @@ private:
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);
stream_socket m_sock;
// the socks5 proxy
std::string m_hostname;
int m_port;
// send and receive buffer
std::vector<char> m_buffer;
// proxy authentication
std::string m_user;
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
#include <boost/limits.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/filesystem/path.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
@ -52,6 +52,9 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/torrent_info.hpp"
#include "libtorrent/piece_picker.hpp"
#include "libtorrent/intrusive_ptr_base.hpp"
#include "libtorrent/peer_request.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/config.hpp"
namespace libtorrent
@ -61,8 +64,11 @@ namespace libtorrent
struct piece_checker_data;
}
namespace fs = boost::filesystem;
class session;
struct file_pool;
struct disk_io_job;
#if defined(_WIN32) && defined(UNICODE)
@ -72,11 +78,11 @@ namespace libtorrent
TORRENT_EXPORT std::vector<std::pair<size_type, std::time_t> > get_filesizes(
torrent_info const& t
, boost::filesystem::path p);
, fs::path p);
TORRENT_EXPORT bool match_filesizes(
torrent_info const& t
, boost::filesystem::path p
, fs::path p
, std::vector<std::pair<size_type, std::time_t> > const& sizes
, bool compact_mode
, std::string* error = 0);
@ -89,6 +95,15 @@ namespace libtorrent
std::string m_msg;
};
struct TORRENT_EXPORT partial_hash
{
partial_hash(): offset(0) {}
// the number of bytes in the piece that has been hashed
int offset;
// the sha-1 context
hasher h;
};
struct TORRENT_EXPORT storage_interface
{
// create directories and set file sizes
@ -103,7 +118,7 @@ namespace libtorrent
// may throw file_error if storage for slot hasn't been allocated
virtual void write(const char* buf, int slot, int offset, int size) = 0;
virtual bool move_storage(boost::filesystem::path save_path) = 0;
virtual bool move_storage(fs::path save_path) = 0;
// verify storage dependent fast resume entries
virtual bool verify_resume_data(entry& rd, std::string& error) = 0;
@ -121,6 +136,9 @@ namespace libtorrent
// in slot3 and the data in slot3 in slot1
virtual void swap_slots3(int slot1, int slot2, int slot3) = 0;
// returns the sha1-hash for the data at the given slot
virtual sha1_hash hash_for_slot(int slot, partial_hash& h, int piece_size) = 0;
// this will close all open files that are opened for
// writing. This is called when a torrent has finished
// downloading.
@ -129,24 +147,32 @@ namespace libtorrent
};
typedef storage_interface* (&storage_constructor_type)(
torrent_info const&, boost::filesystem::path const&
torrent_info const&, fs::path const&
, file_pool&);
TORRENT_EXPORT storage_interface* default_storage_constructor(torrent_info const& ti
, boost::filesystem::path const& path, file_pool& fp);
, fs::path const& path, file_pool& fp);
// returns true if the filesystem the path relies on supports
// sparse files or automatic zero filling of files.
TORRENT_EXPORT bool supports_sparse_files(boost::filesystem::path const& p);
TORRENT_EXPORT bool supports_sparse_files(fs::path const& p);
class TORRENT_EXPORT piece_manager : boost::noncopyable
struct disk_io_thread;
class TORRENT_EXPORT piece_manager
: public intrusive_ptr_base<piece_manager>
, boost::noncopyable
{
friend class invariant_access;
friend struct disk_io_thread;
public:
piece_manager(
const torrent_info& info
, const boost::filesystem::path& path
boost::shared_ptr<void> const& torrent
, torrent_info const& ti
, fs::path const& path
, file_pool& fp
, disk_io_thread& io
, storage_constructor_type sc);
~piece_manager();
@ -156,35 +182,38 @@ namespace libtorrent
std::pair<bool, float> check_files(std::vector<bool>& pieces
, int& num_pieces, boost::recursive_mutex& mutex);
void release_files();
void write_resume_data(entry& rd) const;
bool verify_resume_data(entry& rd, std::string& error);
bool is_allocating() const;
bool allocate_slots(int num_slots, bool abort_on_disk = false);
bool is_allocating() const
{ return m_state == state_allocating; }
void mark_failed(int index);
unsigned long piece_crc(
int slot_index
, int block_size
, piece_picker::block_info const* bi);
int slot_for_piece(int piece_index) const;
size_type read(
char* buf
, int piece_index
, int offset
, int size);
void async_read(
peer_request const& r
, boost::function<void(int, disk_io_job const&)> const& handler);
void write(
const char* buf
, int piece_index
, int offset
, int size);
void async_write(
peer_request const& r
, char const* buffer
, boost::function<void(int, disk_io_job const&)> const& f);
boost::filesystem::path const& save_path() const;
bool move_storage(boost::filesystem::path const&);
void async_hash(int piece, boost::function<void(int, disk_io_job const&)> const& f);
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
// slots to the piece that is stored (or
@ -192,11 +221,134 @@ namespace libtorrent
// of unassigned pieces and -1 is unallocated
void export_piece_map(std::vector<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:
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>
@ -99,8 +100,12 @@ namespace libtorrent
inline bool is_negative(time_duration dt) { return dt.diff < 0; }
inline bool operator<(time_duration lhs, time_duration rhs)
{ return lhs.diff < rhs.diff; }
inline bool operator<=(time_duration lhs, time_duration rhs)
{ return lhs.diff <= rhs.diff; }
inline bool operator>(time_duration lhs, time_duration rhs)
{ return lhs.diff > rhs.diff; }
inline bool operator>=(time_duration lhs, time_duration rhs)
{ return lhs.diff >= rhs.diff; }
// libtorrent time type
struct ptime
@ -381,3 +386,4 @@ namespace libtorrent
#endif
#endif

View File

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

View File

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

View File

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

View File

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

View File

@ -123,7 +123,7 @@ namespace libtorrent
void write_request(peer_request const& r);
void write_cancel(peer_request const& r) {}
void write_have(int index) {}
void write_piece(peer_request const& r) {}
void write_piece(peer_request const& r, char const* buffer) { assert(false); }
void write_keepalive() {}
void on_connected();

View File

@ -21,7 +21,9 @@ torrent_info.cpp tracker_manager.cpp http_connection.cpp \
http_tracker_connection.cpp udp_tracker_connection.cpp \
alert.cpp identify_client.cpp ip_filter.cpp file.cpp metadata_transfer.cpp \
logger.cpp file_pool.cpp ut_pex.cpp lsd.cpp upnp.cpp instantiate_connection.cpp \
socks5_stream.cpp http_stream.cpp connection_queue.cpp $(kademlia_sources)
socks5_stream.cpp socks4_stream.cpp http_stream.cpp connection_queue.cpp \
disk_io_thread.cpp \
$(kademlia_sources)
noinst_HEADERS = \
$(top_srcdir)/include/libtorrent/alert.hpp \
@ -34,6 +36,7 @@ $(top_srcdir)/include/libtorrent/bencode.hpp \
$(top_srcdir)/include/libtorrent/buffer.hpp \
$(top_srcdir)/include/libtorrent/connection_queue.hpp \
$(top_srcdir)/include/libtorrent/debug.hpp \
$(top_srcdir)/include/libtorrent/disk_io_thread.hpp \
$(top_srcdir)/include/libtorrent/entry.hpp \
$(top_srcdir)/include/libtorrent/escape_string.hpp \
$(top_srcdir)/include/libtorrent/extensions.hpp \
@ -50,6 +53,7 @@ $(top_srcdir)/include/libtorrent/session_settings.hpp \
$(top_srcdir)/include/libtorrent/http_tracker_connection.hpp \
$(top_srcdir)/include/libtorrent/identify_client.hpp \
$(top_srcdir)/include/libtorrent/instantiate_connection.hpp \
$(top_srcdir)/include/libtorrent/intrusive_ptr_base.hpp \
$(top_srcdir)/include/libtorrent/invariant_check.hpp \
$(top_srcdir)/include/libtorrent/io.hpp \
$(top_srcdir)/include/libtorrent/ip_filter.hpp \
@ -72,6 +76,7 @@ $(top_srcdir)/include/libtorrent/session.hpp \
$(top_srcdir)/include/libtorrent/size_type.hpp \
$(top_srcdir)/include/libtorrent/socket.hpp \
$(top_srcdir)/include/libtorrent/socket_type.hpp \
$(top_srcdir)/include/libtorrent/socks4_stream.hpp \
$(top_srcdir)/include/libtorrent/socks5_stream.hpp \
$(top_srcdir)/include/libtorrent/stat.hpp \
$(top_srcdir)/include/libtorrent/storage.hpp \

View File

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

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
{
assert(indent >= 0);

View File

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

View File

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

View File

@ -411,6 +411,12 @@ namespace libtorrent
std::min(req.num_want, 999));
m_send_buffer += '&';
}
if (m_settings.announce_ip != address() && !url_has_argument(request, "ip"))
{
m_send_buffer += "ip=";
m_send_buffer += m_settings.announce_ip.to_string();
m_send_buffer += '&';
}
#ifndef TORRENT_DISABLE_ENCRYPTION
m_send_buffer += "supportcrypto=1&";

View File

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

View File

@ -67,6 +67,12 @@ namespace libtorrent
if (ps.type == proxy_settings::socks5_pw)
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
{
throw std::runtime_error("unsupported proxy type");

View File

@ -69,6 +69,15 @@ namespace libtorrent
, m_filter6.export_filter());
}
void port_filter::add_rule(boost::uint16_t first, boost::uint16_t last, int flags)
{
m_filter.add_rule(first, last, flags);
}
int port_filter::access(boost::uint16_t port) const
{
return m_filter.access(port);
}
/*
void ip_filter::print() const
{

View File

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

View File

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

View File

@ -59,21 +59,6 @@ using libtorrent::aux::session_impl;
namespace libtorrent
{
void intrusive_ptr_add_ref(peer_connection const* c)
{
assert(c->m_refs >= 0);
assert(c != 0);
++c->m_refs;
}
void intrusive_ptr_release(peer_connection const* c)
{
assert(c->m_refs > 0);
assert(c != 0);
if (--c->m_refs == 0)
delete c;
}
// outbound connection
peer_connection::peer_connection(
session_impl& ses
@ -94,6 +79,7 @@ namespace libtorrent
, m_packet_size(0)
, m_recv_pos(0)
, m_current_send_buffer(0)
, m_reading_bytes(0)
, m_write_pos(0)
, m_last_receive(time_now())
, m_last_sent(time_now())
@ -122,12 +108,14 @@ namespace libtorrent
, m_prefer_whole_pieces(false)
, m_request_large_blocks(false)
, m_non_prioritized(false)
, m_refs(0)
, m_upload_limit(resource_request::inf)
, m_download_limit(resource_request::inf)
, m_peer_info(peerinfo)
, m_speed(slow)
, m_connection_ticket(-1)
, m_remote_bytes_dled(0)
, m_remote_dl_rate(0)
, m_remote_dl_update(time_now())
#ifndef NDEBUG
, m_in_constructor(true)
#endif
@ -167,6 +155,7 @@ namespace libtorrent
, m_packet_size(0)
, m_recv_pos(0)
, m_current_send_buffer(0)
, m_reading_bytes(0)
, m_write_pos(0)
, m_last_receive(time_now())
, m_last_sent(time_now())
@ -193,11 +182,13 @@ namespace libtorrent
, m_prefer_whole_pieces(false)
, m_request_large_blocks(false)
, m_non_prioritized(false)
, m_refs(0)
, m_upload_limit(resource_request::inf)
, m_download_limit(resource_request::inf)
, m_peer_info(peerinfo)
, m_speed(slow)
, m_remote_bytes_dled(0)
, m_remote_dl_rate(0)
, m_remote_dl_update(time_now())
#ifndef NDEBUG
, m_in_constructor(true)
#endif
@ -742,6 +733,16 @@ namespace libtorrent
&& !is_interesting()
&& t->picker().piece_priority(index) != 0)
t->get_policy().peer_is_interesting(*this);
// this will disregard all have messages we get within
// the first two seconds. Since some clients implements
// lazy bitfields, these will not be reliable to use
// for an estimated peer download rate.
if (!peer_info_struct() || time_now() - peer_info_struct()->connected > seconds(2))
{
// update bytes downloaded since last timer
m_remote_bytes_dled += t->torrent_file().piece_size(index);
}
}
if (is_seed())
@ -1012,7 +1013,7 @@ namespace libtorrent
for (std::vector<piece_picker::downloading_piece>::const_iterator i =
dl_queue.begin(); i != dl_queue.end(); ++i)
{
assert(i->finished < blocks_per_piece);
assert(i->finished <= blocks_per_piece);
}
}
}
@ -1076,7 +1077,6 @@ namespace libtorrent
piece_picker& picker = t->picker();
piece_manager& fs = t->filesystem();
policy& pol = t->get_policy();
std::vector<piece_block> finished_blocks;
piece_block block_finished(p.piece, p.start / t->block_size());
@ -1125,13 +1125,12 @@ namespace libtorrent
}
else
{
// cancel the block from the
/* // cancel the block from the
// peer that has taken over it.
boost::optional<tcp::endpoint> peer
= t->picker().get_downloader(block_finished);
if (peer)
if (peer && t->picker().is_requested(block_finished))
{
assert(!t->picker().is_finished(block_finished));
peer_connection* pc = t->connection_for(*peer);
if (pc && pc != this)
{
@ -1140,7 +1139,7 @@ namespace libtorrent
}
}
else
{
*/ {
if (t->alerts().should_post(alert::debug))
{
t->alerts().post_alert(
@ -1153,15 +1152,28 @@ namespace libtorrent
(*m_logger) << " *** The block we just got was not in the "
"request queue ***\n";
#endif
t->received_redundant_data(p.length);
if (!has_peer_choked())
{
request_a_block(*t, *this);
send_block_requests();
}
return;
}
}
assert(picker.is_requested(block_finished));
// if the block we got is already finished, then ignore it
if (picker.is_finished(block_finished))
if (picker.is_downloaded(block_finished))
{
t->received_redundant_data(t->block_size());
pol.block_finished(*this, block_finished);
t->received_redundant_data(p.length);
if (!has_peer_choked())
{
request_a_block(*t, *this);
send_block_requests();
}
if (request_peer && !request_peer->has_peer_choked() && !t->is_seed())
{
@ -1171,16 +1183,9 @@ namespace libtorrent
return;
}
fs.write(data, p.piece, p.start, p.length);
picker.mark_as_finished(block_finished, m_remote);
try
{
pol.block_finished(*this, block_finished);
send_block_requests();
}
catch (std::exception const&) {}
fs.async_write(p, data, bind(&peer_connection::on_disk_write_complete
, self(), _1, _2, p, t));
picker.mark_as_writing(block_finished, m_remote);
if (request_peer && !request_peer->has_peer_choked() && !t->is_seed())
{
@ -1188,90 +1193,63 @@ namespace libtorrent
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
try
{
#endif
bool was_seed = t->is_seed();
bool was_finished = picker.num_filtered() + t->num_pieces()
== t->torrent_file().num_pieces();
// did we just finish the piece?
if (picker.is_piece_finished(p.piece))
{
#ifndef NDEBUG
check_postcondition post_checker2_(t, false);
#endif
bool verified = t->verify_piece(p.piece);
if (verified)
{
// the following call may cause picker to become invalid
// in case we just became a seed
t->announce_piece(p.piece);
assert(t->valid_metadata());
// if we just became a seed, picker is now invalid, since it
// is deallocated by the torrent once it starts seeding
if (!was_finished
&& (t->is_seed()
|| picker.num_filtered() + t->num_pieces()
== t->torrent_file().num_pieces()))
{
// torrent finished
// i.e. all the pieces we're interested in have
// been downloaded. Release the files (they will open
// in read only mode if needed)
try { t->finished(); }
catch (std::exception& e)
{
#ifndef NDEBUG
std::cerr << e.what() << std::endl;
assert(false);
#endif
}
}
}
else
{
t->piece_failed(p.piece);
}
#ifndef NDEBUG
try
{
#endif
pol.piece_finished(p.piece, verified);
#ifndef NDEBUG
}
catch (std::exception const& e)
{
std::cerr << e.what() << std::endl;
assert(false);
}
#endif
#ifndef NDEBUG
try
{
#endif
if (!was_seed && t->is_seed())
{
assert(verified);
t->completed();
}
#ifndef NDEBUG
}
catch (std::exception const& e)
{
std::cerr << e.what() << std::endl;
assert(false);
}
#endif
t->async_verify_piece(p.piece, bind(&torrent::piece_finished, t
, p.piece, _1));
}
#ifndef NDEBUG
@ -1350,7 +1328,7 @@ namespace libtorrent
assert(block.piece_index < t->torrent_file().num_pieces());
assert(block.block_index >= 0);
assert(block.block_index < t->torrent_file().piece_size(block.piece_index));
assert(!t->picker().is_downloading(block));
assert(!t->picker().is_requested(block));
piece_picker::piece_state_t state;
peer_speed_t speed = peer_speed();
@ -1376,7 +1354,7 @@ namespace libtorrent
assert(block.piece_index < t->torrent_file().num_pieces());
assert(block.block_index >= 0);
assert(block.block_index < t->torrent_file().piece_size(block.piece_index));
assert(t->picker().is_downloading(block));
assert(t->picker().is_requested(block));
t->picker().abort_download(block);
@ -1603,6 +1581,8 @@ namespace libtorrent
void peer_connection::disconnect()
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
boost::intrusive_ptr<peer_connection> me(this);
INVARIANT_CHECK;
@ -1753,12 +1733,14 @@ namespace libtorrent
p.failcount = peer_info_struct()->failcount;
p.num_hashfails = peer_info_struct()->hashfails;
p.flags |= peer_info_struct()->on_parole ? peer_info::on_parole : 0;
p.remote_dl_rate = m_remote_dl_rate;
}
else
{
p.source = 0;
p.failcount = 0;
p.num_hashfails = 0;
p.remote_dl_rate = 0;
}
p.send_buffer_size = send_buffer_size();
@ -1868,10 +1850,13 @@ namespace libtorrent
m_assume_fifo = true;
if (!has_peer_choked())
{
request_a_block(*t, *this);
send_block_requests();
}
}
}
m_statistics.second_tick(tick_interval);
@ -1915,6 +1900,21 @@ namespace libtorrent
, m_upload_limit));
}
// update once every minute
if (now - m_remote_dl_update >= seconds(60))
{
float factor = 0.6666666666667f;
if (m_remote_dl_rate == 0) factor = 0.0f;
m_remote_dl_rate =
(m_remote_dl_rate * factor) +
((m_remote_bytes_dled * (1.0f-factor)) / 60.f);
m_remote_bytes_dled = 0;
m_remote_dl_update = now;
}
fill_send_buffer();
/*
size_type diff = share_diff();
@ -1970,7 +1970,7 @@ namespace libtorrent
else if (buffer_size_watermark > 80 * 1024) buffer_size_watermark = 80 * 1024;
while (!m_requests.empty()
&& (send_buffer_size() < buffer_size_watermark)
&& (send_buffer_size() + m_reading_bytes < buffer_size_watermark)
&& !m_choked)
{
assert(t->valid_metadata());
@ -1982,16 +1982,12 @@ namespace libtorrent
assert(r.start + r.length <= t->torrent_file().piece_size(r.piece));
assert(r.length > 0 && r.start >= 0);
write_piece(r);
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string()
<< " ==> PIECE [ piece: " << r.piece << " | s: " << r.start
<< " | l: " << r.length << " ]\n";
#endif
t->filesystem().async_read(r, bind(&peer_connection::on_disk_read_complete
, self(), _1, _2, r));
m_reading_bytes += r.length;
m_requests.erase(m_requests.begin());
/*
if (m_requests.empty()
&& m_num_invalid_requests > 0
&& is_peer_interested()
@ -2004,9 +2000,49 @@ namespace libtorrent
send_choke();
send_unchoke();
}
*/
}
}
void peer_connection::on_disk_read_complete(int ret, disk_io_job const& j, peer_request r)
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
m_reading_bytes -= r.length;
if (ret != r.length || m_torrent.expired())
{
boost::shared_ptr<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)
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
@ -2599,11 +2635,13 @@ namespace libtorrent
time_duration d2;
d1 = now - m_became_uninterested;
d2 = now - m_became_uninteresting;
// TODO: these timeouts should be user settable
time_duration time_limit = seconds(
m_ses.settings().inactivity_timeout);
if (!m_interesting
&& !m_peer_interested
&& d1 > minutes(10)
&& d2 > minutes(10))
&& d1 > time_limit
&& d2 > time_limit)
{
return true;
}
@ -2663,3 +2701,4 @@ namespace libtorrent
}
}

View File

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

View File

@ -142,7 +142,19 @@ namespace
bool operator()(policy::peer const& p) const
{ return p.ip.address() == m_ip.address(); }
tcp::endpoint m_ip;
tcp::endpoint const& m_ip;
};
struct match_peer_id
{
match_peer_id(peer_id const& id_)
: m_id(id_)
{}
bool operator()(policy::peer const& p) const
{ return p.connection && p.connection->pid() == m_id; }
peer_id const& m_id;
};
struct match_peer_connection
@ -152,9 +164,13 @@ namespace
{}
bool operator()(policy::peer const& p) const
{ return p.connection == &m_conn; }
{
return p.connection == &m_conn
|| (p.ip == m_conn.remote()
&& p.type == policy::peer::connectable);
}
const peer_connection& m_conn;
peer_connection const& m_conn;
};
@ -230,7 +246,7 @@ namespace libtorrent
for (std::vector<piece_block>::iterator i = interesting_pieces.begin();
i != interesting_pieces.end(); ++i)
{
if (p.is_downloading(*i))
if (p.is_requested(*i))
{
busy_pieces.push_back(*i);
continue;
@ -524,6 +540,8 @@ namespace libtorrent
int max_failcount = m_torrent->settings().max_failcount;
int min_reconnect_time = m_torrent->settings().min_reconnect_time;
aux::session_impl& ses = m_torrent->session();
for (iterator i = m_peers.begin(); i != m_peers.end(); ++i)
{
if (i->connection) continue;
@ -533,6 +551,8 @@ namespace libtorrent
if (i->failcount >= max_failcount) continue;
if (now - i->connected < seconds(i->failcount * min_reconnect_time))
continue;
if (ses.m_port_filter.access(i->ip.port()) & port_filter::blocked)
continue;
assert(i->connected <= now);
@ -846,12 +866,13 @@ namespace libtorrent
--m_num_unchoked;
} while (m_num_unchoked > m_torrent->m_uploads_quota.given);
}
else
// this should prevent the choke/unchoke
// problem, since it will not unchoke unless
// there actually are any choked peers
else if (count_choked() > 0)
{
// optimistic unchoke. trade the 'worst'
// unchoked peer with one of the choked
// TODO: This rotation should happen
// far less frequent than this!
assert(m_num_unchoked <= m_torrent->num_peers());
iterator p = find_unchoke_candidate();
if (p != m_peers.end())
@ -871,6 +892,22 @@ namespace libtorrent
}
}
int policy::count_choked() const
{
int ret = 0;
for (const_iterator i = m_peers.begin();
i != m_peers.end(); ++i)
{
if (!i->connection
|| i->connection->is_connecting()
|| i->connection->is_disconnecting()
|| !i->connection->is_peer_interested())
continue;
if (i->connection->is_choked()) ++ret;
}
return ret;
}
void policy::new_connection(peer_connection& c)
{
assert(!c.is_local());
@ -902,7 +939,10 @@ namespace libtorrent
if (m_torrent->settings().allow_multiple_connections_per_ip)
{
i = m_peers.end();
i = std::find_if(
m_peers.begin()
, m_peers.end()
, match_peer_connection(c));
}
else
{
@ -968,13 +1008,29 @@ namespace libtorrent
if(remote.address() == address() || remote.port() == 0)
return;
aux::session_impl& ses = m_torrent->session();
port_filter const& pf = ses.m_port_filter;
if (pf.access(remote.port()) & port_filter::blocked)
{
if (ses.m_alerts.should_post(alert::info))
{
ses.m_alerts.post_alert(peer_blocked_alert(remote.address()
, "outgoing port blocked, peer not added to peer list"));
}
return;
}
try
{
iterator i;
if (m_torrent->settings().allow_multiple_connections_per_ip)
{
i = m_peers.end();
i = std::find_if(
m_peers.begin()
, m_peers.end()
, match_peer_id(pid));
}
else
{
@ -986,8 +1042,6 @@ namespace libtorrent
if (i == m_peers.end())
{
aux::session_impl& ses = m_torrent->session();
// if the IP is blocked, don't add it
if (ses.m_ip_filter.access(remote.address()) & ip_filter::blocked)
{
@ -1095,18 +1149,6 @@ namespace libtorrent
}
}
// TODO: we must be able to get interested
// in a peer again, if a piece fails that
// this peer has.
void policy::block_finished(peer_connection& c, piece_block)
{
INVARIANT_CHECK;
// if the peer hasn't choked us, ask for another piece
if (!c.has_peer_choked() && !m_torrent->is_seed())
request_a_block(*m_torrent, c);
}
// this is called when we are unchoked by a peer
// i.e. a peer lets us know that we will receive
// data from now on
@ -1167,6 +1209,7 @@ namespace libtorrent
c.add_free_upload(-diff);
}
}
/*
if (!c.is_choked())
{
c.send_choke();
@ -1175,6 +1218,7 @@ namespace libtorrent
if (m_torrent->is_seed()) seed_unchoke_one_peer();
else unchoke_one_peer();
}
*/
}
bool policy::unchoke_one_peer()

View File

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

View File

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

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::get;
using boost::tuples::make_tuple;
using boost::filesystem::complete;
using boost::bind;
using boost::mutex;
using libtorrent::aux::session_impl;
@ -147,11 +146,12 @@ namespace
namespace libtorrent
{
torrent::torrent(
session_impl& ses
, aux::checker_impl& checker
, torrent_info const& tf
, boost::filesystem::path const& save_path
, fs::path const& save_path
, tcp::endpoint const& net_interface
, bool compact_mode
, int block_size
@ -174,7 +174,9 @@ namespace libtorrent
, m_resolve_countries(false)
#endif
, m_announce_timer(ses.m_io_service)
#ifndef TORRENT_DISABLE_DHT
, m_last_dht_announce(time_now() - minutes(15))
#endif
, m_policy()
, m_ses(ses)
, m_checker(checker)
@ -202,8 +204,6 @@ namespace libtorrent
m_initial_done = 0;
#endif
INVARIANT_CHECK;
m_uploads_quota.min = 2;
m_connections_quota.min = 2;
// this will be corrected the next time the main session
@ -212,7 +212,6 @@ namespace libtorrent
m_uploads_quota.max = std::numeric_limits<int>::max();
m_connections_quota.max = std::numeric_limits<int>::max();
m_policy.reset(new policy(this));
init();
}
@ -222,7 +221,7 @@ namespace libtorrent
, char const* tracker_url
, sha1_hash const& info_hash
, char const* name
, boost::filesystem::path const& save_path
, fs::path const& save_path
, tcp::endpoint const& net_interface
, bool compact_mode
, int block_size
@ -245,7 +244,9 @@ namespace libtorrent
, m_resolve_countries(false)
#endif
, m_announce_timer(ses.m_io_service)
#ifndef TORRENT_DISABLE_DHT
, m_last_dht_announce(time_now() - minutes(15))
#endif
, m_policy()
, m_ses(ses)
, m_checker(checker)
@ -295,6 +296,7 @@ namespace libtorrent
void torrent::start()
{
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.async_wait(m_ses.m_strand.wrap(
bind(&torrent::on_announce_disp, self, _1)));
@ -327,8 +329,7 @@ namespace libtorrent
INVARIANT_CHECK;
if (m_ses.is_aborted())
m_abort = true;
assert(m_abort);
if (!m_connections.empty())
disconnect_all();
}
@ -347,17 +348,20 @@ namespace libtorrent
}
#endif
// this may not be called from a constructor because of the call to
// shared_from_this()
void torrent::init()
{
INVARIANT_CHECK;
assert(m_torrent_file.is_valid());
assert(m_torrent_file.num_files() > 0);
assert(m_torrent_file.total_size() >= 0);
m_have_pieces.resize(m_torrent_file.num_pieces(), false);
m_storage.reset(new piece_manager(m_torrent_file, m_save_path
, m_ses.m_files, m_storage_constructor));
// the shared_from_this() will create an intentional
// 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_picker.reset(new piece_picker(
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)));
}
}
m_policy->pulse();
if (m_ses.m_alerts.should_post(alert::info))
{
@ -687,7 +690,7 @@ namespace libtorrent
int corr = 0;
int index = i->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
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)
{
assert(i->info[j].finished == 0 || i->info[j].finished == 1);
assert(m_picker->is_finished(piece_block(index, j)) == i->info[j].finished);
corr += i->info[j].finished * m_block_size;
assert(m_picker->is_finished(piece_block(index, j)) == (i->info[j].state == piece_picker::block_info::state_finished));
corr += (i->info[j].state == piece_picker::block_info::state_finished) * m_block_size;
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
// and if we have the last block
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_torrent_file.piece_size(last_piece) % m_block_size;
@ -719,8 +722,8 @@ namespace libtorrent
wanted_done += corr;
}
assert(total_done < m_torrent_file.total_size());
assert(wanted_done < m_torrent_file.total_size());
assert(total_done <= m_torrent_file.total_size());
assert(wanted_done <= m_torrent_file.total_size());
std::map<piece_block, int> downloading_piece;
for (const_peer_iterator i = begin(); i != end(); ++i)
@ -784,7 +787,7 @@ namespace libtorrent
std::cerr << " " << i->index << " ";
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;
}
@ -800,8 +803,8 @@ namespace libtorrent
}
assert(total_done < m_torrent_file.total_size());
assert(wanted_done < m_torrent_file.total_size());
assert(total_done <= m_torrent_file.total_size());
assert(wanted_done <= m_torrent_file.total_size());
#endif
@ -809,6 +812,84 @@ namespace libtorrent
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)
{
// 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()
// INVARIANT_CHECK;
assert(m_storage.get());
assert(m_storage);
assert(m_storage->refcount() > 0);
assert(m_picker.get());
assert(index >= 0);
assert(index < m_torrent_file.num_pieces());
@ -907,6 +989,7 @@ namespace libtorrent
// start with redownloading the pieces that the client
// that has sent the least number of pieces
m_picker->restore_piece(index);
assert(m_storage);
m_storage->mark_failed(index);
assert(m_have_pieces[index] == false);
@ -924,7 +1007,19 @@ namespace libtorrent
// disconnect all peers and close all
// files belonging to the torrents
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)
@ -981,7 +1076,19 @@ namespace libtorrent
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)
{
@ -1713,8 +1820,13 @@ namespace libtorrent
void torrent::set_metadata(entry const& metadata)
{
INVARIANT_CHECK;
assert(!m_torrent_file.is_valid());
m_torrent_file.parse_info_section(metadata);
init();
boost::mutex::scoped_lock(m_checker.m_mutex);
boost::shared_ptr<aux::piece_checker_data> d(
@ -1928,7 +2040,9 @@ namespace libtorrent
std::for_each(seeds.begin(), seeds.end()
, 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)
@ -2004,17 +2118,12 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (!m_storage.get())
{
// this means we have received the metadata through the
// metadata extension, and we have to initialize
init();
}
assert(m_storage.get());
assert(valid_metadata());
bool done = true;
try
{
assert(m_storage);
assert(m_owning_storage.get());
done = m_storage->check_fastresume(data, m_have_pieces, m_num_pieces
, m_compact_mode);
}
@ -2043,11 +2152,12 @@ namespace libtorrent
{
INVARIANT_CHECK;
assert(m_storage.get());
assert(m_owning_storage.get());
std::pair<bool, float> progress(true, 1.f);
try
{
assert(m_storage);
progress = m_storage->check_files(m_have_pieces, m_num_pieces
, m_ses.m_mutex);
}
@ -2082,9 +2192,19 @@ namespace libtorrent
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)
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
@ -2137,34 +2257,45 @@ namespace libtorrent
return m_ses.m_alerts;
}
boost::filesystem::path torrent::save_path() const
fs::path torrent::save_path() const
{
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;
bool ret = true;
if (m_storage.get())
if (m_owning_storage.get())
{
ret = m_storage->move_storage(save_path);
m_save_path = m_storage->save_path();
m_owning_storage->async_move_storage(save_path
, bind(&torrent::on_storage_moved, shared_from_this(), _1, _2));
}
else
{
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()
{
INVARIANT_CHECK;
assert(m_storage.get());
return *m_storage;
assert(m_owning_storage.get());
return *m_owning_storage;
}
@ -2198,11 +2329,11 @@ namespace libtorrent
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
{
assert(m_have_pieces.empty());
assert(m_abort || m_have_pieces.empty());
}
size_type total_done = quantized_bytes_done();
@ -2321,7 +2452,14 @@ namespace libtorrent
m_just_paused = true;
// this will make the storage close all
// 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()
@ -2448,33 +2586,31 @@ namespace libtorrent
m_time_scaler--;
if (m_time_scaler <= 0)
{
m_time_scaler = 10;
m_time_scaler = settings().unchoke_interval;
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 < m_torrent_file.num_pieces());
assert(piece_index < (int)m_have_pieces.size());
int size = static_cast<int>(m_torrent_file.piece_size(piece_index));
std::vector<char> buffer(size);
assert(size > 0);
m_storage->read(&buffer[0], piece_index, 0, size);
m_storage->async_hash(piece_index, bind(&torrent::on_piece_verified
, shared_from_this(), _1, _2, f));
}
hasher h;
h.update(&buffer[0], size);
sha1_hash digest = h.final();
if (m_torrent_file.hash_for_piece(piece_index) != digest)
return false;
return true;
void torrent::on_piece_verified(int ret, disk_io_job const& j
, boost::function<void(bool)> f)
{
sha1_hash h(j.str);
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
f(m_torrent_file.hash_for_piece(j.piece) == h);
}
const tcp::endpoint& torrent::current_tracker() const
@ -2483,7 +2619,7 @@ namespace libtorrent
}
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
{
@ -2533,8 +2669,8 @@ namespace libtorrent
torrent_status st;
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(&std::map<tcp::endpoint,peer_connection*>::value_type::second, _1))));
!boost::bind(&peer_connection::is_connecting
, boost::bind(&std::map<tcp::endpoint,peer_connection*>::value_type::second, _1)));
st.num_complete = m_complete;
st.num_incomplete = m_incomplete;
@ -2635,7 +2771,6 @@ namespace libtorrent
}
else if (st.total_wanted_done == st.total_wanted)
{
assert(st.total_done != m_torrent_file.total_size());
st.state = torrent_status::finished;
}
else
@ -2655,10 +2790,10 @@ namespace libtorrent
{
INVARIANT_CHECK;
return (int)std::count_if(m_connections.begin(), m_connections.end(),
boost::bind(&peer_connection::is_seed,
boost::bind(&std::map<tcp::endpoint
,peer_connection*>::value_type::second, _1)));
return (int)std::count_if(m_connections.begin(), m_connections.end()
, boost::bind(&peer_connection::is_seed
, boost::bind(&std::map<tcp::endpoint
, peer_connection*>::value_type::second, _1)));
}
void torrent::tracker_request_timed_out(

View File

@ -80,6 +80,8 @@ using libtorrent::aux::session_impl;
namespace libtorrent
{
namespace fs = boost::filesystem;
namespace
{
void throw_invalid_handle()
@ -205,12 +207,12 @@ namespace libtorrent
, bind(&torrent::download_limit, _1));
}
bool torrent_handle::move_storage(
boost::filesystem::path const& save_path) const
void torrent_handle::move_storage(
fs::path const& save_path) const
{
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));
}
@ -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
{
INVARIANT_CHECK;
@ -556,9 +566,12 @@ namespace libtorrent
for (int j = 0; j < num_bitmask_bytes; ++j)
{
unsigned char v = 0;
for (int k = 0; k < 8; ++k)
v |= i->info[j*8+k].finished?(1 << k):0;
int bits = std::min(num_blocks_per_piece - j*8, 8);
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);
assert(bits == 8 || j == num_bitmask_bytes - 1);
}
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;
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));
}
@ -717,7 +730,7 @@ namespace libtorrent
{
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
if (peer->associated_torrent().expired()) continue;
@ -760,10 +773,9 @@ namespace libtorrent
pi.blocks_in_piece = p.blocks_in_piece(i->index);
for (int j = 0; j < pi.blocks_in_piece; ++j)
{
pi.peer[j] = i->info[j].peer;
pi.num_downloads[j] = i->info[j].num_downloads;
pi.finished_blocks[j] = i->info[j].finished;
pi.requested_blocks[j] = i->info[j].requested;
pi.blocks[j].peer = i->info[j].peer;
pi.blocks[j].num_downloads = i->info[j].num_downloads;
pi.blocks[j].state = i->info[j].state;
}
pi.piece_index = i->index;
queue.push_back(pi);

View File

@ -62,10 +62,12 @@ namespace pt = boost::posix_time;
namespace gr = boost::gregorian;
using namespace libtorrent;
using namespace boost::filesystem;
namespace
{
namespace fs = boost::filesystem;
void convert_to_utf8(std::string& str, unsigned char chr)
{
str += 0xc0 | ((chr & 0xff) >> 6);
@ -153,7 +155,7 @@ namespace
// encoded string
if (!valid_encoding)
{
target.orig_path.reset(new path(target.path));
target.orig_path.reset(new fs::path(target.path));
target.path = tmp_path;
}
}
@ -203,8 +205,8 @@ namespace
offset += target.back().size;
}
}
void remove_dir(path& p)
/*
void remove_dir(fs::path& p)
{
assert(p.begin() != p.end());
path tmp;
@ -212,6 +214,7 @@ namespace
tmp /= *i;
p = tmp;
}
*/
}
namespace libtorrent
@ -277,6 +280,29 @@ namespace libtorrent
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)
{
// make sure the size is an even power of 2
@ -323,7 +349,7 @@ namespace libtorrent
else
{ m_name = info["name"].string(); }
path tmp = m_name;
fs::path tmp = m_name;
if (tmp.is_complete()) throw std::runtime_error("torrent contains "
"a file with an absolute path: '" + m_name + "'");
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)));
}
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())
{
@ -589,8 +615,6 @@ namespace libtorrent
entry torrent_info::create_info_metadata() const
{
namespace fs = boost::filesystem;
// you have to add files to the torrent first
assert(!m_files.empty());
@ -650,8 +674,6 @@ namespace libtorrent
{
assert(m_piece_length > 0);
namespace fs = boost::filesystem;
if ((m_urls.empty() && m_nodes.empty()) || m_files.empty())
{
// TODO: throw something here

View File

@ -289,28 +289,6 @@ namespace libtorrent
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)
: m_strand(str)
, m_start_time(time_now())
@ -318,7 +296,6 @@ namespace libtorrent
, m_timeout(str.io_service())
, m_completion_timeout(0)
, m_read_timeout(0)
, m_refs(0)
{}
void timeout_handler::set_timeout(int completion_timeout, int read_timeout)
@ -467,8 +444,19 @@ namespace libtorrent
++start;
}
std::string::iterator port_pos
= std::find(start, url.end(), ':');
std::string::iterator port_pos;
// 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)
{

View File

@ -307,6 +307,9 @@ namespace libtorrent
// event
detail::write_int32(req.event, out);
// ip address
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
detail::write_int32(req.key, out);

View File

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

View File

@ -71,7 +71,10 @@ PREF_FUNCTIONS = {
"max_active_torrents" : 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_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",
@ -443,6 +446,7 @@ class Manager:
# altering max_active_torrents), or just from time to time
# ___ALL queuing code should be in this function, and ONLY here___
def apply_queue(self, efficient = True):
print "applying queue";
# Handle autoseeding - downqueue as needed
if self.get_pref('auto_seed_ratio') > 0:
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
def add_range_to_ip_filter(self, 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->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}",
"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;
}
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)
{
M_pe_settings = new pe_settings();
@ -1284,6 +1333,9 @@ static PyMethodDef deluge_core_methods[] =
{"create_torrent", torrent_create_torrent, METH_VARARGS, "."},
{"reset_IP_filter", torrent_reset_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}
};

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_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_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_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))
@ -90,6 +93,9 @@ class PreferencesDlg:
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("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("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())

View File

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