mirror of
https://git.deluge-torrent.org/deluge
synced 2025-04-20 19:44:52 +00:00
lt sync 2486
This commit is contained in:
parent
7dde05d5a3
commit
69e24fe673
33 changed files with 748 additions and 587 deletions
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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> >();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue