lt sync 1912

This commit is contained in:
Marcos Pinto 2008-01-09 06:35:48 +00:00
parent 5c485afe5e
commit e491ecf0df
26 changed files with 492 additions and 186 deletions

View File

@ -41,6 +41,7 @@ TORRENT_EXPORT void assert_fail(const char* expr, int line, char const* file, ch
#define TORRENT_ASSERT(x) if (x) {} else assert_fail(#x, __LINE__, __FILE__, __PRETTY_FUNCTION__) #define TORRENT_ASSERT(x) if (x) {} else assert_fail(#x, __LINE__, __FILE__, __PRETTY_FUNCTION__)
#else #else
#include <cassert>
#define TORRENT_ASSERT(x) assert(x) #define TORRENT_ASSERT(x) assert(x)
#endif #endif

View File

@ -379,6 +379,7 @@ namespace libtorrent
// this pool is used to allocate and recycle send // this pool is used to allocate and recycle send
// buffers from. // buffers from.
boost::pool<> m_send_buffers; boost::pool<> m_send_buffers;
boost::mutex m_send_buffer_mutex;
// the file pool that all storages in this session's // the file pool that all storages in this session's
// torrents uses. It sets a limit on the number of // torrents uses. It sets a limit on the number of

View File

@ -0,0 +1,120 @@
/*
Copyright (c) 2007, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORRENT_BANDWIDTH_LIMIT_HPP_INCLUDED
#define TORRENT_BANDWIDTH_LIMIT_HPP_INCLUDED
#include <boost/integer_traits.hpp>
#include "libtorrent/assert.hpp"
namespace libtorrent {
// member of peer_connection
struct bandwidth_limit
{
static const int inf = boost::integer_traits<int>::const_max;
bandwidth_limit()
: m_quota_left(0)
, m_local_limit(inf)
, m_current_rate(0)
{}
void throttle(int limit)
{
TORRENT_ASSERT(limit > 0);
m_local_limit = limit;
}
int throttle() const
{
return m_local_limit;
}
void assign(int amount)
{
TORRENT_ASSERT(amount >= 0);
m_current_rate += amount;
m_quota_left += amount;
}
void use_quota(int amount)
{
TORRENT_ASSERT(amount <= m_quota_left);
m_quota_left -= amount;
}
int quota_left() const
{
return (std::max)(m_quota_left, 0);
}
void expire(int amount)
{
TORRENT_ASSERT(amount >= 0);
m_current_rate -= amount;
}
int max_assignable() const
{
if (m_local_limit == inf) return inf;
if (m_local_limit <= m_current_rate) return 0;
return m_local_limit - m_current_rate;
}
private:
// this is the amount of bandwidth we have
// been assigned without using yet. i.e.
// the bandwidth that we use up every time
// we receive or send a message. Once this
// hits zero, we need to request more
// bandwidth from the torrent which
// in turn will request bandwidth from
// the bandwidth manager
int m_quota_left;
// the local limit is the number of bytes
// per window size we are allowed to use.
int m_local_limit;
// the current rate is the number of
// bytes we have been assigned within
// the window size.
int m_current_rate;
};
}
#endif

View File

@ -44,6 +44,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/socket.hpp" #include "libtorrent/socket.hpp"
#include "libtorrent/invariant_check.hpp" #include "libtorrent/invariant_check.hpp"
#include "libtorrent/assert.hpp" #include "libtorrent/assert.hpp"
#include "libtorrent/bandwidth_limit.hpp"
#include "libtorrent/bandwidth_queue_entry.hpp"
using boost::weak_ptr; using boost::weak_ptr;
using boost::shared_ptr; using boost::shared_ptr;
@ -77,91 +79,6 @@ struct history_entry
weak_ptr<Torrent> tor; weak_ptr<Torrent> tor;
}; };
template<class PeerConnection>
struct bw_queue_entry
{
bw_queue_entry(boost::intrusive_ptr<PeerConnection> const& pe
, int blk, bool no_prio)
: peer(pe), max_block_size(blk), non_prioritized(no_prio) {}
boost::intrusive_ptr<PeerConnection> peer;
int max_block_size;
bool non_prioritized;
};
// member of peer_connection
struct bandwidth_limit
{
static const int inf = boost::integer_traits<int>::const_max;
bandwidth_limit() throw()
: m_quota_left(0)
, m_local_limit(inf)
, m_current_rate(0)
{}
void throttle(int limit) throw()
{
m_local_limit = limit;
}
int throttle() const throw()
{
return m_local_limit;
}
void assign(int amount) throw()
{
TORRENT_ASSERT(amount >= 0);
m_current_rate += amount;
m_quota_left += amount;
}
void use_quota(int amount) throw()
{
TORRENT_ASSERT(amount <= m_quota_left);
m_quota_left -= amount;
}
int quota_left() const throw()
{
return (std::max)(m_quota_left, 0);
}
void expire(int amount) throw()
{
TORRENT_ASSERT(amount >= 0);
m_current_rate -= amount;
}
int max_assignable() const throw()
{
if (m_local_limit == inf) return inf;
if (m_local_limit <= m_current_rate) return 0;
return m_local_limit - m_current_rate;
}
private:
// this is the amount of bandwidth we have
// been assigned without using yet. i.e.
// the bandwidth that we use up every time
// we receive or send a message. Once this
// hits zero, we need to request more
// bandwidth from the torrent which
// in turn will request bandwidth from
// the bandwidth manager
int m_quota_left;
// the local limit is the number of bytes
// per window size we are allowed to use.
int m_local_limit;
// the current rate is the number of
// bytes we have been assigned within
// the window size.
int m_current_rate;
};
template<class T> template<class T>
T clamp(T val, T ceiling, T floor) throw() T clamp(T val, T ceiling, T floor) throw()
{ {
@ -203,6 +120,19 @@ struct bandwidth_manager
m_history_timer.cancel(); m_history_timer.cancel();
} }
#ifndef NDEBUG
bool is_in_history(PeerConnection const* peer) const
{
mutex_t::scoped_lock l(m_mutex);
for (typename history_t::const_iterator i
= m_history.begin(), end(m_history.end()); i != end; ++i)
{
if (i->peer.get() == peer) return true;
}
return false;
}
#endif
// non prioritized means that, if there's a line for bandwidth, // non prioritized means that, if there's a line for bandwidth,
// others will cut in front of the non-prioritized peers. // others will cut in front of the non-prioritized peers.
// this is used by web seeds // this is used by web seeds
@ -213,6 +143,7 @@ struct bandwidth_manager
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_ASSERT(blk > 0); TORRENT_ASSERT(blk > 0);
mutex_t::scoped_lock l(m_mutex);
TORRENT_ASSERT(!peer->ignore_bandwidth_limits()); TORRENT_ASSERT(!peer->ignore_bandwidth_limits());
// make sure this peer isn't already in line // make sure this peer isn't already in line
@ -224,6 +155,7 @@ struct bandwidth_manager
TORRENT_ASSERT(i->peer < peer || peer < i->peer); TORRENT_ASSERT(i->peer < peer || peer < i->peer);
} }
#endif #endif
TORRENT_ASSERT(peer->max_assignable_bandwidth(m_channel) > 0);
boost::shared_ptr<Torrent> t = peer->associated_torrent().lock(); boost::shared_ptr<Torrent> t = peer->associated_torrent().lock();
@ -257,7 +189,7 @@ struct bandwidth_manager
#ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT #ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT
std::cerr << " req_bandwidht. m_queue.size() = " << m_queue.size() << std::endl; std::cerr << " req_bandwidht. m_queue.size() = " << m_queue.size() << std::endl;
#endif #endif
if (!m_queue.empty()) hand_out_bandwidth(); if (!m_queue.empty()) hand_out_bandwidth(l);
} }
#ifndef NDEBUG #ifndef NDEBUG
@ -309,6 +241,7 @@ private:
TORRENT_ASSERT(!m_history.empty()); TORRENT_ASSERT(!m_history.empty());
mutex_t::scoped_lock l(m_mutex);
ptime now(time_now()); ptime now(time_now());
while (!m_history.empty() && m_history.back().expires_at <= now) while (!m_history.empty() && m_history.back().expires_at <= now)
{ {
@ -318,8 +251,10 @@ private:
TORRENT_ASSERT(m_current_quota >= 0); TORRENT_ASSERT(m_current_quota >= 0);
intrusive_ptr<PeerConnection> c = e.peer; intrusive_ptr<PeerConnection> c = e.peer;
shared_ptr<Torrent> t = e.tor.lock(); shared_ptr<Torrent> t = e.tor.lock();
l.unlock();
if (!c->is_disconnecting()) c->expire_bandwidth(m_channel, e.amount); if (!c->is_disconnecting()) c->expire_bandwidth(m_channel, e.amount);
if (t) t->expire_bandwidth(m_channel, e.amount); if (t) t->expire_bandwidth(m_channel, e.amount);
l.lock();
} }
// now, wait for the next chunk to expire // now, wait for the next chunk to expire
@ -332,7 +267,7 @@ private:
// since some bandwidth just expired, it // since some bandwidth just expired, it
// means we can hand out more (in case there // means we can hand out more (in case there
// are still consumers in line) // are still consumers in line)
if (!m_queue.empty()) hand_out_bandwidth(); if (!m_queue.empty()) hand_out_bandwidth(l);
#ifndef NDEBUG #ifndef NDEBUG
} }
catch (std::exception&) catch (std::exception&)
@ -342,7 +277,7 @@ private:
#endif #endif
} }
void hand_out_bandwidth() throw() void hand_out_bandwidth(boost::mutex::scoped_lock& l) throw()
{ {
// if we're already handing out bandwidth, just return back // if we're already handing out bandwidth, just return back
// to the loop further down on the callstack // to the loop further down on the callstack
@ -355,9 +290,7 @@ private:
ptime now(time_now()); ptime now(time_now());
mutex_t::scoped_lock l(m_mutex);
int limit = m_limit; int limit = m_limit;
l.unlock();
// available bandwidth to hand out // available bandwidth to hand out
int amount = limit - m_current_quota; int amount = limit - m_current_quota;
@ -369,34 +302,41 @@ private:
<< " m_current_quota = " << m_current_quota << std::endl; << " m_current_quota = " << m_current_quota << std::endl;
#endif #endif
while (!m_queue.empty() && amount > 0) if (amount <= 0)
{
m_in_hand_out_bandwidth = false;
return;
}
queue_t q;
queue_t tmp;
m_queue.swap(q);
while (!q.empty() && amount > 0)
{ {
TORRENT_ASSERT(amount == limit - m_current_quota); TORRENT_ASSERT(amount == limit - m_current_quota);
bw_queue_entry<PeerConnection> qe = m_queue.front(); bw_queue_entry<PeerConnection> qe = q.front();
TORRENT_ASSERT(qe.max_block_size > 0); TORRENT_ASSERT(qe.max_block_size > 0);
m_queue.pop_front(); q.pop_front();
shared_ptr<Torrent> t = qe.peer->associated_torrent().lock(); shared_ptr<Torrent> t = qe.peer->associated_torrent().lock();
if (!t) continue; if (!t) continue;
if (qe.peer->is_disconnecting()) if (qe.peer->is_disconnecting())
{ {
l.unlock();
t->expire_bandwidth(m_channel, qe.max_block_size); t->expire_bandwidth(m_channel, qe.max_block_size);
TORRENT_ASSERT(amount == limit - m_current_quota); l.lock();
amount = limit - m_current_quota;
continue; continue;
} }
// at this point, max_assignable may actually be zero. Since // at this point, max_assignable may actually be zero. Since
// the bandwidth quota is subtracted once the data has been // the rate limit of the peer might have changed while it
// sent. If the peer was added to the queue while the data was // was in the queue.
// still being sent, max_assignable may have been > 0 at that time. int max_assignable = qe.peer->max_assignable_bandwidth(m_channel);
int max_assignable = (std::min)(
qe.peer->max_assignable_bandwidth(m_channel)
, t->max_assignable_bandwidth(m_channel));
if (max_assignable == 0) if (max_assignable == 0)
{ {
t->expire_bandwidth(m_channel, qe.max_block_size); TORRENT_ASSERT(is_in_history(qe.peer.get()));
qe.peer->assign_bandwidth(m_channel, 0); tmp.push_back(qe);
TORRENT_ASSERT(amount == limit - m_current_quota);
continue; continue;
} }
@ -441,7 +381,7 @@ private:
#endif #endif
if (amount < block_size / 2) if (amount < block_size / 2)
{ {
m_queue.push_front(qe); tmp.push_back(qe);
break; break;
} }
@ -454,12 +394,16 @@ private:
TORRENT_ASSERT(amount == limit - m_current_quota); TORRENT_ASSERT(amount == limit - m_current_quota);
amount -= hand_out_amount; amount -= hand_out_amount;
TORRENT_ASSERT(hand_out_amount <= qe.max_block_size); TORRENT_ASSERT(hand_out_amount <= qe.max_block_size);
l.unlock();
t->assign_bandwidth(m_channel, hand_out_amount, qe.max_block_size); t->assign_bandwidth(m_channel, hand_out_amount, qe.max_block_size);
qe.peer->assign_bandwidth(m_channel, hand_out_amount); qe.peer->assign_bandwidth(m_channel, hand_out_amount);
l.lock();
add_history_entry(history_entry<PeerConnection, Torrent>( add_history_entry(history_entry<PeerConnection, Torrent>(
qe.peer, t, hand_out_amount, now + bw_window_size)); qe.peer, t, hand_out_amount, now + bw_window_size));
TORRENT_ASSERT(amount == limit - m_current_quota); amount = limit - m_current_quota;
} }
if (!q.empty()) m_queue.insert(m_queue.begin(), q.begin(), q.end());
if (!tmp.empty()) m_queue.insert(m_queue.begin(), tmp.begin(), tmp.end());
#ifndef NDEBUG #ifndef NDEBUG
} }
catch (std::exception& e) catch (std::exception& e)

View File

@ -0,0 +1,54 @@
/*
Copyright (c) 2007, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORRENT_BANDWIDTH_QUEUE_ENTRY_HPP_INCLUDED
#define TORRENT_BANDWIDTH_QUEUE_ENTRY_HPP_INCLUDED
#include <boost/intrusive_ptr.hpp>
namespace libtorrent {
template<class PeerConnection>
struct bw_queue_entry
{
bw_queue_entry(boost::intrusive_ptr<PeerConnection> const& pe
, int blk, bool no_prio)
: peer(pe), max_block_size(blk), non_prioritized(no_prio) {}
boost::intrusive_ptr<PeerConnection> peer;
int max_block_size;
bool non_prioritized;
};
}
#endif

View File

@ -30,6 +30,9 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef TORRENT_DISK_IO_THREAD
#define TORRENT_DISK_IO_THREAD
#ifdef TORRENT_DISK_STATS #ifdef TORRENT_DISK_STATS
#include <fstream> #include <fstream>
#endif #endif
@ -99,7 +102,9 @@ namespace libtorrent
int disk_allocations() const int disk_allocations() const
{ return m_allocations; } { return m_allocations; }
#endif #endif
void join();
// aborts read operations // aborts read operations
void stop(boost::intrusive_ptr<piece_manager> s); void stop(boost::intrusive_ptr<piece_manager> s);
void add_job(disk_io_job const& j void add_job(disk_io_job const& j
@ -152,3 +157,5 @@ namespace libtorrent
} }
#endif

View File

@ -76,9 +76,9 @@ namespace detail
template<class Addr> template<class Addr>
Addr zero() Addr zero()
{ {
typename Addr::bytes_type zero; Addr zero;
std::fill(zero.begin(), zero.end(), 0); std::fill(zero.begin(), zero.end(), 0);
return Addr(zero); return zero;
} }
template<> template<>
@ -87,8 +87,8 @@ namespace detail
template<class Addr> template<class Addr>
Addr plus_one(Addr const& a) Addr plus_one(Addr const& a)
{ {
typename Addr::bytes_type tmp(a.to_bytes()); Addr tmp(a);
typedef typename Addr::bytes_type::reverse_iterator iter; typedef typename Addr::reverse_iterator iter;
for (iter i = tmp.rbegin() for (iter i = tmp.rbegin()
, end(tmp.rend()); i != end; ++i) , end(tmp.rend()); i != end; ++i)
{ {
@ -99,7 +99,7 @@ namespace detail
} }
*i = 0; *i = 0;
} }
return Addr(tmp); return tmp;
} }
inline boost::uint16_t plus_one(boost::uint16_t val) { return val + 1; } inline boost::uint16_t plus_one(boost::uint16_t val) { return val + 1; }
@ -107,8 +107,8 @@ namespace detail
template<class Addr> template<class Addr>
Addr minus_one(Addr const& a) Addr minus_one(Addr const& a)
{ {
typename Addr::bytes_type tmp(a.to_bytes()); Addr tmp(a);
typedef typename Addr::bytes_type::reverse_iterator iter; typedef typename Addr::reverse_iterator iter;
for (iter i = tmp.rbegin() for (iter i = tmp.rbegin()
, end(tmp.rend()); i != end; ++i) , end(tmp.rend()); i != end; ++i)
{ {
@ -119,7 +119,7 @@ namespace detail
} }
*i = (std::numeric_limits<typename iter::value_type>::max)(); *i = (std::numeric_limits<typename iter::value_type>::max)();
} }
return Addr(tmp); return tmp;
} }
inline boost::uint16_t minus_one(boost::uint16_t val) { return val - 1; } inline boost::uint16_t minus_one(boost::uint16_t val) { return val - 1; }
@ -127,9 +127,9 @@ namespace detail
template<class Addr> template<class Addr>
Addr max_addr() Addr max_addr()
{ {
typename Addr::bytes_type tmp; Addr tmp;
std::fill(tmp.begin(), tmp.end() std::fill(tmp.begin(), tmp.end()
, (std::numeric_limits<typename Addr::bytes_type::value_type>::max)()); , (std::numeric_limits<typename Addr::value_type>::max)());
return Addr(tmp); return Addr(tmp);
} }
@ -220,23 +220,24 @@ namespace detail
return i->access; return i->access;
} }
std::vector<ip_range<Addr> > export_filter() const template <class ExternalAddressType>
std::vector<ip_range<ExternalAddressType> > export_filter() const
{ {
std::vector<ip_range<Addr> > ret; std::vector<ip_range<ExternalAddressType> > ret;
ret.reserve(m_access_list.size()); ret.reserve(m_access_list.size());
for (typename range_t::const_iterator i = m_access_list.begin() for (typename range_t::const_iterator i = m_access_list.begin()
, end(m_access_list.end()); i != end;) , end(m_access_list.end()); i != end;)
{ {
ip_range<Addr> r; ip_range<ExternalAddressType> r;
r.first = i->start; r.first = ExternalAddressType(i->start);
r.flags = i->access; r.flags = i->access;
++i; ++i;
if (i == end) if (i == end)
r.last = max_addr<Addr>(); r.last = ExternalAddressType(max_addr<Addr>());
else else
r.last = minus_one(i->start); r.last = ExternalAddressType(minus_one(i->start));
ret.push_back(r); ret.push_back(r);
} }
@ -288,8 +289,8 @@ public:
private: private:
detail::filter_impl<address_v4> m_filter4; detail::filter_impl<address_v4::bytes_type> m_filter4;
detail::filter_impl<address_v6> m_filter6; detail::filter_impl<address_v6::bytes_type> m_filter6;
}; };
class TORRENT_EXPORT port_filter class TORRENT_EXPORT port_filter

View File

@ -62,7 +62,7 @@ namespace libtorrent
private: private:
int get_local_key_size () const int get_local_key_size () const
{ {
assert (m_DH); TORRENT_ASSERT(m_DH);
return BN_num_bytes (m_DH->pub_key); return BN_num_bytes (m_DH->pub_key);
} }
@ -97,8 +97,8 @@ namespace libtorrent
void encrypt (char* pos, int len) void encrypt (char* pos, int len)
{ {
assert (len >= 0); TORRENT_ASSERT(len >= 0);
assert (pos); TORRENT_ASSERT(pos);
RC4 (&m_local_key, len, reinterpret_cast<unsigned char const*>(pos), RC4 (&m_local_key, len, reinterpret_cast<unsigned char const*>(pos),
reinterpret_cast<unsigned char*>(pos)); reinterpret_cast<unsigned char*>(pos));
@ -106,8 +106,8 @@ namespace libtorrent
void decrypt (char* pos, int len) void decrypt (char* pos, int len)
{ {
assert (len >= 0); TORRENT_ASSERT(len >= 0);
assert (pos); TORRENT_ASSERT(pos);
RC4 (&m_remote_key, len, reinterpret_cast<unsigned char const*>(pos), RC4 (&m_remote_key, len, reinterpret_cast<unsigned char const*>(pos),
reinterpret_cast<unsigned char*>(pos)); reinterpret_cast<unsigned char*>(pos));

View File

@ -69,7 +69,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/piece_block_progress.hpp" #include "libtorrent/piece_block_progress.hpp"
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#include "libtorrent/session.hpp" #include "libtorrent/session.hpp"
#include "libtorrent/bandwidth_manager.hpp" #include "libtorrent/bandwidth_limit.hpp"
#include "libtorrent/policy.hpp" #include "libtorrent/policy.hpp"
#include "libtorrent/socket_type.hpp" #include "libtorrent/socket_type.hpp"
#include "libtorrent/intrusive_ptr_base.hpp" #include "libtorrent/intrusive_ptr_base.hpp"

View File

@ -117,6 +117,7 @@ namespace libtorrent
, use_dht_as_fallback(true) , use_dht_as_fallback(true)
#endif #endif
, free_torrent_hashes(true) , free_torrent_hashes(true)
, upnp_ignore_nonrouters(true)
{} {}
// this is the user agent that will be sent to the tracker // this is the user agent that will be sent to the tracker
@ -292,6 +293,11 @@ namespace libtorrent
// make the get_torrent_info() function to return an incomplete // make the get_torrent_info() function to return an incomplete
// torrent object that cannot be passed back to add_torrent() // torrent object that cannot be passed back to add_torrent()
bool free_torrent_hashes; bool free_torrent_hashes;
// when this is true, the upnp port mapper will ignore
// any upnp devices that don't have an address that matches
// our currently configured router.
bool upnp_ignore_nonrouters;
}; };
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT

View File

@ -65,7 +65,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/piece_picker.hpp" #include "libtorrent/piece_picker.hpp"
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#include "libtorrent/escape_string.hpp" #include "libtorrent/escape_string.hpp"
#include "libtorrent/bandwidth_manager.hpp" #include "libtorrent/bandwidth_limit.hpp"
#include "libtorrent/bandwidth_queue_entry.hpp"
#include "libtorrent/storage.hpp" #include "libtorrent/storage.hpp"
#include "libtorrent/hasher.hpp" #include "libtorrent/hasher.hpp"
#include "libtorrent/assert.hpp" #include "libtorrent/assert.hpp"

View File

@ -68,13 +68,14 @@ class upnp : public intrusive_ptr_base<upnp>
public: public:
upnp(io_service& ios, connection_queue& cc upnp(io_service& ios, connection_queue& cc
, address const& listen_interface, std::string const& user_agent , address const& listen_interface, std::string const& user_agent
, portmap_callback_t const& cb); , portmap_callback_t const& cb, bool ignore_nonrouters);
~upnp(); ~upnp();
// maps the ports, if a port is set to 0 // maps the ports, if a port is set to 0
// it will not be mapped // it will not be mapped
void set_mappings(int tcp, int udp); void set_mappings(int tcp, int udp);
void discover_device();
void close(); void close();
private: private:
@ -89,7 +90,6 @@ private:
void resend_request(asio::error_code const& e); void resend_request(asio::error_code const& e);
void on_reply(udp::endpoint const& from, char* buffer void on_reply(udp::endpoint const& from, char* buffer
, std::size_t bytes_transferred); , std::size_t bytes_transferred);
void discover_device();
struct rootdevice; struct rootdevice;
@ -233,6 +233,8 @@ private:
connection_queue& m_cc; connection_queue& m_cc;
std::vector<address> m_filter;
#ifdef TORRENT_UPNP_LOGGING #ifdef TORRENT_UPNP_LOGGING
std::ofstream m_log; std::ofstream m_log;
#endif #endif

View File

@ -120,7 +120,8 @@ namespace libtorrent
void write_interested() {} void write_interested() {}
void write_not_interested() {} void write_not_interested() {}
void write_request(peer_request const& r); void write_request(peer_request const& r);
void write_cancel(peer_request const& r) {} void write_cancel(peer_request const& r)
{ incoming_reject_request(r); }
void write_have(int index) {} void write_have(int index) {}
void write_piece(peer_request const& r, char* buffer) { TORRENT_ASSERT(false); } void write_piece(peer_request const& r, char* buffer) { TORRENT_ASSERT(false); }
void write_keepalive() {} void write_keepalive() {}

View File

@ -170,12 +170,17 @@ namespace libtorrent
for (std::list<socket_entry>::iterator i = m_sockets.begin() for (std::list<socket_entry>::iterator i = m_sockets.begin()
, end(m_sockets.end()); i != end; ++i) , end(m_sockets.end()); i != end; ++i)
{ {
if (!i->socket) continue;
asio::error_code e; asio::error_code e;
i->socket->send_to(asio::buffer(buffer, size), m_multicast_endpoint, 0, e); i->socket->send_to(asio::buffer(buffer, size), m_multicast_endpoint, 0, e);
#ifndef NDEBUG #ifndef NDEBUG
// std::cerr << " sending on " << i->socket->local_endpoint().address().to_string() << std::endl; // std::cerr << " sending on " << i->socket->local_endpoint().address().to_string() << std::endl;
#endif #endif
if (e) ec = e; if (e)
{
i->socket->close(e);
i->socket.reset();
}
} }
} }
@ -184,6 +189,7 @@ namespace libtorrent
{ {
if (ec || bytes_transferred == 0 || !m_on_receive) return; if (ec || bytes_transferred == 0 || !m_on_receive) return;
m_on_receive(s->remote, s->buffer, bytes_transferred); m_on_receive(s->remote, s->buffer, bytes_transferred);
if (!s->socket) return;
s->socket->async_receive_from(asio::buffer(s->buffer, sizeof(s->buffer)) s->socket->async_receive_from(asio::buffer(s->buffer, sizeof(s->buffer))
, s->remote, bind(&broadcast_socket::on_receive, this, s, _1, _2)); , s->remote, bind(&broadcast_socket::on_receive, this, s, _1, _2));
} }
@ -195,6 +201,7 @@ namespace libtorrent
for (std::list<socket_entry>::iterator i = m_sockets.begin() for (std::list<socket_entry>::iterator i = m_sockets.begin()
, end(m_sockets.end()); i != end; ++i) , end(m_sockets.end()); i != end; ++i)
{ {
if (!i->socket) continue;
i->socket->close(); i->socket->close();
} }
} }

View File

@ -295,6 +295,8 @@ namespace libtorrent
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (!m_supports_fast) return;
TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield); TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
TORRENT_ASSERT(associated_torrent().lock()->valid_metadata()); TORRENT_ASSERT(associated_torrent().lock()->valid_metadata());
@ -312,6 +314,7 @@ namespace libtorrent
TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield); TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
TORRENT_ASSERT(associated_torrent().lock()->valid_metadata()); TORRENT_ASSERT(associated_torrent().lock()->valid_metadata());
TORRENT_ASSERT(m_supports_fast);
char msg[] = {0,0,0,5, msg_allowed_fast, 0, 0, 0, 0}; char msg[] = {0,0,0,5, msg_allowed_fast, 0, 0, 0, 0};
char* ptr = msg + 5; char* ptr = msg + 5;
@ -1297,6 +1300,9 @@ namespace libtorrent
detail::write_int32(r.start, ptr); // begin detail::write_int32(r.start, ptr); // begin
detail::write_int32(r.length, ptr); // length detail::write_int32(r.length, ptr); // length
send_buffer(msg, sizeof(msg)); send_buffer(msg, sizeof(msg));
if (!m_supports_fast)
incoming_reject_request(r);
} }
void bt_peer_connection::write_request(peer_request const& r) void bt_peer_connection::write_request(peer_request const& r)

View File

@ -62,12 +62,7 @@ namespace libtorrent
disk_io_thread::~disk_io_thread() disk_io_thread::~disk_io_thread()
{ {
mutex_t::scoped_lock l(m_mutex); TORRENT_ASSERT(m_abort == true);
m_abort = true;
m_signal.notify_all();
l.unlock();
m_disk_io_thread.join();
} }
#ifndef NDEBUG #ifndef NDEBUG
@ -95,6 +90,16 @@ namespace libtorrent
#endif #endif
void disk_io_thread::join()
{
mutex_t::scoped_lock l(m_mutex);
m_abort = true;
m_signal.notify_all();
l.unlock();
m_disk_io_thread.join();
}
// aborts read operations // aborts read operations
void disk_io_thread::stop(boost::intrusive_ptr<piece_manager> s) void disk_io_thread::stop(boost::intrusive_ptr<piece_manager> s)
{ {

View File

@ -44,12 +44,12 @@ namespace libtorrent
if (first.is_v4()) if (first.is_v4())
{ {
TORRENT_ASSERT(last.is_v4()); TORRENT_ASSERT(last.is_v4());
m_filter4.add_rule(first.to_v4(), last.to_v4(), flags); m_filter4.add_rule(first.to_v4().to_bytes(), last.to_v4().to_bytes(), flags);
} }
else if (first.is_v6()) else if (first.is_v6())
{ {
TORRENT_ASSERT(last.is_v6()); TORRENT_ASSERT(last.is_v6());
m_filter6.add_rule(first.to_v6(), last.to_v6(), flags); m_filter6.add_rule(first.to_v6().to_bytes(), last.to_v6().to_bytes(), flags);
} }
else else
TORRENT_ASSERT(false); TORRENT_ASSERT(false);
@ -58,15 +58,15 @@ namespace libtorrent
int ip_filter::access(address const& addr) const int ip_filter::access(address const& addr) const
{ {
if (addr.is_v4()) if (addr.is_v4())
return m_filter4.access(addr.to_v4()); return m_filter4.access(addr.to_v4().to_bytes());
TORRENT_ASSERT(addr.is_v6()); TORRENT_ASSERT(addr.is_v6());
return m_filter6.access(addr.to_v6()); return m_filter6.access(addr.to_v6().to_bytes());
} }
ip_filter::filter_tuple_t ip_filter::export_filter() const ip_filter::filter_tuple_t ip_filter::export_filter() const
{ {
return boost::make_tuple(m_filter4.export_filter() return boost::make_tuple(m_filter4.export_filter<address_v4>()
, m_filter6.export_filter()); , m_filter6.export_filter<address_v6>());
} }
void port_filter::add_rule(boost::uint16_t first, boost::uint16_t last, int flags) void port_filter::add_rule(boost::uint16_t first, boost::uint16_t last, int flags)

View File

@ -95,7 +95,6 @@ namespace libtorrent { namespace
return ret; return ret;
} }
struct metadata_plugin : torrent_plugin struct metadata_plugin : torrent_plugin
{ {
metadata_plugin(torrent& t) metadata_plugin(torrent& t)
@ -217,7 +216,7 @@ namespace libtorrent { namespace
m_metadata_size = total_size; m_metadata_size = total_size;
} }
void piece_pass(int) void on_piece_pass(int)
{ {
// if we became a seed, copy the metadata from // if we became a seed, copy the metadata from
// the torrent before it is deallocated // the torrent before it is deallocated

View File

@ -52,11 +52,11 @@ namespace libtorrent {
m_DH->g = BN_bin2bn (m_dh_generator, sizeof(m_dh_generator), NULL); m_DH->g = BN_bin2bn (m_dh_generator, sizeof(m_dh_generator), NULL);
m_DH->length = 160l; m_DH->length = 160l;
assert (sizeof(m_dh_prime) == DH_size(m_DH)); TORRENT_ASSERT(sizeof(m_dh_prime) == DH_size(m_DH));
DH_generate_key (m_DH); // TODO Check != 0 DH_generate_key (m_DH); // TODO Check != 0
assert (m_DH->pub_key); TORRENT_ASSERT(m_DH->pub_key);
// DH can generate key sizes that are smaller than the size of // DH can generate key sizes that are smaller than the size of
// P with exponentially decreasing probability, in which case // P with exponentially decreasing probability, in which case
@ -78,7 +78,7 @@ namespace libtorrent {
DH_key_exchange::~DH_key_exchange () DH_key_exchange::~DH_key_exchange ()
{ {
assert (m_DH); TORRENT_ASSERT(m_DH);
DH_free (m_DH); DH_free (m_DH);
} }
@ -91,7 +91,7 @@ namespace libtorrent {
// compute shared secret given remote public key // compute shared secret given remote public key
void DH_key_exchange::compute_secret (char const* remote_pubkey) void DH_key_exchange::compute_secret (char const* remote_pubkey)
{ {
assert (remote_pubkey); TORRENT_ASSERT(remote_pubkey);
BIGNUM* bn_remote_pubkey = BN_bin2bn ((unsigned char*)remote_pubkey, 96, NULL); BIGNUM* bn_remote_pubkey = BN_bin2bn ((unsigned char*)remote_pubkey, 96, NULL);
char dh_secret[96]; char dh_secret[96];

View File

@ -759,7 +759,7 @@ namespace libtorrent
} }
// ----------------------------- // -----------------------------
// -------- REJECT PIECE ------- // ------- SUGGEST PIECE -------
// ----------------------------- // -----------------------------
void peer_connection::incoming_suggest(int index) void peer_connection::incoming_suggest(int index)
@ -1127,6 +1127,18 @@ namespace libtorrent
"i: " << m_peer_interested << " | " "i: " << m_peer_interested << " | "
"t: " << (int)t->torrent_file().piece_size(r.piece) << " | " "t: " << (int)t->torrent_file().piece_size(r.piece) << " | "
"n: " << t->torrent_file().num_pieces() << " ]\n"; "n: " << t->torrent_file().num_pieces() << " ]\n";
(*m_logger) << time_now_string()
<< " ==> REJECT_PIECE [ "
"piece: " << r.piece << " | "
"s: " << r.start << " | "
"l: " << r.length << " ]\n";
(*m_logger) << time_now_string()
<< " ==> REJECT_PIECE [ "
"piece: " << r.piece << " | "
"s: " << r.start << " | "
"l: " << r.length << " ]\n";
#endif #endif
write_reject_request(r); write_reject_request(r);
return; return;
@ -1155,8 +1167,13 @@ namespace libtorrent
{ {
write_reject_request(r); write_reject_request(r);
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string() (*m_logger) << time_now_string()
<< " *** REJECTING REQUEST [ peer choked and piece not in allowed fast set ]\n"; << " *** REJECTING REQUEST [ peer choked and piece not in allowed fast set ]\n";
(*m_logger) << time_now_string()
<< " ==> REJECT_PIECE [ "
"piece: " << r.piece << " | "
"s: " << r.start << " | "
"l: " << r.length << " ]\n";
#endif #endif
} }
else else
@ -1179,6 +1196,12 @@ namespace libtorrent
"n: " << t->torrent_file().num_pieces() << " | " "n: " << t->torrent_file().num_pieces() << " | "
"h: " << t->have_piece(r.piece) << " | " "h: " << t->have_piece(r.piece) << " | "
"block_limit: " << t->block_size() << " ]\n"; "block_limit: " << t->block_size() << " ]\n";
(*m_logger) << time_now_string()
<< " ==> REJECT_PIECE [ "
"piece: " << r.piece << " | "
"s: " << r.start << " | "
"l: " << r.length << " ]\n";
#endif #endif
write_reject_request(r); write_reject_request(r);
@ -1365,6 +1388,9 @@ namespace libtorrent
m_outstanding_writing_bytes += p.length; m_outstanding_writing_bytes += p.length;
TORRENT_ASSERT(!m_reading); TORRENT_ASSERT(!m_reading);
picker.mark_as_writing(block_finished, peer_info_struct()); picker.mark_as_writing(block_finished, peer_info_struct());
#ifndef NDEBUG
t->check_invariant();
#endif
} }
void peer_connection::on_disk_write_complete(int ret, disk_io_job const& j void peer_connection::on_disk_write_complete(int ret, disk_io_job const& j
@ -1479,6 +1505,14 @@ namespace libtorrent
if (i != m_requests.end()) if (i != m_requests.end())
{ {
m_requests.erase(i); m_requests.erase(i);
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string()
<< " ==> REJECT_PIECE [ "
"piece: " << r.piece << " | "
"s: " << r.start << " | "
"l: " << r.length << " ]\n";
#endif
write_reject_request(r);
} }
else else
{ {
@ -1612,12 +1646,6 @@ namespace libtorrent
} }
#endif #endif
// if we already have the piece, we can
// ignore this message
if (t->valid_metadata()
&& t->have_piece(index))
return;
if (index < 0 || index >= int(m_have_piece.size())) if (index < 0 || index >= int(m_have_piece.size()))
{ {
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
@ -1627,6 +1655,12 @@ namespace libtorrent
return; return;
} }
// if we already have the piece, we can
// ignore this message
if (t->valid_metadata()
&& t->have_piece(index))
return;
m_allowed_fast.push_back(index); m_allowed_fast.push_back(index);
// if the peer has the piece and we want // if the peer has the piece and we want
@ -1735,11 +1769,6 @@ namespace libtorrent
// sent yet, so we don't have to send a cancel. // sent yet, so we don't have to send a cancel.
return; return;
} }
else
{
m_download_queue.erase(it);
t->picker().abort_download(block);
}
int block_offset = block.block_index * t->block_size(); int block_offset = block.block_index * t->block_size();
int block_size int block_size
@ -1753,13 +1782,12 @@ namespace libtorrent
r.start = block_offset; r.start = block_offset;
r.length = block_size; r.length = block_size;
write_cancel(r);
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string() (*m_logger) << time_now_string()
<< " ==> CANCEL [ piece: " << block.piece_index << " | s: " << " ==> CANCEL [ piece: " << block.piece_index << " | s: "
<< block_offset << " | l: " << block_size << " | " << block.block_index << " ]\n"; << block_offset << " | l: " << block_size << " | " << block.block_index << " ]\n";
#endif #endif
write_cancel(r);
} }
void peer_connection::send_choke() void peer_connection::send_choke()
@ -1783,6 +1811,19 @@ namespace libtorrent
// reject the requests we have in the queue // reject the requests we have in the queue
std::for_each(m_requests.begin(), m_requests.end() std::for_each(m_requests.begin(), m_requests.end()
, bind(&peer_connection::write_reject_request, this, _1)); , bind(&peer_connection::write_reject_request, this, _1));
#ifdef TORRENT_VERBOSE_LOGGING
for (std::deque<peer_request>::iterator i = m_requests.begin()
, end(m_requests.end()); i != end; ++i)
{
peer_request const& r = *i;
(*m_logger) << time_now_string()
<< " ==> REJECT_PIECE [ "
"piece: " << r.piece << " | "
"s: " << r.start << " | "
"l: " << r.length << " ]\n";
}
#endif
m_requests.clear(); m_requests.clear();
} }
@ -2206,18 +2247,24 @@ namespace libtorrent
else else
{ {
piece_picker& picker = t->picker(); piece_picker& picker = t->picker();
while (!m_download_queue.empty())
std::deque<piece_block> dl(m_download_queue);
for (std::deque<piece_block>::iterator i = dl.begin()
, end(dl.end()); i != end; ++i)
{ {
piece_block const& r = m_download_queue.back(); piece_block const& r = m_download_queue.back();
picker.abort_download(r); #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string()
<< " ==> CANCEL [ piece: " << r.piece_index
<< " | block: " << r.block_index
<< " ]\n";
#endif
write_cancel(t->to_req(r)); write_cancel(t->to_req(r));
m_download_queue.pop_back();
} }
while (!m_request_queue.empty()) while (!m_request_queue.empty())
{ {
piece_block const& r = m_request_queue.back(); piece_block const& r = m_request_queue.back();
picker.abort_download(r); picker.abort_download(r);
write_cancel(t->to_req(r));
m_request_queue.pop_back(); m_request_queue.pop_back();
} }
@ -2562,6 +2609,7 @@ namespace libtorrent
// return value is destructed // return value is destructed
buffer::interval peer_connection::allocate_send_buffer(int size) buffer::interval peer_connection::allocate_send_buffer(int size)
{ {
TORRENT_ASSERT(size > 0);
char* insert = m_send_buffer.allocate_appendix(size); char* insert = m_send_buffer.allocate_appendix(size);
if (insert == 0) if (insert == 0)
{ {
@ -2618,6 +2666,7 @@ namespace libtorrent
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << "**ERROR**: " << error.message() << "[in peer_connection::on_receive_data]\n"; (*m_logger) << "**ERROR**: " << error.message() << "[in peer_connection::on_receive_data]\n";
#endif #endif
set_failed();
on_receive(error, bytes_transferred); on_receive(error, bytes_transferred);
throw std::runtime_error(error.message()); throw std::runtime_error(error.message());
} }
@ -2778,6 +2827,7 @@ namespace libtorrent
(*m_ses.m_logger) << "CONNECTION FAILED: " << m_remote.address().to_string() (*m_ses.m_logger) << "CONNECTION FAILED: " << m_remote.address().to_string()
<< ": " << e.message() << "\n"; << ": " << e.message() << "\n";
#endif #endif
set_failed();
m_ses.connection_failed(self(), m_remote, e.message().c_str()); m_ses.connection_failed(self(), m_remote, e.message().c_str());
return; return;
} }
@ -2838,6 +2888,7 @@ namespace libtorrent
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << "**ERROR**: " << error.message() << " [in peer_connection::on_send_data]\n"; (*m_logger) << "**ERROR**: " << error.message() << " [in peer_connection::on_send_data]\n";
#endif #endif
set_failed();
throw std::runtime_error(error.message()); throw std::runtime_error(error.message());
} }
if (m_disconnecting) return; if (m_disconnecting) return;
@ -2869,6 +2920,17 @@ namespace libtorrent
#ifndef NDEBUG #ifndef NDEBUG
void peer_connection::check_invariant() const void peer_connection::check_invariant() const
{ {
for (int i = 0; i < 2; ++i)
{
// this peer is in the bandwidth history iff max_assignable < limit
TORRENT_ASSERT((m_bandwidth_limit[i].max_assignable() < m_bandwidth_limit[i].throttle())
== m_ses.m_bandwidth_manager[i]->is_in_history(this)
|| m_bandwidth_limit[i].throttle() == bandwidth_limit::inf);
}
std::set<piece_block> unique;
std::copy(m_download_queue.begin(), m_download_queue.end(), std::inserter(unique, unique.begin()));
std::copy(m_request_queue.begin(), m_request_queue.end(), std::inserter(unique, unique.begin()));
TORRENT_ASSERT(unique.size() == m_download_queue.size() + m_request_queue.size());
if (m_peer_info) if (m_peer_info)
{ {
TORRENT_ASSERT(m_peer_info->connection == this TORRENT_ASSERT(m_peer_info->connection == this

View File

@ -533,6 +533,12 @@ namespace libtorrent
if (i->second.type == peer::not_connectable) continue; if (i->second.type == peer::not_connectable) continue;
if (i->second.seed && finished) continue; if (i->second.seed && finished) continue;
if (i->second.failcount >= max_failcount) continue; if (i->second.failcount >= max_failcount) continue;
// prefer peers with lower failcount
if (candidate != m_peers.end()
&& candidate->second.failcount < i->second.failcount)
continue;
if (now - i->second.connected < seconds(i->second.failcount * min_reconnect_time)) if (now - i->second.connected < seconds(i->second.failcount * min_reconnect_time))
continue; continue;
if (ses.m_port_filter.access(i->second.ip.port()) & port_filter::blocked) if (ses.m_port_filter.access(i->second.ip.port()) & port_filter::blocked)

View File

@ -2198,6 +2198,11 @@ namespace detail
#endif #endif
m_checker_thread->join(); m_checker_thread->join();
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_logger) << time_now_string() << " waiting for disk io thread\n";
#endif
m_disk_thread.join();
TORRENT_ASSERT(m_torrents.empty()); TORRENT_ASSERT(m_torrents.empty());
TORRENT_ASSERT(m_connections.empty()); TORRENT_ASSERT(m_connections.empty());
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
@ -2345,8 +2350,10 @@ namespace detail
, m_listen_interface.address() , m_listen_interface.address()
, m_settings.user_agent , m_settings.user_agent
, bind(&session_impl::on_port_mapping , bind(&session_impl::on_port_mapping
, this, _1, _2, _3)); , this, _1, _2, _3)
, m_settings.upnp_ignore_nonrouters);
m_upnp->discover_device();
m_upnp->set_mappings(m_listen_interface.port(), m_upnp->set_mappings(m_listen_interface.port(),
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT
m_dht ? m_dht_settings.service_port : m_dht ? m_dht_settings.service_port :
@ -2385,7 +2392,11 @@ namespace detail
std::pair<char*, int> session_impl::allocate_buffer(int size) std::pair<char*, int> session_impl::allocate_buffer(int size)
{ {
TORRENT_ASSERT(size > 0);
int num_buffers = (size + send_buffer_size - 1) / send_buffer_size; int num_buffers = (size + send_buffer_size - 1) / send_buffer_size;
TORRENT_ASSERT(num_buffers > 0);
boost::mutex::scoped_lock l(m_send_buffer_mutex);
#ifdef TORRENT_STATS #ifdef TORRENT_STATS
m_buffer_allocations += num_buffers; m_buffer_allocations += num_buffers;
m_buffer_usage_logger << log_time() << " protocol_buffer: " m_buffer_usage_logger << log_time() << " protocol_buffer: "
@ -2397,8 +2408,12 @@ namespace detail
void session_impl::free_buffer(char* buf, int size) void session_impl::free_buffer(char* buf, int size)
{ {
TORRENT_ASSERT(size > 0);
TORRENT_ASSERT(size % send_buffer_size == 0); TORRENT_ASSERT(size % send_buffer_size == 0);
int num_buffers = size / send_buffer_size; int num_buffers = size / send_buffer_size;
TORRENT_ASSERT(num_buffers > 0);
boost::mutex::scoped_lock l(m_send_buffer_mutex);
#ifdef TORRENT_STATS #ifdef TORRENT_STATS
m_buffer_allocations -= num_buffers; m_buffer_allocations -= num_buffers;
TORRENT_ASSERT(m_buffer_allocations >= 0); TORRENT_ASSERT(m_buffer_allocations >= 0);

View File

@ -1589,6 +1589,18 @@ namespace libtorrent
p->set_peer_info(0); p->set_peer_info(0);
TORRENT_ASSERT(i != m_connections.end()); TORRENT_ASSERT(i != m_connections.end());
m_connections.erase(i); m_connections.erase(i);
// remove from bandwidth request-queue
for (int c = 0; c < 2; ++c)
{
for (queue_t::iterator i = m_bandwidth_queue[c].begin()
, end(m_bandwidth_queue[c].end()); i != end; ++i)
{
if (i->peer != p) continue;
m_bandwidth_queue[c].erase(i);
break;
}
}
} }
catch (std::exception& e) catch (std::exception& e)
{ {
@ -2147,6 +2159,11 @@ namespace libtorrent
throw protocol_error("session is closing"); throw protocol_error("session is closing");
} }
if (int(m_connections.size()) >= m_max_connections)
{
throw protocol_error("reached connection limit");
}
TORRENT_ASSERT(m_connections.find(p) == m_connections.end()); TORRENT_ASSERT(m_connections.find(p) == m_connections.end());
peer_iterator ci = m_connections.insert(p).first; peer_iterator ci = m_connections.insert(p).first;
try try
@ -2220,6 +2237,7 @@ namespace libtorrent
, bool non_prioritized) , bool non_prioritized)
{ {
TORRENT_ASSERT(m_bandwidth_limit[channel].throttle() > 0); TORRENT_ASSERT(m_bandwidth_limit[channel].throttle() > 0);
TORRENT_ASSERT(p->max_assignable_bandwidth(channel) > 0);
int block_size = m_bandwidth_limit[channel].throttle() / 10; int block_size = m_bandwidth_limit[channel].throttle() / 10;
if (block_size <= 0) block_size = 1; if (block_size <= 0) block_size = 1;
@ -2244,16 +2262,23 @@ namespace libtorrent
TORRENT_ASSERT(amount > 0); TORRENT_ASSERT(amount > 0);
m_bandwidth_limit[channel].expire(amount); m_bandwidth_limit[channel].expire(amount);
queue_t tmp;
while (!m_bandwidth_queue[channel].empty()) while (!m_bandwidth_queue[channel].empty())
{ {
bw_queue_entry<peer_connection> qe = m_bandwidth_queue[channel].front(); bw_queue_entry<peer_connection> qe = m_bandwidth_queue[channel].front();
if (m_bandwidth_limit[channel].max_assignable() == 0) if (m_bandwidth_limit[channel].max_assignable() == 0)
break; break;
m_bandwidth_queue[channel].pop_front(); m_bandwidth_queue[channel].pop_front();
if (qe.peer->max_assignable_bandwidth(channel) <= 0)
{
TORRENT_ASSERT(m_ses.m_bandwidth_manager[channel]->is_in_history(qe.peer.get()));
if (!qe.peer->is_disconnecting()) tmp.push_back(qe);
continue;
}
perform_bandwidth_request(channel, qe.peer perform_bandwidth_request(channel, qe.peer
, qe.max_block_size, qe.non_prioritized); , qe.max_block_size, qe.non_prioritized);
} }
m_bandwidth_queue[channel].insert(m_bandwidth_queue[channel].begin(), tmp.begin(), tmp.end());
} }
void torrent::perform_bandwidth_request(int channel void torrent::perform_bandwidth_request(int channel
@ -2592,6 +2617,9 @@ namespace libtorrent
{ {
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
TORRENT_ASSERT(m_bandwidth_queue[0].size() <= m_connections.size());
TORRENT_ASSERT(m_bandwidth_queue[1].size() <= m_connections.size());
int num_uploads = 0; int num_uploads = 0;
std::map<piece_block, int> num_requests; std::map<piece_block, int> num_requests;
for (const_peer_iterator i = begin(); i != end(); ++i) for (const_peer_iterator i = begin(); i != end(); ++i)
@ -2615,7 +2643,8 @@ namespace libtorrent
for (std::map<piece_block, int>::iterator i = num_requests.begin() for (std::map<piece_block, int>::iterator i = num_requests.begin()
, end(num_requests.end()); i != end; ++i) , end(num_requests.end()); i != end; ++i)
{ {
TORRENT_ASSERT(m_picker->num_peers(i->first) == i->second); if (!m_picker->is_downloaded(i->first))
TORRENT_ASSERT(m_picker->num_peers(i->first) == i->second);
} }
} }

View File

@ -350,10 +350,23 @@ namespace libtorrent
{ m_name = info["name"].string(); } { m_name = info["name"].string(); }
fs::path tmp = m_name; fs::path tmp = m_name;
if (tmp.is_complete()) throw std::runtime_error("torrent contains " if (tmp.is_complete())
"a file with an absolute path: '" + m_name + "'"); {
if (tmp.has_branch_path()) throw std::runtime_error( m_name = tmp.leaf();
"torrent contains name with directories: '" + m_name + "'"); }
else if (tmp.has_branch_path())
{
fs::path p;
for (fs::path::iterator i = tmp.begin()
, end(tmp.end()); i != end; ++i)
{
if (*i == "." || *i == "..") continue;
p /= *i;
}
m_name = p.string();
}
if (m_name == ".." || m_name == ".")
throw std::runtime_error("invalid 'name' of torrent (possible exploit attempt)");
// extract file list // extract file list
entry const* i = info.find_key("files"); entry const* i = info.find_key("files");

View File

@ -106,7 +106,6 @@ namespace libtorrent
, udp::resolver::iterator i) try , udp::resolver::iterator i) try
{ {
if (error == asio::error::operation_aborted) return; if (error == asio::error::operation_aborted) return;
if (!m_socket.is_open()) return; // the operation was aborted
if (error || i == udp::resolver::iterator()) if (error || i == udp::resolver::iterator())
{ {
fail(-1, error.message().c_str()); fail(-1, error.message().c_str());

View File

@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/http_tracker_connection.hpp" #include "libtorrent/http_tracker_connection.hpp"
#include "libtorrent/xml_parse.hpp" #include "libtorrent/xml_parse.hpp"
#include "libtorrent/connection_queue.hpp" #include "libtorrent/connection_queue.hpp"
#include "libtorrent/enum_net.hpp"
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/ref.hpp> #include <boost/ref.hpp>
@ -61,7 +62,7 @@ namespace libtorrent
upnp::upnp(io_service& ios, connection_queue& cc upnp::upnp(io_service& ios, connection_queue& cc
, address const& listen_interface, std::string const& user_agent , address const& listen_interface, std::string const& user_agent
, portmap_callback_t const& cb) , portmap_callback_t const& cb, bool ignore_nonrouters)
: m_udp_local_port(0) : m_udp_local_port(0)
, m_tcp_local_port(0) , m_tcp_local_port(0)
, m_user_agent(user_agent) , m_user_agent(user_agent)
@ -81,7 +82,21 @@ upnp::upnp(io_service& ios, connection_queue& cc
m_log.open("upnp.log", std::ios::in | std::ios::out | std::ios::trunc); m_log.open("upnp.log", std::ios::in | std::ios::out | std::ios::trunc);
#endif #endif
m_retry_count = 0; m_retry_count = 0;
discover_device();
if (ignore_nonrouters)
{
asio::error_code ec;
std::vector<address> const& net = enum_net_interfaces(m_io_service, ec);
m_filter.reserve(net.size());
for (std::vector<address>::const_iterator i = net.begin()
, end(net.end()); i != end; ++i)
{
asio::error_code e;
address a = router_for_interface(*i, e);
if (e || is_loopback(a)) continue;
m_filter.push_back(a);
}
}
} }
upnp::~upnp() upnp::~upnp()
@ -266,6 +281,18 @@ try
Server:Microsoft-Windows-NT/5.1 UPnP/1.0 UPnP-Device-Host/1.0 Server:Microsoft-Windows-NT/5.1 UPnP/1.0 UPnP-Device-Host/1.0
*/ */
if (!m_filter.empty() && std::find(m_filter.begin(), m_filter.end()
, from.address()) == m_filter.end())
{
// this upnp device is filtered because it's not in the
// list of configured routers
#ifdef TORRENT_UPNP_LOGGING
m_log << time_now_string() << " <== (" << from << ") Rootdevice "
"ignored because it's not out router" << std::endl;
#endif
return;
}
http_parser p; http_parser p;
try try
{ {
@ -663,7 +690,7 @@ void upnp::on_upnp_xml(asio::error_code const& e
parse_state s; parse_state s;
s.reset("urn:schemas-upnp-org:service:WANIPConnection:1"); s.reset("urn:schemas-upnp-org:service:WANIPConnection:1");
xml_parse((char*)p.get_body().begin, (char*)p.get_body().end xml_parse((char*)p.get_body().begin, (char*)p.get_body().end
, m_strand.wrap(bind(&find_control_url, _1, _2, boost::ref(s)))); , bind(&find_control_url, _1, _2, boost::ref(s)));
if (s.found_service) if (s.found_service)
{ {
d.service_namespace = s.service_type; d.service_namespace = s.service_type;
@ -674,7 +701,7 @@ void upnp::on_upnp_xml(asio::error_code const& e
// a PPP connection // a PPP connection
s.reset("urn:schemas-upnp-org:service:WANPPPConnection:1"); s.reset("urn:schemas-upnp-org:service:WANPPPConnection:1");
xml_parse((char*)p.get_body().begin, (char*)p.get_body().end xml_parse((char*)p.get_body().begin, (char*)p.get_body().end
, m_strand.wrap(bind(&find_control_url, _1, _2, boost::ref(s)))); , bind(&find_control_url, _1, _2, boost::ref(s)));
if (s.found_service) if (s.found_service)
{ {
d.service_namespace = s.service_type; d.service_namespace = s.service_type;
@ -821,7 +848,7 @@ void upnp::on_upnp_map_response(asio::error_code const& e
error_code_parse_state s; error_code_parse_state s;
xml_parse((char*)p.get_body().begin, (char*)p.get_body().end xml_parse((char*)p.get_body().begin, (char*)p.get_body().end
, m_strand.wrap(bind(&find_error_code, _1, _2, boost::ref(s)))); , bind(&find_error_code, _1, _2, boost::ref(s)));
#ifdef TORRENT_UPNP_LOGGING #ifdef TORRENT_UPNP_LOGGING
if (s.error_code != -1) if (s.error_code != -1)