lt sync 2486

This commit is contained in:
Andrew Resch 2008-07-01 21:51:16 +00:00
commit 69e24fe673
33 changed files with 748 additions and 587 deletions

View file

@ -213,16 +213,12 @@ class TorrentManager(component.Component):
self.config["state_location"], self.config["state_location"],
torrent_id + ".fastresume"), torrent_id + ".fastresume"),
"rb") "rb")
try: fastresume = _file.read()
fastresume = lt.bdecode(_file.read())
except RuntimeError, e:
log.warning("Unable to bdecode fastresume file: %s", e)
_file.close() _file.close()
except IOError, e: except IOError, e:
log.debug("Unable to load .fastresume: %s", e) log.debug("Unable to load .fastresume: %s", e)
return fastresume return str(fastresume)
def add(self, torrent_info=None, state=None, options=None, save_state=True, def add(self, torrent_info=None, state=None, options=None, save_state=True,
filedump=None, filename=None): filedump=None, filename=None):
@ -291,7 +287,7 @@ class TorrentManager(component.Component):
options[key] = self.config[key] options[key] = self.config[key]
add_torrent_params["ti"] = torrent_info add_torrent_params["ti"] = torrent_info
add_torrent_params["resume_data"] = None add_torrent_params["resume_data"] = ""
#log.info("Adding torrent: %s", filename) #log.info("Adding torrent: %s", filename)
log.debug("options: %s", options) log.debug("options: %s", options)

View file

@ -4,6 +4,7 @@
#include <libtorrent/extensions.hpp> #include <libtorrent/extensions.hpp>
#include <libtorrent/entry.hpp> #include <libtorrent/entry.hpp>
#include <libtorrent/lazy_entry.hpp>
#include <libtorrent/peer_request.hpp> #include <libtorrent/peer_request.hpp>
#include <libtorrent/disk_buffer_holder.hpp> #include <libtorrent/disk_buffer_holder.hpp>
#include <libtorrent/bitfield.hpp> #include <libtorrent/bitfield.hpp>
@ -42,7 +43,7 @@ namespace
return this->peer_plugin::on_handshake(reserved_bits); return this->peer_plugin::on_handshake(reserved_bits);
} }
bool on_extension_handshake(entry const& e) bool on_extension_handshake(lazy_entry const& e)
{ {
if (override f = this->get_override("on_extension_handshake")) if (override f = this->get_override("on_extension_handshake"))
return f(e); return f(e);
@ -50,7 +51,7 @@ namespace
return peer_plugin::on_extension_handshake(e); return peer_plugin::on_extension_handshake(e);
} }
bool default_on_extension_handshake(entry const& e) bool default_on_extension_handshake(lazy_entry const& e)
{ {
return this->peer_plugin::on_extension_handshake(e); return this->peer_plugin::on_extension_handshake(e);
} }

View file

@ -103,29 +103,32 @@ namespace
add_torrent_params p; add_torrent_params p;
if (params.has_key("ti")) if (params.has_key("ti"))
{ p.ti = new torrent_info(extract<torrent_info const&>(params["ti"]));
boost::intrusive_ptr<torrent_info> ti = new torrent_info(
extract<torrent_info const&>(params["ti"])); std::string url;
p.ti = ti;
}
if (params.has_key("tracker_url")) if (params.has_key("tracker_url"))
{ {
std::string url = extract<std::string>(params["tracker_url"]); url = extract<std::string>(params["tracker_url"]);
p.tracker_url = url.c_str(); p.tracker_url = url.c_str();
} }
if (params.has_key("info_hash")) if (params.has_key("info_hash"))
{ p.info_hash = extract<sha1_hash>(params["info_hash"]);
sha1_hash info_hash = extract<sha1_hash>(params["info_hash"]); std::string name;
p.info_hash = info_hash;
}
if (params.has_key("name")) if (params.has_key("name"))
{ {
std::string name = extract<std::string>(params["name"]); name = extract<std::string>(params["name"]);
p.name = name.c_str(); p.name = name.c_str();
} }
p.save_path = fs::path(extract<std::string>(params["save_path"])); p.save_path = fs::path(extract<std::string>(params["save_path"]));
entry resume = extract<entry>(params["resume_data"]);
p.resume_data = &resume; std::vector<char> resume_buf;
if (params.has_key("resume_data"))
{
std::string resume = extract<std::string>(params["resume_data"]);
resume_buf.resize(resume.size());
std::memcpy(&resume_buf[0], &resume[0], resume.size());
p.resume_data = &resume_buf;
}
p.storage_mode = extract<storage_mode_t>(params["storage_mode"]); p.storage_mode = extract<storage_mode_t>(params["storage_mode"]);
p.paused = params["paused"]; p.paused = params["paused"];
p.auto_managed = params["auto_managed"]; p.auto_managed = params["auto_managed"];
@ -334,6 +337,9 @@ void bind_session()
.def("set_ip_filter", allow_threads(&session::set_ip_filter), session_set_ip_filter_doc) .def("set_ip_filter", allow_threads(&session::set_ip_filter), session_set_ip_filter_doc)
.def("find_torrent", allow_threads(&session::find_torrent)) .def("find_torrent", allow_threads(&session::find_torrent))
.def("get_torrents", &get_torrents) .def("get_torrents", &get_torrents)
.def("pause", allow_threads(&session::pause))
.def("resume", allow_threads(&session::resume))
.def("is_paused", allow_threads(&session::is_paused))
; ;
register_ptr_to_python<std::auto_ptr<alert> >(); register_ptr_to_python<std::auto_ptr<alert> >();

View file

@ -189,6 +189,10 @@ namespace libtorrent
, int nat_transport); , int nat_transport);
bool is_aborted() const { return m_abort; } bool is_aborted() const { return m_abort; }
bool is_paused() const { return m_paused; }
void pause();
void resume();
void set_ip_filter(ip_filter const& f); void set_ip_filter(ip_filter const& f);
void set_port_filter(port_filter const& f); void set_port_filter(port_filter const& f);
@ -454,6 +458,9 @@ namespace libtorrent
// should exit // should exit
volatile bool m_abort; volatile bool m_abort;
// is true if the session is paused
bool m_paused;
// the max number of unchoked peers as set by the user // the max number of unchoked peers as set by the user
int m_max_uploads; int m_max_uploads;

View file

@ -389,7 +389,7 @@ private:
// initialized during write_pe1_2_dhkey, and destroyed on // initialized during write_pe1_2_dhkey, and destroyed on
// creation of m_RC4_handler. Cannot reinitialize once // creation of m_RC4_handler. Cannot reinitialize once
// initialized. // initialized.
boost::scoped_ptr<DH_key_exchange> m_DH_key_exchange; boost::scoped_ptr<dh_key_exchange> m_dh_key_exchange;
// if RC4 is negotiated, this is used for // if RC4 is negotiated, this is used for
// encryption/decryption during the entire session. Destroyed // encryption/decryption during the entire session. Destroyed

View file

@ -56,6 +56,7 @@ namespace libtorrent
struct peer_request; struct peer_request;
class peer_connection; class peer_connection;
class entry; class entry;
struct lazy_entry;
struct disk_buffer_holder; struct disk_buffer_holder;
struct bitfield; struct bitfield;
@ -107,7 +108,7 @@ namespace libtorrent
// supported by this peer. It will result in this peer_plugin // supported by this peer. It will result in this peer_plugin
// being removed from the peer_connection and destructed. // being removed from the peer_connection and destructed.
// this is not called for web seeds // this is not called for web seeds
virtual bool on_extension_handshake(entry const& h) { return true; } virtual bool on_extension_handshake(lazy_entry const& h) { return true; }
// returning true from any of the message handlers // returning true from any of the message handlers
// indicates that the plugin has handeled the message. // indicates that the plugin has handeled the message.

View file

@ -34,7 +34,8 @@ POSSIBILITY OF SUCH DAMAGE.
#define TORRENT_FILE_HPP_INCLUDED #define TORRENT_FILE_HPP_INCLUDED
#include <memory> #include <memory>
#include <stdexcept> #include <string>
#include <vector>
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push, 1) #pragma warning(push, 1)
@ -54,11 +55,6 @@ namespace libtorrent
{ {
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
struct TORRENT_EXPORT file_error: std::runtime_error
{
file_error(std::string const& msg): std::runtime_error(msg) {}
};
class TORRENT_EXPORT file: public boost::noncopyable class TORRENT_EXPORT file: public boost::noncopyable
{ {
public: public:

View file

@ -170,7 +170,7 @@ namespace libtorrent
return m_size; return m_size;
} }
// end points one byte passed end // end points one byte passed last byte
void set_end(char const* end) void set_end(char const* end)
{ {
TORRENT_ASSERT(end > m_begin); TORRENT_ASSERT(end > m_begin);

View file

@ -1,3 +1,35 @@
/*
Copyright (c) 2008, 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.
*/
#ifdef BOOST_BUILD_PCH_ENABLED #ifdef BOOST_BUILD_PCH_ENABLED
#include <algorithm> #include <algorithm>

View file

@ -44,31 +44,30 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
class DH_key_exchange class dh_key_exchange
{ {
public: public:
DH_key_exchange (); dh_key_exchange();
~DH_key_exchange (); ~dh_key_exchange();
bool good() const { return m_dh; }
// Get local public key, always 96 bytes // Get local public key, always 96 bytes
char const* get_local_key (void) const; char const* get_local_key() const;
// read remote_pubkey, generate and store shared secret in // read remote_pubkey, generate and store shared secret in
// m_dh_secret // m_dh_secret.
void compute_secret (const char* remote_pubkey); int compute_secret(const char* remote_pubkey);
const char* get_secret (void) const; const char* get_secret() const;
private: private:
int get_local_key_size () const int get_local_key_size() const
{ {
TORRENT_ASSERT(m_DH); TORRENT_ASSERT(m_dh);
return BN_num_bytes (m_DH->pub_key); return BN_num_bytes(m_dh->pub_key);
} }
DH* m_DH; DH* m_dh;
static const unsigned char m_dh_prime[96];
static const unsigned char m_dh_generator[1];
char m_dh_local_key[96]; char m_dh_local_key[96];
char m_dh_secret[96]; char m_dh_secret[96];
@ -78,24 +77,24 @@ namespace libtorrent
{ {
public: public:
// Input longkeys must be 20 bytes // Input longkeys must be 20 bytes
RC4_handler (const sha1_hash& rc4_local_longkey, RC4_handler(const sha1_hash& rc4_local_longkey,
const sha1_hash& rc4_remote_longkey) const sha1_hash& rc4_remote_longkey)
{ {
RC4_set_key (&m_local_key, 20, RC4_set_key(&m_local_key, 20,
reinterpret_cast<unsigned char const*>(rc4_local_longkey.begin())); reinterpret_cast<unsigned char const*>(rc4_local_longkey.begin()));
RC4_set_key (&m_remote_key, 20, RC4_set_key(&m_remote_key, 20,
reinterpret_cast<unsigned char const*>(rc4_remote_longkey.begin())); reinterpret_cast<unsigned char const*>(rc4_remote_longkey.begin()));
// Discard first 1024 bytes // Discard first 1024 bytes
char buf[1024]; char buf[1024];
encrypt (buf, 1024); encrypt(buf, 1024);
decrypt (buf, 1024); decrypt(buf, 1024);
}; };
~RC4_handler () {}; ~RC4_handler() {};
void encrypt (char* pos, int len) void encrypt(char* pos, int len)
{ {
TORRENT_ASSERT(len >= 0); TORRENT_ASSERT(len >= 0);
TORRENT_ASSERT(pos); TORRENT_ASSERT(pos);
@ -104,7 +103,7 @@ namespace libtorrent
reinterpret_cast<unsigned char*>(pos)); reinterpret_cast<unsigned char*>(pos));
} }
void decrypt (char* pos, int len) void decrypt(char* pos, int len)
{ {
TORRENT_ASSERT(len >= 0); TORRENT_ASSERT(len >= 0);
TORRENT_ASSERT(pos); TORRENT_ASSERT(pos);
@ -122,3 +121,4 @@ namespace libtorrent
#endif // TORRENT_PE_CRYPTO_HPP_INCLUDED #endif // TORRENT_PE_CRYPTO_HPP_INCLUDED
#endif // TORRENT_DISABLE_ENCRYPTION #endif // TORRENT_DISABLE_ENCRYPTION

View file

@ -202,8 +202,6 @@ namespace libtorrent
void set_upload_only(bool u) { m_upload_only = u; } void set_upload_only(bool u) { m_upload_only = u; }
bool upload_only() const { return m_upload_only; } bool upload_only() const { return m_upload_only; }
bool has_timed_out() const;
// will send a keep-alive message to the peer // will send a keep-alive message to the peer
void keep_alive(); void keep_alive();
@ -569,6 +567,12 @@ namespace libtorrent
ptime m_last_receive; ptime m_last_receive;
ptime m_last_sent; ptime m_last_sent;
// the time when the first entry in the
// request queue was requested, increased
// for each entry that is popped from the
// download queue. Used for request timeout
ptime m_requested;
// a timestamp when the remote download rate // a timestamp when the remote download rate
// was last updated // was last updated
ptime m_remote_dl_update; ptime m_remote_dl_update;
@ -825,6 +829,11 @@ namespace libtorrent
// set to true when this peer is only uploading // set to true when this peer is only uploading
bool m_upload_only:1; bool m_upload_only:1;
// set to true when a piece request times out. The
// result is that the desired pending queue size
// is set to 1
bool m_snubbed:1;
#ifndef NDEBUG #ifndef NDEBUG
public: public:
bool m_in_constructor:1; bool m_in_constructor:1;

View file

@ -56,7 +56,8 @@ namespace libtorrent
queued = 0x100, queued = 0x100,
on_parole = 0x200, on_parole = 0x200,
seed = 0x400, seed = 0x400,
optimistic_unchoke = 0x800 optimistic_unchoke = 0x800,
snubbed = 0x1000
#ifndef TORRENT_DISABLE_ENCRYPTION #ifndef TORRENT_DISABLE_ENCRYPTION
, rc4_encrypted = 0x100000, , rc4_encrypted = 0x100000,
plaintext_encrypted = 0x200000 plaintext_encrypted = 0x200000
@ -105,6 +106,10 @@ namespace libtorrent
// time since last download or upload // time since last download or upload
time_duration last_active; time_duration last_active;
// the number of seconds until the current
// pending request times out
int request_timeout;
// the size of the send buffer for this peer, in bytes // the size of the send buffer for this peer, in bytes
int send_buffer_size; int send_buffer_size;
// the number bytes that's actually used of the send buffer // the number bytes that's actually used of the send buffer

View file

@ -140,7 +140,7 @@ namespace libtorrent
sha1_hash info_hash; sha1_hash info_hash;
char const* name; char const* name;
fs::path save_path; fs::path save_path;
entry const* resume_data; std::vector<char>* resume_data;
storage_mode_t storage_mode; storage_mode_t storage_mode;
bool paused; bool paused;
bool auto_managed; bool auto_managed;
@ -212,6 +212,10 @@ namespace libtorrent
session_proxy abort() { return session_proxy(m_impl); } session_proxy abort() { return session_proxy(m_impl); }
void pause();
void resume();
bool is_paused() const;
session_status status() const; session_status status() const;
cache_status get_cache_status() const; cache_status get_cache_status() const;

View file

@ -88,6 +88,7 @@ namespace libtorrent
, stop_tracker_timeout(5) , stop_tracker_timeout(5)
, tracker_maximum_response_length(1024*1024) , tracker_maximum_response_length(1024*1024)
, piece_timeout(10) , piece_timeout(10)
, request_timeout(40)
, request_queue_time(3.f) , request_queue_time(3.f)
, max_allowed_in_request_queue(250) , max_allowed_in_request_queue(250)
, max_out_request_queue(200) , max_out_request_queue(200)
@ -168,6 +169,11 @@ namespace libtorrent
// it times out if no piece response is returned. // it times out if no piece response is returned.
int piece_timeout; int piece_timeout;
// the number of seconds one block (16kB) is expected
// to be received within. If it's not, the block is
// requested from a different peer
int request_timeout;
// the length of the request queue given in the number // the length of the request queue given in the number
// of seconds it should take for the other end to send // of seconds it should take for the other end to send
// all the pieces. i.e. the actual number of requests // all the pieces. i.e. the actual number of requests

View file

@ -133,7 +133,7 @@ namespace libtorrent
virtual bool move_storage(fs::path save_path) = 0; virtual bool move_storage(fs::path save_path) = 0;
// verify storage dependent fast resume entries // verify storage dependent fast resume entries
virtual bool verify_resume_data(entry const& rd, std::string& error) = 0; virtual bool verify_resume_data(lazy_entry const& rd, std::string& error) = 0;
// write storage dependent fast resume entries // write storage dependent fast resume entries
virtual bool write_resume_data(entry& rd) const = 0; virtual bool write_resume_data(entry& rd) const = 0;
@ -212,7 +212,7 @@ namespace libtorrent
boost::intrusive_ptr<torrent_info const> info() const { return m_info; } boost::intrusive_ptr<torrent_info const> info() const { return m_info; }
void write_resume_data(entry& rd) const; void write_resume_data(entry& rd) const;
void async_check_fastresume(entry const* resume_data void async_check_fastresume(lazy_entry const* resume_data
, boost::function<void(int, disk_io_job const&)> const& handler); , boost::function<void(int, disk_io_job const&)> const& handler);
void async_check_files(boost::function<void(int, disk_io_job const&)> const& handler); void async_check_files(boost::function<void(int, disk_io_job const&)> const& handler);
@ -259,7 +259,7 @@ namespace libtorrent
fs::path save_path() const; fs::path save_path() const;
bool verify_resume_data(entry const& rd, std::string& error) bool verify_resume_data(lazy_entry const& rd, std::string& error)
{ return m_storage->verify_resume_data(rd, error); } { return m_storage->verify_resume_data(rd, error); }
bool is_allocating() const bool is_allocating() const
@ -282,7 +282,7 @@ namespace libtorrent
// the error message indicates that the fast resume data was rejected // the error message indicates that the fast resume data was rejected
// if 'fatal_disk_error' is returned, the error message indicates what // if 'fatal_disk_error' is returned, the error message indicates what
// when wrong in the disk access // when wrong in the disk access
int check_fastresume(entry const& rd, std::string& error); int check_fastresume(lazy_entry const& rd, std::string& error);
// this function returns true if the checking is complete // this function returns true if the checking is complete
int check_files(int& current_slot, int& have_piece, std::string& error); int check_files(int& current_slot, int& have_piece, std::string& error);

View file

@ -107,7 +107,7 @@ namespace libtorrent
, int block_size , int block_size
, storage_constructor_type sc , storage_constructor_type sc
, bool paused , bool paused
, entry const* resume_data , std::vector<char>* resume_data
, int seq , int seq
, bool auto_managed); , bool auto_managed);
@ -124,12 +124,14 @@ namespace libtorrent
, int block_size , int block_size
, storage_constructor_type sc , storage_constructor_type sc
, bool paused , bool paused
, entry const* resume_data , std::vector<char>* resume_data
, int seq , int seq
, bool auto_managed); , bool auto_managed);
~torrent(); ~torrent();
void parse_resume_data(std::vector<char>* resume_data);
// starts the announce timer // starts the announce timer
void start(); void start();
@ -195,7 +197,12 @@ namespace libtorrent
bool has_error() const { return !m_error.empty(); } bool has_error() const { return !m_error.empty(); }
void pause(); void pause();
void resume(); void resume();
bool is_paused() const { return m_paused; }
void do_pause();
void do_resume();
bool is_paused() const;
bool is_torrent_paused() const { return m_paused; }
void force_recheck(); void force_recheck();
void save_resume_data(); void save_resume_data();
@ -559,7 +566,7 @@ namespace libtorrent
torrent_handle get_handle(); torrent_handle get_handle();
void write_resume_data(entry& rd) const; void write_resume_data(entry& rd) const;
void read_resume_data(entry const& rd); void read_resume_data(lazy_entry const& rd);
// LOGGING // LOGGING
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
@ -782,7 +789,9 @@ namespace libtorrent
// error message // error message
std::string m_error; std::string m_error;
entry m_resume_data; // used if there is any resume data
std::vector<char> m_resume_data;
lazy_entry m_resume_entry;
// if the torrent is started without metadata, it may // if the torrent is started without metadata, it may
// still be given a name until the metadata is received // still be given a name until the metadata is received

View file

@ -64,6 +64,7 @@ namespace libtorrent
{ {
namespace pt = boost::posix_time; namespace pt = boost::posix_time;
namespace gr = boost::gregorian; namespace gr = boost::gregorian;
namespace fs = boost::filesystem;
struct TORRENT_EXPORT announce_entry struct TORRENT_EXPORT announce_entry
{ {
@ -79,6 +80,8 @@ namespace libtorrent
}; };
#endif #endif
int TORRENT_EXPORT load_file(fs::path const& filename, std::vector<char>& v);
class TORRENT_EXPORT torrent_info : public intrusive_ptr_base<torrent_info> class TORRENT_EXPORT torrent_info : public intrusive_ptr_base<torrent_info>
{ {
public: public:
@ -86,7 +89,7 @@ namespace libtorrent
torrent_info(sha1_hash const& info_hash); torrent_info(sha1_hash const& info_hash);
torrent_info(lazy_entry const& torrent_file); torrent_info(lazy_entry const& torrent_file);
torrent_info(char const* buffer, int size); torrent_info(char const* buffer, int size);
torrent_info(char const* filename); torrent_info(fs::path const& filename);
~torrent_info(); ~torrent_info();
file_storage const& files() const { return m_files; } file_storage const& files() const { return m_files; }

View file

@ -192,6 +192,7 @@ namespace libtorrent
if (out_enc_policy == pe_settings::forced) if (out_enc_policy == pe_settings::forced)
{ {
write_pe1_2_dhkey(); write_pe1_2_dhkey();
if (is_disconnecting()) return;
m_state = read_pe_dhkey; m_state = read_pe_dhkey;
reset_recv_buffer(dh_key_len); reset_recv_buffer(dh_key_len);
@ -214,6 +215,7 @@ namespace libtorrent
fast_reconnect(true); fast_reconnect(true);
write_pe1_2_dhkey(); write_pe1_2_dhkey();
if (is_disconnecting()) return;
m_state = read_pe_dhkey; m_state = read_pe_dhkey;
reset_recv_buffer(dh_key_len); reset_recv_buffer(dh_key_len);
setup_receive(); setup_receive();
@ -372,7 +374,7 @@ namespace libtorrent
TORRENT_ASSERT(!m_encrypted); TORRENT_ASSERT(!m_encrypted);
TORRENT_ASSERT(!m_rc4_encrypted); TORRENT_ASSERT(!m_rc4_encrypted);
TORRENT_ASSERT(!m_DH_key_exchange.get()); TORRENT_ASSERT(!m_dh_key_exchange.get());
TORRENT_ASSERT(!m_sent_handshake); TORRENT_ASSERT(!m_sent_handshake);
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
@ -380,7 +382,12 @@ namespace libtorrent
(*m_logger) << " initiating encrypted handshake\n"; (*m_logger) << " initiating encrypted handshake\n";
#endif #endif
m_DH_key_exchange.reset(new DH_key_exchange); m_dh_key_exchange.reset(new (std::nothrow) dh_key_exchange);
if (!m_dh_key_exchange || !m_dh_key_exchange->good())
{
disconnect("out of memory");
return;
}
int pad_size = std::rand() % 512; int pad_size = std::rand() % 512;
@ -389,11 +396,15 @@ namespace libtorrent
#endif #endif
buffer::interval send_buf = allocate_send_buffer(dh_key_len + pad_size); buffer::interval send_buf = allocate_send_buffer(dh_key_len + pad_size);
if (send_buf.begin == 0) return; // out of memory if (send_buf.begin == 0)
{
disconnect("out of memory");
return;
}
std::copy(m_DH_key_exchange->get_local_key(), std::copy(m_dh_key_exchange->get_local_key(),
m_DH_key_exchange->get_local_key() + dh_key_len, m_dh_key_exchange->get_local_key() + dh_key_len,
send_buf.begin); send_buf.begin);
std::generate(send_buf.begin + dh_key_len, send_buf.end, std::rand); std::generate(send_buf.begin + dh_key_len, send_buf.end, std::rand);
setup_send(); setup_send();
@ -417,7 +428,7 @@ namespace libtorrent
hasher h; hasher h;
sha1_hash const& info_hash = t->torrent_file().info_hash(); sha1_hash const& info_hash = t->torrent_file().info_hash();
char const* const secret = m_DH_key_exchange->get_secret(); char const* const secret = m_dh_key_exchange->get_secret();
int pad_size = rand() % 512; int pad_size = rand() % 512;
@ -452,7 +463,7 @@ namespace libtorrent
// Discard DH key exchange data, setup RC4 keys // Discard DH key exchange data, setup RC4 keys
init_pe_RC4_handler(secret, info_hash); init_pe_RC4_handler(secret, info_hash);
m_DH_key_exchange.reset(); // secret should be invalid at this point m_dh_key_exchange.reset(); // secret should be invalid at this point
// write the verification constant and crypto field // write the verification constant and crypto field
TORRENT_ASSERT(send_buf.left() == 8 + 4 + 2 + pad_size + 2); TORRENT_ASSERT(send_buf.left() == 8 + 4 + 2 + pad_size + 2);
@ -1235,9 +1246,9 @@ namespace libtorrent
buffer::const_interval recv_buffer = receive_buffer(); buffer::const_interval recv_buffer = receive_buffer();
entry root; lazy_entry root;
root = bdecode(recv_buffer.begin + 2, recv_buffer.end); lazy_bdecode(recv_buffer.begin + 2, recv_buffer.end, root);
if (root.type() == entry::undefined_t) if (root.type() != lazy_entry::dict_t)
{ {
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << "invalid extended handshake\n"; (*m_logger) << "invalid extended handshake\n";
@ -1246,14 +1257,12 @@ namespace libtorrent
} }
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
std::stringstream ext; (*m_logger) << "<== EXTENDED HANDSHAKE: \n" << root;
root.print(ext);
(*m_logger) << "<== EXTENDED HANDSHAKE: \n" << ext.str();
#endif #endif
#ifndef TORRENT_DISABLE_EXTENSIONS #ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin() for (extension_list_t::iterator i = m_extensions.begin();
, end(m_extensions.end()); i != end;) !m_extensions.empty() && i != m_extensions.end();)
{ {
// a false return value means that the extension // a false return value means that the extension
// isn't supported by the other end. So, it is removed. // isn't supported by the other end. So, it is removed.
@ -1265,56 +1274,39 @@ namespace libtorrent
#endif #endif
// there is supposed to be a remote listen port // there is supposed to be a remote listen port
if (entry* listen_port = root.find_key("p")) int listen_port = root.dict_find_int_value("p");
if (listen_port > 0 && peer_info_struct() != 0)
{ {
if (listen_port->type() == entry::int_t t->get_policy().update_peer_port(listen_port
&& peer_info_struct() != 0) , peer_info_struct(), peer_info::incoming);
{
t->get_policy().update_peer_port(int(listen_port->integer())
, peer_info_struct(), peer_info::incoming);
}
} }
// there should be a version too // there should be a version too
// but where do we put that info? // but where do we put that info?
if (entry* client_info = root.find_key("v")) std::string client_info = root.dict_find_string_value("v");
{ if (!client_info.empty()) m_client_version = client_info;
if (client_info->type() == entry::string_t)
m_client_version = client_info->string();
}
if (entry* reqq = root.find_key("reqq")) int reqq = root.dict_find_int_value("reqq");
{ if (reqq > 0) m_max_out_request_queue = reqq;
if (reqq->type() == entry::int_t)
m_max_out_request_queue = int(reqq->integer());
if (m_max_out_request_queue < 1)
m_max_out_request_queue = 1;
}
if (entry* upload_only = root.find_key("upload_only")) if (root.dict_find_int_value("upload_only"))
{ set_upload_only(true);
if (upload_only->type() == entry::int_t && upload_only->integer() != 0)
set_upload_only(true);
}
if (entry* myip = root.find_key("yourip")) std::string myip = root.dict_find_string_value("yourip");
if (!myip.empty())
{ {
// TODO: don't trust this blindly // TODO: don't trust this blindly
if (myip->type() == entry::string_t) if (myip.size() == address_v4::bytes_type::static_size)
{ {
std::string const& my_ip = myip->string().c_str(); address_v4::bytes_type bytes;
if (my_ip.size() == address_v4::bytes_type::static_size) std::copy(myip.begin(), myip.end(), bytes.begin());
{ m_ses.set_external_address(address_v4(bytes));
address_v4::bytes_type bytes; }
std::copy(my_ip.begin(), my_ip.end(), bytes.begin()); else if (myip.size() == address_v6::bytes_type::static_size)
m_ses.set_external_address(address_v4(bytes)); {
} address_v6::bytes_type bytes;
else if (my_ip.size() == address_v6::bytes_type::static_size) std::copy(myip.begin(), myip.end(), bytes.begin());
{ m_ses.set_external_address(address_v6(bytes));
address_v6::bytes_type bytes;
std::copy(my_ip.begin(), my_ip.end(), bytes.begin());
m_ses.set_external_address(address_v6(bytes));
}
} }
} }
@ -1752,13 +1744,17 @@ namespace libtorrent
if (!packet_finished()) return; if (!packet_finished()) return;
// write our dh public key. m_DH_key_exchange is // write our dh public key. m_dh_key_exchange is
// initialized in write_pe1_2_dhkey() // initialized in write_pe1_2_dhkey()
if (!is_local()) if (!is_local()) write_pe1_2_dhkey();
write_pe1_2_dhkey(); if (is_disconnecting()) return;
// read dh key, generate shared secret // read dh key, generate shared secret
m_DH_key_exchange->compute_secret (recv_buffer.begin); // TODO handle errors if (m_dh_key_exchange->compute_secret(recv_buffer.begin) == -1)
{
disconnect("out of memory");
return;
}
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << " received DH key\n"; (*m_logger) << " received DH key\n";
@ -1822,7 +1818,7 @@ namespace libtorrent
// compute synchash (hash('req1',S)) // compute synchash (hash('req1',S))
h.update("req1", 4); h.update("req1", 4);
h.update(m_DH_key_exchange->get_secret(), dh_key_len); h.update(m_dh_key_exchange->get_secret(), dh_key_len);
m_sync_hash.reset(new sha1_hash(h.final())); m_sync_hash.reset(new sha1_hash(h.final()));
} }
@ -1895,7 +1891,7 @@ namespace libtorrent
h.reset(); h.reset();
h.update("req3", 4); h.update("req3", 4);
h.update(m_DH_key_exchange->get_secret(), dh_key_len); h.update(m_dh_key_exchange->get_secret(), dh_key_len);
obfs_hash = h.final(); obfs_hash = h.final();
obfs_hash ^= skey_hash; obfs_hash ^= skey_hash;
@ -1912,7 +1908,7 @@ namespace libtorrent
TORRENT_ASSERT(t); TORRENT_ASSERT(t);
} }
init_pe_RC4_handler(m_DH_key_exchange->get_secret(), info_hash); init_pe_RC4_handler(m_dh_key_exchange->get_secret(), info_hash);
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << " stream key found, torrent located.\n"; (*m_logger) << " stream key found, torrent located.\n";
#endif #endif
@ -2641,7 +2637,7 @@ namespace libtorrent
void bt_peer_connection::check_invariant() const void bt_peer_connection::check_invariant() const
{ {
#ifndef TORRENT_DISABLE_ENCRYPTION #ifndef TORRENT_DISABLE_ENCRYPTION
TORRENT_ASSERT( (bool(m_state != read_pe_dhkey) || m_DH_key_exchange.get()) TORRENT_ASSERT( (bool(m_state != read_pe_dhkey) || m_dh_key_exchange.get())
|| !is_local()); || !is_local());
TORRENT_ASSERT(!m_rc4_encrypted || m_RC4_handler.get()); TORRENT_ASSERT(!m_rc4_encrypted || m_RC4_handler.get());

View file

@ -1048,7 +1048,7 @@ namespace libtorrent
#ifdef TORRENT_DISK_STATS #ifdef TORRENT_DISK_STATS
m_log << log_time() << " check fastresume" << std::endl; m_log << log_time() << " check fastresume" << std::endl;
#endif #endif
entry const* rd = (entry const*)j.buffer; lazy_entry const* rd = (lazy_entry const*)j.buffer;
TORRENT_ASSERT(rd != 0); TORRENT_ASSERT(rd != 0);
ret = j.storage->check_fastresume(*rd, j.str); ret = j.storage->check_fastresume(*rd, j.str);
break; break;

View file

@ -70,6 +70,7 @@ BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);
#include "libtorrent/file.hpp" #include "libtorrent/file.hpp"
#include <sstream> #include <sstream>
#include <cstring> #include <cstring>
#include <vector>
#ifndef O_BINARY #ifndef O_BINARY
#define O_BINARY 0 #define O_BINARY 0
@ -130,7 +131,6 @@ namespace
namespace libtorrent namespace libtorrent
{ {
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
const file::open_mode file::in(mode_in); const file::open_mode file::in(mode_in);
@ -160,7 +160,6 @@ namespace libtorrent
bool open(fs::path const& path, int mode) bool open(fs::path const& path, int mode)
{ {
TORRENT_ASSERT(path.is_complete());
close(); close();
#if defined(_WIN32) && defined(UNICODE) #if defined(_WIN32) && defined(UNICODE)
std::wstring wpath(safe_convert(path.native_file_string())); std::wstring wpath(safe_convert(path.native_file_string()));

View file

@ -81,11 +81,10 @@ namespace
virtual void add_handshake(entry&) {} virtual void add_handshake(entry&) {}
// called when the extension handshake from the other end is received // called when the extension handshake from the other end is received
virtual bool on_extension_handshake(entry const& h) virtual bool on_extension_handshake(lazy_entry const& h)
{ {
log_timestamp(); log_timestamp();
m_file << "<== EXTENSION_HANDSHAKE\n"; m_file << "<== EXTENSION_HANDSHAKE\n" << h;
h.print(m_file);
return true; return true;
} }

View file

@ -560,34 +560,32 @@ namespace libtorrent
return false; return false;
} }
bool verify_resume_data(entry const& rd, std::string& error) bool verify_resume_data(lazy_entry const& rd, std::string& error)
{ {
if (rd.type() != entry::dictionary_t) if (rd.type() != lazy_entry::dict_t)
{ {
error = "invalid fastresume file"; error = "invalid fastresume file (not a dictionary)";
return true; return true;
} }
std::vector<std::pair<size_type, std::time_t> > file_sizes; std::vector<std::pair<size_type, std::time_t> > file_sizes;
entry const* file_sizes_ent = rd.find_key("file sizes"); lazy_entry const* file_sizes_ent = rd.dict_find_list("file sizes");
if (file_sizes_ent == 0 || file_sizes_ent->type() != entry::list_t) if (file_sizes_ent == 0)
{ {
error = "missing or invalid 'file sizes' entry in resume data"; error = "missing or invalid 'file sizes' entry in resume data";
return false; return false;
} }
entry::list_type const& l = file_sizes_ent->list(); for (int i = 0; i < file_sizes_ent->list_size(); ++i)
for (entry::list_type::const_iterator i = l.begin();
i != l.end(); ++i)
{ {
if (i->type() != entry::list_t) break; lazy_entry const* e = file_sizes_ent->list_at(i);
entry::list_type const& pair = i->list(); if (e->type() != lazy_entry::list_t
if (pair.size() != 2 || pair.front().type() != entry::int_t || e->list_size() != 2
|| pair.back().type() != entry::int_t) || e->list_at(0)->type() != lazy_entry::int_t
break; || e->list_at(1)->type() != lazy_entry::int_t)
continue;
file_sizes.push_back(std::pair<size_type, std::time_t>( file_sizes.push_back(std::pair<size_type, std::time_t>(
pair.front().integer(), pair.back().integer())); e->list_int_value_at(0), std::time_t(e->list_int_value_at(1))));
} }
if (file_sizes.empty()) if (file_sizes.empty())
@ -596,24 +594,30 @@ namespace libtorrent
return false; return false;
} }
entry const* slots_ent = rd.find_key("slots"); lazy_entry const* slots = rd.dict_find_list("slots");
if (slots_ent == 0 || slots_ent->type() != entry::list_t) if (slots == 0)
{ {
error = "missing or invalid 'slots' entry in resume data"; error = "missing or invalid 'slots' entry in resume data";
return false; return false;
} }
entry::list_type const& slots = slots_ent->list(); bool seed = false;
bool seed = int(slots.size()) == files().num_pieces()
&& std::find_if(slots.begin(), slots.end() if (int(slots->list_size()) == m_files.num_pieces())
, boost::bind<bool>(std::less<int>() {
, boost::bind((size_type const& (entry::*)() const) bool seed = true;
&entry::integer, _1), 0)) == slots.end(); for (int i = 0; i < slots->list_size(); ++i)
{
lazy_entry const* e = slots->list_at(i);
if (e->list_int_value_at(i, -1) >= 0) continue;
seed = false;
break;
}
}
bool full_allocation_mode = false; bool full_allocation_mode = false;
entry const* allocation_mode = rd.find_key("allocation"); if (rd.dict_find_string_value("allocation") == "full")
if (allocation_mode && allocation_mode->type() == entry::string_t) full_allocation_mode = true;
full_allocation_mode = allocation_mode->string() == "full";
if (seed) if (seed)
{ {
@ -640,7 +644,6 @@ namespace libtorrent
return false; return false;
} }
} }
return true;
} }
return match_filesizes(files(), m_save_path, file_sizes return match_filesizes(files(), m_save_path, file_sizes

View file

@ -278,15 +278,16 @@ namespace libtorrent { namespace
} }
// called when the extension handshake from the other end is received // called when the extension handshake from the other end is received
virtual bool on_extension_handshake(entry const& h) virtual bool on_extension_handshake(lazy_entry const& h)
{ {
m_message_index = 0; m_message_index = 0;
entry const* messages = h.find_key("m"); if (h.type() != lazy_entry::dict_t) return false;
if (!messages || messages->type() != entry::dictionary_t) return false; lazy_entry const* messages = h.dict_find("m");
if (!messages || messages->type() != lazy_entry::dict_t) return false;
entry const* index = messages->find_key("LT_metadata"); int index = messages->dict_find_int_value("LT_metadata", -1);
if (!index || index->type() != entry::int_t) return false; if (index == -1) return false;
m_message_index = int(index->integer()); m_message_index = index;
return true; return true;
} }

View file

@ -42,29 +42,46 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
namespace
{
const unsigned char dh_prime[96] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
0xA6, 0x3A, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x63
};
const unsigned char dh_generator[1] = { 2 };
}
// Set the prime P and the generator, generate local public key // Set the prime P and the generator, generate local public key
DH_key_exchange::DH_key_exchange() dh_key_exchange::dh_key_exchange()
{ {
m_DH = DH_new(); m_dh = DH_new();
if (m_DH == 0) throw std::bad_alloc(); if (m_dh == 0) return;
m_DH->p = BN_bin2bn(m_dh_prime, sizeof(m_dh_prime), NULL); m_dh->p = BN_bin2bn(dh_prime, sizeof(dh_prime), 0);
m_DH->g = BN_bin2bn(m_dh_generator, sizeof(m_dh_generator), NULL); m_dh->g = BN_bin2bn(dh_generator, sizeof(dh_generator), 0);
if (m_DH->p == 0 || m_DH->g == 0) if (m_dh->p == 0 || m_dh->g == 0)
{ {
DH_free(m_DH); DH_free(m_dh);
throw std::bad_alloc(); m_dh = 0;
return;
} }
m_DH->length = 160l; m_dh->length = 160l;
TORRENT_ASSERT(sizeof(m_dh_prime) == DH_size(m_DH)); TORRENT_ASSERT(sizeof(dh_prime) == DH_size(m_dh));
if (DH_generate_key(m_DH) == 0 || m_DH->pub_key == 0) if (DH_generate_key(m_dh) == 0 || m_dh->pub_key == 0)
{ {
DH_free(m_DH); DH_free(m_dh);
throw std::bad_alloc(); m_dh = 0;
return;
} }
// DH can generate key sizes that are smaller than the size of // DH can generate key sizes that are smaller than the size of
@ -72,42 +89,53 @@ namespace libtorrent
// the msb's of m_dh_local_key need to be zeroed // the msb's of m_dh_local_key need to be zeroed
// appropriately. // appropriately.
int key_size = get_local_key_size(); int key_size = get_local_key_size();
int len_dh = sizeof(m_dh_prime); // must equal DH_size(m_DH) int len_dh = sizeof(dh_prime); // must equal DH_size(m_DH)
if (key_size != len_dh) if (key_size != len_dh)
{ {
TORRENT_ASSERT(key_size > 0 && key_size < len_dh); TORRENT_ASSERT(key_size > 0 && key_size < len_dh);
int pad_zero_size = len_dh - key_size; int pad_zero_size = len_dh - key_size;
std::fill(m_dh_local_key, m_dh_local_key + pad_zero_size, 0); std::fill(m_dh_local_key, m_dh_local_key + pad_zero_size, 0);
BN_bn2bin(m_DH->pub_key, (unsigned char*)m_dh_local_key + pad_zero_size); if (BN_bn2bin(m_dh->pub_key, (unsigned char*)m_dh_local_key + pad_zero_size) == 0)
{
DH_free(m_dh);
m_dh = 0;
return;
}
} }
else else
BN_bn2bin(m_DH->pub_key, (unsigned char*)m_dh_local_key); // TODO Check return value {
if (BN_bn2bin(m_dh->pub_key, (unsigned char*)m_dh_local_key) == 0)
{
DH_free(m_dh);
m_dh = 0;
return;
}
}
} }
DH_key_exchange::~DH_key_exchange() dh_key_exchange::~dh_key_exchange()
{ {
TORRENT_ASSERT(m_DH); if (m_dh) DH_free(m_dh);
DH_free(m_DH);
} }
char const* DH_key_exchange::get_local_key() const char const* dh_key_exchange::get_local_key() const
{ {
return m_dh_local_key; return m_dh_local_key;
} }
// compute shared secret given remote public key // compute shared secret given remote public key
void DH_key_exchange::compute_secret(char const* remote_pubkey) int dh_key_exchange::compute_secret(char const* remote_pubkey)
{ {
TORRENT_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);
if (bn_remote_pubkey == 0) throw std::bad_alloc(); if (bn_remote_pubkey == 0) return -1;
char dh_secret[96]; char dh_secret[96];
int secret_size = DH_compute_key((unsigned char*)dh_secret int secret_size = DH_compute_key((unsigned char*)dh_secret
, bn_remote_pubkey, m_DH); , bn_remote_pubkey, m_dh);
if (secret_size < 0 || secret_size > 96) throw std::bad_alloc(); if (secret_size < 0 || secret_size > 96) return -1;
if (secret_size != 96) if (secret_size != 96)
{ {
@ -116,26 +144,14 @@ namespace libtorrent
} }
std::copy(dh_secret, dh_secret + secret_size, m_dh_secret + 96 - secret_size); std::copy(dh_secret, dh_secret + secret_size, m_dh_secret + 96 - secret_size);
BN_free(bn_remote_pubkey); BN_free(bn_remote_pubkey);
return 0;
} }
char const* DH_key_exchange::get_secret() const char const* dh_key_exchange::get_secret() const
{ {
return m_dh_secret; return m_dh_secret;
} }
const unsigned char DH_key_exchange::m_dh_prime[96] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
0xA6, 0x3A, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x63
};
const unsigned char DH_key_exchange::m_dh_generator[1] = { 2 };
} // namespace libtorrent } // namespace libtorrent
#endif // #ifndef TORRENT_DISABLE_ENCRYPTION #endif // #ifndef TORRENT_DISABLE_ENCRYPTION

View file

@ -81,6 +81,7 @@ namespace libtorrent
, m_last_unchoke(min_time()) , m_last_unchoke(min_time())
, m_last_receive(time_now()) , m_last_receive(time_now())
, m_last_sent(time_now()) , m_last_sent(time_now())
, m_requested(min_time())
, m_remote_dl_update(time_now()) , m_remote_dl_update(time_now())
, m_became_uninterested(time_now()) , m_became_uninterested(time_now())
, m_became_uninteresting(time_now()) , m_became_uninteresting(time_now())
@ -126,6 +127,7 @@ namespace libtorrent
, m_queued(true) , m_queued(true)
, m_request_large_blocks(false) , m_request_large_blocks(false)
, m_upload_only(false) , m_upload_only(false)
, m_snubbed(false)
#ifndef NDEBUG #ifndef NDEBUG
, m_in_constructor(true) , m_in_constructor(true)
#endif #endif
@ -166,7 +168,7 @@ namespace libtorrent
// incoming connection // incoming connection
peer_connection::peer_connection( peer_connection::peer_connection(
session_impl& ses session_impl& ses
, boost::shared_ptr<socket_type> s , shared_ptr<socket_type> s
, tcp::endpoint const& endp , tcp::endpoint const& endp
, policy::peer* peerinfo) , policy::peer* peerinfo)
: :
@ -182,6 +184,7 @@ namespace libtorrent
, m_last_unchoke(min_time()) , m_last_unchoke(min_time())
, m_last_receive(time_now()) , m_last_receive(time_now())
, m_last_sent(time_now()) , m_last_sent(time_now())
, m_requested(min_time())
, m_remote_dl_update(time_now()) , m_remote_dl_update(time_now())
, m_became_uninterested(time_now()) , m_became_uninterested(time_now())
, m_became_uninteresting(time_now()) , m_became_uninteresting(time_now())
@ -226,6 +229,7 @@ namespace libtorrent
, m_queued(false) , m_queued(false)
, m_request_large_blocks(false) , m_request_large_blocks(false)
, m_upload_only(false) , m_upload_only(false)
, m_snubbed(false)
#ifndef NDEBUG #ifndef NDEBUG
, m_in_constructor(true) , m_in_constructor(true)
#endif #endif
@ -1562,12 +1566,19 @@ namespace libtorrent
TORRENT_ASSERT(*b == block_finished); TORRENT_ASSERT(*b == block_finished);
} }
if (total_seconds(time_now() - m_requested) < m_ses.settings().request_timeout)
m_snubbed = false;
// if the block we got is already finished, then ignore it // if the block we got is already finished, then ignore it
if (picker.is_downloaded(block_finished)) if (picker.is_downloaded(block_finished))
{ {
t->received_redundant_data(p.length); t->received_redundant_data(p.length);
m_download_queue.erase(b); m_download_queue.erase(b);
if (!m_download_queue.empty())
m_requested = time_now();
request_a_block(*t, *this); request_a_block(*t, *this);
send_block_requests(); send_block_requests();
return; return;
@ -1579,6 +1590,9 @@ namespace libtorrent
TORRENT_ASSERT(m_channel_state[download_channel] == peer_info::bw_idle); TORRENT_ASSERT(m_channel_state[download_channel] == peer_info::bw_idle);
m_download_queue.erase(b); m_download_queue.erase(b);
if (!m_download_queue.empty())
m_requested = time_now();
// did we request this block from any other peers? // did we request this block from any other peers?
bool multi = picker.num_peers(block_finished) > 1; bool multi = picker.num_peers(block_finished) > 1;
picker.mark_as_writing(block_finished, peer_info_struct()); picker.mark_as_writing(block_finished, peer_info_struct());
@ -2073,6 +2087,8 @@ namespace libtorrent
if ((int)m_download_queue.size() >= m_desired_queue_size) return; if ((int)m_download_queue.size() >= m_desired_queue_size) return;
bool empty_download_queue = m_download_queue.empty();
while (!m_request_queue.empty() while (!m_request_queue.empty()
&& (int)m_download_queue.size() < m_desired_queue_size) && (int)m_download_queue.size() < m_desired_queue_size)
{ {
@ -2166,6 +2182,13 @@ namespace libtorrent
#endif #endif
} }
m_last_piece = time_now(); m_last_piece = time_now();
if (!m_download_queue.empty()
&& empty_download_queue)
{
// This means we just added a request to this connection
m_requested = time_now();
}
} }
void peer_connection::timed_out() void peer_connection::timed_out()
@ -2321,6 +2344,8 @@ namespace libtorrent
{ {
TORRENT_ASSERT(!associated_torrent().expired()); TORRENT_ASSERT(!associated_torrent().expired());
ptime now = time_now();
p.download_rate_peak = m_download_rate_peak; p.download_rate_peak = m_download_rate_peak;
p.upload_rate_peak = m_upload_rate_peak; p.upload_rate_peak = m_upload_rate_peak;
p.rtt = m_rtt; p.rtt = m_rtt;
@ -2333,6 +2358,8 @@ namespace libtorrent
p.pending_disk_bytes = m_outstanding_writing_bytes; p.pending_disk_bytes = m_outstanding_writing_bytes;
p.send_quota = m_bandwidth_limit[upload_channel].quota_left(); p.send_quota = m_bandwidth_limit[upload_channel].quota_left();
p.receive_quota = m_bandwidth_limit[download_channel].quota_left(); p.receive_quota = m_bandwidth_limit[download_channel].quota_left();
if (m_download_queue.empty()) p.request_timeout = -1;
else p.request_timeout = total_seconds(m_requested - now) + m_ses.settings().request_timeout;
#ifndef TORRENT_DISABLE_GEO_IP #ifndef TORRENT_DISABLE_GEO_IP
p.inet_as_name = m_inet_as_name; p.inet_as_name = m_inet_as_name;
#endif #endif
@ -2377,7 +2404,6 @@ namespace libtorrent
} }
p.pieces = get_bitfield(); p.pieces = get_bitfield();
ptime now = time_now();
p.last_request = now - m_last_request; p.last_request = now - m_last_request;
p.last_active = now - (std::max)(m_last_sent, m_last_receive); p.last_active = now - (std::max)(m_last_sent, m_last_receive);
@ -2386,6 +2412,7 @@ namespace libtorrent
get_specific_peer_info(p); get_specific_peer_info(p);
p.flags |= is_seed() ? peer_info::seed : 0; p.flags |= is_seed() ? peer_info::seed : 0;
p.flags |= m_snubbed ? peer_info::snubbed : 0;
if (peer_info_struct()) if (peer_info_struct())
{ {
policy::peer* pi = peer_info_struct(); policy::peer* pi = peer_info_struct();
@ -2483,11 +2510,13 @@ namespace libtorrent
void peer_connection::second_tick(float tick_interval) void peer_connection::second_tick(float tick_interval)
{ {
INVARIANT_CHECK;
ptime now(time_now()); ptime now(time_now());
boost::intrusive_ptr<peer_connection> me(self()); boost::intrusive_ptr<peer_connection> me(self());
// the invariant check must be run before me is destructed
// in case the peer got disconnected
INVARIANT_CHECK;
boost::shared_ptr<torrent> t = m_torrent.lock(); boost::shared_ptr<torrent> t = m_torrent.lock();
if (!t || m_disconnecting) if (!t || m_disconnecting)
{ {
@ -2505,8 +2534,103 @@ namespace libtorrent
{ {
(*i)->tick(); (*i)->tick();
} }
if (is_disconnecting()) return;
#endif #endif
// if the peer hasn't said a thing for a certain
// time, it is considered to have timed out
time_duration d;
d = now - m_last_receive;
if (d > seconds(m_timeout) && !m_connecting)
{
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
(*m_logger) << time_now_string() << " *** LAST ACTIVITY [ "
<< total_seconds(d) << " seconds ago ] ***\n";
#endif
disconnect("timed out: inactivity");
return;
}
// do not stall waiting for a handshake
if (!m_connecting
&& in_handshake()
&& d > seconds(m_ses.settings().handshake_timeout))
{
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
(*m_logger) << time_now_string() << " *** NO HANDSHAKE [ waited "
<< total_seconds(d) << " seconds ] ***\n";
#endif
disconnect("timed out: no handshake");
return;
}
// disconnect peers that we unchoked, but
// they didn't send a request within 20 seconds.
// but only if we're a seed
d = now - (std::max)(m_last_unchoke, m_last_incoming_request);
if (!m_connecting
&& m_requests.empty()
&& !m_choked
&& m_peer_interested
&& t && t->is_finished()
&& d > seconds(20))
{
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
(*m_logger) << time_now_string() << " *** NO REQUEST [ t: "
<< total_seconds(d) << " ] ***\n";
#endif
disconnect("timed out: no request when unchoked");
return;
}
// if the peer hasn't become interested and we haven't
// become interested in the peer for 10 minutes, it
// has also timed out.
time_duration d1;
time_duration d2;
d1 = now - m_became_uninterested;
d2 = now - m_became_uninteresting;
time_duration time_limit = seconds(
m_ses.settings().inactivity_timeout);
// don't bother disconnect peers we haven't been interested
// in (and that hasn't been interested in us) for a while
// unless we have used up all our connection slots
if (!m_interesting
&& !m_peer_interested
&& d1 > time_limit
&& d2 > time_limit
&& (m_ses.num_connections() >= m_ses.max_connections()
|| (t && t->num_peers() >= t->max_connections())))
{
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
(*m_logger) << time_now_string() << " *** MUTUAL NO INTEREST [ "
"t1: " << total_seconds(d1) << " | "
"t2: " << total_seconds(d2) << " ] ***\n";
#endif
disconnect("timed out: no interest");
return;
}
if (!m_download_queue.empty()
&& now > m_requested + seconds(m_ses.settings().request_timeout)
&& t->has_picker())
{
m_snubbed = true;
m_desired_queue_size = 1;
piece_picker& picker = t->picker();
// the front request timed out!
picker.abort_download(m_download_queue[0]);
m_download_queue.pop_front();
if (!m_download_queue.empty())
m_requested = time_now();
request_a_block(*t, *this);
send_block_requests();
}
// if we haven't sent something in too long, send a keep-alive
keep_alive();
m_ignore_bandwidth_limits = m_ses.settings().ignore_limits_on_local_network m_ignore_bandwidth_limits = m_ses.settings().ignore_limits_on_local_network
&& on_local_network(); && on_local_network();
@ -2544,12 +2668,19 @@ namespace libtorrent
? t->torrent_file().piece_length() : t->block_size(); ? t->torrent_file().piece_length() : t->block_size();
TORRENT_ASSERT(block_size > 0); TORRENT_ASSERT(block_size > 0);
m_desired_queue_size = static_cast<int>(queue_time if (m_snubbed)
* statistics().download_rate() / block_size); {
if (m_desired_queue_size > m_max_out_request_queue) m_desired_queue_size = 1;
m_desired_queue_size = m_max_out_request_queue; }
if (m_desired_queue_size < min_request_queue) else
m_desired_queue_size = min_request_queue; {
m_desired_queue_size = static_cast<int>(queue_time
* statistics().download_rate() / block_size);
if (m_desired_queue_size > m_max_out_request_queue)
m_desired_queue_size = m_max_out_request_queue;
if (m_desired_queue_size < min_request_queue)
m_desired_queue_size = min_request_queue;
}
if (!m_download_queue.empty() if (!m_download_queue.empty()
&& now - m_last_piece > seconds(m_ses.settings().piece_timeout)) && now - m_last_piece > seconds(m_ses.settings().piece_timeout))
@ -2564,6 +2695,9 @@ namespace libtorrent
<< " " << total_seconds(now - m_last_piece) << "] ***\n"; << " " << total_seconds(now - m_last_piece) << "] ***\n";
#endif #endif
m_snubbed = true;
m_desired_queue_size = 1;
if (t->is_seed()) if (t->is_seed())
{ {
m_download_queue.clear(); m_download_queue.clear();
@ -3521,94 +3655,6 @@ namespace libtorrent
} }
#endif #endif
bool peer_connection::has_timed_out() const
{
// TODO: the timeout should be called by an event
INVARIANT_CHECK;
ptime now(time_now());
// if the socket is still connecting, don't
// consider it timed out. Because Windows XP SP2
// may delay connection attempts.
if (m_connecting) return false;
// if the peer hasn't said a thing for a certain
// time, it is considered to have timed out
time_duration d;
d = now - m_last_receive;
if (d > seconds(m_timeout))
{
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
(*m_logger) << time_now_string() << " *** LAST ACTIVITY [ "
<< total_seconds(d) << " seconds ago ] ***\n";
#endif
return true;
}
// do not stall waiting for a handshake
if (in_handshake() && d > seconds(m_ses.settings().handshake_timeout))
{
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
(*m_logger) << time_now_string() << " *** NO HANDSHAKE [ waited "
<< total_seconds(d) << " seconds ] ***\n";
#endif
return true;
}
// disconnect peers that we unchoked, but
// they didn't send a request within 20 seconds.
// but only if we're a seed
boost::shared_ptr<torrent> t = m_torrent.lock();
d = now - (std::max)(m_last_unchoke, m_last_incoming_request);
if (m_requests.empty()
&& !m_choked
&& m_peer_interested
&& t && t->is_finished()
&& d > seconds(20))
{
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
(*m_logger) << time_now_string() << " *** NO REQUEST [ t: "
<< total_seconds(d) << " ] ***\n";
#endif
return true;
}
// TODO: as long as we have less than 95% of the
// global (or local) connection limit, connections should
// never time out for another reason
// if the peer hasn't become interested and we haven't
// become interested in the peer for 10 minutes, it
// has also timed out.
time_duration d1;
time_duration d2;
d1 = now - m_became_uninterested;
d2 = now - m_became_uninteresting;
time_duration time_limit = seconds(
m_ses.settings().inactivity_timeout);
// don't bother disconnect peers we haven't been interested
// in (and that hasn't been interested in us) for a while
// unless we have used up all our connection slots
if (!m_interesting
&& !m_peer_interested
&& d1 > time_limit
&& d2 > time_limit
&& (m_ses.num_connections() >= m_ses.max_connections()
|| (t && t->num_peers() >= t->max_connections())))
{
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
(*m_logger) << time_now_string() << " *** MUTUAL NO INTEREST [ "
"t1: " << total_seconds(d1) << " | "
"t2: " << total_seconds(d2) << " ] ***\n";
#endif
return true;
}
return false;
}
peer_connection::peer_speed_t peer_connection::peer_speed() peer_connection::peer_speed_t peer_connection::peer_speed()
{ {
shared_ptr<torrent> t = m_torrent.lock(); shared_ptr<torrent> t = m_torrent.lock();

View file

@ -257,7 +257,12 @@ namespace libtorrent
add_torrent_params p(sc); add_torrent_params p(sc);
p.ti = tip; p.ti = tip;
p.save_path = save_path; p.save_path = save_path;
p.resume_data = &resume_data; std::vector<char> buf;
if (resume_data.type() != entry::undefined_t)
{
bencode(std::back_inserter(buf), resume_data);
p.resume_data = &buf;
}
p.storage_mode = storage_mode; p.storage_mode = storage_mode;
p.paused = paused; p.paused = paused;
return m_impl->add_torrent(p); return m_impl->add_torrent(p);
@ -275,7 +280,12 @@ namespace libtorrent
add_torrent_params p(sc); add_torrent_params p(sc);
p.ti = ti; p.ti = ti;
p.save_path = save_path; p.save_path = save_path;
p.resume_data = &resume_data; std::vector<char> buf;
if (resume_data.type() != entry::undefined_t)
{
bencode(std::back_inserter(buf), resume_data);
p.resume_data = &buf;
}
p.storage_mode = storage_mode; p.storage_mode = storage_mode;
p.paused = paused; p.paused = paused;
p.userdata = userdata; p.userdata = userdata;
@ -324,6 +334,10 @@ namespace libtorrent
return m_impl->status(); return m_impl->status();
} }
void session::pause() { m_impl->pause(); }
void session::resume() { m_impl->resume(); }
bool session::is_paused() const { return m_impl->is_paused(); }
void session::get_cache_info(sha1_hash const& ih void session::get_cache_info(sha1_hash const& ih
, std::vector<cached_piece_info>& ret) const , std::vector<cached_piece_info>& ret) const
{ {

View file

@ -158,6 +158,7 @@ namespace aux {
, m_listen_port_retries(listen_port_range.second - listen_port_range.first) , m_listen_port_retries(listen_port_range.second - listen_port_range.first)
, m_listen_interface(address::from_string(listen_interface), listen_port_range.first) , m_listen_interface(address::from_string(listen_interface), listen_port_range.first)
, m_abort(false) , m_abort(false)
, m_paused(false)
, m_max_uploads(8) , m_max_uploads(8)
, m_allowed_upload_slots(8) , m_allowed_upload_slots(8)
, m_max_connections(200) , m_max_connections(200)
@ -389,6 +390,32 @@ namespace aux {
} }
#endif #endif
void session_impl::pause()
{
mutex_t::scoped_lock l(m_mutex);
if (m_paused) return;
m_paused = true;
for (torrent_map::iterator i = m_torrents.begin()
, end(m_torrents.end()); i != end; ++i)
{
torrent& t = *i->second;
if (!t.is_torrent_paused()) t.do_pause();
}
}
void session_impl::resume()
{
mutex_t::scoped_lock l(m_mutex);
if (!m_paused) return;
m_paused = false;
for (torrent_map::iterator i = m_torrents.begin()
, end(m_torrents.end()); i != end; ++i)
{
torrent& t = *i->second;
t.do_resume();
}
}
void session_impl::abort() void session_impl::abort()
{ {
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
@ -1207,32 +1234,6 @@ namespace aux {
} }
} }
// do the second_tick() on each connection
// this will update their statistics (download and upload speeds)
// also purge sockets that have timed out
// and keep sockets open by keeping them alive.
for (connection_map::iterator i = m_connections.begin();
i != m_connections.end();)
{
// we need to do like this because j->second->disconnect() will
// erase the connection from the map we're iterating
connection_map::iterator j = i;
++i;
// if this socket has timed out
// close it.
peer_connection& c = *j->get();
if (c.has_timed_out())
{
#if defined(TORRENT_VERBOSE_LOGGING)
(*c.m_logger) << "*** CONNECTION TIMED OUT\n";
#endif
c.disconnect("timed out: inactive", 1);
continue;
}
c.keep_alive();
}
// -------------------------------------------------------------- // --------------------------------------------------------------
// auto managed torrent // auto managed torrent
// -------------------------------------------------------------- // --------------------------------------------------------------
@ -1389,7 +1390,6 @@ namespace aux {
&& t->state() != torrent_status::checking_files) && t->state() != torrent_status::checking_files)
{ {
--num_downloaders; --num_downloaders;
--num_seeds;
if (t->is_paused()) t->resume(); if (t->is_paused()) t->resume();
} }
} }
@ -1412,7 +1412,6 @@ namespace aux {
if (num_seeds > 0 && hard_limit > 0) if (num_seeds > 0 && hard_limit > 0)
{ {
--hard_limit; --hard_limit;
--num_downloaders;
--num_seeds; --num_seeds;
if (t->is_paused()) t->resume(); if (t->is_paused()) t->resume();
} }

View file

@ -422,7 +422,7 @@ namespace libtorrent
bool move_slot(int src_slot, int dst_slot); bool move_slot(int src_slot, int dst_slot);
bool swap_slots(int slot1, int slot2); bool swap_slots(int slot1, int slot2);
bool swap_slots3(int slot1, int slot2, int slot3); bool swap_slots3(int slot1, int slot2, int slot3);
bool verify_resume_data(entry const& rd, std::string& error); bool verify_resume_data(lazy_entry const& rd, std::string& error);
bool write_resume_data(entry& rd) const; bool write_resume_data(entry& rd) const;
sha1_hash hash_for_slot(int slot, partial_hash& ph, int piece_size); sha1_hash hash_for_slot(int slot, partial_hash& ph, int piece_size);
@ -685,34 +685,32 @@ namespace libtorrent
return false; return false;
} }
bool storage::verify_resume_data(entry const& rd, std::string& error) bool storage::verify_resume_data(lazy_entry const& rd, std::string& error)
{ {
if (rd.type() != entry::dictionary_t) if (rd.type() != lazy_entry::dict_t)
{ {
error = "invalid fastresume file (not a dictionary)"; error = "invalid fastresume file (not a dictionary)";
return true; return true;
} }
std::vector<std::pair<size_type, std::time_t> > file_sizes; std::vector<std::pair<size_type, std::time_t> > file_sizes;
entry const* file_sizes_ent = rd.find_key("file sizes"); lazy_entry const* file_sizes_ent = rd.dict_find_list("file sizes");
if (file_sizes_ent == 0 || file_sizes_ent->type() != entry::list_t) if (file_sizes_ent == 0)
{ {
error = "missing or invalid 'file sizes' entry in resume data"; error = "missing or invalid 'file sizes' entry in resume data";
return false; return false;
} }
entry::list_type const& l = file_sizes_ent->list(); for (int i = 0; i < file_sizes_ent->list_size(); ++i)
for (entry::list_type::const_iterator i = l.begin();
i != l.end(); ++i)
{ {
if (i->type() != entry::list_t) break; lazy_entry const* e = file_sizes_ent->list_at(i);
entry::list_type const& pair = i->list(); if (e->type() != lazy_entry::list_t
if (pair.size() != 2 || pair.front().type() != entry::int_t || e->list_size() != 2
|| pair.back().type() != entry::int_t) || e->list_at(0)->type() != lazy_entry::int_t
break; || e->list_at(1)->type() != lazy_entry::int_t)
continue;
file_sizes.push_back(std::pair<size_type, std::time_t>( file_sizes.push_back(std::pair<size_type, std::time_t>(
pair.front().integer(), std::time_t(pair.back().integer()))); e->list_int_value_at(0), std::time_t(e->list_int_value_at(1))));
} }
if (file_sizes.empty()) if (file_sizes.empty())
@ -721,32 +719,38 @@ namespace libtorrent
return false; return false;
} }
entry const* slots_ent = rd.find_key("slots"); lazy_entry const* slots = rd.dict_find_list("slots");
if (slots_ent == 0 || slots_ent->type() != entry::list_t) if (slots == 0)
{ {
error = "missing or invalid 'slots' entry in resume data"; error = "missing or invalid 'slots' entry in resume data";
return false; return false;
} }
entry::list_type const& slots = slots_ent->list(); bool seed = false;
bool seed = int(slots.size()) == m_files.num_pieces()
&& std::find_if(slots.begin(), slots.end() if (int(slots->list_size()) == m_files.num_pieces())
, boost::bind<bool>(std::less<int>() {
, boost::bind((size_type const& (entry::*)() const) bool seed = true;
&entry::integer, _1), 0)) == slots.end(); for (int i = 0; i < slots->list_size(); ++i)
{
lazy_entry const* e = slots->list_at(i);
if (e->list_int_value_at(i, -1) >= 0) continue;
seed = false;
break;
}
}
bool full_allocation_mode = false; bool full_allocation_mode = false;
entry const* allocation_mode = rd.find_key("allocation"); if (rd.dict_find_string_value("allocation") == "full")
if (allocation_mode && allocation_mode->type() == entry::string_t) full_allocation_mode = true;
full_allocation_mode = allocation_mode->string() == "full";
if (seed) if (seed)
{ {
if (m_files.num_files() != (int)file_sizes.size()) if (files().num_files() != (int)file_sizes.size())
{ {
error = "the number of files does not match the torrent (num: " error = "the number of files does not match the torrent (num: "
+ boost::lexical_cast<std::string>(file_sizes.size()) + " actual: " + boost::lexical_cast<std::string>(file_sizes.size()) + " actual: "
+ boost::lexical_cast<std::string>(m_files.num_files()) + ")"; + boost::lexical_cast<std::string>(files().num_files()) + ")";
return false; return false;
} }
@ -1300,7 +1304,7 @@ namespace libtorrent
m_io_thread.add_job(j, handler); m_io_thread.add_job(j, handler);
} }
void piece_manager::async_check_fastresume(entry const* resume_data void piece_manager::async_check_fastresume(lazy_entry const* resume_data
, boost::function<void(int, disk_io_job const&)> const& handler) , boost::function<void(int, disk_io_job const&)> const& handler)
{ {
TORRENT_ASSERT(resume_data != 0); TORRENT_ASSERT(resume_data != 0);
@ -1783,7 +1787,7 @@ namespace libtorrent
// isn't return false and the full check // isn't return false and the full check
// will be run // will be run
int piece_manager::check_fastresume( int piece_manager::check_fastresume(
entry const& rd, std::string& error) lazy_entry const& rd, std::string& error)
{ {
boost::recursive_mutex::scoped_lock lock(m_mutex); boost::recursive_mutex::scoped_lock lock(m_mutex);
@ -1792,29 +1796,25 @@ namespace libtorrent
TORRENT_ASSERT(m_files.piece_length() > 0); TORRENT_ASSERT(m_files.piece_length() > 0);
// if we don't have any resume data, return // if we don't have any resume data, return
if (rd.type() == entry::undefined_t) return check_no_fastresume(error); if (rd.type() == lazy_entry::none_t) return check_no_fastresume(error);
if (rd.type() != entry::dictionary_t) if (rd.type() != lazy_entry::dict_t)
{ {
error = "invalid fastresume data (not a bencoded dictionary)"; error = "invalid fastresume data (not a dictionary)";
return check_no_fastresume(error); return check_no_fastresume(error);
} }
int block_size = (std::min)(16 * 1024, m_files.piece_length()); int block_size = (std::min)(16 * 1024, m_files.piece_length());
entry const* blocks_per_piece_ent = rd.find_key("blocks per piece"); int blocks_per_piece = rd.dict_find_int_value("blocks per piece", -1);
if (blocks_per_piece_ent != 0 if (blocks_per_piece != -1
&& blocks_per_piece_ent->type() == entry::int_t && blocks_per_piece != m_files.piece_length() / block_size)
&& blocks_per_piece_ent->integer() != m_files.piece_length() / block_size)
{ {
error = "invalid 'blocks per piece' entry"; error = "invalid 'blocks per piece' entry";
return check_no_fastresume(error); return check_no_fastresume(error);
} }
storage_mode_t storage_mode = storage_mode_compact; storage_mode_t storage_mode = storage_mode_compact;
entry const* allocation = rd.find_key("allocation"); if (rd.dict_find_string_value("allocation") != "compact")
if (allocation != 0
&& allocation->type() == entry::string_t
&& allocation->string() != "compact")
storage_mode = storage_mode_sparse; storage_mode = storage_mode_sparse;
// assume no piece is out of place (i.e. in a slot // assume no piece is out of place (i.e. in a slot
@ -1823,20 +1823,20 @@ namespace libtorrent
// if we don't have a piece map, we need the slots // if we don't have a piece map, we need the slots
// if we're in compact mode, we also need the slots map // if we're in compact mode, we also need the slots map
if (storage_mode == storage_mode_compact || rd.find_key("pieces") == 0) if (storage_mode == storage_mode_compact || rd.dict_find("pieces") == 0)
{ {
// read slots map // read slots map
entry const* slots = rd.find_key("slots"); lazy_entry const* slots = rd.dict_find_list("slots");
if (slots == 0 || slots->type() != entry::list_t) if (slots == 0)
{ {
error = "missing slot list"; error = "missing slot list";
return check_no_fastresume(error); return check_no_fastresume(error);
} }
if ((int)slots->list().size() > m_files.num_pieces()) if ((int)slots->list_size() > m_files.num_pieces())
{ {
error = "file has more slots than torrent (slots: " error = "file has more slots than torrent (slots: "
+ boost::lexical_cast<std::string>(slots->list().size()) + " size: " + boost::lexical_cast<std::string>(slots->list_size()) + " size: "
+ boost::lexical_cast<std::string>(m_files.num_pieces()) + " )"; + boost::lexical_cast<std::string>(m_files.num_pieces()) + " )";
return check_no_fastresume(error); return check_no_fastresume(error);
} }
@ -1846,17 +1846,16 @@ namespace libtorrent
int num_pieces = int(m_files.num_pieces()); int num_pieces = int(m_files.num_pieces());
m_slot_to_piece.resize(num_pieces, unallocated); m_slot_to_piece.resize(num_pieces, unallocated);
m_piece_to_slot.resize(num_pieces, has_no_slot); m_piece_to_slot.resize(num_pieces, has_no_slot);
int slot = 0; for (int i = 0; i < slots->list_size(); ++i)
for (entry::list_type::const_iterator i = slots->list().begin();
i != slots->list().end(); ++i, ++slot)
{ {
if (i->type() != entry::int_t) lazy_entry const* e = slots->list_at(i);
if (e->type() != lazy_entry::int_t)
{ {
error = "invalid entry type in slot list"; error = "invalid entry type in slot list";
return check_no_fastresume(error); return check_no_fastresume(error);
} }
int index = int(i->integer()); int index = int(e->int_value());
if (index >= num_pieces || index < -2) if (index >= num_pieces || index < -2)
{ {
error = "too high index number in slot map (index: " error = "too high index number in slot map (index: "
@ -1866,37 +1865,36 @@ namespace libtorrent
} }
if (index >= 0) if (index >= 0)
{ {
m_slot_to_piece[slot] = index; m_slot_to_piece[i] = index;
m_piece_to_slot[index] = slot; m_piece_to_slot[index] = i;
if (slot != index) out_of_place = true; if (i != index) out_of_place = true;
} }
else if (index == unassigned) else if (index == unassigned)
{ {
if (m_storage_mode == storage_mode_compact) if (m_storage_mode == storage_mode_compact)
m_free_slots.push_back(slot); m_free_slots.push_back(i);
} }
else else
{ {
TORRENT_ASSERT(index == unallocated); TORRENT_ASSERT(index == unallocated);
if (m_storage_mode == storage_mode_compact) if (m_storage_mode == storage_mode_compact)
m_unallocated_slots.push_back(slot); m_unallocated_slots.push_back(i);
} }
} }
} }
else else
{ {
int slot = 0; for (int i = 0; i < slots->list_size(); ++i)
for (entry::list_type::const_iterator i = slots->list().begin();
i != slots->list().end(); ++i, ++slot)
{ {
if (i->type() != entry::int_t) lazy_entry const* e = slots->list_at(i);
if (e->type() != lazy_entry::int_t)
{ {
error = "invalid entry type in slot list"; error = "invalid entry type in slot list";
return check_no_fastresume(error); return check_no_fastresume(error);
} }
int index = int(i->integer()); int index = int(e->int_value());
if (index != slot && index >= 0) if (index != i && index >= 0)
{ {
error = "invalid slot index"; error = "invalid slot index";
return check_no_fastresume(error); return check_no_fastresume(error);
@ -1937,17 +1935,17 @@ namespace libtorrent
else if (m_storage_mode == storage_mode_compact) else if (m_storage_mode == storage_mode_compact)
{ {
// read piece map // read piece map
entry const* pieces = rd.find_key("pieces"); lazy_entry const* pieces = rd.dict_find("pieces");
if (pieces == 0 || pieces->type() != entry::string_t) if (pieces == 0 || pieces->type() != lazy_entry::string_t)
{ {
error = "missing pieces entry"; error = "missing pieces entry";
return check_no_fastresume(error); return check_no_fastresume(error);
} }
if ((int)pieces->string().size() != m_files.num_pieces()) if ((int)pieces->string_length() != m_files.num_pieces())
{ {
error = "file has more slots than torrent (slots: " error = "file has more slots than torrent (slots: "
+ boost::lexical_cast<std::string>(pieces->string().size()) + " size: " + boost::lexical_cast<std::string>(pieces->string_length()) + " size: "
+ boost::lexical_cast<std::string>(m_files.num_pieces()) + " )"; + boost::lexical_cast<std::string>(m_files.num_pieces()) + " )";
return check_no_fastresume(error); return check_no_fastresume(error);
} }
@ -1955,7 +1953,7 @@ namespace libtorrent
int num_pieces = int(m_files.num_pieces()); int num_pieces = int(m_files.num_pieces());
m_slot_to_piece.resize(num_pieces, unallocated); m_slot_to_piece.resize(num_pieces, unallocated);
m_piece_to_slot.resize(num_pieces, has_no_slot); m_piece_to_slot.resize(num_pieces, has_no_slot);
std::string const& have_pieces = pieces->string(); char const* have_pieces = pieces->string_ptr();
for (int i = 0; i < num_pieces; ++i) for (int i = 0; i < num_pieces; ++i)
{ {
if (have_pieces[i] & 1) if (have_pieces[i] & 1)

View file

@ -144,7 +144,7 @@ namespace libtorrent
, int block_size , int block_size
, storage_constructor_type sc , storage_constructor_type sc
, bool paused , bool paused
, entry const* resume_data , std::vector<char>* resume_data
, int seq , int seq
, bool auto_managed) , bool auto_managed)
: m_policy(this) : m_policy(this)
@ -203,7 +203,7 @@ namespace libtorrent
, m_has_incoming(false) , m_has_incoming(false)
, m_files_checked(false) , m_files_checked(false)
{ {
if (resume_data) m_resume_data = *resume_data; parse_resume_data(resume_data);
} }
torrent::torrent( torrent::torrent(
@ -217,7 +217,7 @@ namespace libtorrent
, int block_size , int block_size
, storage_constructor_type sc , storage_constructor_type sc
, bool paused , bool paused
, entry const* resume_data , std::vector<char>* resume_data
, int seq , int seq
, bool auto_managed) , bool auto_managed)
: m_policy(this) : m_policy(this)
@ -274,7 +274,7 @@ namespace libtorrent
, m_connections_initialized(false) , m_connections_initialized(false)
, m_has_incoming(false) , m_has_incoming(false)
{ {
if (resume_data) m_resume_data = *resume_data; parse_resume_data(resume_data);
#ifndef NDEBUG #ifndef NDEBUG
m_files_checked = false; m_files_checked = false;
#endif #endif
@ -289,6 +289,25 @@ namespace libtorrent
} }
} }
void torrent::parse_resume_data(std::vector<char>* resume_data)
{
if (!resume_data) return;
m_resume_data.swap(*resume_data);
if (lazy_bdecode(&m_resume_data[0], &m_resume_data[0]
+ m_resume_data.size(), m_resume_entry) != 0)
{
std::vector<char>().swap(m_resume_data);
if (m_ses.m_alerts.should_post(alert::warning))
{
m_ses.m_alerts.post_alert(fastresume_rejected_alert(get_handle(), "parse failed"));
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
(*m_ses.m_logger) << "fastresume data for "
<< torrent_file().name() << " rejected: parse failed\n";
#endif
}
}
}
void torrent::start() void torrent::start()
{ {
boost::weak_ptr<torrent> self(shared_from_this()); boost::weak_ptr<torrent> self(shared_from_this());
@ -429,18 +448,17 @@ namespace libtorrent
m_state = torrent_status::queued_for_checking; m_state = torrent_status::queued_for_checking;
if (m_resume_data.type() == entry::dictionary_t) if (m_resume_entry.type() == lazy_entry::dict_t)
{ {
char const* error = 0; char const* error = 0;
entry const* file_format = m_resume_data.find_key("file-format"); if (m_resume_entry.dict_find_string_value("file-format") != "libtorrent resume file")
if (file_format->string() != "libtorrent resume file")
error = "invalid file format tag"; error = "invalid file format tag";
entry const* info_hash = m_resume_data.find_key("info-hash"); std::string info_hash = m_resume_entry.dict_find_string_value("info-hash");
if (!error && (info_hash == 0 || info_hash->type() != entry::string_t)) if (!error && info_hash.empty())
error = "missing info-hash"; error = "missing info-hash";
if (!error && sha1_hash(info_hash->string()) != m_torrent_file->info_hash()) if (!error && sha1_hash(info_hash) != m_torrent_file->info_hash())
error = "mismatching info-hash"; error = "mismatching info-hash";
if (error && m_ses.m_alerts.should_post(alert::warning)) if (error && m_ses.m_alerts.should_post(alert::warning))
@ -453,11 +471,18 @@ namespace libtorrent
#endif #endif
} }
if (error) m_resume_data = entry(); if (error)
else read_resume_data(m_resume_data); {
std::vector<char>().swap(m_resume_data);
m_resume_entry = lazy_entry();
}
else
{
read_resume_data(m_resume_entry);
}
} }
m_storage->async_check_fastresume(&m_resume_data m_storage->async_check_fastresume(&m_resume_entry
, bind(&torrent::on_resume_data_checked , bind(&torrent::on_resume_data_checked
, shared_from_this(), _1, _2)); , shared_from_this(), _1, _2));
} }
@ -483,54 +508,41 @@ namespace libtorrent
return; return;
} }
// parse out "peers" from the resume data and add them to the peer list if (m_resume_entry.type() == lazy_entry::dict_t)
entry const* peers_entry = m_resume_data.find_key("peers");
if (peers_entry && peers_entry->type() == entry::list_t)
{ {
peer_id id; // parse out "peers" from the resume data and add them to the peer list
std::fill(id.begin(), id.end(), 0); if (lazy_entry const* peers_entry = m_resume_entry.dict_find_list("peers"))
entry::list_type const& peer_list = peers_entry->list();
for (entry::list_type::const_iterator i = peer_list.begin();
i != peer_list.end(); ++i)
{ {
if (i->type() != entry::dictionary_t) continue; peer_id id(0);
entry const* ip = i->find_key("ip");
entry const* port = i->find_key("port"); for (int i = 0; i < peers_entry->list_size(); ++i)
if (ip == 0 || port == 0 {
|| ip->type() != entry::string_t lazy_entry const* e = peers_entry->list_at(i);
|| port->type() != entry::int_t) if (e->type() != lazy_entry::dict_t) continue;
continue; std::string ip = e->dict_find_string_value("ip");
tcp::endpoint a( int port = e->dict_find_int_value("port");
address::from_string(ip->string()) if (ip.empty() || port == 0) continue;
, (unsigned short)port->integer()); tcp::endpoint a(address::from_string(ip), (unsigned short)port);
m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0); m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0);
}
} }
}
// parse out "banned_peers" and add them as banned // parse out "banned_peers" and add them as banned
entry const* banned_peers_entry = m_resume_data.find_key("banned_peers"); if (lazy_entry const* banned_peers_entry = m_resume_entry.dict_find_list("banned_peers"))
if (banned_peers_entry != 0 && banned_peers_entry->type() == entry::list_t)
{
peer_id id;
std::fill(id.begin(), id.end(), 0);
entry::list_type const& peer_list = banned_peers_entry->list();
for (entry::list_type::const_iterator i = peer_list.begin();
i != peer_list.end(); ++i)
{ {
if (i->type() != entry::dictionary_t) continue; peer_id id(0);
entry const* ip = i->find_key("ip");
entry const* port = i->find_key("port"); for (int i = 0; i < banned_peers_entry->list_size(); ++i)
if (ip == 0 || port == 0 {
|| ip->type() != entry::string_t lazy_entry const* e = banned_peers_entry->list_at(i);
|| port->type() != entry::int_t) if (e->type() != lazy_entry::dict_t) continue;
continue; std::string ip = e->dict_find_string_value("ip");
tcp::endpoint a( int port = e->dict_find_int_value("port");
address::from_string(ip->string()) if (ip.empty() || port == 0) continue;
, (unsigned short)port->integer()); tcp::endpoint a(address::from_string(ip), (unsigned short)port);
policy::peer* p = m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0); policy::peer* p = m_policy.peer_from_tracker(a, id, peer_info::resume_data, 0);
if (p) p->banned = true; if (p) p->banned = true;
}
} }
} }
@ -551,17 +563,15 @@ namespace libtorrent
// there are either no files for this torrent // there are either no files for this torrent
// or the resume_data was accepted // or the resume_data was accepted
if (!fastresume_rejected) if (!fastresume_rejected && m_resume_entry.type() == lazy_entry::dict_t)
{ {
TORRENT_ASSERT(m_resume_data.type() == entry::dictionary_t);
// parse have bitmask // parse have bitmask
entry const* pieces = m_resume_data.find_key("pieces"); lazy_entry const* pieces = m_resume_entry.dict_find("pieces");
if (pieces && pieces->type() == entry::string_t if (pieces && pieces->type() == lazy_entry::string_t
&& int(pieces->string().length()) == m_torrent_file->num_pieces()) && int(pieces->string_length()) == m_torrent_file->num_pieces())
{ {
std::string const& pieces_str = pieces->string(); char const* pieces_str = pieces->string_ptr();
for (int i = 0, end(pieces_str.size()); i < end; ++i) for (int i = 0, end(pieces->string_length()); i < end; ++i)
{ {
if ((pieces_str[i] & 1) == 0) continue; if ((pieces_str[i] & 1) == 0) continue;
m_picker->we_have(i); m_picker->we_have(i);
@ -572,27 +582,20 @@ namespace libtorrent
int num_blocks_per_piece = int num_blocks_per_piece =
static_cast<int>(torrent_file().piece_length()) / block_size(); static_cast<int>(torrent_file().piece_length()) / block_size();
entry const* unfinished_ent = m_resume_data.find_key("unfinished"); if (lazy_entry const* unfinished_ent = m_resume_entry.dict_find_list("unfinished"))
if (unfinished_ent != 0 && unfinished_ent->type() == entry::list_t)
{ {
entry::list_type const& unfinished = unfinished_ent->list(); for (int i = 0; i < unfinished_ent->list_size(); ++i)
int index = 0;
for (entry::list_type::const_iterator i = unfinished.begin();
i != unfinished.end(); ++i, ++index)
{ {
if (i->type() != entry::dictionary_t) continue; lazy_entry const* e = unfinished_ent->list_at(i);
entry const* piece = i->find_key("piece"); if (e->type() != lazy_entry::dict_t) continue;
if (piece == 0 || piece->type() != entry::int_t) continue; int piece = e->dict_find_int_value("piece", -1);
int piece_index = int(piece->integer()); if (piece < 0 || piece > torrent_file().num_pieces()) continue;
if (piece_index < 0 || piece_index >= torrent_file().num_pieces())
continue;
if (m_picker->have_piece(piece_index)) if (m_picker->have_piece(piece))
m_picker->we_dont_have(piece_index); m_picker->we_dont_have(piece);
entry const* bitmask_ent = i->find_key("bitmask"); std::string bitmask = e->dict_find_string_value("bitmask");
if (bitmask_ent == 0 || bitmask_ent->type() != entry::string_t) break; if (bitmask.empty()) continue;
std::string const& bitmask = bitmask_ent->string();
const int num_bitmask_bytes = (std::max)(num_blocks_per_piece / 8, 1); const int num_bitmask_bytes = (std::max)(num_blocks_per_piece / 8, 1);
if ((int)bitmask.size() != num_bitmask_bytes) continue; if ((int)bitmask.size() != num_bitmask_bytes) continue;
@ -605,10 +608,10 @@ namespace libtorrent
const int bit = j * 8 + k; const int bit = j * 8 + k;
if (bits & (1 << k)) if (bits & (1 << k))
{ {
m_picker->mark_as_finished(piece_block(piece_index, bit), 0); m_picker->mark_as_finished(piece_block(piece, bit), 0);
if (m_picker->is_piece_finished(piece_index)) if (m_picker->is_piece_finished(piece))
async_verify_piece(piece_index, bind(&torrent::piece_finished async_verify_piece(piece, bind(&torrent::piece_finished
, shared_from_this(), piece_index, _1)); , shared_from_this(), piece, _1));
} }
} }
} }
@ -649,8 +652,9 @@ namespace libtorrent
if (m_auto_managed) if (m_auto_managed)
set_queue_position((std::numeric_limits<int>::max)()); set_queue_position((std::numeric_limits<int>::max)());
m_resume_data = entry(); std::vector<char>().swap(m_resume_data);
m_storage->async_check_fastresume(&m_resume_data m_resume_entry = lazy_entry();
m_storage->async_check_fastresume(&m_resume_entry
, bind(&torrent::on_force_recheck , bind(&torrent::on_force_recheck
, shared_from_this(), _1, _2)); , shared_from_this(), _1, _2));
} }
@ -761,8 +765,7 @@ namespace libtorrent
bind(&torrent::on_announce_disp, self, _1)); bind(&torrent::on_announce_disp, self, _1));
// announce with the local discovery service // announce with the local discovery service
if (!m_paused) if (!is_paused()) m_ses.announce_lsd(m_torrent_file->info_hash());
m_ses.announce_lsd(m_torrent_file->info_hash());
} }
else else
{ {
@ -772,7 +775,7 @@ namespace libtorrent
} }
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT
if (m_paused) return; if (is_paused()) return;
if (!m_ses.m_dht) return; if (!m_ses.m_dht) return;
ptime now = time_now(); ptime now = time_now();
if (should_announce_dht() && now - m_last_dht_announce > minutes(14)) if (should_announce_dht() && now - m_last_dht_announce > minutes(14))
@ -842,7 +845,7 @@ namespace libtorrent
m_just_paused = false; m_just_paused = false;
return true; return true;
} }
return !m_paused && m_next_request < time_now(); return !is_paused() && m_next_request < time_now();
} }
void torrent::tracker_warning(tracker_request const& req, std::string const& msg) void torrent::tracker_warning(tracker_request const& req, std::string const& msg)
@ -1501,7 +1504,7 @@ namespace libtorrent
m_abort = true; m_abort = true;
// if the torrent is paused, it doesn't need // if the torrent is paused, it doesn't need
// to announce with even=stopped again. // to announce with even=stopped again.
if (!m_paused) if (!is_paused())
m_event = tracker_request::stopped; m_event = tracker_request::stopped;
// disconnect all peers and close all // disconnect all peers and close all
// files belonging to the torrents // files belonging to the torrents
@ -2414,31 +2417,14 @@ namespace libtorrent
} }
#endif #endif
void torrent::read_resume_data(entry const& rd) void torrent::read_resume_data(lazy_entry const& rd)
{ {
entry const* e = 0; m_total_uploaded = rd.dict_find_int_value("total_uploaded");
e = rd.find_key("total_uploaded"); m_total_downloaded = rd.dict_find_int_value("total_downloaded");
m_total_uploaded = (e != 0 && e->type() == entry::int_t)?e->integer():0; m_active_time = seconds(rd.dict_find_int_value("active_time"));
e = rd.find_key("total_downloaded"); m_seeding_time = seconds(rd.dict_find_int_value("seeding_time"));
m_total_downloaded = (e != 0 && e->type() == entry::int_t)?e->integer():0; m_complete = rd.dict_find_int_value("num_seeds", -1);
m_incomplete = rd.dict_find_int_value("num_downloaders", -1);
e = rd.find_key("active_time");
m_active_time = seconds((e != 0 && e->type() == entry::int_t)?e->integer():0);
e = rd.find_key("seeding_time");
m_seeding_time = seconds((e != 0 && e->type() == entry::int_t)?e->integer():0);
e = rd.find_key("num_seeds");
m_complete = (e != 0 && e->type() == entry::int_t)?e->integer():-1;
e = rd.find_key("num_downloaders");
m_incomplete = (e != 0 && e->type() == entry::int_t)?e->integer():-1;
/*
m_total_uploaded = rd.find_int_value("total_uploaded");
m_total_downloaded = rd.find_inte_value("total_downloaded");
m_active_time = rd.find_int_value("active_time");
m_seeding_time = rd.find_int_value("seeding_time");
m_complete = rd.find_int_value("num_seeds", -1);
m_incomplete = rd.find_int_value("num_downloaders", -1);
*/
} }
void torrent::write_resume_data(entry& ret) const void torrent::write_resume_data(entry& ret) const
@ -2865,7 +2851,7 @@ namespace libtorrent
bool torrent::want_more_peers() const bool torrent::want_more_peers() const
{ {
return int(m_connections.size()) < m_max_connections return int(m_connections.size()) < m_max_connections
&& !m_paused && !is_paused()
&& m_state != torrent_status::checking_files && m_state != torrent_status::checking_files
&& (m_state != torrent_status::queued_for_checking && (m_state != torrent_status::queued_for_checking
|| !valid_metadata()) || !valid_metadata())
@ -3333,8 +3319,8 @@ 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_resume_data.type() == entry::dictionary_t TORRENT_ASSERT(m_resume_entry.type() == lazy_entry::dict_t
|| m_resume_data.type() == entry::undefined_t); || m_resume_entry.type() == lazy_entry::none_t);
TORRENT_ASSERT(m_bandwidth_queue[0].size() <= m_connections.size()); TORRENT_ASSERT(m_bandwidth_queue[0].size() <= m_connections.size());
TORRENT_ASSERT(m_bandwidth_queue[1].size() <= m_connections.size()); TORRENT_ASSERT(m_bandwidth_queue[1].size() <= m_connections.size());
@ -3596,7 +3582,7 @@ namespace libtorrent
#endif #endif
disconnect_all(); disconnect_all();
if (!m_paused) if (!is_paused())
m_just_paused = true; m_just_paused = true;
m_paused = true; m_paused = true;
// tell the tracker that we stopped // tell the tracker that we stopped
@ -3711,11 +3697,24 @@ namespace libtorrent
} }
} }
bool torrent::is_paused() const
{
return m_paused || m_ses.is_paused();
}
void torrent::pause() void torrent::pause()
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_paused) return; if (m_paused) return;
m_paused = true;
if (m_ses.is_paused()) return;
do_pause();
}
void torrent::do_pause()
{
if (!is_paused()) return;
#ifndef TORRENT_DISABLE_EXTENSIONS #ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin() for (extension_list_t::iterator i = m_extensions.begin()
@ -3740,7 +3739,6 @@ namespace libtorrent
#endif #endif
disconnect_all(); disconnect_all();
m_paused = true;
// tell the tracker that we stopped // tell the tracker that we stopped
m_event = tracker_request::stopped; m_event = tracker_request::stopped;
m_just_paused = true; m_just_paused = true;
@ -3766,6 +3764,13 @@ namespace libtorrent
INVARIANT_CHECK; INVARIANT_CHECK;
if (!m_paused) return; if (!m_paused) return;
m_paused = false;
do_resume();
}
void torrent::do_resume()
{
if (is_paused()) return;
#ifndef TORRENT_DISABLE_EXTENSIONS #ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin() for (extension_list_t::iterator i = m_extensions.begin()
@ -3781,7 +3786,6 @@ namespace libtorrent
} }
#endif #endif
m_paused = false;
m_started = time_now(); m_started = time_now();
m_error.clear(); m_error.clear();

View file

@ -47,7 +47,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/next_prior.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#ifdef _MSC_VER #ifdef _MSC_VER
@ -58,6 +57,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/bencode.hpp" #include "libtorrent/bencode.hpp"
#include "libtorrent/hasher.hpp" #include "libtorrent/hasher.hpp"
#include "libtorrent/entry.hpp" #include "libtorrent/entry.hpp"
#include "libtorrent/file.hpp"
namespace gr = boost::gregorian; namespace gr = boost::gregorian;
@ -207,6 +207,21 @@ namespace
namespace libtorrent namespace libtorrent
{ {
int load_file(fs::path const& filename, std::vector<char>& v)
{
file f;
if (!f.open(filename, file::in)) return -1;
f.seek(0, file::end);
size_type s = f.tell();
if (s > 5000000) return -2;
v.resize(s);
f.seek(0);
size_type read = f.read(&v[0], s);
if (read != s) return -3;
return 0;
}
// standard constructor that parses a torrent file // standard constructor that parses a torrent file
torrent_info::torrent_info(entry const& torrent_file) torrent_info::torrent_info(entry const& torrent_file)
: m_creation_date(pt::ptime(pt::not_a_date_time)) : m_creation_date(pt::ptime(pt::not_a_date_time))
@ -226,7 +241,7 @@ namespace libtorrent
if (!parse_torrent_file(e, error)) if (!parse_torrent_file(e, error))
throw invalid_torrent_file(); throw invalid_torrent_file();
#else #else
read_torrent_info(e, error); parse_torrent_file(e, error);
#endif #endif
} }
@ -242,7 +257,7 @@ namespace libtorrent
if (!parse_torrent_file(torrent_file, error)) if (!parse_torrent_file(torrent_file, error))
throw invalid_torrent_file(); throw invalid_torrent_file();
#else #else
read_torrent_info(torrent_file, error); parse_torrent_file(torrent_file, error);
#endif #endif
} }
@ -260,7 +275,7 @@ namespace libtorrent
if (!parse_torrent_file(e, error)) if (!parse_torrent_file(e, error))
throw invalid_torrent_file(); throw invalid_torrent_file();
#else #else
read_torrent_info(e, error); parse_torrent_file(e, error);
#endif #endif
} }
@ -277,26 +292,23 @@ namespace libtorrent
, m_piece_hashes(0) , m_piece_hashes(0)
{} {}
torrent_info::torrent_info(char const* filename) torrent_info::torrent_info(fs::path const& filename)
: m_creation_date(pt::ptime(pt::not_a_date_time)) : m_creation_date(pt::ptime(pt::not_a_date_time))
, m_multifile(false) , m_multifile(false)
, m_private(false) , m_private(false)
{ {
size_type s = fs::file_size(fs::path(filename)); std::vector<char> buf;
// don't load torrent files larger than 2 MB int ret = load_file(filename, buf);
if (s > 2000000) return; if (ret < 0) return;
std::vector<char> buf(s);
std::ifstream f(filename);
f.read(&buf[0], s);
std::string error;
lazy_entry e; lazy_entry e;
lazy_bdecode(&buf[0], &buf[0] + buf.size(), e); lazy_bdecode(&buf[0], &buf[0] + buf.size(), e);
std::string error;
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
if (!parse_torrent_file(e, error)) if (!parse_torrent_file(e, error))
throw invalid_torrent_file(); throw invalid_torrent_file();
#else #else
read_torrent_info(e, error); parse_torrent_file(e, error);
#endif #endif
} }

View file

@ -82,7 +82,7 @@ upnp::upnp(io_service& ios, connection_queue& cc
if (state) if (state)
{ {
upnp_state_t* s = (upnp_state_t*)s; upnp_state_t* s = (upnp_state_t*)state;
m_devices.swap(s->devices); m_devices.swap(s->devices);
m_mappings.swap(s->mappings); m_mappings.swap(s->mappings);
delete s; delete s;

View file

@ -235,18 +235,20 @@ namespace libtorrent { namespace
} }
// called when the extension handshake from the other end is received // called when the extension handshake from the other end is received
virtual bool on_extension_handshake(entry const& h) virtual bool on_extension_handshake(lazy_entry const& h)
{ {
entry const* metadata_size = h.find_key("metadata_size"); m_message_index = 0;
if (metadata_size && metadata_size->type() == entry::int_t) if (h.type() != lazy_entry::dict_t) return false;
m_tp.metadata_size(metadata_size->integer()); lazy_entry const* messages = h.dict_find("m");
if (!messages || messages->type() != lazy_entry::dict_t) return false;
entry const* messages = h.find_key("m"); int index = messages->dict_find_int_value("ut_metadata", -1);
if (!messages || messages->type() != entry::dictionary_t) return false; if (index == -1) return false;
m_message_index = index;
entry const* index = messages->find_key("ut_metadata"); int metadata_size = h.dict_find_int_value("metadata_size");
if (!index || index->type() != entry::int_t) return false; if (metadata_size > 0)
m_message_index = int(index->integer()); m_tp.metadata_size(metadata_size);
return true; return true;
} }

View file

@ -196,16 +196,16 @@ namespace libtorrent { namespace
messages[extension_name] = extension_index; messages[extension_name] = extension_index;
} }
virtual bool on_extension_handshake(entry const& h) virtual bool on_extension_handshake(lazy_entry const& h)
{ {
m_message_index = 0; m_message_index = 0;
entry const* messages = h.find_key("m"); if (h.type() != lazy_entry::dict_t) return false;
if (!messages || messages->type() != entry::dictionary_t) return false; lazy_entry const* messages = h.dict_find("m");
if (!messages || messages->type() != lazy_entry::dict_t) return false;
entry const* index = messages->find_key(extension_name); int index = messages->dict_find_int_value(extension_name, -1);
if (!index || index->type() != entry::int_t) return false; if (index == -1) return false;
m_message_index = index;
m_message_index = int(index->integer());
return true; return true;
} }
@ -222,58 +222,55 @@ namespace libtorrent { namespace
if (body.left() < length) return true; if (body.left() < length) return true;
entry pex_msg = bdecode(body.begin, body.end); lazy_entry pex_msg;
if (pex_msg.type() == entry::undefined_t) int ret = lazy_bdecode(body.begin, body.end, pex_msg);
if (pex_msg.type() != lazy_entry::dict_t)
{ {
m_pc.disconnect("invalid bencoding in ut_metadata message", 2); m_pc.disconnect("invalid bencoding in ut_metadata message", 2);
return true; return true;
} }
entry const* p = pex_msg.find_key("added"); lazy_entry const* p = pex_msg.dict_find("added");
entry const* pf = pex_msg.find_key("added.f"); lazy_entry const* pf = pex_msg.dict_find("added.f");
if (p != 0 && pf != 0 && p->type() == entry::string_t && pf->type() == entry::string_t) if (p != 0
&& pf != 0
&& p->type() == lazy_entry::string_t
&& pf->type() == lazy_entry::string_t
&& pf->string_length() == p->string_length() / 6)
{ {
std::string const& peers = p->string(); int num_peers = pf->string_length();
std::string const& peer_flags = pf->string(); char const* in = p->string_ptr();
char const* fin = pf->string_ptr();
int num_peers = peers.length() / 6;
char const* in = peers.c_str();
char const* fin = peer_flags.c_str();
if (int(peer_flags.size()) != num_peers)
return true;
peer_id pid(0); peer_id pid(0);
policy& p = m_torrent.get_policy(); policy& p = m_torrent.get_policy();
for (int i = 0; i < num_peers; ++i) for (int i = 0; i < num_peers; ++i)
{ {
tcp::endpoint adr = detail::read_v4_endpoint<tcp::endpoint>(in); tcp::endpoint adr = detail::read_v4_endpoint<tcp::endpoint>(in);
char flags = detail::read_uint8(fin); char flags = *fin++;
p.peer_from_tracker(adr, pid, peer_info::pex, flags); p.peer_from_tracker(adr, pid, peer_info::pex, flags);
} }
} }
entry const* p6 = pex_msg.find_key("added6"); lazy_entry const* p6 = pex_msg.dict_find("added6");
entry const* p6f = pex_msg.find_key("added6.f"); lazy_entry const* p6f = pex_msg.dict_find("added6.f");
if (p6 && p6f && p6->type() == entry::string_t && p6f->type() == entry::string_t) if (p6 != 0
&& p6f != 0
&& p6->type() == lazy_entry::string_t
&& p6f->type() == lazy_entry::string_t
&& p6f->string_length() == p6->string_length() / 18)
{ {
std::string const& peers6 = p6->string(); int num_peers = p6f->string_length();
std::string const& peer6_flags = p6f->string(); char const* in = p6->string_ptr();
char const* fin = p6f->string_ptr();
int num_peers = peers6.length() / 18;
char const* in = peers6.c_str();
char const* fin = peer6_flags.c_str();
if (int(peer6_flags.size()) != num_peers)
return true;
peer_id pid(0); peer_id pid(0);
policy& p = m_torrent.get_policy(); policy& p = m_torrent.get_policy();
for (int i = 0; i < num_peers; ++i) for (int i = 0; i < num_peers; ++i)
{ {
tcp::endpoint adr = detail::read_v6_endpoint<tcp::endpoint>(in); tcp::endpoint adr = detail::read_v6_endpoint<tcp::endpoint>(in);
char flags = detail::read_uint8(fin); char flags = *fin++;
p.peer_from_tracker(adr, pid, peer_info::pex, flags); p.peer_from_tracker(adr, pid, peer_info::pex, flags);
} }
} }