lt sync 2486

This commit is contained in:
Andrew Resch 2008-07-01 21:51:16 +00:00
parent 7dde05d5a3
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"],
torrent_id + ".fastresume"),
"rb")
try:
fastresume = lt.bdecode(_file.read())
except RuntimeError, e:
log.warning("Unable to bdecode fastresume file: %s", e)
fastresume = _file.read()
_file.close()
except IOError, 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,
filedump=None, filename=None):
@ -291,7 +287,7 @@ class TorrentManager(component.Component):
options[key] = self.config[key]
add_torrent_params["ti"] = torrent_info
add_torrent_params["resume_data"] = None
add_torrent_params["resume_data"] = ""
#log.info("Adding torrent: %s", filename)
log.debug("options: %s", options)

View file

@ -4,6 +4,7 @@
#include <libtorrent/extensions.hpp>
#include <libtorrent/entry.hpp>
#include <libtorrent/lazy_entry.hpp>
#include <libtorrent/peer_request.hpp>
#include <libtorrent/disk_buffer_holder.hpp>
#include <libtorrent/bitfield.hpp>
@ -42,7 +43,7 @@ namespace
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"))
return f(e);
@ -50,7 +51,7 @@ namespace
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);
}

View file

@ -97,35 +97,38 @@ namespace
allow_threading_guard guard;
s.add_extension(invoke_extension_factory(e));
}
torrent_handle add_torrent(session& s, dict params)
{
add_torrent_params p;
if (params.has_key("ti"))
{
boost::intrusive_ptr<torrent_info> ti = new torrent_info(
extract<torrent_info const&>(params["ti"]));
p.ti = ti;
}
p.ti = new torrent_info(extract<torrent_info const&>(params["ti"]));
std::string 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();
}
if (params.has_key("info_hash"))
{
sha1_hash info_hash = extract<sha1_hash>(params["info_hash"]);
p.info_hash = info_hash;
}
p.info_hash = extract<sha1_hash>(params["info_hash"]);
std::string 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.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.paused = params["paused"];
p.auto_managed = params["auto_managed"];
@ -133,7 +136,7 @@ namespace
return s.add_torrent(p);
}
void start_natpmp(session& s)
{
allow_threading_guard guard;
@ -147,7 +150,7 @@ namespace
s.start_upnp();
return;
}
list get_torrents(session& s)
{
list ret;
@ -334,6 +337,9 @@ void bind_session()
.def("set_ip_filter", allow_threads(&session::set_ip_filter), session_set_ip_filter_doc)
.def("find_torrent", allow_threads(&session::find_torrent))
.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> >();

View file

@ -189,6 +189,10 @@ namespace libtorrent
, int nat_transport);
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_port_filter(port_filter const& f);
@ -454,6 +458,9 @@ namespace libtorrent
// should exit
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
int m_max_uploads;

View file

@ -389,7 +389,7 @@ private:
// initialized during write_pe1_2_dhkey, and destroyed on
// creation of m_RC4_handler. Cannot reinitialize once
// 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
// encryption/decryption during the entire session. Destroyed

View file

@ -56,6 +56,7 @@ namespace libtorrent
struct peer_request;
class peer_connection;
class entry;
struct lazy_entry;
struct disk_buffer_holder;
struct bitfield;
@ -107,7 +108,7 @@ namespace libtorrent
// supported by this peer. It will result in this peer_plugin
// being removed from the peer_connection and destructed.
// 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
// indicates that the plugin has handeled the message.

View file

@ -34,7 +34,8 @@ POSSIBILITY OF SUCH DAMAGE.
#define TORRENT_FILE_HPP_INCLUDED
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>
#ifdef _MSC_VER
#pragma warning(push, 1)
@ -54,11 +55,6 @@ namespace libtorrent
{
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
{
public:

View file

@ -170,7 +170,7 @@ namespace libtorrent
return m_size;
}
// end points one byte passed end
// end points one byte passed last byte
void set_end(char const* end)
{
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
#include <algorithm>

View file

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

View file

@ -202,8 +202,6 @@ namespace libtorrent
void set_upload_only(bool u) { m_upload_only = u; }
bool upload_only() const { return m_upload_only; }
bool has_timed_out() const;
// will send a keep-alive message to the peer
void keep_alive();
@ -569,6 +567,12 @@ namespace libtorrent
ptime m_last_receive;
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
// was last updated
ptime m_remote_dl_update;
@ -825,6 +829,11 @@ namespace libtorrent
// set to true when this peer is only uploading
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
public:
bool m_in_constructor:1;

View file

@ -56,7 +56,8 @@ namespace libtorrent
queued = 0x100,
on_parole = 0x200,
seed = 0x400,
optimistic_unchoke = 0x800
optimistic_unchoke = 0x800,
snubbed = 0x1000
#ifndef TORRENT_DISABLE_ENCRYPTION
, rc4_encrypted = 0x100000,
plaintext_encrypted = 0x200000
@ -105,6 +106,10 @@ namespace libtorrent
// time since last download or upload
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
int send_buffer_size;
// the number bytes that's actually used of the send buffer

View file

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

View file

@ -88,6 +88,7 @@ namespace libtorrent
, stop_tracker_timeout(5)
, tracker_maximum_response_length(1024*1024)
, piece_timeout(10)
, request_timeout(40)
, request_queue_time(3.f)
, max_allowed_in_request_queue(250)
, max_out_request_queue(200)
@ -168,6 +169,11 @@ namespace libtorrent
// it times out if no piece response is returned.
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
// of seconds it should take for the other end to send
// 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;
// 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
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; }
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);
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;
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); }
bool is_allocating() const
@ -282,7 +282,7 @@ namespace libtorrent
// the error message indicates that the fast resume data was rejected
// if 'fatal_disk_error' is returned, the error message indicates what
// 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
int check_files(int& current_slot, int& have_piece, std::string& error);

View file

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

View file

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

View file

@ -192,6 +192,7 @@ namespace libtorrent
if (out_enc_policy == pe_settings::forced)
{
write_pe1_2_dhkey();
if (is_disconnecting()) return;
m_state = read_pe_dhkey;
reset_recv_buffer(dh_key_len);
@ -214,6 +215,7 @@ namespace libtorrent
fast_reconnect(true);
write_pe1_2_dhkey();
if (is_disconnecting()) return;
m_state = read_pe_dhkey;
reset_recv_buffer(dh_key_len);
setup_receive();
@ -372,7 +374,7 @@ namespace libtorrent
TORRENT_ASSERT(!m_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);
#ifdef TORRENT_VERBOSE_LOGGING
@ -380,7 +382,12 @@ namespace libtorrent
(*m_logger) << " initiating encrypted handshake\n";
#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;
@ -389,11 +396,15 @@ namespace libtorrent
#endif
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(),
m_DH_key_exchange->get_local_key() + dh_key_len,
send_buf.begin);
std::copy(m_dh_key_exchange->get_local_key(),
m_dh_key_exchange->get_local_key() + dh_key_len,
send_buf.begin);
std::generate(send_buf.begin + dh_key_len, send_buf.end, std::rand);
setup_send();
@ -417,7 +428,7 @@ namespace libtorrent
hasher h;
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;
@ -452,7 +463,7 @@ namespace libtorrent
// Discard DH key exchange data, setup RC4 keys
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
TORRENT_ASSERT(send_buf.left() == 8 + 4 + 2 + pad_size + 2);
@ -1235,9 +1246,9 @@ namespace libtorrent
buffer::const_interval recv_buffer = receive_buffer();
entry root;
root = bdecode(recv_buffer.begin + 2, recv_buffer.end);
if (root.type() == entry::undefined_t)
lazy_entry root;
lazy_bdecode(recv_buffer.begin + 2, recv_buffer.end, root);
if (root.type() != lazy_entry::dict_t)
{
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << "invalid extended handshake\n";
@ -1246,14 +1257,12 @@ namespace libtorrent
}
#ifdef TORRENT_VERBOSE_LOGGING
std::stringstream ext;
root.print(ext);
(*m_logger) << "<== EXTENDED HANDSHAKE: \n" << ext.str();
(*m_logger) << "<== EXTENDED HANDSHAKE: \n" << root;
#endif
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end;)
for (extension_list_t::iterator i = m_extensions.begin();
!m_extensions.empty() && i != m_extensions.end();)
{
// a false return value means that the extension
// isn't supported by the other end. So, it is removed.
@ -1265,56 +1274,39 @@ namespace libtorrent
#endif
// 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
&& peer_info_struct() != 0)
{
t->get_policy().update_peer_port(int(listen_port->integer())
, peer_info_struct(), peer_info::incoming);
}
t->get_policy().update_peer_port(listen_port
, peer_info_struct(), peer_info::incoming);
}
// there should be a version too
// but where do we put that info?
if (entry* client_info = root.find_key("v"))
{
if (client_info->type() == entry::string_t)
m_client_version = client_info->string();
}
std::string client_info = root.dict_find_string_value("v");
if (!client_info.empty()) m_client_version = client_info;
if (entry* reqq = root.find_key("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;
}
int reqq = root.dict_find_int_value("reqq");
if (reqq > 0) m_max_out_request_queue = reqq;
if (entry* upload_only = root.find_key("upload_only"))
{
if (upload_only->type() == entry::int_t && upload_only->integer() != 0)
set_upload_only(true);
}
if (root.dict_find_int_value("upload_only"))
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
if (myip->type() == entry::string_t)
if (myip.size() == address_v4::bytes_type::static_size)
{
std::string const& my_ip = myip->string().c_str();
if (my_ip.size() == address_v4::bytes_type::static_size)
{
address_v4::bytes_type bytes;
std::copy(my_ip.begin(), my_ip.end(), bytes.begin());
m_ses.set_external_address(address_v4(bytes));
}
else if (my_ip.size() == address_v6::bytes_type::static_size)
{
address_v6::bytes_type bytes;
std::copy(my_ip.begin(), my_ip.end(), bytes.begin());
m_ses.set_external_address(address_v6(bytes));
}
address_v4::bytes_type bytes;
std::copy(myip.begin(), myip.end(), bytes.begin());
m_ses.set_external_address(address_v4(bytes));
}
else if (myip.size() == address_v6::bytes_type::static_size)
{
address_v6::bytes_type bytes;
std::copy(myip.begin(), myip.end(), bytes.begin());
m_ses.set_external_address(address_v6(bytes));
}
}
@ -1752,13 +1744,17 @@ namespace libtorrent
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()
if (!is_local())
write_pe1_2_dhkey();
if (!is_local()) write_pe1_2_dhkey();
if (is_disconnecting()) return;
// 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
(*m_logger) << " received DH key\n";
@ -1822,7 +1818,7 @@ namespace libtorrent
// compute synchash (hash('req1',S))
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()));
}
@ -1895,7 +1891,7 @@ namespace libtorrent
h.reset();
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 ^= skey_hash;
@ -1912,7 +1908,7 @@ namespace libtorrent
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
(*m_logger) << " stream key found, torrent located.\n";
#endif
@ -2641,7 +2637,7 @@ namespace libtorrent
void bt_peer_connection::check_invariant() const
{
#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());
TORRENT_ASSERT(!m_rc4_encrypted || m_RC4_handler.get());

View file

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

View file

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

View file

@ -81,11 +81,10 @@ namespace
virtual void add_handshake(entry&) {}
// 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();
m_file << "<== EXTENSION_HANDSHAKE\n";
h.print(m_file);
m_file << "<== EXTENSION_HANDSHAKE\n" << h;
return true;
}

View file

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

View file

@ -42,29 +42,46 @@ POSSIBILITY OF SUCH DAMAGE.
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
DH_key_exchange::DH_key_exchange()
dh_key_exchange::dh_key_exchange()
{
m_DH = DH_new();
if (m_DH == 0) throw std::bad_alloc();
m_dh = DH_new();
if (m_dh == 0) return;
m_DH->p = BN_bin2bn(m_dh_prime, sizeof(m_dh_prime), NULL);
m_DH->g = BN_bin2bn(m_dh_generator, sizeof(m_dh_generator), NULL);
if (m_DH->p == 0 || m_DH->g == 0)
m_dh->p = BN_bin2bn(dh_prime, sizeof(dh_prime), 0);
m_dh->g = BN_bin2bn(dh_generator, sizeof(dh_generator), 0);
if (m_dh->p == 0 || m_dh->g == 0)
{
DH_free(m_DH);
throw std::bad_alloc();
DH_free(m_dh);
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);
throw std::bad_alloc();
DH_free(m_dh);
m_dh = 0;
return;
}
// 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
// appropriately.
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)
{
TORRENT_ASSERT(key_size > 0 && key_size < len_dh);
int pad_zero_size = len_dh - key_size;
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
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);
DH_free(m_DH);
if (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;
}
// 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);
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];
int secret_size = DH_compute_key((unsigned char*)dh_secret
, bn_remote_pubkey, m_DH);
if (secret_size < 0 || secret_size > 96) throw std::bad_alloc();
, bn_remote_pubkey, m_dh);
if (secret_size < 0 || secret_size > 96) return -1;
if (secret_size != 96)
{
@ -116,26 +144,14 @@ namespace libtorrent
}
std::copy(dh_secret, dh_secret + secret_size, m_dh_secret + 96 - secret_size);
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;
}
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
#endif // #ifndef TORRENT_DISABLE_ENCRYPTION

View file

@ -81,6 +81,7 @@ namespace libtorrent
, m_last_unchoke(min_time())
, m_last_receive(time_now())
, m_last_sent(time_now())
, m_requested(min_time())
, m_remote_dl_update(time_now())
, m_became_uninterested(time_now())
, m_became_uninteresting(time_now())
@ -126,6 +127,7 @@ namespace libtorrent
, m_queued(true)
, m_request_large_blocks(false)
, m_upload_only(false)
, m_snubbed(false)
#ifndef NDEBUG
, m_in_constructor(true)
#endif
@ -166,7 +168,7 @@ namespace libtorrent
// incoming connection
peer_connection::peer_connection(
session_impl& ses
, boost::shared_ptr<socket_type> s
, shared_ptr<socket_type> s
, tcp::endpoint const& endp
, policy::peer* peerinfo)
:
@ -182,6 +184,7 @@ namespace libtorrent
, m_last_unchoke(min_time())
, m_last_receive(time_now())
, m_last_sent(time_now())
, m_requested(min_time())
, m_remote_dl_update(time_now())
, m_became_uninterested(time_now())
, m_became_uninteresting(time_now())
@ -226,6 +229,7 @@ namespace libtorrent
, m_queued(false)
, m_request_large_blocks(false)
, m_upload_only(false)
, m_snubbed(false)
#ifndef NDEBUG
, m_in_constructor(true)
#endif
@ -1433,7 +1437,7 @@ namespace libtorrent
{
disconnect("out of memory");
return;
}
}
disk_buffer_holder holder(m_ses, buffer);
std::memcpy(buffer, data, p.length);
incoming_piece(p, holder);
@ -1562,12 +1566,19 @@ namespace libtorrent
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 (picker.is_downloaded(block_finished))
{
t->received_redundant_data(p.length);
m_download_queue.erase(b);
if (!m_download_queue.empty())
m_requested = time_now();
request_a_block(*t, *this);
send_block_requests();
return;
@ -1579,6 +1590,9 @@ namespace libtorrent
TORRENT_ASSERT(m_channel_state[download_channel] == peer_info::bw_idle);
m_download_queue.erase(b);
if (!m_download_queue.empty())
m_requested = time_now();
// did we request this block from any other peers?
bool multi = picker.num_peers(block_finished) > 1;
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;
bool empty_download_queue = m_download_queue.empty();
while (!m_request_queue.empty()
&& (int)m_download_queue.size() < m_desired_queue_size)
{
@ -2166,6 +2182,13 @@ namespace libtorrent
#endif
}
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()
@ -2321,6 +2344,8 @@ namespace libtorrent
{
TORRENT_ASSERT(!associated_torrent().expired());
ptime now = time_now();
p.download_rate_peak = m_download_rate_peak;
p.upload_rate_peak = m_upload_rate_peak;
p.rtt = m_rtt;
@ -2333,6 +2358,8 @@ namespace libtorrent
p.pending_disk_bytes = m_outstanding_writing_bytes;
p.send_quota = m_bandwidth_limit[upload_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
p.inet_as_name = m_inet_as_name;
#endif
@ -2377,7 +2404,6 @@ namespace libtorrent
}
p.pieces = get_bitfield();
ptime now = time_now();
p.last_request = now - m_last_request;
p.last_active = now - (std::max)(m_last_sent, m_last_receive);
@ -2386,6 +2412,7 @@ namespace libtorrent
get_specific_peer_info(p);
p.flags |= is_seed() ? peer_info::seed : 0;
p.flags |= m_snubbed ? peer_info::snubbed : 0;
if (peer_info_struct())
{
policy::peer* pi = peer_info_struct();
@ -2483,11 +2510,13 @@ namespace libtorrent
void peer_connection::second_tick(float tick_interval)
{
INVARIANT_CHECK;
ptime now(time_now());
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();
if (!t || m_disconnecting)
{
@ -2505,8 +2534,103 @@ namespace libtorrent
{
(*i)->tick();
}
if (is_disconnecting()) return;
#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
&& on_local_network();
@ -2544,12 +2668,19 @@ namespace libtorrent
? t->torrent_file().piece_length() : t->block_size();
TORRENT_ASSERT(block_size > 0);
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_snubbed)
{
m_desired_queue_size = 1;
}
else
{
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()
&& now - m_last_piece > seconds(m_ses.settings().piece_timeout))
@ -2564,6 +2695,9 @@ namespace libtorrent
<< " " << total_seconds(now - m_last_piece) << "] ***\n";
#endif
m_snubbed = true;
m_desired_queue_size = 1;
if (t->is_seed())
{
m_download_queue.clear();
@ -3521,94 +3655,6 @@ namespace libtorrent
}
#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()
{
shared_ptr<torrent> t = m_torrent.lock();

View file

@ -257,7 +257,12 @@ namespace libtorrent
add_torrent_params p(sc);
p.ti = tip;
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.paused = paused;
return m_impl->add_torrent(p);
@ -275,7 +280,12 @@ namespace libtorrent
add_torrent_params p(sc);
p.ti = ti;
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.paused = paused;
p.userdata = userdata;
@ -324,6 +334,10 @@ namespace libtorrent
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
, 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_interface(address::from_string(listen_interface), listen_port_range.first)
, m_abort(false)
, m_paused(false)
, m_max_uploads(8)
, m_allowed_upload_slots(8)
, m_max_connections(200)
@ -389,6 +390,32 @@ namespace aux {
}
#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()
{
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
// --------------------------------------------------------------
@ -1389,7 +1390,6 @@ namespace aux {
&& t->state() != torrent_status::checking_files)
{
--num_downloaders;
--num_seeds;
if (t->is_paused()) t->resume();
}
}
@ -1412,7 +1412,6 @@ namespace aux {
if (num_seeds > 0 && hard_limit > 0)
{
--hard_limit;
--num_downloaders;
--num_seeds;
if (t->is_paused()) t->resume();
}

View file

@ -422,7 +422,7 @@ namespace libtorrent
bool move_slot(int src_slot, int dst_slot);
bool swap_slots(int slot1, int slot2);
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;
sha1_hash hash_for_slot(int slot, partial_hash& ph, int piece_size);
@ -685,34 +685,32 @@ namespace libtorrent
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)";
return true;
}
std::vector<std::pair<size_type, std::time_t> > file_sizes;
entry const* file_sizes_ent = rd.find_key("file sizes");
if (file_sizes_ent == 0 || file_sizes_ent->type() != entry::list_t)
lazy_entry const* file_sizes_ent = rd.dict_find_list("file sizes");
if (file_sizes_ent == 0)
{
error = "missing or invalid 'file sizes' entry in resume data";
return false;
}
entry::list_type const& l = file_sizes_ent->list();
for (entry::list_type::const_iterator i = l.begin();
i != l.end(); ++i)
for (int i = 0; i < file_sizes_ent->list_size(); ++i)
{
if (i->type() != entry::list_t) break;
entry::list_type const& pair = i->list();
if (pair.size() != 2 || pair.front().type() != entry::int_t
|| pair.back().type() != entry::int_t)
break;
lazy_entry const* e = file_sizes_ent->list_at(i);
if (e->type() != lazy_entry::list_t
|| e->list_size() != 2
|| e->list_at(0)->type() != lazy_entry::int_t
|| e->list_at(1)->type() != lazy_entry::int_t)
continue;
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())
@ -721,32 +719,38 @@ namespace libtorrent
return false;
}
entry const* slots_ent = rd.find_key("slots");
if (slots_ent == 0 || slots_ent->type() != entry::list_t)
lazy_entry const* slots = rd.dict_find_list("slots");
if (slots == 0)
{
error = "missing or invalid 'slots' entry in resume data";
return false;
}
entry::list_type const& slots = slots_ent->list();
bool seed = int(slots.size()) == m_files.num_pieces()
&& std::find_if(slots.begin(), slots.end()
, boost::bind<bool>(std::less<int>()
, boost::bind((size_type const& (entry::*)() const)
&entry::integer, _1), 0)) == slots.end();
bool seed = false;
if (int(slots->list_size()) == m_files.num_pieces())
{
bool seed = true;
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;
entry const* allocation_mode = rd.find_key("allocation");
if (allocation_mode && allocation_mode->type() == entry::string_t)
full_allocation_mode = allocation_mode->string() == "full";
if (rd.dict_find_string_value("allocation") == "full")
full_allocation_mode = true;
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: "
+ 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;
}
@ -1300,7 +1304,7 @@ namespace libtorrent
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)
{
TORRENT_ASSERT(resume_data != 0);
@ -1783,7 +1787,7 @@ namespace libtorrent
// isn't return false and the full check
// will be run
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);
@ -1792,29 +1796,25 @@ namespace libtorrent
TORRENT_ASSERT(m_files.piece_length() > 0);
// 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);
}
int block_size = (std::min)(16 * 1024, m_files.piece_length());
entry const* blocks_per_piece_ent = rd.find_key("blocks per piece");
if (blocks_per_piece_ent != 0
&& blocks_per_piece_ent->type() == entry::int_t
&& blocks_per_piece_ent->integer() != m_files.piece_length() / block_size)
int blocks_per_piece = rd.dict_find_int_value("blocks per piece", -1);
if (blocks_per_piece != -1
&& blocks_per_piece != m_files.piece_length() / block_size)
{
error = "invalid 'blocks per piece' entry";
return check_no_fastresume(error);
}
storage_mode_t storage_mode = storage_mode_compact;
entry const* allocation = rd.find_key("allocation");
if (allocation != 0
&& allocation->type() == entry::string_t
&& allocation->string() != "compact")
if (rd.dict_find_string_value("allocation") != "compact")
storage_mode = storage_mode_sparse;
// 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'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
entry const* slots = rd.find_key("slots");
if (slots == 0 || slots->type() != entry::list_t)
lazy_entry const* slots = rd.dict_find_list("slots");
if (slots == 0)
{
error = "missing slot list";
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: "
+ 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()) + " )";
return check_no_fastresume(error);
}
@ -1846,17 +1846,16 @@ namespace libtorrent
int num_pieces = int(m_files.num_pieces());
m_slot_to_piece.resize(num_pieces, unallocated);
m_piece_to_slot.resize(num_pieces, has_no_slot);
int slot = 0;
for (entry::list_type::const_iterator i = slots->list().begin();
i != slots->list().end(); ++i, ++slot)
for (int i = 0; i < slots->list_size(); ++i)
{
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";
return check_no_fastresume(error);
}
int index = int(i->integer());
int index = int(e->int_value());
if (index >= num_pieces || index < -2)
{
error = "too high index number in slot map (index: "
@ -1866,37 +1865,36 @@ namespace libtorrent
}
if (index >= 0)
{
m_slot_to_piece[slot] = index;
m_piece_to_slot[index] = slot;
if (slot != index) out_of_place = true;
m_slot_to_piece[i] = index;
m_piece_to_slot[index] = i;
if (i != index) out_of_place = true;
}
else if (index == unassigned)
{
if (m_storage_mode == storage_mode_compact)
m_free_slots.push_back(slot);
m_free_slots.push_back(i);
}
else
{
TORRENT_ASSERT(index == unallocated);
if (m_storage_mode == storage_mode_compact)
m_unallocated_slots.push_back(slot);
m_unallocated_slots.push_back(i);
}
}
}
else
{
int slot = 0;
for (entry::list_type::const_iterator i = slots->list().begin();
i != slots->list().end(); ++i, ++slot)
for (int i = 0; i < slots->list_size(); ++i)
{
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";
return check_no_fastresume(error);
}
int index = int(i->integer());
if (index != slot && index >= 0)
int index = int(e->int_value());
if (index != i && index >= 0)
{
error = "invalid slot index";
return check_no_fastresume(error);
@ -1937,17 +1935,17 @@ namespace libtorrent
else if (m_storage_mode == storage_mode_compact)
{
// read piece map
entry const* pieces = rd.find_key("pieces");
if (pieces == 0 || pieces->type() != entry::string_t)
lazy_entry const* pieces = rd.dict_find("pieces");
if (pieces == 0 || pieces->type() != lazy_entry::string_t)
{
error = "missing pieces entry";
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: "
+ 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()) + " )";
return check_no_fastresume(error);
}
@ -1955,7 +1953,7 @@ namespace libtorrent
int num_pieces = int(m_files.num_pieces());
m_slot_to_piece.resize(num_pieces, unallocated);
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)
{
if (have_pieces[i] & 1)

View file

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

View file

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

View file

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

View file

@ -235,18 +235,20 @@ namespace libtorrent { namespace
}
// 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");
if (metadata_size && metadata_size->type() == entry::int_t)
m_tp.metadata_size(metadata_size->integer());
m_message_index = 0;
if (h.type() != lazy_entry::dict_t) return false;
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");
if (!messages || messages->type() != entry::dictionary_t) return false;
int index = messages->dict_find_int_value("ut_metadata", -1);
if (index == -1) return false;
m_message_index = index;
entry const* index = messages->find_key("ut_metadata");
if (!index || index->type() != entry::int_t) return false;
m_message_index = int(index->integer());
int metadata_size = h.dict_find_int_value("metadata_size");
if (metadata_size > 0)
m_tp.metadata_size(metadata_size);
return true;
}

View file

@ -196,16 +196,16 @@ namespace libtorrent { namespace
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;
entry const* messages = h.find_key("m");
if (!messages || messages->type() != entry::dictionary_t) return false;
if (h.type() != lazy_entry::dict_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);
if (!index || index->type() != entry::int_t) return false;
m_message_index = int(index->integer());
int index = messages->dict_find_int_value(extension_name, -1);
if (index == -1) return false;
m_message_index = index;
return true;
}
@ -222,58 +222,55 @@ namespace libtorrent { namespace
if (body.left() < length) return true;
entry pex_msg = bdecode(body.begin, body.end);
if (pex_msg.type() == entry::undefined_t)
lazy_entry pex_msg;
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);
return true;
}
entry const* p = pex_msg.find_key("added");
entry const* pf = pex_msg.find_key("added.f");
lazy_entry const* p = pex_msg.dict_find("added");
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();
std::string const& peer_flags = pf->string();
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;
int num_peers = pf->string_length();
char const* in = p->string_ptr();
char const* fin = pf->string_ptr();
peer_id pid(0);
policy& p = m_torrent.get_policy();
for (int i = 0; i < num_peers; ++i)
{
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);
}
}
entry const* p6 = pex_msg.find_key("added6");
entry const* p6f = pex_msg.find_key("added6.f");
if (p6 && p6f && p6->type() == entry::string_t && p6f->type() == entry::string_t)
lazy_entry const* p6 = pex_msg.dict_find("added6");
lazy_entry const* p6f = pex_msg.dict_find("added6.f");
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();
std::string const& peer6_flags = p6f->string();
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;
int num_peers = p6f->string_length();
char const* in = p6->string_ptr();
char const* fin = p6f->string_ptr();
peer_id pid(0);
policy& p = m_torrent.get_policy();
for (int i = 0; i < num_peers; ++i)
{
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);
}
}